1 /*
2  * Copyright (C) 2022 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 com.android.adservices.ui.settings;
17 
18 import static com.android.adservices.service.ui.ux.collection.PrivacySandboxUxCollection.GA_UX;
19 
20 import static com.google.common.truth.Truth.assertThat;
21 
22 import static org.mockito.ArgumentMatchers.any;
23 import static org.mockito.Mockito.doNothing;
24 import static org.mockito.Mockito.doReturn;
25 import static org.mockito.Mockito.timeout;
26 import static org.mockito.Mockito.verify;
27 
28 import android.content.Context;
29 import android.content.Intent;
30 import android.os.RemoteException;
31 
32 import androidx.test.ext.junit.runners.AndroidJUnit4;
33 import androidx.test.filters.FlakyTest;
34 import androidx.test.platform.app.InstrumentationRegistry;
35 import androidx.test.uiautomator.By;
36 import androidx.test.uiautomator.UiDevice;
37 import androidx.test.uiautomator.UiObject2;
38 import androidx.test.uiautomator.Until;
39 
40 import com.android.adservices.LogUtil;
41 import com.android.adservices.api.R;
42 import com.android.adservices.common.AdServicesExtendedMockitoTestCase;
43 import com.android.adservices.common.AdservicesTestHelper;
44 import com.android.adservices.data.topics.Topic;
45 import com.android.adservices.service.Flags;
46 import com.android.adservices.service.FlagsFactory;
47 import com.android.adservices.service.common.BackgroundJobsManager;
48 import com.android.adservices.service.consent.AdServicesApiConsent;
49 import com.android.adservices.service.consent.AdServicesApiType;
50 import com.android.adservices.service.consent.App;
51 import com.android.adservices.service.consent.ConsentManager;
52 import com.android.adservices.shared.testing.annotations.RequiresSdkLevelAtLeastT;
53 import com.android.adservices.ui.util.ApkTestUtil;
54 import com.android.dx.mockito.inline.extended.ExtendedMockito;
55 import com.android.modules.utils.testing.ExtendedMockitoRule.SpyStatic;
56 
57 import com.google.common.collect.ImmutableList;
58 
59 import org.junit.After;
60 import org.junit.Before;
61 import org.junit.Test;
62 import org.junit.runner.RunWith;
63 import org.mockito.Mock;
64 
65 import java.util.ArrayList;
66 import java.util.List;
67 
68 @SpyStatic(FlagsFactory.class)
69 @SpyStatic(BackgroundJobsManager.class)
70 @SpyStatic(ConsentManager.class)
71 @RequiresSdkLevelAtLeastT(reason = "Back Compat only support GA UX")
72 @RunWith(AndroidJUnit4.class)
73 public final class DialogFragmentTest extends AdServicesExtendedMockitoTestCase {
74 
75     private static final String PRIVACY_SANDBOX_TEST_PACKAGE = "android.test.adservices.ui.MAIN";
76     private static final int LAUNCH_TIMEOUT = 5000;
77     private static UiDevice sDevice;
78 
79     @Mock
80     private ConsentManager mConsentManager;
81     @Mock
82     private Flags mMockFlags;
83 
84     @Before
setup()85     public void setup() throws Exception {
86         mocker.mockGetFlags(mMockFlags);
87         doReturn(true).when(mMockFlags).getGaUxFeatureEnabled();
88         doReturn(false).when(mMockFlags).getUiOtaStringsFeatureEnabled();
89         // UiDialogFragmentEnable flag should be on for this test
90         doReturn(true).when(mMockFlags).getUiDialogFragmentEnabled();
91         doReturn(true).when(mMockFlags).getUiDialogsFeatureEnabled();
92         doReturn(true).when(mMockFlags).getRecordManualInteractionEnabled();
93         List<Topic> tempList = new ArrayList<>();
94         tempList.add(Topic.create(10001, 1, 1));
95         tempList.add(Topic.create(10002, 1, 1));
96         tempList.add(Topic.create(10003, 1, 1));
97         ImmutableList<Topic> topicsList = ImmutableList.copyOf(tempList);
98         doReturn(topicsList).when(mConsentManager).getKnownTopicsWithConsent();
99 
100         tempList = new ArrayList<>();
101         tempList.add(Topic.create(10004, 1, 1));
102         tempList.add(Topic.create(10005, 1, 1));
103         ImmutableList<Topic> blockedTopicsList = ImmutableList.copyOf(tempList);
104         doReturn(blockedTopicsList).when(mConsentManager).getTopicsWithRevokedConsent();
105 
106         List<App> appTempList = new ArrayList<>();
107         appTempList.add(App.create("app1"));
108         appTempList.add(App.create("app2"));
109         ImmutableList<App> appsList = ImmutableList.copyOf(appTempList);
110         doReturn(appsList).when(mConsentManager).getKnownAppsWithConsent();
111 
112         appTempList = new ArrayList<>();
113         appTempList.add(App.create("app3"));
114         ImmutableList<App> blockedAppsList = ImmutableList.copyOf(appTempList);
115         doReturn(blockedAppsList).when(mConsentManager).getAppsWithRevokedConsent();
116 
117         doNothing().when(mConsentManager).resetTopicsAndBlockedTopics();
118         doNothing().when(mConsentManager).resetTopics();
119         doNothing().when(mConsentManager).revokeConsentForTopic(any(Topic.class));
120         doNothing().when(mConsentManager).restoreConsentForTopic(any(Topic.class));
121         doNothing().when(mConsentManager).resetAppsAndBlockedApps();
122         doNothing().when(mConsentManager).resetApps();
123         doNothing().when(mConsentManager).revokeConsentForApp(any(App.class));
124         doNothing().when(mConsentManager).restoreConsentForApp(any(App.class));
125         doNothing().when(mConsentManager).resetMeasurement();
126 
127         ExtendedMockito.doNothing()
128                 .when(() -> BackgroundJobsManager.scheduleAllBackgroundJobs(any(Context.class)));
129         ExtendedMockito.doReturn(mConsentManager).when(() -> ConsentManager.getInstance());
130         doReturn(AdServicesApiConsent.GIVEN).when(mConsentManager).getConsent();
131         doReturn(AdServicesApiConsent.GIVEN)
132                 .when(mConsentManager)
133                 .getConsent(AdServicesApiType.TOPICS);
134         doReturn(AdServicesApiConsent.GIVEN)
135                 .when(mConsentManager)
136                 .getConsent(AdServicesApiType.FLEDGE);
137         doReturn(AdServicesApiConsent.GIVEN)
138                 .when(mConsentManager)
139                 .getConsent(AdServicesApiType.MEASUREMENTS);
140 
141         doNothing().when(mConsentManager).enable(any(Context.class));
142         doNothing().when(mConsentManager).disable(any(Context.class));
143         doReturn(GA_UX).when(mConsentManager).getUx();
144 
145         try {
146             startActivityFromHomeAndCheckMainSwitch();
147         } catch (RemoteException e) {
148             LogUtil.e("RemoteException from setOrientation.");
149         }
150     }
151 
startActivityFromHomeAndCheckMainSwitch()152     private void startActivityFromHomeAndCheckMainSwitch() throws RemoteException {
153         // Initialize UiDevice instance
154         sDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
155 
156         // Start from the home screen
157         sDevice.pressHome();
158         sDevice.setOrientationNatural();
159 
160         // Wait for launcher
161         final String launcherPackage = sDevice.getLauncherPackageName();
162         assertThat(launcherPackage).isNotNull();
163         sDevice.wait(Until.hasObject(By.pkg(launcherPackage).depth(0)), LAUNCH_TIMEOUT);
164 
165         // launch app
166         Context context = appContext.get();
167         Intent intent = new Intent(PRIVACY_SANDBOX_TEST_PACKAGE);
168         intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
169         context.startActivity(intent);
170 
171         // Wait for the app to appear
172         sDevice.wait(
173                 Until.hasObject(By.pkg(PRIVACY_SANDBOX_TEST_PACKAGE).depth(0)), LAUNCH_TIMEOUT);
174     }
175 
176     @After
teardown()177     public void teardown() {
178         ApkTestUtil.takeScreenshot(sDevice, getClass().getSimpleName() + "_" + getTestName() + "_");
179         AdservicesTestHelper.killAdservicesProcess(sContext);
180     }
181 
182     @Test
183     @FlakyTest(bugId = 301779505)
blockTopicDialogTest()184     public void blockTopicDialogTest() throws Exception {
185         // open topics view
186         ApkTestUtil.scrollToAndClick(sDevice, R.string.settingsUI_topics_ga_title);
187         UiObject2 blockTopicText =
188                 ApkTestUtil.getElement(sDevice, R.string.settingsUI_block_topic_title, 0);
189         assertThat(blockTopicText).isNotNull();
190 
191         // click block
192         blockTopicText.click();
193         UiObject2 dialogTitle =
194                 ApkTestUtil.getElement(sDevice, R.string.settingsUI_dialog_block_topic_message);
195         UiObject2 positiveText =
196                 ApkTestUtil.getElement(
197                         sDevice, R.string.settingsUI_dialog_block_topic_positive_text);
198         assertThat(dialogTitle).isNotNull();
199         assertThat(positiveText).isNotNull();
200 
201         // confirm
202         positiveText.click();
203         verify(mConsentManager, timeout(1000)).revokeConsentForTopic(any(Topic.class));
204         blockTopicText = ApkTestUtil.getElement(sDevice, R.string.settingsUI_block_topic_title, 0);
205         assertThat(blockTopicText).isNotNull();
206 
207         // click block again
208         blockTopicText.click();
209         dialogTitle =
210                 ApkTestUtil.getElement(sDevice, R.string.settingsUI_dialog_block_topic_message);
211         UiObject2 negativeText =
212                 ApkTestUtil.getElement(sDevice, R.string.settingsUI_dialog_negative_text);
213         assertThat(dialogTitle).isNotNull();
214         assertThat(negativeText).isNotNull();
215 
216         // cancel and verify it has still only been called once
217         negativeText.click();
218         verify(mConsentManager).revokeConsentForTopic(any(Topic.class));
219     }
220 
221     @Test
222     @FlakyTest(bugId = 301779505)
unblockTopicDialogTest()223     public void unblockTopicDialogTest() throws Exception {
224         // open topics view
225         ApkTestUtil.scrollToAndClick(sDevice, R.string.settingsUI_topics_ga_title);
226 
227         // open blocked topics view
228         ApkTestUtil.scrollToAndClick(sDevice, R.string.settingsUI_blocked_topics_ga_title);
229         UiObject2 unblockTopicText =
230                 ApkTestUtil.getElement(sDevice, R.string.settingsUI_unblock_topic_title, 0);
231         assertThat(unblockTopicText).isNotNull();
232 
233         // click unblock
234         unblockTopicText.click();
235         UiObject2 dialogTitle =
236                 ApkTestUtil.getElement(sDevice, R.string.settingsUI_dialog_unblock_topic_message);
237         UiObject2 positiveText =
238                 ApkTestUtil.getElement(
239                         sDevice, R.string.settingsUI_dialog_unblock_topic_positive_text);
240         assertThat(dialogTitle).isNotNull();
241         assertThat(positiveText).isNotNull();
242 
243         // confirm
244         positiveText.click();
245         verify(mConsentManager).restoreConsentForTopic(any(Topic.class));
246         unblockTopicText =
247                 ApkTestUtil.getElement(sDevice, R.string.settingsUI_unblock_topic_title, 0);
248         assertThat(unblockTopicText).isNotNull();
249     }
250 
251     @Test
resetTopicDialogTest()252     public void resetTopicDialogTest() throws Exception {
253         // open topics view
254         ApkTestUtil.scrollToAndClick(sDevice, R.string.settingsUI_topics_ga_title);
255 
256         // click reset
257         ApkTestUtil.scrollToAndClick(sDevice, R.string.settingsUI_reset_topics_ga_title);
258         UiObject2 dialogTitle =
259                 ApkTestUtil.getElement(sDevice, R.string.settingsUI_dialog_reset_topic_message);
260         UiObject2 positiveText =
261                 ApkTestUtil.getElement(
262                         sDevice, R.string.settingsUI_dialog_reset_topic_positive_text);
263         assertThat(dialogTitle).isNotNull();
264         assertThat(positiveText).isNotNull();
265 
266         // confirm
267         positiveText.click();
268         verify(mConsentManager, timeout(1000)).resetTopics();
269 
270         // click reset again
271         ApkTestUtil.scrollToAndClick(sDevice, R.string.settingsUI_reset_topics_ga_title);
272         dialogTitle =
273                 ApkTestUtil.getElement(sDevice, R.string.settingsUI_dialog_reset_topic_message);
274         UiObject2 negativeText =
275                 ApkTestUtil.getElement(sDevice, R.string.settingsUI_dialog_negative_text);
276         assertThat(dialogTitle).isNotNull();
277         assertThat(negativeText).isNotNull();
278 
279         // cancel and verify it has still only been called once
280         negativeText.click();
281         verify(mConsentManager).resetTopics();
282     }
283 
284     @Test
285     @FlakyTest(bugId = 301779505)
blockAppDialogTest()286     public void blockAppDialogTest() throws Exception {
287         // perform a gentle swipe so scroll won't miss the text close to the
288         // bottom of the current screen.
289         UiObject2 appsTitle = ApkTestUtil.getElement(sDevice, R.string.settingsUI_apps_ga_title);
290         if (appsTitle == null) {
291             ApkTestUtil.gentleSwipe(sDevice);
292         }
293 
294         // open apps view
295         ApkTestUtil.scrollToAndClick(sDevice, R.string.settingsUI_apps_ga_title);
296         UiObject2 blockAppText =
297                 ApkTestUtil.getElement(sDevice, R.string.settingsUI_block_app_title, 0);
298         assertThat(blockAppText).isNotNull();
299 
300         // click block
301         blockAppText.click();
302         UiObject2 dialogTitle =
303                 ApkTestUtil.getElement(sDevice, R.string.settingsUI_dialog_block_app_message);
304         UiObject2 positiveText =
305                 ApkTestUtil.getElement(sDevice, R.string.settingsUI_dialog_block_app_positive_text);
306         assertThat(dialogTitle).isNotNull();
307         assertThat(positiveText).isNotNull();
308 
309         // confirm
310         positiveText.click();
311         verify(mConsentManager, timeout(1000)).revokeConsentForApp(any(App.class));
312         blockAppText = ApkTestUtil.getElement(sDevice, R.string.settingsUI_block_app_title, 0);
313         assertThat(blockAppText).isNotNull();
314 
315         // click block again
316         blockAppText.click();
317         dialogTitle = ApkTestUtil.getElement(sDevice, R.string.settingsUI_dialog_block_app_message);
318         UiObject2 negativeText =
319                 ApkTestUtil.getElement(sDevice, R.string.settingsUI_dialog_negative_text);
320         assertThat(dialogTitle).isNotNull();
321         assertThat(negativeText).isNotNull();
322 
323         // cancel and verify it has still only been called once
324         negativeText.click();
325         verify(mConsentManager).revokeConsentForApp(any(App.class));
326     }
327 
328     @Test
329     @FlakyTest(bugId = 301779505)
unblockAppDialogTest()330     public void unblockAppDialogTest() throws Exception {
331         UiObject2 appsTitle = ApkTestUtil.getElement(sDevice, R.string.settingsUI_apps_ga_title);
332         if (appsTitle == null) {
333             ApkTestUtil.gentleSwipe(sDevice);
334         }
335 
336         // open apps view
337         ApkTestUtil.scrollToAndClick(sDevice, R.string.settingsUI_apps_ga_title);
338 
339         // perform a gentle swipe so scroll won't miss the text close to the
340         // bottom of the current screen.
341         ApkTestUtil.gentleSwipe(sDevice);
342 
343         // open blocked apps view
344         ApkTestUtil.scrollToAndClick(sDevice, R.string.settingsUI_blocked_apps_ga_title);
345         UiObject2 unblockAppText =
346                 ApkTestUtil.getElement(sDevice, R.string.settingsUI_unblock_app_title, 0);
347         assertThat(unblockAppText).isNotNull();
348 
349         // click unblock
350         unblockAppText.click();
351         UiObject2 dialogTitle =
352                 ApkTestUtil.getElement(sDevice, R.string.settingsUI_dialog_unblock_app_message);
353         UiObject2 positiveText =
354                 ApkTestUtil.getElement(
355                         sDevice, R.string.settingsUI_dialog_unblock_app_positive_text);
356         assertThat(dialogTitle).isNotNull();
357         assertThat(positiveText).isNotNull();
358 
359         // confirm
360         positiveText.click();
361         verify(mConsentManager).restoreConsentForApp(any(App.class));
362         unblockAppText = ApkTestUtil.getElement(sDevice, R.string.settingsUI_unblock_app_title, 0);
363         assertThat(unblockAppText).isNotNull();
364     }
365 
366     @Test
resetAppDialogTest()367     public void resetAppDialogTest() throws Exception {
368         UiObject2 appsTitle = ApkTestUtil.getElement(sDevice, R.string.settingsUI_apps_ga_title);
369         if (appsTitle != null) {
370             ApkTestUtil.gentleSwipe(sDevice);
371         }
372 
373         // open apps view
374         ApkTestUtil.scrollToAndClick(sDevice, R.string.settingsUI_apps_ga_title);
375 
376         // click reset
377         ApkTestUtil.scrollToAndClick(sDevice, R.string.settingsUI_reset_apps_ga_title);
378         UiObject2 dialogTitle =
379                 ApkTestUtil.getElement(sDevice, R.string.settingsUI_dialog_reset_app_message);
380         UiObject2 positiveText =
381                 ApkTestUtil.getElement(sDevice, R.string.settingsUI_dialog_reset_app_positive_text);
382         assertThat(dialogTitle).isNotNull();
383         assertThat(positiveText).isNotNull();
384 
385         // confirm
386         positiveText.click();
387         verify(mConsentManager, timeout(1000)).resetApps();
388 
389         // click reset again
390         ApkTestUtil.scrollToAndClick(sDevice, R.string.settingsUI_reset_apps_ga_title);
391         dialogTitle = ApkTestUtil.getElement(sDevice, R.string.settingsUI_dialog_reset_app_message);
392         UiObject2 negativeText =
393                 ApkTestUtil.getElement(sDevice, R.string.settingsUI_dialog_negative_text);
394         assertThat(dialogTitle).isNotNull();
395         assertThat(negativeText).isNotNull();
396 
397         // cancel and verify it has still only been called once
398         negativeText.click();
399         verify(mConsentManager).resetApps();
400     }
401 }
402