1 /*
2  * Copyright (C) 2023 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.tests.ui.libs;
17 
18 import static android.Manifest.permission.POST_NOTIFICATIONS;
19 
20 import static com.android.adservices.tests.ui.libs.UiConstants.AD_ID_ENABLED;
21 import static com.android.adservices.tests.ui.libs.UiConstants.ENTRY_POINT_ENABLED;
22 import static com.android.adservices.tests.ui.libs.UiConstants.SYSTEM_UI_NAME;
23 import static com.android.adservices.tests.ui.libs.UiConstants.SYSTEM_UI_RESOURCE_ID;
24 
25 import static com.google.common.truth.Truth.assertThat;
26 
27 import android.adservices.common.AdServicesCommonManager;
28 import android.adservices.common.AdServicesStates;
29 import android.content.Context;
30 import android.graphics.Point;
31 import android.os.OutcomeReceiver;
32 
33 import androidx.test.platform.app.InstrumentationRegistry;
34 import androidx.test.uiautomator.By;
35 import androidx.test.uiautomator.BySelector;
36 import androidx.test.uiautomator.Direction;
37 import androidx.test.uiautomator.SearchCondition;
38 import androidx.test.uiautomator.UiDevice;
39 import androidx.test.uiautomator.UiObject2;
40 import androidx.test.uiautomator.Until;
41 
42 import com.android.adservices.LogUtil;
43 import com.android.adservices.api.R;
44 import com.android.adservices.common.AdservicesTestHelper;
45 import com.android.adservices.shared.testing.common.FileHelper;
46 import com.android.compatibility.common.util.ShellUtils;
47 
48 import com.google.common.util.concurrent.SettableFuture;
49 
50 import java.io.File;
51 import java.text.SimpleDateFormat;
52 import java.time.Instant;
53 import java.util.Date;
54 import java.util.List;
55 import java.util.Locale;
56 import java.util.UUID;
57 import java.util.concurrent.Executors;
58 import java.util.regex.Pattern;
59 
60 public class UiUtils {
61     private static final String PRIVACY_SANDBOX_PACKAGE_NAME = "android.adservices.ui.SETTINGS";
62     private static final String NOTIFICATION_PACKAGE_NAME = "android.adservices.ui.NOTIFICATIONS";
63     public static final int LAUNCH_TIMEOUT = 5000;
64     public static final int PRIMITIVE_UI_OBJECTS_LAUNCH_TIMEOUT = 500;
65     public static final int SCROLL_WAIT_TIME = 1000;
66 
67     private static final int DEFAULT_BINDER_CONNECTION_TIMEOUT_MS = 10000;
68 
69     private static final String ANDROID_WIDGET_SCROLLVIEW = "android.widget.ScrollView";
70 
forceSetFlag(String flagName, boolean newFlagValue)71     private static void forceSetFlag(String flagName, boolean newFlagValue) throws Exception {
72         String shellCmdGetTemplate;
73         String shellCmdSetTemplate;
74         if (flagName.endsWith("debug_mode")) {
75             shellCmdGetTemplate = "getprop debug.adservices.%s";
76             shellCmdSetTemplate = "setprop debug.adservices.%s %s";
77         } else {
78             shellCmdGetTemplate = "device_config get adservices %s";
79             shellCmdSetTemplate = "device_config put adservices %s %s";
80         }
81         String currentFlagValue = ShellUtils.runShellCommand(shellCmdGetTemplate, flagName);
82 
83         for (int i = 0; i < 5; i++) {
84             if (currentFlagValue.equals(String.valueOf(newFlagValue))) {
85                 return;
86             }
87 
88             ShellUtils.runShellCommand(shellCmdSetTemplate, flagName, newFlagValue);
89 
90             Thread.sleep(250);
91 
92             currentFlagValue = ShellUtils.runShellCommand(shellCmdGetTemplate, flagName);
93 
94             LogUtil.e(String.format("Flag was not set on iteration %d.", i));
95         }
96 
97         throw new IllegalStateException("Unable to set flag in 5 iterations.");
98     }
99 
refreshConsentResetToken()100     public static void refreshConsentResetToken() {
101         ShellUtils.runShellCommand(
102                 "device_config put adservices consent_notification_reset_token "
103                         + UUID.randomUUID().toString());
104     }
105 
turnOffEnableAdsServicesAPI()106     public static void turnOffEnableAdsServicesAPI() throws Exception {
107         forceSetFlag("enable_ad_services_system_api", false);
108     }
109 
turnOnEnableAdsServicesAPI()110     public static void turnOnEnableAdsServicesAPI() throws Exception {
111         forceSetFlag("enable_ad_services_system_api", true);
112     }
113 
disableSchedulingParams()114     public static void disableSchedulingParams() {
115         ShellUtils.runShellCommand(
116                 "device_config put adservices consent_notification_interval_begin_ms 0");
117         // set the notification interval end time to 12:00 AM
118         ShellUtils.runShellCommand(
119                 "device_config put adservices consent_notification_interval_end_ms 86400000");
120     }
121 
enableConsentDebugMode()122     public static void enableConsentDebugMode() throws Exception {
123         forceSetFlag("consent_notification_debug_mode", true);
124     }
125 
disableConsentDebugMode()126     public static void disableConsentDebugMode() throws Exception {
127         forceSetFlag("consent_notification_debug_mode", false);
128     }
129 
enableGlobalKillSwitch()130     public static void enableGlobalKillSwitch() throws Exception {
131         forceSetFlag("global_kill_switch", true);
132     }
133 
setAsEuDevice()134     public static void setAsEuDevice() throws Exception {
135         forceSetFlag("is_eea_device", true);
136     }
137 
setAsRowDevice()138     public static void setAsRowDevice() throws Exception {
139         forceSetFlag("is_eea_device", false);
140     }
141 
enableU18()142     public static void enableU18() throws Exception {
143         forceSetFlag("u18_ux_enabled", true);
144     }
145 
enableGa()146     public static void enableGa() throws Exception {
147         forceSetFlag("ga_ux_enabled", true);
148     }
149 
150     /** Override flag rvc_ux_enabled in tests to true */
enableRvc()151     public static void enableRvc() throws Exception {
152         forceSetFlag("rvc_ux_enabled", true);
153     }
154 
155     /** Override flag rvc_post_ota_notification_enabled in tests to true */
enableRvcNotification()156     public static void enableRvcNotification() throws Exception {
157         forceSetFlag("rvc_post_ota_notification_enabled", true);
158     }
159 
160     /** Override flag rvc_ux_enabled in tests to false */
disableRvc()161     public static void disableRvc() throws Exception {
162         forceSetFlag("rvc_ux_enabled", false);
163     }
164 
165     /** Disables the enableAdServices system API. */
turnOffEnableAdServicesSystemApi()166     public static void turnOffEnableAdServicesSystemApi() throws Exception {
167         forceSetFlag("enable_ad_services_system_api", false);
168     }
169 
170     /** Enables the enableAdServices system API. */
turnOnAdServicesSystemApi()171     public static void turnOnAdServicesSystemApi() throws Exception {
172         forceSetFlag("enable_ad_services_system_api", true);
173     }
174 
enableBeta()175     public static void enableBeta() throws Exception {
176         forceSetFlag("ga_ux_enabled", false);
177     }
178 
enableOtaStrings()179     public static void enableOtaStrings() throws Exception {
180         forceSetFlag("ui_ota_strings_feature_enabled", true);
181     }
182 
disableOtaStrings()183     public static void disableOtaStrings() throws Exception {
184         forceSetFlag("ui_ota_strings_feature_enabled", false);
185     }
186 
restartAdservices()187     public static void restartAdservices() {
188         ShellUtils.runShellCommand("am force-stop com.google.android.adservices.api");
189         ShellUtils.runShellCommand("am force-stop com.android.adservices.api");
190     }
191 
clearSavedStatus()192     public static void clearSavedStatus() {
193         ShellUtils.runShellCommand(
194                 "rm /data/user/0/com.google.android.adservices.api/files/"
195                         + "ConsentManagerStorageIdentifier.xml");
196         ShellUtils.runShellCommand(
197                 "rm /data/user/0/com.android.adservices.api/files/"
198                         + "ConsentManagerStorageIdentifier.xml");
199         ShellUtils.runShellCommand(
200                 "rm /data/system/adservices/0/consent/ConsentManagerStorageIdentifier.xml");
201     }
202 
setSourceOfTruthToPPAPI()203     public static void setSourceOfTruthToPPAPI() {
204         ShellUtils.runShellCommand("device_config put adservices consent_source_of_truth 1");
205     }
206 
207     /** Set flag consent_manager_debug_mode to true in tests */
setConsentManagerDebugMode()208     public static void setConsentManagerDebugMode() {
209         ShellUtils.runShellCommand("setprop debug.adservices.consent_manager_debug_mode true");
210     }
211 
212     /** Set flag consent_manager_ota_debug_mode to true in tests */
setConsentManagerOtaDebugMode()213     public static void setConsentManagerOtaDebugMode() {
214         ShellUtils.runShellCommand("setprop debug.adservices.consent_manager_ota_debug_mode true");
215     }
216 
217     /** Set flag consent_manager_debug_mode to false in tests */
resetConsentManagerDebugMode()218     public static void resetConsentManagerDebugMode() {
219         ShellUtils.runShellCommand("setprop debug.adservices.consent_manager_debug_mode false");
220     }
221 
enableNotificationPermission()222     public static void enableNotificationPermission() {
223         InstrumentationRegistry.getInstrumentation()
224                 .getUiAutomation()
225                 .grantRuntimePermission("com.android.adservices.api", POST_NOTIFICATIONS);
226     }
227 
disableNotificationFlowV2()228     public static void disableNotificationFlowV2() throws Exception {
229         forceSetFlag("eu_notif_flow_change_enabled", false);
230     }
231 
232     /** set the binder time for cts test */
setBinderTimeout()233     public static void setBinderTimeout() throws Exception {
234         ShellUtils.runShellCommand(
235                 "setprop debug.adservices.binder_timeout %s", DEFAULT_BINDER_CONNECTION_TIMEOUT_MS);
236     }
237 
238     /** enable pas */
enablePas()239     public static void enablePas() throws Exception {
240         forceSetFlag("pas_ux_enabled", true);
241     }
242 
243     /** disable pas */
disablePas()244     public static void disablePas() throws Exception {
245         forceSetFlag("pas_ux_enabled", false);
246     }
247 
verifyNotification( Context context, UiDevice device, boolean isDisplayed, boolean isEuTest, UiConstants.UX ux)248     public static void verifyNotification(
249             Context context,
250             UiDevice device,
251             boolean isDisplayed,
252             boolean isEuTest,
253             UiConstants.UX ux)
254             throws Exception {
255         int notificationTitle = -1;
256         int notificationHeader = -1;
257         switch (ux) {
258             case GA_UX:
259                 // Should match the contentTitle string in ConsentNotificationTrigger.java.
260                 notificationTitle =
261                         isEuTest
262                                 ? R.string.notificationUI_notification_ga_title_eu_v2
263                                 : R.string.notificationUI_notification_ga_title_v2;
264                 // Should match the text in consent_notification_screen_1_ga_v2_eu.xml and
265                 // consent_notification_screen_1_ga_v2_row.xml, respectively.
266                 notificationHeader =
267                         isEuTest
268                                 ? R.string.notificationUI_fledge_measurement_title_v2
269                                 : R.string.notificationUI_header_ga_title_v2;
270                 break;
271             case BETA_UX:
272                 notificationTitle =
273                         isEuTest
274                                 ? R.string.notificationUI_notification_title_eu
275                                 : R.string.notificationUI_notification_title;
276                 notificationHeader =
277                         isEuTest
278                                 ? R.string.notificationUI_header_title_eu
279                                 : R.string.notificationUI_header_title;
280                 break;
281             case U18_UX:
282                 notificationTitle = R.string.notificationUI_u18_notification_title;
283                 notificationHeader = R.string.notificationUI_u18_header_title;
284                 break;
285         }
286 
287         verifyNotification(context, device, isDisplayed, notificationTitle, notificationHeader);
288     }
289 
verifyNotification( Context context, UiDevice device, boolean isDisplayed, int notificationTitle, int notificationHeader)290     public static void verifyNotification(
291             Context context,
292             UiDevice device,
293             boolean isDisplayed,
294             int notificationTitle,
295             int notificationHeader)
296             throws Exception {
297         device.openNotification();
298         device.waitForIdle(LAUNCH_TIMEOUT);
299         // Wait few seconds for Adservices notification to show, waitForIdle is not enough.
300         Thread.sleep(LAUNCH_TIMEOUT);
301         UiObject2 scroller = device.findObject(By.res(SYSTEM_UI_RESOURCE_ID));
302 
303         BySelector notificationTitleSelector = By.text(getString(context, notificationTitle));
304         if (!isDisplayed) {
305             assertThat(scroller.hasObject(notificationTitleSelector)).isFalse();
306             return;
307         }
308         assertThat(scroller.hasObject(notificationTitleSelector)).isTrue();
309         UiObject2 notificationCard =
310                 scroller.findObject(By.text(getString(context, notificationTitle)));
311 
312         notificationCard.click();
313         device.waitForIdle(LAUNCH_TIMEOUT);
314         Thread.sleep(LAUNCH_TIMEOUT);
315         UiObject2 title = getElement(context, device, notificationHeader);
316         assertThat(title).isNotNull();
317     }
318 
setupOTAStrings( Context context, UiDevice device, AdServicesCommonManager commonManager, String mddURL)319     public static void setupOTAStrings(
320             Context context, UiDevice device, AdServicesCommonManager commonManager, String mddURL)
321             throws Exception {
322         setAdServicesFlagsForOTATesting(mddURL);
323 
324         AdservicesTestHelper.killAdservicesProcess(context);
325 
326         // Consent is required to trigger the MDD job.
327         commonManager.setAdServicesEnabled(ENTRY_POINT_ENABLED, AD_ID_ENABLED);
328         Thread.sleep(LAUNCH_TIMEOUT);
329 
330         ShellUtils.runShellCommand("cmd jobscheduler run -f com.google.android.adservices.api 14");
331 
332         Thread.sleep(LAUNCH_TIMEOUT);
333         clearNotifications(context, device);
334     }
335 
setAdServicesFlagsForOTATesting(String mddURL)336     public static void setAdServicesFlagsForOTATesting(String mddURL) throws Exception {
337         ShellUtils.runShellCommand("device_config put adservices ga_ux_enabled false");
338         ShellUtils.runShellCommand(
339                 "device_config put adservices ui_ota_strings_feature_enabled true");
340         ShellUtils.runShellCommand("device_config put adservices adservice_enabled true");
341         ShellUtils.runShellCommand("setprop debug.adservices.consent_notification_debug_mode true");
342         ShellUtils.runShellCommand("device_config put adservices global_kill_switch false");
343         ShellUtils.runShellCommand(
344                 "device_config put adservices mdd_ui_ota_strings_manifest_file_url " + mddURL);
345 
346         // Set as ROW device for default consent opt-in.
347         UiUtils.setAsRowDevice();
348     }
349 
setOTADownloadTimeout(long timeout)350     public static void setOTADownloadTimeout(long timeout) {
351         ShellUtils.runShellCommand(
352                 String.format(
353                         "device_config put adservices ui_ota_strings_download_deadline %d",
354                         timeout));
355     }
356 
clearNotifications(Context context, UiDevice device)357     public static void clearNotifications(Context context, UiDevice device)
358             throws InterruptedException {
359         device.openNotification();
360         Thread.sleep(LAUNCH_TIMEOUT);
361         UiObject2 scroller2 =
362                 device.findObject(By.res("com.android.systemui:id/notification_stack_scroller"));
363         UiObject2 notificationCard =
364                 scroller2.findObject(
365                         By.textContains(
366                                 getString(context, R.string.notificationUI_notification_title)));
367 
368         if (notificationCard != null) {
369             notificationCard.click();
370         }
371         Thread.sleep(LAUNCH_TIMEOUT);
372         device.pressHome();
373     }
374 
verifyNotificationAndSettingsPage( Context context, UiDevice device, Boolean isOTA)375     public static void verifyNotificationAndSettingsPage(
376             Context context, UiDevice device, Boolean isOTA) throws InterruptedException {
377         // open notification tray
378         device.openNotification();
379         Thread.sleep(LAUNCH_TIMEOUT);
380         device.wait(Until.hasObject(By.pkg("com.android.systemui")), LAUNCH_TIMEOUT);
381 
382         // verify notification card
383         UiObject2 scroller =
384                 device.findObject(By.res("com.android.systemui:id/notification_stack_scroller"));
385 
386         String targetStr =
387                 isOTA
388                         ? getOTAString(context, R.string.notificationUI_notification_title)
389                         : getString(context, R.string.notificationUI_notification_title);
390 
391         UiObject2 notificationCard = scroller.findObject(By.text(targetStr));
392         Thread.sleep(LAUNCH_TIMEOUT);
393 
394         notificationCard.click();
395 
396         // Wait for the notification landing page to appear
397         device.wait(Until.hasObject(By.pkg(NOTIFICATION_PACKAGE_NAME).depth(0)), LAUNCH_TIMEOUT);
398 
399         // verify strings
400         UiObject2 title =
401                 isOTA
402                         ? scrollToOTAElement(context, device, R.string.notificationUI_header_title)
403                         : scrollToElement(context, device, R.string.notificationUI_header_title);
404 
405         assertThat(title).isNotNull();
406         // open settings
407         scrollToThenClickElementContainingText(
408                 device,
409                 isOTA
410                         ? "Manage privacy settings!"
411                         : getString(context, R.string.notificationUI_left_control_button_text));
412 
413         // Wait for the app to appear
414         device.wait(Until.hasObject(By.pkg(PRIVACY_SANDBOX_PACKAGE_NAME).depth(0)), LAUNCH_TIMEOUT);
415 
416         // verify strings have changed
417         UiObject2 appButton =
418                 isOTA
419                         ? scrollToOTAElement(context, device, R.string.settingsUI_apps_title)
420                         : scrollToElement(context, device, R.string.settingsUI_apps_title);
421 
422         device.waitForIdle(LAUNCH_TIMEOUT);
423         assertThat(appButton).isNotNull();
424         UiObject2 topicsButton =
425                 isOTA
426                         ? scrollToOTAElement(context, device, R.string.settingsUI_topics_title)
427                         : scrollToElement(context, device, R.string.settingsUI_topics_title);
428         assertThat(topicsButton).isNotNull();
429     }
430 
connectToWifi()431     public static void connectToWifi() {
432         ShellUtils.runShellCommand("svc wifi enable");
433         ShellUtils.runShellCommand("cmd wifi connect-network VirtWifi open");
434     }
435 
turnOffWifi()436     public static void turnOffWifi() {
437         ShellUtils.runShellCommand("svc wifi disable");
438     }
439 
scrollToThenClickElementContainingText(UiDevice device, String text)440     private static void scrollToThenClickElementContainingText(UiDevice device, String text) {
441         UiObject2 element = scrollToElement(device, text);
442         element.click();
443     }
444 
scrollToOTAElement(Context context, UiDevice device, int resId)445     private static UiObject2 scrollToOTAElement(Context context, UiDevice device, int resId) {
446         return scrollToElement(device, getOTAString(context, resId));
447     }
448 
scrollToElement(UiDevice device, String targetStr)449     private static UiObject2 scrollToElement(UiDevice device, String targetStr) {
450         UiObject2 scrollView =
451                 device.findObject(By.clazz(ANDROID_WIDGET_SCROLLVIEW).scrollable(true));
452         UiObject2 element =
453                 scrollView.scrollUntil(
454                         Direction.DOWN, Until.findObject(By.textContains(targetStr)));
455         if (element != null) {
456             return element;
457         }
458         return device.findObject(By.textContains(targetStr));
459     }
460 
scrollToElement(Context context, UiDevice device, int resId)461     private static UiObject2 scrollToElement(Context context, UiDevice device, int resId) {
462         return scrollToElement(device, getString(context, resId));
463     }
464 
465     // Test strings for OTA have an exclamation mark appended to the end
getOTAString(Context context, int resourceId)466     private static String getOTAString(Context context, int resourceId) {
467         return getString(context, resourceId) + "!";
468     }
469 
470     /**
471      * Swipes through the screen to show elements on the button of the page but hidden by the
472      * navigation bar.
473      */
gentleSwipe(UiDevice device)474     public static void gentleSwipe(UiDevice device) {
475         UiObject2 scrollView =
476                 device.findObject(By.scrollable(true).clazz(ANDROID_WIDGET_SCROLLVIEW));
477         // Some devices on R is not scrollable
478         if (scrollView != null) {
479                 scrollView.scroll(Direction.DOWN, /* percent */ 0.25F);
480         }
481     }
482 
setFlipFlow(boolean isFlip)483     public static void setFlipFlow(boolean isFlip) {
484         ShellUtils.runShellCommand(
485                 "device_config put adservices eu_notif_flow_change_enabled " + isFlip);
486     }
487 
488     /** set get adservices common states services enabled */
setGetAdservicesCommonStatesServiceEnable(boolean enable)489     public static void setGetAdservicesCommonStatesServiceEnable(boolean enable) {
490         ShellUtils.runShellCommand(
491                 "device_config put adservices get_adservices_common_states_api_enabled " + enable);
492     }
493 
494     /** set get adservices common states services enabled */
setGetAdservicesCommonStatesAllowList(String list)495     public static void setGetAdservicesCommonStatesAllowList(String list) {
496         ShellUtils.runShellCommand(
497                 "device_config put adservices get_adservices_common_states_allow_list " + list);
498     }
499 
getString(Context context, int resourceId)500     public static String getString(Context context, int resourceId) {
501         return context.getResources().getString(resourceId);
502     }
503 
scrollToAndClick(Context context, UiDevice device, int resId)504     public static void scrollToAndClick(Context context, UiDevice device, int resId) {
505         scrollTo(context, device, resId);
506         UiObject2 consentPageButton =
507                 device.wait(
508                         getSearchCondByResId(context, resId), PRIMITIVE_UI_OBJECTS_LAUNCH_TIMEOUT);
509         clickTopLeft(consentPageButton);
510     }
511 
getSearchCondByResId(Context context, int resId)512     public static SearchCondition<UiObject2> getSearchCondByResId(Context context, int resId) {
513         String targetStr = getString(context, resId);
514         return Until.findObject(By.text(Pattern.compile(targetStr, Pattern.CASE_INSENSITIVE)));
515     }
516 
getPageElement(Context context, UiDevice device, int resId)517     public static UiObject2 getPageElement(Context context, UiDevice device, int resId) {
518         return device.findObject(By.text(getString(context, resId)));
519     }
520 
scrollTo(Context context, UiDevice device, int resId)521     public static UiObject2 scrollTo(Context context, UiDevice device, int resId) {
522         UiObject2 scrollView =
523                 device.findObject(By.scrollable(true).clazz(ANDROID_WIDGET_SCROLLVIEW));
524         if (scrollView != null) {
525             String targetStr = getString(context, resId);
526             scrollView.scrollUntil(
527                     Direction.DOWN,
528                     Until.findObject(
529                             By.text(Pattern.compile(targetStr, Pattern.CASE_INSENSITIVE))));
530         }
531         return getElement(context, device, resId);
532     }
533 
getElement(Context context, UiDevice device, int resId)534     public static UiObject2 getElement(Context context, UiDevice device, int resId) {
535         return getElement(context, device, resId, 0);
536     }
537 
getElement(Context context, UiDevice device, int resId, int index)538     public static UiObject2 getElement(Context context, UiDevice device, int resId, int index) {
539         String targetStr = getString(context, resId);
540         List<UiObject2> objList =
541                 device.findObjects(By.text(Pattern.compile(targetStr, Pattern.CASE_INSENSITIVE)));
542         if (objList.size() <= index) {
543             return null;
544         }
545         return objList.get(index);
546     }
547 
clickTopLeft(UiObject2 obj)548     public static void clickTopLeft(UiObject2 obj) {
549         assertThat(obj).isNotNull();
550         obj.click(new Point(obj.getVisibleBounds().top, obj.getVisibleBounds().left));
551     }
552 
takeScreenshot(UiDevice device, String methodName)553     public static void takeScreenshot(UiDevice device, String methodName) {
554         try {
555             String timeStamp =
556                     new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.US)
557                             .format(Date.from(Instant.now()));
558 
559             File screenshotFile =
560                     new File(
561                             FileHelper.getAdServicesTestsOutputDir(),
562                             methodName + timeStamp + ".png");
563             device.takeScreenshot(screenshotFile);
564         } catch (RuntimeException e) {
565             LogUtil.e("Failed to take screenshot: " + e.getMessage());
566         }
567     }
568 
resetAdServicesConsentData(Context context)569     public static void resetAdServicesConsentData(Context context) throws Exception {
570         // Neeed to disable debug mode since it takes precedence over reset channel.
571         disableConsentDebugMode();
572         turnOnAdServicesSystemApi();
573 
574         AdServicesCommonManager mCommonManager = AdServicesCommonManager.get(context);
575 
576         // Reset consent and thereby AdServices data before each test.
577         UiUtils.refreshConsentResetToken();
578 
579         SettableFuture<Boolean> responseFuture = SettableFuture.create();
580 
581         mCommonManager.enableAdServices(
582                 new AdServicesStates.Builder()
583                         .setAdIdEnabled(true)
584                         .setAdultAccount(true)
585                         .setU18Account(true)
586                         .setPrivacySandboxUiEnabled(true)
587                         .setPrivacySandboxUiRequest(false)
588                         .build(),
589                 Executors.newCachedThreadPool(),
590                 new OutcomeReceiver<>() {
591                     @Override
592                     public void onResult(Boolean result) {
593                         responseFuture.set(result);
594                     }
595 
596                     @Override
597                     public void onError(Exception exception) {
598                         responseFuture.setException(exception);
599                     }
600                 });
601 
602         Boolean response = responseFuture.get();
603         assertThat(response).isTrue();
604     }
605 
606     /** Returns a [BySelector] of a resource in sysui package. */
sysuiResSelector(String resourceId)607     public static BySelector sysuiResSelector(String resourceId) {
608         return By.pkg(SYSTEM_UI_NAME).res(SYSTEM_UI_NAME, resourceId);
609     }
610 }
611