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