fix: 引入Settings的Module
This commit is contained in:
38
Settings/tests/componenttests/Android.bp
Normal file
38
Settings/tests/componenttests/Android.bp
Normal file
@@ -0,0 +1,38 @@
|
||||
//############################################################
|
||||
// Settings Component test target. #
|
||||
//############################################################
|
||||
package {
|
||||
default_team: "trendy_team_android_settings_app",
|
||||
// See: http://go/android-license-faq
|
||||
// A large-scale-change added 'default_applicable_licenses' to import
|
||||
// all of the 'license_kinds' from "packages_apps_Settings_license"
|
||||
// to get the below license kinds:
|
||||
// SPDX-license-identifier-Apache-2.0
|
||||
default_applicable_licenses: ["packages_apps_Settings_license"],
|
||||
}
|
||||
|
||||
android_test {
|
||||
name: "SettingsComponentTests",
|
||||
certificate: "platform",
|
||||
privileged: true,
|
||||
srcs: [
|
||||
"src/**/*.java",
|
||||
],
|
||||
|
||||
static_libs: [
|
||||
"truth",
|
||||
"androidx.test.core",
|
||||
"androidx.test.espresso.core",
|
||||
"androidx.test.espresso.intents-nodeps",
|
||||
"androidx.test.runner",
|
||||
"androidx.test.rules",
|
||||
"androidx.test.ext.junit",
|
||||
"mockito-target",
|
||||
],
|
||||
|
||||
test_suites: ["device-tests"],
|
||||
optimize: {
|
||||
enabled: false,
|
||||
},
|
||||
instrumentation_for: "Settings",
|
||||
}
|
||||
43
Settings/tests/componenttests/AndroidManifest.xml
Normal file
43
Settings/tests/componenttests/AndroidManifest.xml
Normal file
@@ -0,0 +1,43 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright (C) 2016 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.
|
||||
-->
|
||||
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
|
||||
package="com.android.settings.tests.component"
|
||||
android:sharedUserId="android.uid.systemui">
|
||||
|
||||
<uses-permission android:name="android.permission.BLUETOOTH" />
|
||||
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
|
||||
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
|
||||
<uses-permission android:name="android.permission.BLUETOOTH_SCAN" />
|
||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
|
||||
<uses-permission android:name="android.permission.USE_CREDENTIALS" />
|
||||
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
|
||||
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
|
||||
<uses-permission android:name="android.permission.INTERACT_ACROSS_USERS" />
|
||||
<uses-permission android:name="android.permission.UPDATE_APP_OPS_STATS" />
|
||||
<uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
|
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||
|
||||
<application/>
|
||||
|
||||
<instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
|
||||
android:targetPackage="com.android.settings"
|
||||
android:label="Settings Test Cases">
|
||||
</instrumentation>
|
||||
|
||||
</manifest>
|
||||
30
Settings/tests/componenttests/AndroidTest.xml
Normal file
30
Settings/tests/componenttests/AndroidTest.xml
Normal file
@@ -0,0 +1,30 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright (C) 2017 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.
|
||||
-->
|
||||
<configuration description="Runs Settings Test Cases.">
|
||||
<option name="test-suite-tag" value="apct" />
|
||||
<option name="test-suite-tag" value="apct-instrumentation" />
|
||||
<target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
|
||||
<option name="cleanup-apks" value="true" />
|
||||
<option name="test-file-name" value="SettingsComponentTests.apk" />
|
||||
</target_preparer>
|
||||
|
||||
<option name="test-tag" value="SettingsComponentTests" />
|
||||
<test class="com.android.tradefed.testtype.AndroidJUnitTest" >
|
||||
<option name="package" value="com.android.settings.tests.component" />
|
||||
<option name="runner" value="androidx.test.runner.AndroidJUnitRunner" />
|
||||
<option name="hidden-api-checks" value="false"/>
|
||||
</test>
|
||||
</configuration>
|
||||
3
Settings/tests/componenttests/OWNERS
Normal file
3
Settings/tests/componenttests/OWNERS
Normal file
@@ -0,0 +1,3 @@
|
||||
# People who can approve changes for submission
|
||||
jyhsu@google.com
|
||||
syaoranx@google.com
|
||||
@@ -0,0 +1,201 @@
|
||||
/*
|
||||
* Copyright (C) 2021 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.settings.biometrics;
|
||||
|
||||
import static android.hardware.biometrics.BiometricManager.Authenticators.BIOMETRIC_STRONG;
|
||||
import static android.provider.Settings.ACTION_BIOMETRIC_ENROLL;
|
||||
|
||||
import static androidx.test.espresso.intent.Intents.intended;
|
||||
import static androidx.test.espresso.intent.matcher.IntentMatchers.hasComponent;
|
||||
import static androidx.test.espresso.intent.matcher.IntentMatchers.hasExtra;
|
||||
|
||||
import static com.android.settings.password.ChooseLockSettingsHelper.EXTRA_KEY_FOR_BIOMETRICS;
|
||||
import static com.android.settings.password.ChooseLockSettingsHelper.EXTRA_KEY_FOR_FACE;
|
||||
import static com.android.settings.password.ChooseLockSettingsHelper.EXTRA_KEY_FOR_FINGERPRINT;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.junit.Assume.assumeTrue;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.hardware.biometrics.SensorProperties;
|
||||
import android.hardware.face.FaceManager;
|
||||
import android.hardware.face.FaceSensorPropertiesInternal;
|
||||
import android.hardware.fingerprint.FingerprintManager;
|
||||
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
|
||||
import android.os.UserHandle;
|
||||
import android.provider.Settings;
|
||||
|
||||
import androidx.test.core.app.ActivityScenario;
|
||||
import androidx.test.core.app.ApplicationProvider;
|
||||
import androidx.test.espresso.intent.Intents;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
import androidx.test.filters.MediumTest;
|
||||
|
||||
import com.android.internal.widget.LockPatternChecker;
|
||||
import com.android.internal.widget.LockPatternUtils;
|
||||
import com.android.internal.widget.LockscreenCredential;
|
||||
import com.android.settings.biometrics.face.FaceEnrollIntroduction;
|
||||
import com.android.settings.biometrics.fingerprint.FingerprintEnrollIntroduction;
|
||||
import com.android.settings.password.ChooseLockGeneric;
|
||||
import com.android.settings.password.ChooseLockSettingsHelper;
|
||||
import com.android.settings.password.ConfirmLockPassword;
|
||||
import com.android.settings.testutils.AdbUtils;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
@MediumTest
|
||||
public class BiometricEnrollActivityTest {
|
||||
|
||||
private static final String TAG = "BiometricEnrollActivityTest";
|
||||
private static final int ADB_TIMEOUT_MS = 5000;
|
||||
private static final String TEST_PIN = "1234";
|
||||
|
||||
private final Context mContext = ApplicationProvider.getApplicationContext();
|
||||
private boolean mHasFace;
|
||||
private boolean mHasFingerprint;
|
||||
private boolean mIsFaceStrong;
|
||||
private boolean mIsFingerprintStrong;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
Intents.init();
|
||||
final PackageManager pm = mContext.getPackageManager();
|
||||
mHasFingerprint = pm.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT);
|
||||
mHasFace = pm.hasSystemFeature(PackageManager.FEATURE_FACE);
|
||||
|
||||
if (mHasFace) {
|
||||
final FaceManager faceManager = mContext.getSystemService(FaceManager.class);
|
||||
final List<FaceSensorPropertiesInternal> faceProperties =
|
||||
faceManager.getSensorPropertiesInternal();
|
||||
if (!faceProperties.isEmpty()) {
|
||||
final FaceSensorPropertiesInternal faceProp = faceProperties.get(0);
|
||||
mIsFaceStrong = faceProp.sensorStrength == SensorProperties.STRENGTH_STRONG;
|
||||
}
|
||||
}
|
||||
|
||||
if (mHasFingerprint) {
|
||||
final FingerprintManager fingerprintManager = mContext.getSystemService(
|
||||
FingerprintManager.class);
|
||||
final List<FingerprintSensorPropertiesInternal> fingerProperties =
|
||||
fingerprintManager.getSensorPropertiesInternal();
|
||||
if (!fingerProperties.isEmpty()) {
|
||||
final FingerprintSensorPropertiesInternal fingerProp = fingerProperties.get(0);
|
||||
mIsFingerprintStrong =
|
||||
fingerProp.sensorStrength == SensorProperties.STRENGTH_STRONG;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@After
|
||||
public void teardown() throws Exception {
|
||||
Intents.release();
|
||||
AdbUtils.checkStringInAdbCommandOutput(TAG, "locksettings clear --old " + TEST_PIN,
|
||||
"", "", ADB_TIMEOUT_MS);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void launchWithoutPin_setsPin() {
|
||||
try (ActivityScenario<BiometricEnrollActivity> scenario =
|
||||
ActivityScenario.launch(getIntent())) {
|
||||
intended(hasComponent(ChooseLockGeneric.class.getName()));
|
||||
if (mHasFace && mHasFingerprint) {
|
||||
intended(hasExtra(EXTRA_KEY_FOR_BIOMETRICS, true));
|
||||
} else if (mHasFace) {
|
||||
intended(hasExtra(EXTRA_KEY_FOR_FACE, true));
|
||||
} else if (mHasFingerprint) {
|
||||
intended(hasExtra(EXTRA_KEY_FOR_FINGERPRINT, true));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void launchWithPin_confirmsPin() throws Exception {
|
||||
setPin();
|
||||
try (ActivityScenario<BiometricEnrollActivity> scenario =
|
||||
ActivityScenario.launch(getIntent())) {
|
||||
intended(hasComponent(ConfirmLockPassword.InternalActivity.class.getName()));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void launchWithPinAndPwHandle_confirmsPin() throws Exception {
|
||||
assumeTrue(mHasFace || mHasFingerprint);
|
||||
|
||||
setPin();
|
||||
final Intent intent = getIntent(true /* useInternal */);
|
||||
LockPatternChecker.verifyCredential(new LockPatternUtils(mContext),
|
||||
LockscreenCredential.createPin(TEST_PIN), UserHandle.myUserId(),
|
||||
LockPatternUtils.VERIFY_FLAG_REQUEST_GK_PW_HANDLE, (response, timeoutMs) -> {
|
||||
assertThat(response.containsGatekeeperPasswordHandle()).isTrue();
|
||||
intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_GK_PW_HANDLE,
|
||||
response.getGatekeeperPasswordHandle());
|
||||
}).get();
|
||||
|
||||
try (ActivityScenario<BiometricEnrollActivity> scenario =
|
||||
ActivityScenario.launch(intent)) {
|
||||
intended(hasComponent(mHasFace && !mHasFingerprint
|
||||
? FaceEnrollIntroduction.class.getName()
|
||||
: FingerprintEnrollIntroduction.class.getName()));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void launchWithStrongBiometricAllowed_doNotEnrollWeak() throws Exception {
|
||||
assumeTrue(mHasFace || mHasFingerprint);
|
||||
|
||||
// Allow only strong biometrics
|
||||
Intent intent = getIntent();
|
||||
intent.putExtra(Settings.EXTRA_BIOMETRIC_AUTHENTICATORS_ALLOWED, BIOMETRIC_STRONG);
|
||||
|
||||
try (ActivityScenario<BiometricEnrollActivity> scenario =
|
||||
ActivityScenario.launch(intent)) {
|
||||
intended(hasComponent(ChooseLockGeneric.class.getName()));
|
||||
if (mIsFaceStrong && mIsFingerprintStrong) {
|
||||
intended(hasExtra(EXTRA_KEY_FOR_BIOMETRICS, true));
|
||||
} else if (mIsFaceStrong) {
|
||||
intended(hasExtra(EXTRA_KEY_FOR_FACE, true));
|
||||
} else if (mIsFingerprintStrong) {
|
||||
intended(hasExtra(EXTRA_KEY_FOR_FINGERPRINT, true));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Intent getIntent() {
|
||||
return getIntent(false /* useInternal */);
|
||||
}
|
||||
|
||||
private Intent getIntent(boolean useInternal) {
|
||||
final Intent intent = new Intent(mContext, useInternal
|
||||
? BiometricEnrollActivity.InternalActivity.class : BiometricEnrollActivity.class);
|
||||
intent.setAction(ACTION_BIOMETRIC_ENROLL);
|
||||
return intent;
|
||||
}
|
||||
|
||||
private static void setPin() throws Exception {
|
||||
assertThat(AdbUtils.checkStringInAdbCommandOutput(TAG, "locksettings set-pin " + TEST_PIN,
|
||||
"Pin set to ", "'" + TEST_PIN + "'", ADB_TIMEOUT_MS)).isTrue();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,144 @@
|
||||
/*
|
||||
* Copyright (C) 2021 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.settings.display.darkmode;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import android.app.Instrumentation;
|
||||
import android.app.TimePickerDialog;
|
||||
import android.app.UiModeManager;
|
||||
import android.content.Intent;
|
||||
import android.content.res.Configuration;
|
||||
import android.provider.Settings;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.fragment.app.FragmentActivity;
|
||||
import androidx.test.core.app.ActivityScenario;
|
||||
import androidx.test.ext.junit.rules.ActivityScenarioRule;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
import androidx.test.filters.SmallTest;
|
||||
import androidx.test.platform.app.InstrumentationRegistry;
|
||||
import androidx.test.runner.lifecycle.Stage;
|
||||
|
||||
import com.android.settings.testutils.CommonUtils;
|
||||
import com.android.settings.testutils.UiUtils;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import java.time.LocalTime;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
@SmallTest
|
||||
public class DarkThemeScheduleComponentTest {
|
||||
private static final int DIALOG_START_TIME = 0;
|
||||
private static final int DIALOG_END_TIME = 1;
|
||||
/** The identifier for the positive button. */
|
||||
private static final int BUTTON_POSITIVE = -1;
|
||||
public final String TAG = this.getClass().getName();
|
||||
private final Instrumentation mInstrumentation = InstrumentationRegistry.getInstrumentation();
|
||||
|
||||
@Rule
|
||||
public ActivityScenarioRule<com.android.settings.Settings.DarkThemeSettingsActivity> rule =
|
||||
new ActivityScenarioRule<>(
|
||||
new Intent(
|
||||
Settings.ACTION_DARK_THEME_SETTINGS).setFlags(
|
||||
Intent.FLAG_ACTIVITY_NEW_TASK));
|
||||
private UiModeManager mUiModeManager;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
mUiModeManager = mInstrumentation.getTargetContext().getSystemService(UiModeManager.class);
|
||||
if (mUiModeManager.getNightMode() != UiModeManager.MODE_NIGHT_NO) {
|
||||
mUiModeManager.setNightMode(UiModeManager.MODE_NIGHT_NO);
|
||||
}
|
||||
}
|
||||
|
||||
private void test_step_for_custom_time(int startTimeDiff, int endTimeDiff) {
|
||||
|
||||
ActivityScenario scenario = rule.getScenario();
|
||||
scenario.onActivity(activity -> {
|
||||
mUiModeManager.setNightMode(UiModeManager.MODE_NIGHT_CUSTOM);
|
||||
Fragment f =
|
||||
((FragmentActivity) activity).getSupportFragmentManager().getFragments().get(0);
|
||||
DarkModeSettingsFragment fragment = (DarkModeSettingsFragment) f;
|
||||
|
||||
setCustomTime(fragment, DIALOG_START_TIME, LocalTime.now().plusMinutes(startTimeDiff));
|
||||
setCustomTime(fragment, DIALOG_END_TIME, LocalTime.now().plusMinutes(endTimeDiff));
|
||||
|
||||
// The night mode need to reopen the screen to trigger UI change after mode change.
|
||||
CommonUtils.reopenScreen();
|
||||
});
|
||||
|
||||
// Relaunch the scenario to make sure UI apply new mode.
|
||||
scenario.onActivity(activity -> {
|
||||
Log.d(TAG, "Activity Recreated!");
|
||||
UiUtils.waitForActivitiesInStage(2000, Stage.RESUMED);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_dark_mode_in_custom_time() {
|
||||
test_step_for_custom_time(-1, 11);
|
||||
assertThat(checkNightMode(true)).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_dark_mode_after_custom_time() {
|
||||
test_step_for_custom_time(-11, -1);
|
||||
assertThat(checkNightMode(false)).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_dark_mode_before_custom_time() {
|
||||
test_step_for_custom_time(2, 20);
|
||||
assertThat(checkNightMode(false)).isTrue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets custom time for night mode.
|
||||
*
|
||||
* @param fragment The DarkModeSettingsFragment.
|
||||
* @param dialogId Dialog id for start time or end time.
|
||||
* @param time The time to be set.
|
||||
*/
|
||||
private void setCustomTime(DarkModeSettingsFragment fragment, int dialogId, LocalTime time) {
|
||||
Log.d(TAG, "Start to set custom time " + (dialogId == DIALOG_START_TIME ? "StartTime"
|
||||
: "EndTime") + " to " + time.getHour() + ":" + time.getMinute());
|
||||
TimePickerDialog startTimeDialog = (TimePickerDialog) fragment.onCreateDialog(dialogId);
|
||||
startTimeDialog.updateTime(time.getHour(), time.getMinute());
|
||||
startTimeDialog.onClick(startTimeDialog, BUTTON_POSITIVE);
|
||||
}
|
||||
|
||||
private boolean checkNightMode(boolean isNightMode) {
|
||||
int mask = (isNightMode ? Configuration.UI_MODE_NIGHT_YES : Configuration.UI_MODE_NIGHT_NO);
|
||||
int mode = mInstrumentation.getTargetContext().getResources().getConfiguration().uiMode;
|
||||
return (mode & mask) != 0;
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() {
|
||||
Log.d(TAG, "tearDown.");
|
||||
if (mUiModeManager.getNightMode() != UiModeManager.MODE_NIGHT_NO) {
|
||||
mUiModeManager.setNightMode(UiModeManager.MODE_NIGHT_NO);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,118 @@
|
||||
/*
|
||||
* Copyright (C) 2020 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.settings.fuelgauge.batterysaver;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static com.google.common.truth.Truth.assert_;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.Instrumentation;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.PowerManager;
|
||||
import android.provider.Settings;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.fragment.app.FragmentActivity;
|
||||
import androidx.test.core.app.ActivityScenario;
|
||||
import androidx.test.core.app.ApplicationProvider;
|
||||
import androidx.test.ext.junit.rules.ActivityScenarioRule;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
import androidx.test.filters.SmallTest;
|
||||
import androidx.test.platform.app.InstrumentationRegistry;
|
||||
|
||||
import com.android.settings.Settings.BatterySaverSettingsActivity;
|
||||
import com.android.settings.SettingsPreferenceFragment;
|
||||
import com.android.settings.testutils.AdbUtils;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
@SmallTest
|
||||
public class BatterySaverButtonPreferenceControllerComponentTest {
|
||||
private static final String TAG =
|
||||
BatterySaverButtonPreferenceControllerComponentTest.class.getSimpleName();
|
||||
private final Instrumentation mInstrumentation = InstrumentationRegistry.getInstrumentation();
|
||||
private final PowerManager mManager =
|
||||
(PowerManager) mInstrumentation.getTargetContext().getSystemService(
|
||||
Context.POWER_SERVICE);
|
||||
@Rule
|
||||
public ActivityScenarioRule<BatterySaverSettingsActivity> rule = new ActivityScenarioRule<>(
|
||||
new Intent(
|
||||
Settings.ACTION_BATTERY_SAVER_SETTINGS).setFlags(
|
||||
Intent.FLAG_ACTIVITY_NEW_TASK));
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
mInstrumentation.getUiAutomation().executeShellCommand("dumpsys battery unplug");
|
||||
mInstrumentation.getUiAutomation().executeShellCommand("settings get global low_power 0");
|
||||
}
|
||||
|
||||
private BatterySaverButtonPreferenceController get_battery_saver_controller(Activity activity) {
|
||||
BatterySaverButtonPreferenceController controller =
|
||||
new BatterySaverButtonPreferenceController(
|
||||
ApplicationProvider.getApplicationContext(), "battery_saver");
|
||||
Fragment f =
|
||||
((FragmentActivity) activity).getSupportFragmentManager().getFragments().get(0);
|
||||
controller.displayPreference(((SettingsPreferenceFragment) f).getPreferenceScreen());
|
||||
return controller;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_check_battery_saver_button() throws Exception {
|
||||
ActivityScenario scenario = rule.getScenario();
|
||||
scenario.onActivity(activity -> {
|
||||
BatterySaverButtonPreferenceController controller =
|
||||
get_battery_saver_controller(activity);
|
||||
controller.setChecked(true);
|
||||
checkPowerSaverMode(true);
|
||||
|
||||
controller.setChecked(false);
|
||||
checkPowerSaverMode(false);
|
||||
});
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() {
|
||||
mInstrumentation.getUiAutomation().executeShellCommand("settings get global low_power 0");
|
||||
mInstrumentation.getUiAutomation().executeShellCommand("dumpsys battery reset");
|
||||
}
|
||||
|
||||
private void checkPowerSaverMode(boolean enabled) {
|
||||
//Check through adb. Note that this needs to be done first, or a wait and poll needs to be
|
||||
//done to the manager.isPowerSaveMode(), because calling isPowerSaveMode immediately after
|
||||
//setting it does not return true. It takes a while for isPowerSaveMode() to return the
|
||||
//up-to-date value.
|
||||
try {
|
||||
assertThat(
|
||||
AdbUtils.checkStringInAdbCommandOutput(TAG, "settings get global low_power",
|
||||
null, enabled ? "1" : "0", 1000)).isTrue();
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, e.getMessage());
|
||||
assert_().fail();
|
||||
}
|
||||
|
||||
//Check through manager
|
||||
assertThat(mManager.isPowerSaveMode() == enabled).isTrue();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,137 @@
|
||||
/*
|
||||
* Copyright (C) 2021 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.settings.homepage;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static com.google.common.truth.Truth.assert_;
|
||||
|
||||
import android.app.Instrumentation;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Intent;
|
||||
import android.provider.Settings;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
import androidx.test.filters.SmallTest;
|
||||
import androidx.test.platform.app.InstrumentationRegistry;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
@SmallTest
|
||||
public class HomepageComponentTest {
|
||||
public final String TAG = this.getClass().getSimpleName();
|
||||
|
||||
private final Instrumentation mInstrumentation = InstrumentationRegistry.getInstrumentation();
|
||||
|
||||
@Test
|
||||
public void test_launch_all_settings_in_home()
|
||||
throws ClassNotFoundException {
|
||||
|
||||
List<Intent> launchIntents = ImmutableList.of(
|
||||
|
||||
// Wifi
|
||||
// Implemented in WifiSettings2ActivityTest
|
||||
|
||||
// Connected devices
|
||||
new Intent(Settings.ACTION_BLUETOOTH_SETTINGS),
|
||||
|
||||
// Applications
|
||||
new Intent(Settings.ACTION_AUTO_ROTATE_SETTINGS),
|
||||
|
||||
// Notifications
|
||||
new Intent(Settings.ACTION_NOTIFICATION_SETTINGS),
|
||||
|
||||
// Display
|
||||
new Intent(Settings.ACTION_DISPLAY_SETTINGS),
|
||||
|
||||
// Battery
|
||||
// Implemented in fuelgauge.batterysaver
|
||||
|
||||
// Storage
|
||||
new Intent(Settings.ACTION_INTERNAL_STORAGE_SETTINGS),
|
||||
|
||||
// Sound
|
||||
new Intent(Settings.ACTION_SOUND_SETTINGS),
|
||||
|
||||
// Display
|
||||
new Intent(Settings.ACTION_DISPLAY_SETTINGS),
|
||||
|
||||
// Wallpaper
|
||||
new Intent(mInstrumentation.getTargetContext(), Class.forName(
|
||||
"com.android.settings.wallpaper.WallpaperSuggestionActivity")),
|
||||
|
||||
// A11y
|
||||
new Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS),
|
||||
|
||||
// Security
|
||||
new Intent(Settings.ACTION_SECURITY_SETTINGS),
|
||||
|
||||
// Privacy
|
||||
new Intent(Settings.ACTION_PRIVACY_SETTINGS),
|
||||
|
||||
// Location
|
||||
new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS),
|
||||
|
||||
// Emergency ? EmergencyDashboardFragment
|
||||
// TODO: find out launch method
|
||||
|
||||
// Password & Account
|
||||
new Intent(Settings.ACTION_SYNC_SETTINGS),
|
||||
|
||||
// Digital wellbeing
|
||||
// Use IA link
|
||||
new Intent().setComponent(
|
||||
new ComponentName(
|
||||
"com.google.android.apps.wellbeing",
|
||||
"com.google.android.apps.wellbeing.settings"
|
||||
+ ".TopLevelSettingsActivity")),
|
||||
|
||||
// Google
|
||||
// Use IA link
|
||||
new Intent().setComponent(
|
||||
new ComponentName(
|
||||
"com.google.android.gms",
|
||||
"com.google.android.gms.app.settings.GoogleSettingsIALink")),
|
||||
|
||||
// System ?
|
||||
// TODO: find out launch method.
|
||||
|
||||
// About
|
||||
new Intent(Settings.ACTION_DEVICE_INFO_SETTINGS)
|
||||
|
||||
);
|
||||
|
||||
for (Intent intent : launchIntents) {
|
||||
Log.d(TAG, "Start to launch intent " + intent.getAction());
|
||||
try {
|
||||
mInstrumentation.getTargetContext()
|
||||
.startActivity(intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "Launch with exception. " + e.toString());
|
||||
assert_().fail();
|
||||
}
|
||||
// Launch success without exception.
|
||||
assertThat(Boolean.TRUE).isTrue();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
* Copyright (C) 2021 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.settings.network;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import android.app.Instrumentation;
|
||||
import android.provider.Settings;
|
||||
import android.provider.SettingsSlicesContract;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
import androidx.test.filters.SmallTest;
|
||||
import androidx.test.platform.app.InstrumentationRegistry;
|
||||
|
||||
import com.android.settings.testutils.UiUtils;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
@SmallTest
|
||||
public class AirplaneModePreferenceControllerComponentTest {
|
||||
// Airplane on off status
|
||||
private static final int ON = 1;
|
||||
private static final int OFF = 0;
|
||||
public final String TAG = this.getClass().getName();
|
||||
private final Instrumentation mInstrumentation = InstrumentationRegistry.getInstrumentation();
|
||||
private boolean mOriginAirplaneModeIsOn;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
// Make sure origin airplane mode is OFF.
|
||||
mOriginAirplaneModeIsOn = is_airplane_mode_on();
|
||||
if (mOriginAirplaneModeIsOn) {
|
||||
Log.d(TAG, "Origin airplane mode is on, turn it off.");
|
||||
Settings.Global.putInt(mInstrumentation.getTargetContext().getContentResolver(),
|
||||
Settings.Global.AIRPLANE_MODE_ON, OFF);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests on/off airplane mode repeatedly.
|
||||
* Previously, a bug describe that crash issue if user on off airplane mode repeatedly.
|
||||
* This case try to switch on & off airplane mode for 10 times to check crash issue.
|
||||
*/
|
||||
@Test
|
||||
public void test_on_off_airplane_mode_multiple_times() {
|
||||
AirplaneModePreferenceController controller =
|
||||
new AirplaneModePreferenceController(mInstrumentation.getTargetContext(),
|
||||
SettingsSlicesContract.KEY_AIRPLANE_MODE);
|
||||
|
||||
for (int i = 0; i < 10; ++i) {
|
||||
Log.d(TAG, "Test #" + (i + 1));
|
||||
controller.setChecked(true);
|
||||
assertThat(UiUtils.waitUntilCondition(1000,
|
||||
() -> is_airplane_mode_on())).isTrue();
|
||||
|
||||
controller.setChecked(false);
|
||||
assertThat(UiUtils.waitUntilCondition(1000,
|
||||
() -> !is_airplane_mode_on())).isTrue();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private boolean is_airplane_mode_on() {
|
||||
return Settings.System.getInt(
|
||||
mInstrumentation.getTargetContext().getContentResolver(),
|
||||
Settings.Global.AIRPLANE_MODE_ON, OFF) != 0;
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() {
|
||||
if (is_airplane_mode_on() != mOriginAirplaneModeIsOn) {
|
||||
Settings.Global.putInt(mInstrumentation.getTargetContext().getContentResolver(),
|
||||
Settings.Global.AIRPLANE_MODE_ON, (
|
||||
mOriginAirplaneModeIsOn ? ON : OFF));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,175 @@
|
||||
/*
|
||||
* Copyright (C) 2021 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.settings.network.telephony;
|
||||
|
||||
import static com.android.settings.testutils.CommonUtils.set_wifi_enabled;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
import android.app.Instrumentation;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.net.wifi.WifiManager;
|
||||
import android.telecom.TelecomManager;
|
||||
import android.telephony.SubscriptionManager;
|
||||
import android.telephony.TelephonyManager;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.fragment.app.FragmentActivity;
|
||||
import androidx.fragment.app.FragmentManager;
|
||||
import androidx.lifecycle.LifecycleOwner;
|
||||
import androidx.test.core.app.ActivityScenario;
|
||||
import androidx.test.ext.junit.rules.ActivityScenarioRule;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
import androidx.test.filters.SmallTest;
|
||||
import androidx.test.platform.app.InstrumentationRegistry;
|
||||
|
||||
import com.android.settings.Settings;
|
||||
import com.android.settings.testutils.CommonUtils;
|
||||
import com.android.settings.testutils.UiUtils;
|
||||
import com.android.settingslib.core.lifecycle.Lifecycle;
|
||||
import com.android.settingslib.mobile.dataservice.MobileNetworkInfoEntity;
|
||||
import com.android.settingslib.mobile.dataservice.SubscriptionInfoEntity;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Assume;
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.Mockito;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
@SmallTest
|
||||
public class MobileDataPreferenceControllerComponentTest {
|
||||
|
||||
@Mock
|
||||
private Lifecycle mLifecycle;
|
||||
@Mock
|
||||
private LifecycleOwner mLifecycleOwner;
|
||||
|
||||
public static final int TIMEOUT = 2000;
|
||||
private static int sSubscriptionId = 2;
|
||||
public final String TAG = this.getClass().getName();
|
||||
private final Instrumentation mInstrumentation = InstrumentationRegistry.getInstrumentation();
|
||||
private final WifiManager mWifiManager =
|
||||
(WifiManager) mInstrumentation.getTargetContext().getSystemService(
|
||||
Context.WIFI_SERVICE);
|
||||
private final TelephonyManager mTelephonyManager =
|
||||
(TelephonyManager) mInstrumentation.getTargetContext().getSystemService(
|
||||
Context.TELEPHONY_SERVICE);
|
||||
private final TelecomManager mTelecomManager =
|
||||
(TelecomManager) mInstrumentation.getTargetContext().getSystemService(
|
||||
Context.TELECOM_SERVICE);
|
||||
|
||||
@Rule
|
||||
public ActivityScenarioRule<Settings.MobileNetworkActivity>
|
||||
rule = new ActivityScenarioRule<>(
|
||||
new Intent(android.provider.Settings.ACTION_DATA_ROAMING_SETTINGS)
|
||||
.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
|
||||
private boolean mOriginDataEnabled;
|
||||
private boolean mOriginWifiEnabled;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
mOriginWifiEnabled = mWifiManager.isWifiEnabled();
|
||||
// Disable wifi
|
||||
set_wifi_enabled(false);
|
||||
|
||||
// Enable mobile data
|
||||
mOriginDataEnabled = mTelephonyManager.isDataEnabled();
|
||||
if (!mOriginDataEnabled) {
|
||||
mTelephonyManager.enableDataConnectivity();
|
||||
}
|
||||
|
||||
// Current sim card is not available for data network.
|
||||
sSubscriptionId = SubscriptionManager.getDefaultDataSubscriptionId();
|
||||
Assume.assumeTrue("Device cannot mobile network! Should ignore test.",
|
||||
sSubscriptionId != SubscriptionManager.INVALID_SUBSCRIPTION_ID);
|
||||
|
||||
int simState = mTelephonyManager.getSimState();
|
||||
Assume.assumeTrue("Sim card is not ready. Expect: " + TelephonyManager.SIM_STATE_READY
|
||||
+ ", Actual: " + simState, simState == TelephonyManager.SIM_STATE_READY);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the mobile network is disabled.
|
||||
* Precondition:
|
||||
* Disabled wifi, and enabled mobile network.
|
||||
* Steps:
|
||||
* 1. Launch mobile data page.
|
||||
* 2. Turn off mobile data from switch.
|
||||
* [Check]
|
||||
* - Mobile data is turned off via TelephonyManager.
|
||||
* - Open socket connection https://www.google.net and check the connection failed.
|
||||
*/
|
||||
@Test
|
||||
public void test_disable_mobile_network() {
|
||||
ActivityScenario scenario = rule.getScenario();
|
||||
scenario.onActivity(activity -> {
|
||||
try {
|
||||
URL url = new URL("https://www.google.net");
|
||||
MobileDataPreferenceController controller = new MobileDataPreferenceController(
|
||||
mInstrumentation.getTargetContext(), "mobile_data", mLifecycle,
|
||||
mLifecycleOwner, sSubscriptionId);
|
||||
FragmentManager manager = ((FragmentActivity) activity).getSupportFragmentManager();
|
||||
controller.init(manager, sSubscriptionId, mock(SubscriptionInfoEntity.class), mock(
|
||||
MobileNetworkInfoEntity.class));
|
||||
|
||||
// Make sure mobile network can connect at first.
|
||||
assertThat(UiUtils.waitUntilCondition(1000,
|
||||
() -> CommonUtils.connectToURL(url))).isTrue();
|
||||
|
||||
Log.d(TAG, "Start to click ");
|
||||
controller.setChecked(false);
|
||||
Log.d(TAG, "Set Checked, wait for fully close.");
|
||||
|
||||
// Assert the configuration is set.
|
||||
assertThat(UiUtils.waitUntilCondition(10000,
|
||||
() -> !mTelephonyManager.isDataEnabled())).isTrue();
|
||||
|
||||
// Assert the network is not connectable.
|
||||
assertThat(UiUtils.waitUntilCondition(1000,
|
||||
() -> CommonUtils.connectToURL(url))).isFalse();
|
||||
|
||||
} catch (IOException e) {
|
||||
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() {
|
||||
// Restore wifi status wifi
|
||||
set_wifi_enabled(mOriginWifiEnabled);
|
||||
|
||||
// Restore mobile data status
|
||||
if (mOriginDataEnabled != mTelephonyManager.isDataEnabled()) {
|
||||
if (mOriginDataEnabled) {
|
||||
mTelephonyManager.enableDataConnectivity();
|
||||
} else {
|
||||
mTelephonyManager.disableDataConnectivity();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,126 @@
|
||||
/*
|
||||
* Copyright (C) 2021 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.settings.notification;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import android.app.Instrumentation;
|
||||
import android.content.Intent;
|
||||
import android.provider.Settings;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.test.core.app.ActivityScenario;
|
||||
import androidx.test.ext.junit.rules.ActivityScenarioRule;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
import androidx.test.filters.SmallTest;
|
||||
import androidx.test.platform.app.InstrumentationRegistry;
|
||||
import androidx.test.runner.lifecycle.Stage;
|
||||
|
||||
import com.android.settings.testutils.CommonUtils;
|
||||
import com.android.settings.testutils.UiUtils;
|
||||
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
@SmallTest
|
||||
public class AppNotificationComponentTest {
|
||||
private final Instrumentation mInstrumentation = InstrumentationRegistry.getInstrumentation();
|
||||
private final String mNoSlientAppName = "com.google.android.dialer";
|
||||
public final String TAG = this.getClass().getName();
|
||||
|
||||
@Rule
|
||||
public ActivityScenarioRule<com.android.settings.Settings.AppNotificationSettingsActivity>
|
||||
rule = new ActivityScenarioRule<>(
|
||||
new Intent(Settings.ACTION_APP_NOTIFICATION_SETTINGS)
|
||||
.putExtra(Settings.EXTRA_APP_PACKAGE, mNoSlientAppName)
|
||||
.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
|
||||
|
||||
/**
|
||||
* Tests user should not able to modify notification settings for some system apps.
|
||||
* In this case, test `phone` app that will disabled notification configuration.
|
||||
* Steps:
|
||||
* 1. Open notification page of phone app.
|
||||
* 2. Checks system privilege notification should not able to be changed.
|
||||
*/
|
||||
@Test
|
||||
public void test_special_app_could_not_disable_notification() {
|
||||
List<String> disabledList = Arrays.asList("Default", "Incoming calls",
|
||||
"Background Processing", "Missed calls",
|
||||
"Ongoing calls", "Voicemails");
|
||||
|
||||
ActivityScenario ac = rule.getScenario();
|
||||
ac.onActivity(
|
||||
activity -> {
|
||||
View recyclerView = activity.findViewById(
|
||||
CommonUtils.getResId("recycler_view"));
|
||||
|
||||
if (recyclerView == null) {
|
||||
Log.d("UI_UTILS",
|
||||
"Target not found: R.id.recycler_view #" + Integer.toHexString(
|
||||
CommonUtils.getResId("recycler_view")));
|
||||
UiUtils.dumpView(UiUtils.getFirstViewFromActivity(activity));
|
||||
assertThat(Boolean.TRUE).isFalse();
|
||||
}
|
||||
|
||||
UiUtils.waitUntilCondition(5000,
|
||||
() -> recyclerView.findViewById(CommonUtils.getResId("recycler_view"))
|
||||
!= null);
|
||||
|
||||
View mainSwitchBar = recyclerView.findViewById(
|
||||
CommonUtils.getResId("main_switch_bar"));
|
||||
|
||||
assertThat(mainSwitchBar.isEnabled()).isEqualTo(false);
|
||||
Log.d(TAG, "main switch bar = " + mainSwitchBar.isEnabled());
|
||||
|
||||
UiUtils.waitForActivitiesInStage(10000, Stage.RESUMED);
|
||||
Log.d(TAG, "In stage!.");
|
||||
|
||||
UiUtils.dumpView(UiUtils.getFirstViewFromActivity(activity));
|
||||
|
||||
// The privileges are under the recycle view. Fetch all of them and check.
|
||||
ViewGroup viewGroup = (ViewGroup) recyclerView;
|
||||
|
||||
for (int i = 0; i < viewGroup.getChildCount(); i++) {
|
||||
if (viewGroup.getChildAt(i) instanceof LinearLayout) {
|
||||
// A notification in Settings should have both switch_widget and text.
|
||||
// There has another circle pin is no belongs to Settings package.
|
||||
// But belongs to Switch in Android.
|
||||
View sWidget = viewGroup.getChildAt(i).findViewById(
|
||||
CommonUtils.getResId("switchWidget"));
|
||||
TextView sText = viewGroup.getChildAt(i).findViewById(
|
||||
android.R.id.title);
|
||||
if (sText != null && sWidget != null
|
||||
&& disabledList.stream().anyMatch(
|
||||
str -> str.equals(sText.getText().toString().trim()))) {
|
||||
|
||||
assertThat(sWidget.isEnabled()).isFalse();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* Copyright (C) 2020 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.settings.privacy;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import android.app.Instrumentation;
|
||||
|
||||
import androidx.test.core.app.ApplicationProvider;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
import androidx.test.filters.SmallTest;
|
||||
import androidx.test.platform.app.InstrumentationRegistry;
|
||||
|
||||
import com.android.settings.testutils.AdbUtils;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
@SmallTest
|
||||
public class EnabledContentCapturePreferenceControllerComponentTest {
|
||||
private Instrumentation mInstrumentation;
|
||||
private static final String TAG =
|
||||
EnabledContentCapturePreferenceControllerComponentTest.class.getSimpleName();
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
if (null == mInstrumentation) {
|
||||
mInstrumentation = InstrumentationRegistry.getInstrumentation();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_uncheck_content_capture() throws Exception {
|
||||
content_capture_checkbox_test_helper(false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_check_content_capture() throws Exception {
|
||||
content_capture_checkbox_test_helper(true);
|
||||
}
|
||||
|
||||
private void content_capture_checkbox_test_helper(boolean check) throws Exception {
|
||||
EnableContentCapturePreferenceController enableContentCapturePreferenceController =
|
||||
new EnableContentCapturePreferenceController(
|
||||
ApplicationProvider.getApplicationContext(),
|
||||
"Test_key");
|
||||
enableContentCapturePreferenceController.setChecked(check);
|
||||
|
||||
//Check through adb command
|
||||
assertThat(AdbUtils.checkStringInAdbCommandOutput(TAG, "dumpsys content_capture",
|
||||
"Users disabled by Settings: ", check ? "{}" : "{0=true}", 1000)).isTrue();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* Copyright (C) 2020 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.settings.testutils;
|
||||
|
||||
import android.os.ParcelFileDescriptor;
|
||||
|
||||
import androidx.test.platform.app.InstrumentationRegistry;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class AdbUtils {
|
||||
public static String getCallerClassName() {
|
||||
StackTraceElement[] stElements = Thread.currentThread().getStackTrace();
|
||||
for (int i = 1; i < stElements.length; i++) {
|
||||
StackTraceElement ste = stElements[i];
|
||||
if (!ste.getClassName().equals(new Object() {
|
||||
}.getClass().getEnclosingClass().getName()) && ste.getClassName().indexOf(
|
||||
"java.lang.Thread") != 0) {
|
||||
return ste.getClassName();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static boolean checkStringInAdbCommandOutput(String logTag, String command,
|
||||
String prefix, String target, int timeoutInMillis) throws Exception {
|
||||
long start = System.nanoTime();
|
||||
|
||||
//Sometimes the change do no reflect in adn output immediately, so need a wait and poll here
|
||||
while (System.nanoTime() - start < (timeoutInMillis * 1000000)) {
|
||||
String result = shell(command);
|
||||
if (result.contains(prefix == null ? "" : prefix)
|
||||
&& result.contains(target == null ? "" : target)) {
|
||||
return true;
|
||||
} else {
|
||||
Thread.sleep(100);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static String shell(String shellCommand) {
|
||||
String returnValue = "";
|
||||
try (ParcelFileDescriptor.AutoCloseInputStream in =
|
||||
new ParcelFileDescriptor.AutoCloseInputStream(
|
||||
InstrumentationRegistry.getInstrumentation()
|
||||
.getUiAutomation()
|
||||
.executeShellCommand(shellCommand))) {
|
||||
try (BufferedReader br =
|
||||
new BufferedReader(
|
||||
new InputStreamReader(in, StandardCharsets.UTF_8))) {
|
||||
returnValue = br.lines().collect(Collectors.joining());
|
||||
}
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return returnValue;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,165 @@
|
||||
/*
|
||||
* Copyright (C) 2021 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.settings.testutils;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.Instrumentation;
|
||||
import android.content.Context;
|
||||
import android.graphics.Bitmap;
|
||||
import android.net.wifi.WifiManager;
|
||||
import android.os.Environment;
|
||||
import android.os.PowerManager;
|
||||
import android.os.StrictMode;
|
||||
import android.os.SystemClock;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
|
||||
import androidx.test.platform.app.InstrumentationRegistry;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URL;
|
||||
|
||||
import javax.net.ssl.HttpsURLConnection;
|
||||
|
||||
public class CommonUtils {
|
||||
private static final String TAG = CommonUtils.class.getSimpleName();
|
||||
private static final Instrumentation sInstrumentation =
|
||||
InstrumentationRegistry.getInstrumentation();
|
||||
private static final WifiManager sWifiManager =
|
||||
(WifiManager) sInstrumentation.getTargetContext().getSystemService(
|
||||
Context.WIFI_SERVICE);
|
||||
private static final PowerManager sPowerManager =
|
||||
(PowerManager) sInstrumentation.getTargetContext().getSystemService(
|
||||
Context.POWER_SERVICE);
|
||||
|
||||
public static void takeScreenshot(Activity activity) {
|
||||
long now = System.currentTimeMillis();
|
||||
|
||||
try {
|
||||
// image naming and path to include sd card appending name you choose for file
|
||||
String mPath =
|
||||
Environment.getExternalStorageDirectory().toString() + "/" + now + ".jpg";
|
||||
Log.d(TAG, "screenshot path is " + mPath);
|
||||
|
||||
// create bitmap screen capture
|
||||
View v1 = activity.getWindow().getDecorView().getRootView();
|
||||
v1.setDrawingCacheEnabled(true);
|
||||
Bitmap bitmap = Bitmap.createBitmap(v1.getDrawingCache());
|
||||
v1.setDrawingCacheEnabled(false);
|
||||
|
||||
File imageFile = new File(mPath);
|
||||
|
||||
FileOutputStream outputStream = new FileOutputStream(imageFile);
|
||||
int quality = 100;
|
||||
bitmap.compress(Bitmap.CompressFormat.JPEG, quality, outputStream);
|
||||
outputStream.flush();
|
||||
outputStream.close();
|
||||
} catch (Throwable e) {
|
||||
// Several error may come out with file handling or DOM
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean connectToURL(URL url) {
|
||||
StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
|
||||
StrictMode.setThreadPolicy(policy);
|
||||
HttpURLConnection connection = null;
|
||||
try {
|
||||
connection = (HttpsURLConnection) url.openConnection();
|
||||
connection.setRequestMethod("GET");
|
||||
connection.setConnectTimeout(8000);
|
||||
connection.setReadTimeout(8000);
|
||||
connection.connect();
|
||||
if (HttpURLConnection.HTTP_OK == connection.getResponseCode()) {
|
||||
InputStream in = connection.getInputStream();
|
||||
BufferedReader reader = new BufferedReader(new InputStreamReader(in));
|
||||
StringBuilder response = new StringBuilder();
|
||||
String line;
|
||||
while (null != (line = reader.readLine())) {
|
||||
response.append(line);
|
||||
}
|
||||
Log.d(TAG, "Connection success! " + response.toString());
|
||||
return true;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, e.toString());
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
} finally {
|
||||
if (null != connection) {
|
||||
connection.disconnect();
|
||||
}
|
||||
}
|
||||
Log.d(TAG, "End, return false.");
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a resource identifier for the given resource name in Settings app.
|
||||
*
|
||||
* @param name The name of the desired resource.
|
||||
* @return int The associated resource identifier. Returns 0 if no such resource was found. (0
|
||||
* is not a valid resource ID.)
|
||||
*/
|
||||
public static int getResId(String name) {
|
||||
return InstrumentationRegistry.getInstrumentation().getTargetContext().getResources()
|
||||
.getIdentifier(name, "id", Constants.SETTINGS_PACKAGE_NAME);
|
||||
}
|
||||
|
||||
public static void reopenScreen() {
|
||||
sPowerManager.goToSleep(SystemClock.uptimeMillis());
|
||||
// According to local test, we need to sleep to wait it fully processed.
|
||||
// 1000 ms is a good value to sleep, otherwise it might cause keyDispatchingTimedOut.
|
||||
try {
|
||||
Thread.sleep(1000);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
UiUtils.waitUntilCondition(1000, () -> !sPowerManager.isInteractive());
|
||||
sPowerManager.wakeUp(SystemClock.uptimeMillis());
|
||||
UiUtils.waitUntilCondition(1000, () -> sPowerManager.isInteractive());
|
||||
|
||||
// After power on screen, need to unlock and goto home page.
|
||||
sPowerManager.wakeUp(1000, PowerManager.WAKE_REASON_POWER_BUTTON, "Wakeup");
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets wifi status to given enable / disable via ADB command.
|
||||
*/
|
||||
public static void set_wifi_enabled(boolean enable) {
|
||||
final int timeoutMsec = 10000;
|
||||
Log.d(TAG, "Set wifi status to " + enable);
|
||||
if (sWifiManager.isWifiEnabled() != enable) {
|
||||
AdbUtils.shell("svc wifi " + (enable ? "enable" : "disable"));
|
||||
if (!UiUtils.waitUntilCondition(timeoutMsec,
|
||||
() -> sWifiManager.isWifiEnabled() == enable)) {
|
||||
Log.e(TAG, "Cannot set wifi to " + (enable ? "enabl" : "disable") + ", timeout "
|
||||
+ timeoutMsec + " (ms).");
|
||||
Log.e(TAG, "See logcat for more information.");
|
||||
}
|
||||
Log.d(TAG, "After configuration wifi status = " + sWifiManager.isWifiEnabled());
|
||||
} else {
|
||||
Log.d(TAG, "Wifi is enable is already " + enable + ", no need to change.");
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Copyright (C) 2021 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.settings.testutils;
|
||||
|
||||
public class Constants {
|
||||
public static final long ACTIVITY_LAUNCH_WAIT_TIMEOUT = 5000;
|
||||
public static final long VIEW_APPEAR_WAIT_MEDIUM_TIMEOUT = 5000;
|
||||
public static final long WIFI_CONNECT_WAIT_TIMEOUT = 15000;
|
||||
public static final String SETTINGS_PACKAGE_NAME = "com.android.settings";
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
* Copyright (C) 2020 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.settings.testutils;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import androidx.fragment.app.FragmentActivity;
|
||||
import androidx.test.runner.lifecycle.ActivityLifecycleMonitorRegistry;
|
||||
import androidx.test.runner.lifecycle.Stage;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public class UiUtils {
|
||||
private static final String TAG = "UI_UTILS";
|
||||
|
||||
public static boolean waitUntilCondition(long timeoutInMillis, Supplier<Boolean> condition) {
|
||||
long start = System.nanoTime();
|
||||
while (System.nanoTime() - start < (timeoutInMillis * 1000000)) {
|
||||
try {
|
||||
//Eat NPE from condition because there's a concurrency issue that when calling
|
||||
//findViewById when the view hierarchy is still rendering, it sometimes encounter
|
||||
//null views that may exist few milliseconds before, and causes a NPE.
|
||||
if (condition.get()) {
|
||||
return true;
|
||||
}
|
||||
} catch (NullPointerException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
Log.w(TAG, "Condition not match and timeout for waiting " + timeoutInMillis + "(ms).");
|
||||
return false;
|
||||
}
|
||||
|
||||
public static boolean waitForActivitiesInStage(long timeoutInMillis, Stage stage) {
|
||||
final Collection<Activity> activities = new ArrayList<>();
|
||||
waitUntilCondition(Constants.ACTIVITY_LAUNCH_WAIT_TIMEOUT, () -> {
|
||||
activities.addAll(
|
||||
ActivityLifecycleMonitorRegistry.getInstance().getActivitiesInStage(
|
||||
Stage.RESUMED));
|
||||
return activities.size() > 0;
|
||||
});
|
||||
|
||||
return activities.size() > 0;
|
||||
}
|
||||
|
||||
public static void dumpView(View view) {
|
||||
dumpViewRecursive(view, 0, 0, 0);
|
||||
}
|
||||
|
||||
public static View getFirstViewFromActivity(Activity activity) {
|
||||
return ((FragmentActivity) activity).getSupportFragmentManager().getFragments().get(
|
||||
0).getView();
|
||||
}
|
||||
|
||||
private static void dumpViewRecursive(View view, int layer, int index, int total) {
|
||||
if (view instanceof ViewGroup) {
|
||||
Log.i(TAG, "L[" + layer + "] PARENT -> " + (index + 1) + "/" + total + " >> "
|
||||
+ view.toString());
|
||||
System.out.println(
|
||||
TAG + " L[" + layer + "] PARENT -> " + (index + 1) + "/" + total + " >> "
|
||||
+ view.toString());
|
||||
for (int i = 0; i < ((ViewGroup) view).getChildCount(); i++) {
|
||||
dumpViewRecursive(((ViewGroup) view).getChildAt(i), layer + 1, i + 1,
|
||||
((ViewGroup) view).getChildCount());
|
||||
}
|
||||
} else {
|
||||
Log.i(TAG, "L[" + layer + "] =END= -> " + (index + 1) + "/" + total + " >> "
|
||||
+ view.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,139 @@
|
||||
/*
|
||||
* Copyright (C) 2021 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.settings.users;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import android.app.Instrumentation;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.UserInfo;
|
||||
import android.os.UserManager;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.fragment.app.FragmentActivity;
|
||||
import androidx.test.core.app.ActivityScenario;
|
||||
import androidx.test.ext.junit.rules.ActivityScenarioRule;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
import androidx.test.filters.SmallTest;
|
||||
import androidx.test.platform.app.InstrumentationRegistry;
|
||||
|
||||
import com.android.settings.Settings;
|
||||
import com.android.settings.testutils.AdbUtils;
|
||||
import com.android.settings.testutils.UiUtils;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Random;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
@SmallTest
|
||||
public class UserSettingsComponentTest {
|
||||
public static final int TIMEOUT = 2000;
|
||||
private static final int USER_TYPE_RESTRICTED_PROFILE = 2;
|
||||
public final String TAG = this.getClass().getName();
|
||||
private final Instrumentation mInstrumentation = InstrumentationRegistry.getInstrumentation();
|
||||
private final ArrayList<Integer> mOriginUserIds = new ArrayList<>();
|
||||
private final UserManager mUserManager =
|
||||
(UserManager) mInstrumentation.getTargetContext().getSystemService("user");
|
||||
@Rule
|
||||
public ActivityScenarioRule<Settings.UserSettingsActivity>
|
||||
rule = new ActivityScenarioRule<>(
|
||||
new Intent(android.provider.Settings.ACTION_USER_SETTINGS)
|
||||
.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
for (UserInfo info : mUserManager.getUsers()) {
|
||||
mOriginUserIds.add(info.id);
|
||||
}
|
||||
|
||||
// Enable multiple user switch.
|
||||
if (!mUserManager.isUserSwitcherEnabled()) {
|
||||
android.provider.Settings.Global.putInt(
|
||||
mInstrumentation.getTargetContext().getContentResolver(),
|
||||
android.provider.Settings.Global.USER_SWITCHER_ENABLED, 1);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_new_user_on_multiple_setting_page() throws IOException {
|
||||
String randomUserName = gendrate_random_name(10);
|
||||
ActivityScenario scenario = rule.getScenario();
|
||||
scenario.onActivity(activity -> {
|
||||
Fragment f =
|
||||
((FragmentActivity) activity).getSupportFragmentManager().getFragments().get(0);
|
||||
UserSettings us = (UserSettings) f;
|
||||
Log.d(TAG, "Start to add user :" + randomUserName);
|
||||
us.createUser(USER_TYPE_RESTRICTED_PROFILE, randomUserName);
|
||||
});
|
||||
|
||||
assertThat(
|
||||
UiUtils.waitUntilCondition(5000, () -> mUserManager.getAliveUsers().stream().filter(
|
||||
(user) -> user.name.equals(
|
||||
randomUserName)).findFirst().isPresent())).isTrue();
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() {
|
||||
int retryNumber = 5;
|
||||
for (int i = 0; i < retryNumber; ++i) {
|
||||
int currentUsersCount = mUserManager.getUserCount();
|
||||
if (currentUsersCount == mOriginUserIds.size()) {
|
||||
break;
|
||||
} else if (i != 0) {
|
||||
Log.d(TAG, "[tearDown] User not fully removed. Retry #" + (i = 1) + " of total "
|
||||
+ mOriginUserIds.size());
|
||||
}
|
||||
|
||||
for (UserInfo info : mUserManager.getUsers()) {
|
||||
if (mOriginUserIds.contains(info.id)) {
|
||||
continue;
|
||||
}
|
||||
Log.d(TAG, "[tearDown] Clean up user {" + info.id + "}:" + info.name);
|
||||
try {
|
||||
AdbUtils.shell("pm remove-user " + info.id);
|
||||
} catch (Exception e) {
|
||||
Log.w(TAG, "[tearDown] Error occurs while removing user. " + e.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private String gendrate_random_name(int length) {
|
||||
String seed = "abcdefghijklmnopqrstuvwxyABCDEFGHIJKLMNOPQSTUVWXYZ";
|
||||
Random r1 = new Random();
|
||||
String result = "";
|
||||
for (int i = 0; i < length; ++i) {
|
||||
result = result + seed.charAt(r1.nextInt(seed.length() - 1));
|
||||
}
|
||||
if (mUserManager.getAliveUsers().stream().map(user -> user.name).collect(
|
||||
Collectors.toList()).contains(result)) {
|
||||
Log.d(TAG, "Name repeated! add padding 'rpt' in the end of name.");
|
||||
result += "rpt";
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,126 @@
|
||||
/*
|
||||
* Copyright (C) 2021 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.settings.wifi;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import android.app.Instrumentation;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.net.ConnectivityManager;
|
||||
import android.provider.Settings;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
import android.widget.Button;
|
||||
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.fragment.app.FragmentActivity;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
import androidx.test.filters.MediumTest;
|
||||
import androidx.test.platform.app.InstrumentationRegistry;
|
||||
import androidx.test.runner.lifecycle.ActivityLifecycleMonitorRegistry;
|
||||
import androidx.test.runner.lifecycle.Stage;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.Settings.NetworkProviderSettingsActivity;
|
||||
import com.android.settings.fuelgauge.batterysaver.BatterySaverButtonPreferenceControllerComponentTest;
|
||||
import com.android.settings.network.NetworkProviderSettings;
|
||||
import com.android.settings.testutils.CommonUtils;
|
||||
import com.android.settings.testutils.Constants;
|
||||
import com.android.settings.testutils.UiUtils;
|
||||
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import java.net.URL;
|
||||
import java.util.List;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
@MediumTest
|
||||
/*
|
||||
This test is just for demonstration purpose. For component tests, this approach is not recommended.
|
||||
The reason why it is written this way is because the current Settings app wifi codes have tight
|
||||
coupling with UI, so it's not easy to drive from API without binding the test deeply with the code.
|
||||
*/
|
||||
public class WifiSettings2ActivityTest {
|
||||
private static final String TAG =
|
||||
BatterySaverButtonPreferenceControllerComponentTest.class.getSimpleName();
|
||||
private final Instrumentation mInstrumentation = InstrumentationRegistry.getInstrumentation();
|
||||
|
||||
@Test @Ignore
|
||||
public void test_connect_to_wifi() throws Exception {
|
||||
//For some reason the ActivityScenario gets null activity here
|
||||
mInstrumentation.getTargetContext().startActivity(
|
||||
new Intent(Settings.ACTION_WIFI_SETTINGS).setFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
|
||||
UiUtils.waitForActivitiesInStage(Constants.ACTIVITY_LAUNCH_WAIT_TIMEOUT, Stage.RESUMED);
|
||||
|
||||
final NetworkProviderSettings[] settings = new NetworkProviderSettings[1];
|
||||
mInstrumentation.runOnMainSync(() -> {
|
||||
NetworkProviderSettingsActivity activity = (NetworkProviderSettingsActivity)
|
||||
ActivityLifecycleMonitorRegistry.getInstance().getActivitiesInStage(
|
||||
Stage.RESUMED).iterator().next();
|
||||
settings[0] =
|
||||
(NetworkProviderSettings) activity.getSupportFragmentManager().getFragments()
|
||||
.get(0);
|
||||
});
|
||||
|
||||
//For some reason this view does not appear immediately after the fragment is resumed.
|
||||
View root = settings[0].getView();
|
||||
UiUtils.waitUntilCondition(Constants.VIEW_APPEAR_WAIT_MEDIUM_TIMEOUT,
|
||||
() -> root.findViewById(R.id.settings_button) != null);
|
||||
View view = root.findViewById(R.id.settings_button);
|
||||
view.callOnClick();
|
||||
|
||||
UiUtils.waitForActivitiesInStage(Constants.ACTIVITY_LAUNCH_WAIT_TIMEOUT, Stage.RESUMED);
|
||||
Button[] button = new Button[1];
|
||||
mInstrumentation.runOnMainSync(() -> {
|
||||
FragmentActivity activity =
|
||||
(FragmentActivity) ActivityLifecycleMonitorRegistry.getInstance()
|
||||
.getActivitiesInStage(Stage.RESUMED).iterator().next();
|
||||
List<Fragment> fragments = activity.getSupportFragmentManager().getFragments();
|
||||
Log.d(TAG, "fragment class is " + fragments.get(0).getClass());
|
||||
button[0] = fragments.get(0).getView().findViewById(R.id.button3);
|
||||
});
|
||||
|
||||
//HttpURLConnection needs to run outside of main thread, so running it in the test thread
|
||||
final URL url = new URL("https://www.google.net/");
|
||||
|
||||
//Make sure the connectivity is available before disconnecting from wifi
|
||||
assertThat(CommonUtils.connectToURL(url)).isTrue();
|
||||
|
||||
//Disconnect from wifi
|
||||
button[0].callOnClick();
|
||||
|
||||
//Make sure the Internet connectivity is gone
|
||||
assertThat(CommonUtils.connectToURL(url)).isFalse();
|
||||
|
||||
//Connect to wifi
|
||||
button[0].callOnClick();
|
||||
ConnectivityManager manager =
|
||||
(ConnectivityManager) mInstrumentation.getTargetContext().getSystemService(
|
||||
Context.CONNECTIVITY_SERVICE);
|
||||
|
||||
//For some reason I can't find a way to tell the time that the internet connectivity is
|
||||
//actually available with the new, non-deprecated ways, so I still need to use this.
|
||||
UiUtils.waitUntilCondition(Constants.WIFI_CONNECT_WAIT_TIMEOUT,
|
||||
() -> manager.getActiveNetworkInfo().isConnected());
|
||||
|
||||
//Make sure the connectivity is back again
|
||||
assertThat(CommonUtils.connectToURL(url)).isTrue();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* Copyright (C) 2023 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.settings.wifi.dpp;
|
||||
|
||||
import static android.app.Activity.RESULT_OK;
|
||||
|
||||
import static androidx.test.espresso.intent.Intents.intended;
|
||||
import static androidx.test.espresso.intent.matcher.IntentMatchers.hasAction;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
|
||||
import android.app.KeyguardManager;
|
||||
|
||||
import androidx.activity.result.ActivityResult;
|
||||
import androidx.test.core.app.ActivityScenario;
|
||||
import androidx.test.espresso.intent.Intents;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
import androidx.test.filters.SmallTest;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
@SmallTest
|
||||
public class WifiDppConfiguratorAuthActivityTest {
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
Intents.init();
|
||||
}
|
||||
|
||||
@After
|
||||
public void teardown() throws Exception {
|
||||
Intents.release();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void launchActivity_sendAuthIntent() {
|
||||
ActivityScenario<WifiDppConfiguratorAuthActivity> activityScenario =
|
||||
ActivityScenario.launch(WifiDppConfiguratorAuthActivity.class);
|
||||
assertThat(activityScenario).isNotNull();
|
||||
intended(hasAction(equalTo(KeyguardManager.ACTION_CONFIRM_DEVICE_CREDENTIAL_WITH_USER)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void launchActivity_sendQrCodeIntent() {
|
||||
ActivityScenario.launch(WifiDppConfiguratorAuthActivity.class).onActivity(activity ->
|
||||
activity.onAuthResult(new ActivityResult(RESULT_OK, /* data= */ null))
|
||||
);
|
||||
intended(hasAction(
|
||||
equalTo(WifiDppConfiguratorActivity.ACTION_CONFIGURATOR_QR_CODE_GENERATOR)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void launchActivity_shouldFinish() {
|
||||
ActivityScenario.launch(WifiDppConfiguratorAuthActivity.class).onActivity(activity -> {
|
||||
activity.onAuthResult(new ActivityResult(RESULT_OK, /* data= */ null));
|
||||
assertThat(activity.isFinishing()).isTrue();
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
/*
|
||||
* Copyright (C) 2021 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.settingslib.applications;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
|
||||
import androidx.test.core.app.ActivityScenario;
|
||||
import androidx.test.ext.junit.rules.ActivityScenarioRule;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
import androidx.test.filters.SmallTest;
|
||||
|
||||
import com.android.settings.Settings;
|
||||
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
@SmallTest
|
||||
public class ApplicationStateComponentTest {
|
||||
private static final String TAG =
|
||||
ApplicationStateComponentTest.class.getSimpleName();
|
||||
private Context mRuntimeApplication;
|
||||
private ApplicationsState mApplicationsState;
|
||||
|
||||
@Rule
|
||||
public ActivityScenarioRule<Settings.ManageApplicationsActivity> rule =
|
||||
new ActivityScenarioRule<>(
|
||||
new Intent(
|
||||
android.provider.Settings.ACTION_MANAGE_ALL_APPLICATIONS_SETTINGS)
|
||||
.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
|
||||
|
||||
private ApplicationsState.AppEntry createAppEntry(String label, String packageName, int id) {
|
||||
ApplicationInfo appInfo = createApplicationInfo(packageName, id);
|
||||
ApplicationsState.AppEntry appEntry = new ApplicationsState.AppEntry(mRuntimeApplication,
|
||||
appInfo, id);
|
||||
appEntry.label = label;
|
||||
appEntry.mounted = true;
|
||||
return appEntry;
|
||||
}
|
||||
|
||||
private ApplicationInfo createApplicationInfo(String packageName, int uid) {
|
||||
ApplicationInfo appInfo = new ApplicationInfo();
|
||||
appInfo.sourceDir = "foo";
|
||||
appInfo.flags |= ApplicationInfo.FLAG_INSTALLED;
|
||||
appInfo.storageUuid = UUID.randomUUID();
|
||||
appInfo.packageName = packageName;
|
||||
appInfo.uid = uid;
|
||||
return appInfo;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_all_apps_sorting_alpha() {
|
||||
// TODO: Potential unit test candidate.
|
||||
// To test all app list has sorted alphabetical, only need to verify sort function.
|
||||
// This case focus on logic in sort function, and ignore origin locale sorting rule by Java.
|
||||
|
||||
ActivityScenario scenario = rule.getScenario();
|
||||
|
||||
scenario.onActivity(activity -> {
|
||||
mRuntimeApplication = activity.getApplication();
|
||||
mApplicationsState = ApplicationsState.getInstance(activity.getApplication());
|
||||
|
||||
ApplicationsState.AppEntry entry1 = createAppEntry("Info01", "Package1", 0);
|
||||
ApplicationsState.AppEntry entry2 = createAppEntry("Info02", "Package1", 0);
|
||||
ApplicationsState.AppEntry entry3 = createAppEntry("Info01", "Package2", 0);
|
||||
ApplicationsState.AppEntry entry4 = createAppEntry("Info02", "Package2", 0);
|
||||
ApplicationsState.AppEntry entry5 = createAppEntry("Info02", "Package2", 1);
|
||||
assertThat(ApplicationsState.ALPHA_COMPARATOR.compare(entry1, entry2)).isEqualTo(-1);
|
||||
assertThat(ApplicationsState.ALPHA_COMPARATOR.compare(entry2, entry3)).isEqualTo(1);
|
||||
assertThat(ApplicationsState.ALPHA_COMPARATOR.compare(entry3, entry2)).isEqualTo(-1);
|
||||
assertThat(ApplicationsState.ALPHA_COMPARATOR.compare(entry3, entry3)).isEqualTo(0);
|
||||
assertThat(ApplicationsState.ALPHA_COMPARATOR.compare(entry1, entry3)).isEqualTo(-1);
|
||||
assertThat(ApplicationsState.ALPHA_COMPARATOR.compare(entry4, entry5)).isEqualTo(-1);
|
||||
assertThat(ApplicationsState.ALPHA_COMPARATOR.compare(entry5, entry3)).isEqualTo(1);
|
||||
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user