blob: 22e29d146291d427bf4bcbee05e0e41c9b322196 [file] [log] [blame]
/*
* Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.adservices.ui.settings;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.spy;
import android.content.Context;
import android.os.Build;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.platform.app.InstrumentationRegistry;
import androidx.test.uiautomator.By;
import androidx.test.uiautomator.UiDevice;
import androidx.test.uiautomator.UiObject;
import androidx.test.uiautomator.UiObjectNotFoundException;
import androidx.test.uiautomator.UiSelector;
import androidx.test.uiautomator.Until;
import com.android.adservices.api.R;
import com.android.adservices.common.AdservicesTestHelper;
import com.android.adservices.service.Flags;
import com.android.adservices.service.FlagsFactory;
import com.android.adservices.service.PhFlags;
import com.android.adservices.service.common.BackgroundJobsManager;
import com.android.adservices.service.consent.AdServicesApiType;
import com.android.adservices.ui.util.ApkTestUtil;
import com.android.compatibility.common.util.ShellUtils;
import com.android.dx.mockito.inline.extended.ExtendedMockito;
import com.android.modules.utils.build.SdkLevel;
import org.junit.After;
import org.junit.Assume;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoSession;
import org.mockito.quality.Strictness;
@RunWith(AndroidJUnit4.class)
public class ConsentSettingsUiAutomatorTest {
private static final Context CONTEXT = ApplicationProvider.getApplicationContext();
private static final int LAUNCH_TIMEOUT = 5000;
private static UiDevice sDevice;
private MockitoSession mStaticMockSession;
private PhFlags mPhFlags;
@Mock Flags mMockFlags;
@Before
public void setup() {
// Skip the test if it runs on unsupported platforms.
Assume.assumeTrue(ApkTestUtil.isDeviceSupported());
// Initialize UiDevice instance
sDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
// Start from the home screen
sDevice.pressHome();
// Wait for launcher
final String launcherPackage = sDevice.getLauncherPackageName();
assertThat(launcherPackage).isNotNull();
sDevice.wait(Until.hasObject(By.pkg(launcherPackage).depth(0)), LAUNCH_TIMEOUT);
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) {
startMockCompatFlags();
} else {
ShellUtils.runShellCommand("device_config put adservices ga_ux_enabled false");
}
}
@After
public void teardown() {
if (!ApkTestUtil.isDeviceSupported()) return;
AdservicesTestHelper.killAdservicesProcess(CONTEXT);
if (mStaticMockSession != null) {
mStaticMockSession.finishMocking();
}
}
@Test
public void consentSystemServerOnlyTest() throws UiObjectNotFoundException {
Assume.assumeTrue(SdkLevel.isAtLeastT());
ShellUtils.runShellCommand("device_config put adservices consent_source_of_truth 0");
ShellUtils.runShellCommand("device_config put adservices ui_dialogs_feature_enabled false");
consentTest(false);
}
@Test
public void consentPpApiOnlyTest() throws UiObjectNotFoundException {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) {
doReturn(1).when(mMockFlags).getConsentSourceOfTruth();
doReturn(false).when(mPhFlags).getUIDialogsFeatureEnabled();
} else {
ShellUtils.runShellCommand("device_config put adservices consent_source_of_truth 1");
ShellUtils.runShellCommand(
"device_config put adservices ui_dialogs_feature_enabled false");
}
consentTest(false);
}
@Test
public void consentSystemServerAndPpApiTest() throws UiObjectNotFoundException {
Assume.assumeTrue(SdkLevel.isAtLeastT());
ShellUtils.runShellCommand("device_config put adservices consent_source_of_truth 2");
ShellUtils.runShellCommand("device_config put adservices ui_dialogs_feature_enabled false");
consentTest(false);
}
@Test
public void consentSystemServerOnlyDialogsOnTest() throws UiObjectNotFoundException {
Assume.assumeTrue(SdkLevel.isAtLeastT());
ShellUtils.runShellCommand("device_config put adservices consent_source_of_truth 0");
ShellUtils.runShellCommand("device_config put adservices ui_dialogs_feature_enabled true");
consentTest(true);
}
@Test
public void consentPpApiOnlyDialogsOnTest() throws UiObjectNotFoundException {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) {
doReturn(1).when(mMockFlags).getConsentSourceOfTruth();
doReturn(true).when(mPhFlags).getUIDialogsFeatureEnabled();
} else {
ShellUtils.runShellCommand("device_config put adservices consent_source_of_truth 1");
ShellUtils.runShellCommand(
"device_config put adservices ui_dialogs_feature_enabled true");
}
consentTest(true);
}
@Test
public void consentSystemServerAndPpApiDialogsOnTest() throws UiObjectNotFoundException {
Assume.assumeTrue(SdkLevel.isAtLeastT());
ShellUtils.runShellCommand("device_config put adservices consent_source_of_truth 2");
ShellUtils.runShellCommand("device_config put adservices ui_dialogs_feature_enabled true");
consentTest(true);
}
@Test
public void consentAppSearchOnlyTest() throws UiObjectNotFoundException {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) {
doReturn(true).when(mMockFlags).getEnableAppsearchConsentData();
doReturn(Flags.APPSEARCH_ONLY).when(mMockFlags).getConsentSourceOfTruth();
consentTest(true);
} else {
ShellUtils.runShellCommand(
"device_config put adservices enable_appsearch_consent_data true");
ShellUtils.runShellCommand("device_config put adservices consent_source_of_truth 3");
consentTest(true);
ShellUtils.runShellCommand("device_config put adservices consent_source_of_truth null");
ShellUtils.runShellCommand(
"device_config put adservices enable_appsearch_consent_data null");
}
}
@Test
public void consentAppSearchOnlyDialogsOnTest() throws UiObjectNotFoundException {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) {
doReturn(true).when(mMockFlags).getEnableAppsearchConsentData();
doReturn(Flags.APPSEARCH_ONLY).when(mMockFlags).getConsentSourceOfTruth();
doReturn(true).when(mPhFlags).getUIDialogsFeatureEnabled();
consentTest(true);
} else {
ShellUtils.runShellCommand(
"device_config put adservices enable_appsearch_consent_data true");
ShellUtils.runShellCommand("device_config put adservices consent_source_of_truth 3");
ShellUtils.runShellCommand(
"device_config put adservices ui_dialogs_feature_enabled true");
consentTest(true);
ShellUtils.runShellCommand("device_config put adservices consent_source_of_truth null");
}
}
private void consentTest(boolean dialogsOn) throws UiObjectNotFoundException {
ApkTestUtil.launchSettingView(
ApplicationProvider.getApplicationContext(), sDevice, LAUNCH_TIMEOUT);
UiObject mainSwitch =
sDevice.findObject(new UiSelector().className("android.widget.Switch"));
assertThat(mainSwitch.exists()).isTrue();
setConsentToFalse(dialogsOn);
// click switch
performSwitchClick(dialogsOn, mainSwitch);
assertThat(mainSwitch.isChecked()).isTrue();
// click switch
performSwitchClick(dialogsOn, mainSwitch);
assertThat(mainSwitch.isChecked()).isFalse();
}
private void setConsentToFalse(boolean dialogsOn) throws UiObjectNotFoundException {
UiObject mainSwitch =
sDevice.findObject(new UiSelector().className("android.widget.Switch"));
if (mainSwitch.isChecked()) {
performSwitchClick(dialogsOn, mainSwitch);
}
}
private void performSwitchClick(boolean dialogsOn, UiObject mainSwitch)
throws UiObjectNotFoundException {
if (dialogsOn && mainSwitch.isChecked()) {
mainSwitch.click();
UiObject dialogTitle =
ApkTestUtil.getElement(sDevice, R.string.settingsUI_dialog_opt_out_title);
UiObject positiveText =
ApkTestUtil.getElement(
sDevice, R.string.settingsUI_dialog_opt_out_positive_text);
assertThat(dialogTitle.exists()).isTrue();
assertThat(positiveText.exists()).isTrue();
positiveText.click();
} else {
mainSwitch.click();
}
}
private void startMockCompatFlags() {
// Static mocking
mStaticMockSession =
ExtendedMockito.mockitoSession()
.spyStatic(PhFlags.class)
.spyStatic(FlagsFactory.class)
.spyStatic(BackgroundJobsManager.class)
.strictness(Strictness.WARN)
.initMocks(this)
.startMocking();
// Mock static method FlagsFactory.getFlags() to return Mock Flags.
ExtendedMockito.doReturn(mMockFlags).when(FlagsFactory::getFlags);
ExtendedMockito.doNothing()
.when(() -> BackgroundJobsManager.scheduleAllBackgroundJobs(any(Context.class)));
ExtendedMockito.doNothing()
.when(
() ->
BackgroundJobsManager.scheduleJobsPerApi(
any(Context.class), any(AdServicesApiType.class)));
mPhFlags = spy(PhFlags.getInstance());
ExtendedMockito.doReturn(mPhFlags).when(PhFlags::getInstance);
doReturn(false).when(mMockFlags).getGaUxFeatureEnabled();
// Back compat only supports the following flags
doReturn(1).when(mMockFlags).getBlockedTopicsSourceOfTruth();
doReturn(true).when(mMockFlags).getMeasurementRollbackDeletionKillSwitch();
}
}