44
55package io .flutter .plugins .quickactionsexample ;
66
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 ;
912import 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 .*;
1017import io .flutter .plugins .quickactions .QuickActionsPlugin ;
18+ import org .junit .After ;
19+ import org .junit .Assert ;
20+ import org .junit .Before ;
1121import 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 .*;
1229
30+ @ RunWith (AndroidJUnit4 .class )
1331public 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+
1449 @ Test
1550 public void imagePickerPluginIsAdded () {
1651 final ActivityScenario <QuickActionsTestActivity > scenario =
@@ -20,4 +55,108 @@ public void imagePickerPluginIsAdded() {
2055 assertTrue (activity .engine .getPlugins ().has (QuickActionsPlugin .class ));
2156 });
2257 }
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+ }
23162}
0 commit comments