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