• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2017 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package android.autofillservice.cts.commontests;
17 
18 import static com.google.common.truth.Truth.assertThat;
19 
20 import static org.junit.Assume.assumeTrue;
21 
22 import android.app.Activity;
23 import android.app.PendingIntent;
24 import android.autofillservice.cts.R;
25 import android.autofillservice.cts.activities.AbstractAutoFillActivity;
26 import android.autofillservice.cts.testcore.Helper;
27 import android.autofillservice.cts.testcore.UiBot;
28 import android.content.Intent;
29 import android.service.autofill.CustomDescription;
30 import android.widget.RemoteViews;
31 
32 import androidx.annotation.NonNull;
33 import androidx.test.filters.FlakyTest;
34 import androidx.test.uiautomator.By;
35 import androidx.test.uiautomator.UiObject2;
36 
37 import org.junit.Test;
38 
39 /**
40  * Template for tests cases that test what happens when a link in the {@link CustomDescription} is
41  * tapped by the user.
42  *
43  * <p>It must be extend by 2 sub-class to provide tests for the 2 distinct scenarios:
44  * <ul>
45  *   <li>Save is triggered by 1st activity finishing and launching a 2nd activity.
46  *   <li>Save is triggered by explicit {@link android.view.autofill.AutofillManager#commit()} call
47  *       and shown in the same activity.
48  * </ul>
49  *
50  * <p>The overall behavior should be the same in both cases, although the implementation of the
51  * tests per se will be sligthly different.
52  */
53 public abstract class CustomDescriptionWithLinkTestCase<A extends AbstractAutoFillActivity> extends
54         AutoFillServiceTestCase.AutoActivityLaunch<A> {
55 
56     private static final String ID_LINK = "link";
57 
58     private final Class<A> mActivityClass;
59 
60     protected A mActivity;
61 
CustomDescriptionWithLinkTestCase(@onNull Class<A> activityClass)62     protected CustomDescriptionWithLinkTestCase(@NonNull Class<A> activityClass) {
63         mActivityClass = activityClass;
64     }
65 
startActivity()66     protected void startActivity() {
67         startActivity(false);
68     }
69 
startActivity(boolean remainOnRecents)70     protected void startActivity(boolean remainOnRecents) {
71         final Intent intent = new Intent(mContext, mActivityClass);
72         if (remainOnRecents) {
73             intent.setFlags(
74                     Intent.FLAG_ACTIVITY_RETAIN_IN_RECENTS | Intent.FLAG_ACTIVITY_NEW_TASK);
75         }
76         mActivity = launchActivity(intent);
77     }
78 
79     /**
80      * Tests scenarios when user taps a link in the custom description and then taps back:
81      * the Save UI should have been restored.
82      */
83     @Test
testTapLink_tapBack()84     public final void testTapLink_tapBack() throws Exception {
85         saveUiRestoredAfterTappingLinkTest(PostSaveLinkTappedAction.TAP_BACK_BUTTON);
86     }
87 
88     /**
89      * Tests scenarios when user taps a link in the custom description, change the screen
90      * orientation while the new activity is show, then taps back:
91      * the Save UI should have been restored.
92      */
93     @Test
testTapLink_changeOrientationThenTapBack()94     public final void testTapLink_changeOrientationThenTapBack() throws Exception {
95         assumeTrue("Rotation is supported", Helper.isRotationSupported(mContext));
96         assumeTrue("Device state is not REAR_DISPLAY",
97                 !Helper.isDeviceInState(mContext, Helper.DeviceStateEnum.REAR_DISPLAY));
98 
99         mUiBot.assumeMinimumResolution(500);
100         mUiBot.setScreenOrientation(UiBot.PORTRAIT);
101         try {
102             saveUiRestoredAfterTappingLinkTest(
103                     PostSaveLinkTappedAction.ROTATE_THEN_TAP_BACK_BUTTON);
104         } finally {
105             try {
106                 mUiBot.setScreenOrientation(UiBot.PORTRAIT);
107                 cleanUpAfterScreenOrientationIsBackToPortrait();
108             } catch (Exception e) {
109                 mSafeCleanerRule.add(e);
110             } finally {
111                 mUiBot.resetScreenResolution();
112             }
113         }
114     }
115 
116     /**
117      * Tests scenarios when user taps a link in the custom description, then the new activity
118      * finishes:
119      * the Save UI should have been restored.
120      */
121     @Test
testTapLink_finishActivity()122     public final void testTapLink_finishActivity() throws Exception {
123         saveUiRestoredAfterTappingLinkTest(PostSaveLinkTappedAction.FINISH_ACTIVITY);
124     }
125 
saveUiRestoredAfterTappingLinkTest(PostSaveLinkTappedAction type)126     protected abstract void saveUiRestoredAfterTappingLinkTest(PostSaveLinkTappedAction type)
127             throws Exception;
128 
cleanUpAfterScreenOrientationIsBackToPortrait()129     protected void cleanUpAfterScreenOrientationIsBackToPortrait() throws Exception {
130     }
131 
132     /**
133      * Tests scenarios when user taps a link in the custom description, taps back to return to the
134      * activity with the Save UI, and touch outside the Save UI to dismiss it.
135      *
136      * <p>Then user starts a new session by focusing in a field.
137      */
138     @Test
testTapLink_tapBack_thenStartOverByTouchOutsideAndFocus()139     public final void testTapLink_tapBack_thenStartOverByTouchOutsideAndFocus()
140             throws Exception {
141         tapLinkThenTapBackThenStartOverTest(PostSaveLinkTappedAction.TOUCH_OUTSIDE, false);
142     }
143 
144     /**
145      * Tests scenarios when user taps a link in the custom description, taps back to return to the
146      * activity with the Save UI, and touch outside the Save UI to dismiss it.
147      *
148      * <p>Then user starts a new session by forcing autofill.
149      */
150     @Test
testTapLink_tapBack_thenStartOverByTouchOutsideAndManualRequest()151     public void testTapLink_tapBack_thenStartOverByTouchOutsideAndManualRequest()
152             throws Exception {
153         tapLinkThenTapBackThenStartOverTest(PostSaveLinkTappedAction.TOUCH_OUTSIDE, true);
154     }
155 
156     /**
157      * Tests scenarios when user taps a link in the custom description, taps back to return to the
158      * activity with the Save UI, and tap the "No" button to dismiss it.
159      *
160      * <p>Then user starts a new session by focusing in a field.
161      */
162     @Test
testTapLink_tapBack_thenStartOverBySayingNoAndFocus()163     public final void testTapLink_tapBack_thenStartOverBySayingNoAndFocus()
164             throws Exception {
165         tapLinkThenTapBackThenStartOverTest(PostSaveLinkTappedAction.TAP_NO_ON_SAVE_UI,
166                 false);
167     }
168 
169     /**
170      * Tests scenarios when user taps a link in the custom description, taps back to return to the
171      * activity with the Save UI, and tap the "No" button to dismiss it.
172      *
173      * <p>Then user starts a new session by forcing autofill.
174      */
175     @Test
testTapLink_tapBack_thenStartOverBySayingNoAndManualRequest()176     public final void testTapLink_tapBack_thenStartOverBySayingNoAndManualRequest()
177             throws Exception {
178         tapLinkThenTapBackThenStartOverTest(PostSaveLinkTappedAction.TAP_NO_ON_SAVE_UI, true);
179     }
180 
181     /**
182      * Tests scenarios when user taps a link in the custom description, taps back to return to the
183      * activity with the Save UI, and the "Yes" button to save it.
184      *
185      * <p>Then user starts a new session by focusing in a field.
186      */
187     @Test
testTapLink_tapBack_thenStartOverBySayingYesAndFocus()188     public final void testTapLink_tapBack_thenStartOverBySayingYesAndFocus()
189             throws Exception {
190         tapLinkThenTapBackThenStartOverTest(PostSaveLinkTappedAction.TAP_YES_ON_SAVE_UI,
191                 false);
192     }
193 
194     /**
195      * Tests scenarios when user taps a link in the custom description, taps back to return to the
196      * activity with the Save UI, and the "Yes" button to save it.
197      *
198      * <p>Then user starts a new session by forcing autofill.
199      */
200     @Test
testTapLink_tapBack_thenStartOverBySayingYesAndManualRequest()201     public final void testTapLink_tapBack_thenStartOverBySayingYesAndManualRequest()
202             throws Exception {
203         tapLinkThenTapBackThenStartOverTest(PostSaveLinkTappedAction.TAP_YES_ON_SAVE_UI, true);
204     }
205 
tapLinkThenTapBackThenStartOverTest( PostSaveLinkTappedAction action, boolean manualRequest)206     protected abstract void tapLinkThenTapBackThenStartOverTest(
207             PostSaveLinkTappedAction action, boolean manualRequest) throws Exception;
208 
209     /**
210      * Tests scenarios when user taps a link in the custom description, then re-launches the
211      * original activity:
212      * the Save UI should have been canceled.
213      */
214     @Test
testTapLink_backToPreviousActivityByLaunchingIt()215     public final void testTapLink_backToPreviousActivityByLaunchingIt()
216             throws Exception {
217         saveUiCancelledAfterTappingLinkTest(PostSaveLinkTappedAction.LAUNCH_PREVIOUS_ACTIVITY);
218     }
219 
220     /**
221      * Tests scenarios when user taps a link in the custom description, then launches a 3rd
222      * activity:
223      * the Save UI should have been canceled.
224      */
225     @Test
testTapLink_launchNewActivityThenTapBack()226     public final void testTapLink_launchNewActivityThenTapBack() throws Exception {
227         saveUiCancelledAfterTappingLinkTest(PostSaveLinkTappedAction.LAUNCH_NEW_ACTIVITY);
228     }
229 
saveUiCancelledAfterTappingLinkTest(PostSaveLinkTappedAction type)230     protected abstract void saveUiCancelledAfterTappingLinkTest(PostSaveLinkTappedAction type)
231             throws Exception;
232 
233     @Test
234     @FlakyTest(bugId = 177259617)
testTapLink_launchTrampolineActivityThenTapBackAndStartNewSession()235     public final void testTapLink_launchTrampolineActivityThenTapBackAndStartNewSession()
236             throws Exception {
237         // Reset AutofillOptions to avoid cts package was added to augmented autofill allowlist.
238         Helper.resetApplicationAutofillOptions(sContext);
239 
240         tapLinkLaunchTrampolineActivityThenTapBackAndStartNewSessionTest();
241 
242         // Clear AutofillOptions.
243         Helper.clearApplicationAutofillOptions(sContext);
244     }
245 
tapLinkLaunchTrampolineActivityThenTapBackAndStartNewSessionTest()246     protected abstract void tapLinkLaunchTrampolineActivityThenTapBackAndStartNewSessionTest()
247             throws Exception;
248 
249     @Test
testTapLinkAfterUpdateAppliedToLinkView()250     public final void testTapLinkAfterUpdateAppliedToLinkView() throws Exception {
251         tapLinkAfterUpdateAppliedTest(true);
252     }
253 
254     @Test
testTapLinkAfterUpdateAppliedToAnotherView()255     public final void testTapLinkAfterUpdateAppliedToAnotherView() throws Exception {
256         tapLinkAfterUpdateAppliedTest(false);
257     }
258 
tapLinkAfterUpdateAppliedTest(boolean updateLinkView)259     protected abstract void tapLinkAfterUpdateAppliedTest(boolean updateLinkView) throws Exception;
260 
261     public enum PostSaveLinkTappedAction {
262         TAP_BACK_BUTTON,
263         ROTATE_THEN_TAP_BACK_BUTTON,
264         FINISH_ACTIVITY,
265         LAUNCH_NEW_ACTIVITY,
266         LAUNCH_PREVIOUS_ACTIVITY,
267         TOUCH_OUTSIDE,
268         TAP_NO_ON_SAVE_UI,
269         TAP_YES_ON_SAVE_UI
270     }
271 
startActivityOnNewTask(Class<?> clazz)272     protected final void startActivityOnNewTask(Class<?> clazz) {
273         final Intent intent = new Intent(mContext, clazz);
274         intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
275         mContext.startActivity(intent);
276     }
277 
newTemplate()278     protected RemoteViews newTemplate() {
279         final RemoteViews presentation = new RemoteViews(mPackageName,
280                 R.layout.custom_description_with_link);
281         return presentation;
282     }
283 
newCustomDescriptionBuilder( Class<? extends Activity> activityClass)284     protected final CustomDescription.Builder newCustomDescriptionBuilder(
285             Class<? extends Activity> activityClass) {
286         final Intent intent = new Intent(mContext, activityClass);
287         intent.setFlags(Intent.FLAG_ACTIVITY_RETAIN_IN_RECENTS | Intent.FLAG_ACTIVITY_NEW_DOCUMENT);
288         return newCustomDescriptionBuilder(intent);
289     }
290 
newCustomDescription( Class<? extends Activity> activityClass)291     protected final CustomDescription newCustomDescription(
292             Class<? extends Activity> activityClass) {
293         return newCustomDescriptionBuilder(activityClass).build();
294     }
295 
newCustomDescriptionBuilder(Intent intent)296     protected final CustomDescription.Builder newCustomDescriptionBuilder(Intent intent) {
297         final RemoteViews presentation = newTemplate();
298         final PendingIntent pendingIntent =
299                 PendingIntent.getActivity(mContext, 0, intent, PendingIntent.FLAG_MUTABLE);
300         presentation.setOnClickPendingIntent(R.id.link, pendingIntent);
301         return new CustomDescription.Builder(presentation);
302     }
303 
newCustomDescription(Intent intent)304     protected final CustomDescription newCustomDescription(Intent intent) {
305         return newCustomDescriptionBuilder(intent).build();
306     }
307 
assertSaveUiWithLinkIsShown(int saveType)308     protected final UiObject2 assertSaveUiWithLinkIsShown(int saveType) throws Exception {
309         return assertSaveUiWithLinkIsShown(saveType, "DON'T TAP ME!");
310     }
311 
assertSaveUiWithLinkIsShown(int saveType, String expectedText)312     protected final UiObject2 assertSaveUiWithLinkIsShown(int saveType, String expectedText)
313             throws Exception {
314         // First make sure the UI is shown...
315         final UiObject2 saveUi = mUiBot.assertSaveShowing(saveType);
316         // Then make sure it does have the custom view with link on it...
317         final UiObject2 link = getLink(saveUi);
318         assertThat(link.getText()).isEqualTo(expectedText);
319         return saveUi;
320     }
321 
getLink(final UiObject2 container)322     protected final UiObject2 getLink(final UiObject2 container) {
323         final UiObject2 link = container.findObject(By.res(mPackageName, ID_LINK));
324         assertThat(link).isNotNull();
325         return link;
326     }
327 
tapSaveUiLink(UiObject2 saveUi)328     protected final void tapSaveUiLink(UiObject2 saveUi) {
329         getLink(saveUi).click();
330     }
331 }
332