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