4
4
5
5
package io .flutter .plugins .quickactionsexample ;
6
6
7
- import static org .junit .Assert .assertTrue ;
7
+ import static org .junit .Assert .* ;
8
8
9
+ import android .content .Context ;
10
+ import android .content .pm .ShortcutInfo ;
11
+ import android .content .pm .ShortcutManager ;
12
+ import android .util .Log ;
13
+ import androidx .lifecycle .Lifecycle ;
9
14
import androidx .test .core .app .ActivityScenario ;
15
+ import androidx .test .core .app .ApplicationProvider ;
16
+ import androidx .test .ext .junit .runners .AndroidJUnit4 ;
17
+ import androidx .test .platform .app .InstrumentationRegistry ;
18
+ import androidx .test .uiautomator .*;
10
19
import io .flutter .plugins .quickactions .QuickActionsPlugin ;
20
+ import java .util .ArrayList ;
21
+ import java .util .List ;
22
+ import java .util .concurrent .atomic .AtomicReference ;
23
+ import org .junit .After ;
24
+ import org .junit .Assert ;
25
+ import org .junit .Before ;
11
26
import org .junit .Test ;
27
+ import org .junit .runner .RunWith ;
12
28
29
+ @ RunWith (AndroidJUnit4 .class )
13
30
public class QuickActionsTest {
31
+ private Context context ;
32
+ private UiDevice device ;
33
+ private ActivityScenario <QuickActionsTestActivity > scenario ;
34
+
35
+ @ Before
36
+ public void setUp () {
37
+ context = ApplicationProvider .getApplicationContext ();
38
+ device = UiDevice .getInstance (InstrumentationRegistry .getInstrumentation ());
39
+ scenario = ensureAppRunToView ();
40
+ }
41
+
42
+ @ After
43
+ public void tearDown () {
44
+ scenario .close ();
45
+ Log .i (QuickActionsTest .class .getSimpleName (), "Run to completion" );
46
+ }
47
+
14
48
@ Test
15
49
public void imagePickerPluginIsAdded () {
16
50
final ActivityScenario <QuickActionsTestActivity > scenario =
@@ -20,4 +54,108 @@ public void imagePickerPluginIsAdded() {
20
54
assertTrue (activity .engine .getPlugins ().has (QuickActionsPlugin .class ));
21
55
});
22
56
}
57
+
58
+ @ Test
59
+ public void appShortcutsAreCreated () {
60
+ // Arrange
61
+ List <Shortcut > expectedShortcuts = createMockShortcuts ();
62
+
63
+ // Act
64
+ ShortcutManager shortcutManager =
65
+ (ShortcutManager ) context .getSystemService (Context .SHORTCUT_SERVICE );
66
+ List <ShortcutInfo > dynamicShortcuts = shortcutManager .getDynamicShortcuts ();
67
+ Object [] shortcuts = dynamicShortcuts .stream ().map (Shortcut ::new ).toArray ();
68
+
69
+ // Assert the app shortcuts defined in ../lib/main.dart.
70
+ assertFalse (dynamicShortcuts .isEmpty ());
71
+ assertEquals (2 , dynamicShortcuts .size ());
72
+ assertArrayEquals (expectedShortcuts .toArray (), shortcuts );
73
+ }
74
+
75
+ @ Test
76
+ public void appShortcutExistsAfterLongPressingAppIcon () throws UiObjectNotFoundException {
77
+ // Arrange
78
+ List <Shortcut > shortcuts = createMockShortcuts ();
79
+ String appName = context .getApplicationInfo ().loadLabel (context .getPackageManager ()).toString ();
80
+
81
+ // Act
82
+ findAppIcon (device , appName ).longClick ();
83
+
84
+ // Assert
85
+ for (Shortcut shortcut : shortcuts ) {
86
+ Assert .assertTrue (
87
+ "The specified shortcut label '" + shortcut .shortLabel + "' does not exists." ,
88
+ device .hasObject (By .text (shortcut .shortLabel )));
89
+ }
90
+ }
91
+
92
+ @ Test
93
+ public void appShortcutLaunchActivityAfterPressing () throws UiObjectNotFoundException {
94
+ // Arrange
95
+ List <Shortcut > shortcuts = createMockShortcuts ();
96
+ String appName = context .getApplicationInfo ().loadLabel (context .getPackageManager ()).toString ();
97
+ Shortcut firstShortcut = shortcuts .get (0 );
98
+ AtomicReference <QuickActionsTestActivity > initialActivity = new AtomicReference <>();
99
+ scenario .onActivity (initialActivity ::set );
100
+
101
+ // Act
102
+ findAppIcon (device , appName ).longClick ();
103
+ UiObject appShortcut = device .findObject (new UiSelector ().text (firstShortcut .shortLabel ));
104
+ appShortcut .clickAndWaitForNewWindow ();
105
+ AtomicReference <QuickActionsTestActivity > currentActivity = new AtomicReference <>();
106
+ scenario .onActivity (currentActivity ::set );
107
+
108
+ // Assert
109
+ Assert .assertTrue (
110
+ "AppShortcut:" + firstShortcut .type + " does not launch the correct activity" ,
111
+ // We can only find the shortcut type in content description while inspecting it in Ui
112
+ // Automator Viewer.
113
+ device .hasObject (By .desc (firstShortcut .type )));
114
+ // This is Android SingleTop behavior in which Android does not destroy the initial activity and
115
+ // launch a new activity.
116
+ Assert .assertEquals (initialActivity .get (), currentActivity .get ());
117
+ }
118
+
119
+ private List <Shortcut > createMockShortcuts () {
120
+ List <Shortcut > expectedShortcuts = new ArrayList <>();
121
+ String actionOneLocalizedTitle = "Action one" ;
122
+ expectedShortcuts .add (
123
+ new Shortcut ("action_one" , actionOneLocalizedTitle , actionOneLocalizedTitle ));
124
+
125
+ String actionTwoLocalizedTitle = "Action two" ;
126
+ expectedShortcuts .add (
127
+ new Shortcut ("action_two" , actionTwoLocalizedTitle , actionTwoLocalizedTitle ));
128
+
129
+ return expectedShortcuts ;
130
+ }
131
+
132
+ private ActivityScenario <QuickActionsTestActivity > ensureAppRunToView () {
133
+ final ActivityScenario <QuickActionsTestActivity > scenario =
134
+ ActivityScenario .launch (QuickActionsTestActivity .class );
135
+ scenario .moveToState (Lifecycle .State .STARTED );
136
+ return scenario ;
137
+ }
138
+
139
+ private UiObject findAppIcon (UiDevice device , String appName ) throws UiObjectNotFoundException {
140
+ device .pressHome ();
141
+
142
+ // Swipe up to open App Drawer
143
+ UiScrollable homeView = new UiScrollable (new UiSelector ().scrollable (true ));
144
+ homeView .scrollForward ();
145
+
146
+ if (!device .hasObject (By .text (appName ))) {
147
+ Log .i (
148
+ QuickActionsTest .class .getSimpleName (),
149
+ "Attempting to scroll App Drawer for App Icon..." );
150
+ UiScrollable appDrawer = new UiScrollable (new UiSelector ().scrollable (true ));
151
+ // The scrollTextIntoView scrolls to the beginning before performing searching scroll; this
152
+ // causes an issue in a scenario where the view is already in the beginning. In this case, it
153
+ // scrolls back to home view. Therefore, we perform a dummy forward scroll to ensure it is not
154
+ // in the beginning.
155
+ appDrawer .scrollForward ();
156
+ appDrawer .scrollTextIntoView (appName );
157
+ }
158
+
159
+ return device .findObject (new UiSelector ().text (appName ));
160
+ }
23
161
}
0 commit comments