1 /* 2 * Copyright (C) 2024 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.common; 17 18 import static android.adservices.common.AdServicesStatusUtils.SECURITY_EXCEPTION_CALLER_NOT_ALLOWED_ERROR_MESSAGE; 19 20 import static com.google.common.truth.Truth.assertThat; 21 22 import android.adservices.common.AdServicesCommonManager; 23 import android.adservices.common.AdServicesCommonStates; 24 import android.adservices.common.AdServicesCommonStatesResponse; 25 import android.adservices.common.AdServicesOutcomeReceiver; 26 import android.adservices.common.AdServicesStates; 27 import android.adservices.common.ConsentStatus; 28 import android.os.OutcomeReceiver; 29 import android.os.Parcel; 30 import android.platform.test.rule.ScreenRecordRule; 31 32 import androidx.concurrent.futures.CallbackToFutureAdapter; 33 import androidx.test.platform.app.InstrumentationRegistry; 34 import androidx.test.uiautomator.UiDevice; 35 36 import com.android.adservices.common.AdservicesTestHelper; 37 import com.android.adservices.tests.ui.libs.AdservicesWorkflows; 38 import com.android.adservices.tests.ui.libs.UiConstants.UX; 39 import com.android.adservices.tests.ui.libs.UiUtils; 40 import com.android.adservices.tests.ui.libs.pages.NotificationPages; 41 import com.android.adservices.tests.ui.libs.pages.SettingsPages; 42 43 import com.google.common.util.concurrent.ListenableFuture; 44 import com.google.common.util.concurrent.SettableFuture; 45 46 import org.junit.After; 47 import org.junit.Assert; 48 import org.junit.Before; 49 import org.junit.Rule; 50 import org.junit.Test; 51 52 import java.util.concurrent.Executor; 53 import java.util.concurrent.Executors; 54 55 /** Test for get adservices common states. */ 56 @ScreenRecordRule.ScreenRecord 57 public final class CommonServicesTest extends AdServicesCommonStatesServicesTestCase { 58 private AdServicesCommonManager mCommonManager; 59 60 private UiDevice mDevice; 61 62 private String mTestName; 63 64 private OutcomeReceiver<Boolean, Exception> mCallback; 65 66 private static final Executor CALLBACK_EXECUTOR = Executors.newCachedThreadPool(); 67 68 private static final String TEST_PACKAGE_NAME = "com.android.adservices.tests.ui.common"; 69 private static final String INVALID_PACKAGE_NAME = "invalidPackage"; 70 71 @Rule public final ScreenRecordRule sScreenRecordRule = new ScreenRecordRule(); 72 73 @Before setUp()74 public void setUp() throws Exception { 75 mTestName = getTestName(); 76 77 UiUtils.setBinderTimeout(flags); 78 AdservicesTestHelper.killAdservicesProcess(mContext); 79 UiUtils.resetAdServicesConsentData(mContext, flags); 80 UiUtils.enableNotificationPermission(); 81 UiUtils.enableGa(flags); 82 UiUtils.enablePas(flags); 83 UiUtils.enableU18(flags); 84 UiUtils.setFlipFlow(flags, true); 85 UiUtils.disableOtaStrings(flags); 86 UiUtils.setGetAdservicesCommonStatesServiceEnable(flags, true); 87 UiUtils.setGetAdservicesCommonStatesAllowList(flags, TEST_PACKAGE_NAME); 88 89 mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()); 90 91 mCommonManager = AdServicesCommonManager.get(mContext); 92 93 // General purpose callback used for expected success calls. 94 mCallback = 95 new OutcomeReceiver<>() { 96 @Override 97 public void onResult(Boolean result) { 98 assertThat(result).isTrue(); 99 } 100 101 @Override 102 public void onError(Exception exception) { 103 Assert.fail(); 104 } 105 }; 106 107 // Reset consent and thereby AdServices data before each test. 108 UiUtils.refreshConsentResetToken(flags); 109 110 SettableFuture<Boolean> responseFuture = SettableFuture.create(); 111 112 mCommonManager.enableAdServices( 113 new AdServicesStates.Builder() 114 .setAdIdEnabled(true) 115 .setAdultAccount(true) 116 .setPrivacySandboxUiEnabled(true) 117 .build(), 118 Executors.newCachedThreadPool(), 119 new OutcomeReceiver<>() { 120 @Override 121 public void onResult(Boolean result) { 122 responseFuture.set(result); 123 } 124 125 @Override 126 public void onError(Exception exception) { 127 responseFuture.setException(exception); 128 } 129 }); 130 131 Boolean response = responseFuture.get(); 132 assertThat(response).isTrue(); 133 134 mDevice.pressHome(); 135 } 136 137 @After tearDown()138 public void tearDown() throws Exception { 139 UiUtils.takeScreenshot(mDevice, getClass().getSimpleName() + "_" + mTestName + "_"); 140 UiUtils.disablePas(flags); 141 AdservicesTestHelper.killAdservicesProcess(mContext); 142 } 143 144 /** Verify that for GA, ROW devices get adservices common states of opt-in consent. */ 145 @Test testGetAdservicesCommonStatesOptIn()146 public void testGetAdservicesCommonStatesOptIn() throws Exception { 147 UiUtils.setAsRowDevice(flags); 148 AdservicesTestHelper.killAdservicesProcess(mContext); 149 150 // Set consents to true. 151 AdservicesWorkflows.testSettingsPageFlow( 152 mContext, 153 mDevice, 154 flags, 155 /* ux type */ UX.GA_UX, 156 /* consent opt-in */ true, 157 /* flip consent */ false, 158 /* assert consent */ true); 159 160 AdServicesStates adServicesStates = 161 new AdServicesStates.Builder() 162 .setAdIdEnabled(true) 163 .setAdultAccount(true) 164 .setPrivacySandboxUiEnabled(true) 165 .build(); 166 167 mCommonManager.enableAdServices( 168 adServicesStates, Executors.newCachedThreadPool(), mCallback); 169 170 // Trigger Pas re-notify notification. 171 NotificationPages.verifyNotification( 172 mContext, 173 mDevice, 174 /* isDisplayed */ true, 175 /* isEuTest */ false, 176 /* ux type */ UX.GA_UX, 177 /* isFlipFlow */ true, 178 /* isPas */ true, 179 /* isPasRenotify */ true); 180 181 ListenableFuture<AdServicesCommonStatesResponse> adServicesCommonStatesResponse = 182 getAdservicesCommonStates(); 183 184 AdServicesCommonStates commonStates = 185 adServicesCommonStatesResponse.get().getAdServicesCommonStates(); 186 assertThat(commonStates.getMeasurementState()).isEqualTo(ConsentStatus.GIVEN); 187 assertThat(commonStates.getPaState()).isEqualTo(ConsentStatus.GIVEN); 188 } 189 190 /** Verify that for GA devices get adservices common states of opt-out consent. */ 191 @Test testGetAdservicesCommonStatesOptOut()192 public void testGetAdservicesCommonStatesOptOut() throws Exception { 193 UiUtils.setFlipFlow(flags, true); 194 UiUtils.setAsRowDevice(flags); 195 UiUtils.setGetAdservicesCommonStatesServiceEnable(flags, true); 196 AdservicesTestHelper.killAdservicesProcess(mContext); 197 198 // Set consents to true. 199 AdservicesWorkflows.testSettingsPageFlow( 200 mContext, 201 mDevice, 202 flags, 203 /* ux type */ UX.GA_UX, 204 /* consent opt-in */ true, 205 /* flip consent */ false, 206 /* assert consent */ true); 207 208 AdServicesStates adServicesStates = 209 new AdServicesStates.Builder() 210 .setAdIdEnabled(true) 211 .setAdultAccount(true) 212 .setPrivacySandboxUiEnabled(true) 213 .build(); 214 215 mCommonManager.enableAdServices( 216 adServicesStates, Executors.newCachedThreadPool(), mCallback); 217 218 AdservicesWorkflows.testClickNotificationFlow( 219 mContext, 220 mDevice, 221 /* isDisplayed */ true, 222 /* isEuTest */ false, 223 /* ux type */ UX.GA_UX, 224 /* isFlipFlow */ true, 225 /* consent opt-in */ true, 226 /* isPas */ true, 227 /* isPasRenotify */ true); 228 229 // Set consents to false. 230 SettingsPages.testSettingsPageConsents( 231 mContext, 232 mDevice, 233 /* ux type */ UX.GA_UX, 234 /* consent opt-in */ false, 235 /* flip consent */ false, 236 /* assert consent */ false); 237 238 ListenableFuture<AdServicesCommonStatesResponse> adServicesCommonStatesResponse = 239 getAdservicesCommonStates(); 240 241 AdServicesCommonStates commonStates = 242 adServicesCommonStatesResponse.get().getAdServicesCommonStates(); 243 assertThat(commonStates.getMeasurementState()).isEqualTo(ConsentStatus.REVOKED); 244 assertThat(commonStates.getPaState()).isEqualTo(ConsentStatus.REVOKED); 245 } 246 247 /** Verify that for GA, ROW devices get adservices common states of opt-in consent. */ 248 @Test testGetAdservicesCommonStatesNotEnabled()249 public void testGetAdservicesCommonStatesNotEnabled() throws Exception { 250 UiUtils.setAsRowDevice(flags); 251 UiUtils.setGetAdservicesCommonStatesServiceEnable(flags, false); 252 AdservicesTestHelper.killAdservicesProcess(mContext); 253 254 ListenableFuture<AdServicesCommonStatesResponse> adServicesCommonStatesResponse = 255 getAdservicesCommonStates(); 256 257 AdServicesCommonStates commonStates = 258 adServicesCommonStatesResponse.get().getAdServicesCommonStates(); 259 assertThat(commonStates.getMeasurementState()).isEqualTo(ConsentStatus.SERVICE_NOT_ENABLED); 260 assertThat(commonStates.getPaState()).isEqualTo(ConsentStatus.SERVICE_NOT_ENABLED); 261 } 262 263 @Test testGetAdservicesCommonStatesNotAllowed()264 public void testGetAdservicesCommonStatesNotAllowed() throws Exception { 265 UiUtils.setAsRowDevice(flags); 266 UiUtils.setGetAdservicesCommonStatesServiceEnable(flags, false); 267 UiUtils.setGetAdservicesCommonStatesAllowList(flags, INVALID_PACKAGE_NAME); 268 AdservicesTestHelper.killAdservicesProcess(mContext); 269 270 ListenableFuture<AdServicesCommonStatesResponse> adServicesCommonStatesResponse = 271 getAdservicesCommonStates(); 272 273 Exception e = Assert.assertThrows(Exception.class, adServicesCommonStatesResponse::get); 274 assertThat("class " + e.getMessage()) 275 .isEqualTo( 276 e.getCause().getClass() 277 + ": " 278 + SECURITY_EXCEPTION_CALLER_NOT_ALLOWED_ERROR_MESSAGE); 279 } 280 getAdservicesCommonStates()281 private ListenableFuture<AdServicesCommonStatesResponse> getAdservicesCommonStates() { 282 return CallbackToFutureAdapter.getFuture( 283 completer -> { 284 mCommonManager.getAdservicesCommonStates( 285 CALLBACK_EXECUTOR, 286 new AdServicesOutcomeReceiver<>() { 287 @Override 288 public void onResult(AdServicesCommonStatesResponse result) { 289 completer.set(result); 290 } 291 292 @Override 293 public void onError(Exception error) { 294 completer.setException(error); 295 } 296 }); 297 // This value is used only for debug purposes: it will be used in toString() 298 // of returned future or error cases. 299 return "getStatus"; 300 }); 301 } 302 303 @Test 304 public void testAdservicesCommonStatesCoverages() { 305 AdServicesCommonStates states = 306 new AdServicesCommonStates.Builder() 307 .setMeasurementState(ConsentStatus.GIVEN) 308 .setPaState(ConsentStatus.REVOKED) 309 .build(); 310 311 Parcel parcel = Parcel.obtain(); 312 313 try { 314 states.writeToParcel(parcel, 0); 315 parcel.setDataPosition(0); 316 317 AdServicesCommonStates createdParams = 318 AdServicesCommonStates.CREATOR.createFromParcel(parcel); 319 assertThat(createdParams.describeContents()).isEqualTo(0); 320 assertThat(createdParams).isNotSameInstanceAs(states); 321 assertThat(createdParams.getPaState()).isEqualTo(states.getPaState()); 322 assertThat(createdParams.getMeasurementState()).isEqualTo(states.getMeasurementState()); 323 assertThat(createdParams.equals(states)).isTrue(); 324 assertThat(createdParams.hashCode()).isEqualTo(states.hashCode()); 325 assertThat(createdParams.toString()).isEqualTo(states.toString()); 326 } finally { 327 parcel.recycle(); 328 } 329 } 330 331 @Test 332 public void testAdservicesCommonStatesResponseCoverages() { 333 AdServicesCommonStates states = 334 new AdServicesCommonStates.Builder() 335 .setMeasurementState(ConsentStatus.GIVEN) 336 .setPaState(ConsentStatus.REVOKED) 337 .build(); 338 AdServicesCommonStatesResponse response = 339 new AdServicesCommonStatesResponse.Builder(states) 340 .setAdservicesCommonStates(states) 341 .build(); 342 343 Parcel parcel = Parcel.obtain(); 344 345 try { 346 response.writeToParcel(parcel, 0); 347 parcel.setDataPosition(0); 348 349 AdServicesCommonStatesResponse createdParams = 350 AdServicesCommonStatesResponse.CREATOR.createFromParcel(parcel); 351 assertThat(createdParams.describeContents()).isEqualTo(0); 352 assertThat(createdParams).isNotSameInstanceAs(response); 353 assertThat(createdParams.getAdServicesCommonStates().getPaState()) 354 .isEqualTo(states.getPaState()); 355 assertThat(createdParams.getAdServicesCommonStates().getMeasurementState()) 356 .isEqualTo(states.getMeasurementState()); 357 assertThat(createdParams.toString()).isEqualTo(response.toString()); 358 } finally { 359 parcel.recycle(); 360 } 361 } 362 } 363