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