44
55package io .flutter .plugins .quickactionsexample ;
66
7- import static org .junit .Assert .assertTrue ;
7+ import static org .junit .Assert .* ;
88
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 ;
914import 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 .*;
1019import 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 ;
1126import org .junit .Test ;
27+ import org .junit .runner .RunWith ;
1228
29+ @ RunWith (AndroidJUnit4 .class )
1330public 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+
1448 @ Test
1549 public void imagePickerPluginIsAdded () {
1650 final ActivityScenario <QuickActionsTestActivity > scenario =
@@ -20,4 +54,108 @@ public void imagePickerPluginIsAdded() {
2054 assertTrue (activity .engine .getPlugins ().has (QuickActionsPlugin .class ));
2155 });
2256 }
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 exist." ,
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+ }
23161}
0 commit comments