Skip to content

Commit 1fd8d5f

Browse files
committed
chore: configure automatic screenshots
1 parent c6b95f2 commit 1fd8d5f

File tree

5 files changed

+261
-3
lines changed

5 files changed

+261
-3
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
name: "Android Screenshots Workflow"
2+
3+
inputs:
4+
ANDROID_EMULATOR_API:
5+
description: 'Emulator API to be used when running tests'
6+
required: false
7+
default: 34
8+
ANDROID_EMULATOR_ARCH:
9+
description: 'Emulator architecture to be used when running tests'
10+
required: false
11+
default: x86_64
12+
13+
runs:
14+
using: "composite"
15+
steps:
16+
- name: Enable KVM group perms
17+
shell: bash
18+
run: |
19+
echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules
20+
sudo udevadm control --reload-rules
21+
sudo udevadm trigger --name-match=kvm
22+
- name: Cache AVD
23+
uses: actions/cache@v4
24+
id: avd-cache
25+
with:
26+
path: |
27+
~/.android/avd/*
28+
~/.android/adb*
29+
key: avd-${{ inputs.ANDROID_EMULATOR_API }}-${{ inputs.ANDROID_EMULATOR_ARCH }}
30+
31+
- name: Create AVD and Cache Snapshot
32+
if: steps.avd-cache.outputs.cache-hit != 'true'
33+
uses: reactivecircus/android-emulator-runner@v2
34+
with:
35+
api-level: ${{ inputs.ANDROID_EMULATOR_API }}
36+
arch: ${{ inputs.ANDROID_EMULATOR_ARCH }}
37+
profile: pixel_6
38+
avd-name: pixel_6
39+
force-avd-creation: false
40+
emulator-options: -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none
41+
disable-animations: false
42+
script: echo "Generated AVD snapshot for caching."
43+
44+
- name: Create Android Screenshots
45+
uses: reactivecircus/android-emulator-runner@v2
46+
with:
47+
api-level: ${{ inputs.ANDROID_EMULATOR_API }}
48+
arch: ${{ inputs.ANDROID_EMULATOR_ARCH }}
49+
profile: pixel_6
50+
avd-name: pixel_6
51+
force-avd-creation: false
52+
emulator-options: -no-snapshot-save -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none
53+
disable-animations: true
54+
script: |
55+
bundle exec fastlane screengrab
56+
if [[ $? -ne 0 ]]; then
57+
exit 1
58+
fi

.github/workflows/release.yml

+10-3
Original file line numberDiff line numberDiff line change
@@ -41,20 +41,27 @@ jobs:
4141
read -r version_code < versionCode.txt
4242
echo "VERSION_CODE=$version_code" >> $GITHUB_OUTPUT
4343
44-
- name: Add Changelogs to fastlane branch
45-
run: |
4644
git config --global user.name "github-actions[bot]"
4745
git config --global user.email "41898282+github-actions[bot]@users.noreply.github.com"
4846
4947
git clone --branch=fastlane --depth=1 https://${{ github.repository_owner }}:${{ github.token }}@github.com/${{ github.repository }} fastlane
48+
49+
- name: Android Screenshot Workflow
50+
uses: ./.github/actions/screenshot-android
51+
with:
52+
ANDROID_EMULATOR_API: ${{ env.ANDROID_EMULATOR_API }}
53+
ANDROID_EMULATOR_ARCH: ${{ env.ANDROID_EMULATOR_ARCH }}
54+
55+
- name: Add Changelogs to fastlane branch
56+
run: |
5057
cd fastlane
5158
5259
echo "${{ github.event.release.body }}" > metadata/android/en-US/changelogs/${{ steps.download-assets.outputs.VERSION_CODE }}.txt
5360
5461
# Force push to fastlane branch
5562
git checkout --orphan temporary
5663
git add --all .
57-
git commit -am "[Auto] Add changelogs for versionCode: ${{ steps.download-assets.outputs.VERSION_CODE }} ($(date +%Y-%m-%d.%H:%M:%S))"
64+
git commit -am "[Auto] Update metadata for versionCode: ${{ steps.download-assets.outputs.VERSION_CODE }} ($(date +%Y-%m-%d.%H:%M:%S))"
5865
git branch -D fastlane
5966
git branch -m fastlane
6067
git push --force origin fastlane

app/build.gradle.kts

+6
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ android {
1818
versionCode = System.getenv("VERSION_CODE")?.toInt() ?: 1
1919
versionName = System.getenv("VERSION_NAME") ?: "1.0.0"
2020
resConfigs("en","ru","ar","si","pl")
21+
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
2122
}
2223

2324
signingConfigs {
@@ -97,6 +98,11 @@ dependencies {
9798

9899
// OKHTTP
99100
implementation("com.squareup.okhttp3:okhttp:4.12.0")
101+
androidTestImplementation("tools.fastlane:screengrab:2.1.1")
102+
androidTestImplementation("androidx.test.espresso:espresso-core:3.6.1")
103+
androidTestImplementation("androidx.test.ext:junit:1.2.1")
104+
androidTestImplementation("androidx.test.espresso:espresso-contrib:3.6.1")
105+
androidTestImplementation("androidx.test:rules:1.6.1")
100106

101107
// ButterKnife
102108
val butterKnifeVersion = "10.2.3"
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,183 @@
1+
package io.pslab.activity;
2+
3+
4+
import static androidx.test.espresso.Espresso.onView;
5+
import static androidx.test.espresso.action.ViewActions.*;
6+
import static androidx.test.espresso.contrib.RecyclerViewActions.actionOnItemAtPosition;
7+
import static androidx.test.espresso.matcher.ViewMatchers.*;
8+
import static org.hamcrest.Matchers.allOf;
9+
import static org.hamcrest.Matchers.is;
10+
11+
import android.view.View;
12+
import android.view.ViewGroup;
13+
import android.view.ViewParent;
14+
15+
import androidx.test.espresso.Espresso;
16+
import androidx.test.ext.junit.rules.ActivityScenarioRule;
17+
18+
import tools.fastlane.screengrab.FalconScreenshotStrategy;
19+
import tools.fastlane.screengrab.Screengrab;
20+
import tools.fastlane.screengrab.locale.LocaleTestRule;
21+
22+
import androidx.test.ext.junit.runners.AndroidJUnit4;
23+
import androidx.test.filters.LargeTest;
24+
import androidx.test.rule.GrantPermissionRule;
25+
26+
import org.hamcrest.Description;
27+
import org.hamcrest.Matcher;
28+
import org.hamcrest.TypeSafeMatcher;
29+
import org.junit.ClassRule;
30+
import org.junit.Rule;
31+
import org.junit.Test;
32+
import org.junit.runner.RunWith;
33+
34+
import io.pslab.R;
35+
36+
@LargeTest
37+
@RunWith(AndroidJUnit4.class)
38+
public class ScreenshotsTest {
39+
40+
@ClassRule
41+
public static final LocaleTestRule localeTestRule = new LocaleTestRule();
42+
43+
@Rule
44+
public ActivityScenarioRule<MainActivity> mActivityScenarioRule =
45+
new ActivityScenarioRule<>(MainActivity.class);
46+
47+
@Rule
48+
public GrantPermissionRule mGrantPermissionRule =
49+
GrantPermissionRule.grant(
50+
"android.permission.ACCESS_FINE_LOCATION",
51+
"android.permission.RECORD_AUDIO",
52+
"android.permission.WRITE_EXTERNAL_STORAGE");
53+
54+
@Test
55+
public void testTakeScreenshot() {
56+
mActivityScenarioRule.getScenario().onActivity(activity -> Screengrab.setDefaultScreenshotStrategy(new FalconScreenshotStrategy(activity)));
57+
58+
Screengrab.screenshot("dashboard");
59+
60+
onView(
61+
allOf(withContentDescription("open_drawer"),
62+
childAtPosition(
63+
allOf(withId(R.id.toolbar),
64+
childAtPosition(
65+
withClassName(is("com.google.android.material.appbar.AppBarLayout")),
66+
0)),
67+
1),
68+
isDisplayed())).perform(click());
69+
70+
Screengrab.screenshot("drawer");
71+
72+
Espresso.pressBack();
73+
74+
onView(
75+
allOf(withId(R.id.applications_recycler_view),
76+
childAtPosition(
77+
withClassName(is("android.widget.RelativeLayout")),
78+
0))).perform(actionOnItemAtPosition(7, click()));
79+
80+
Screengrab.screenshot("instrument_accelerometer_view");
81+
82+
Espresso.pressBack();
83+
84+
onView(
85+
allOf(withId(R.id.applications_recycler_view),
86+
childAtPosition(
87+
withClassName(is("android.widget.RelativeLayout")),
88+
0))).perform(actionOnItemAtPosition(8, click()));
89+
90+
Screengrab.screenshot("instrument_barometer_view");
91+
92+
Espresso.pressBack();
93+
94+
onView(
95+
allOf(withId(R.id.applications_recycler_view),
96+
childAtPosition(
97+
withClassName(is("android.widget.RelativeLayout")),
98+
0))).perform(actionOnItemAtPosition(1, click()));
99+
100+
Screengrab.screenshot("instrument_multimeter_view");
101+
102+
Espresso.pressBack();
103+
104+
onView(
105+
allOf(withId(R.id.applications_recycler_view),
106+
childAtPosition(
107+
withClassName(is("android.widget.RelativeLayout")),
108+
0))).perform(actionOnItemAtPosition(2, click()));
109+
110+
Screengrab.screenshot("logic_analyzer_view");
111+
112+
Espresso.pressBack();
113+
114+
onView(
115+
allOf(withContentDescription("More options"),
116+
childAtPosition(
117+
childAtPosition(
118+
withId(R.id.toolbar),
119+
2),
120+
1),
121+
isDisplayed())).perform(click());
122+
123+
onView(
124+
allOf(withId(me.zhanghai.android.materialprogressbar.R.id.title), withText("Pin Layout Front"),
125+
childAtPosition(
126+
childAtPosition(
127+
withId(R.id.content),
128+
0),
129+
0),
130+
isDisplayed())).perform(click());
131+
132+
Screengrab.screenshot("layout_pin_front");
133+
134+
onView(
135+
allOf(withContentDescription("open_drawer"),
136+
childAtPosition(
137+
allOf(withId(R.id.toolbar),
138+
childAtPosition(
139+
withClassName(is("com.google.android.material.appbar.AppBarLayout")),
140+
0)),
141+
1),
142+
isDisplayed())).perform(click());
143+
144+
onView(
145+
allOf(withId(R.id.nav_instruments),
146+
childAtPosition(
147+
allOf(withId(com.google.android.material.R.id.design_navigation_view),
148+
childAtPosition(
149+
withId(R.id.nav_view),
150+
0)),
151+
1),
152+
isDisplayed())).perform(click());
153+
154+
onView(
155+
allOf(withId(R.id.applications_recycler_view),
156+
childAtPosition(
157+
withClassName(is("android.widget.RelativeLayout")),
158+
0))).perform(actionOnItemAtPosition(0, click()));
159+
160+
Screengrab.screenshot("oscilloscope_channel_view");
161+
162+
Espresso.pressBack();
163+
}
164+
165+
private static Matcher<View> childAtPosition(
166+
final Matcher<View> parentMatcher, final int position) {
167+
168+
return new TypeSafeMatcher<View>() {
169+
@Override
170+
public void describeTo(Description description) {
171+
description.appendText("Child at position " + position + " in parent ");
172+
parentMatcher.describeTo(description);
173+
}
174+
175+
@Override
176+
public boolean matchesSafely(View view) {
177+
ViewParent parent = view.getParent();
178+
return parent instanceof ViewGroup && parentMatcher.matches(parent)
179+
&& view.equals(((ViewGroup) parent).getChildAt(position));
180+
}
181+
};
182+
}
183+
}

app/src/main/AndroidManifest.xml

+4
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,10 @@
1313
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
1414
<uses-permission android:name="android.permission.HIGH_SAMPLING_RATE_SENSORS"
1515
tools:ignore="HighSamplingRate" />
16+
<uses-permission android:name="android.permission.DISABLE_KEYGUARD"/>
17+
<uses-permission android:name="android.permission.WAKE_LOCK"/>
18+
<uses-permission android:name="android.permission.CHANGE_CONFIGURATION"/>
19+
<uses-permission android:name="android.permission.DUMP"/>
1620

1721
<uses-feature
1822
android:name="android.hardware.sensor.light"

0 commit comments

Comments
 (0)