Initial commit for Settings component test
Test: Tested on local device
Bug: 178765084
Change-Id: I3b8f36daa31b0a44e788fe4c84f94d48653ee037
diff --git a/tests/componenttests/Android.bp b/tests/componenttests/Android.bp
new file mode 100644
index 0000000..77932ef
--- /dev/null
+++ b/tests/componenttests/Android.bp
@@ -0,0 +1,23 @@
+//############################################################
+// Settings Component test target. #
+//############################################################
+android_test {
+ name: "SettingsComponentTests",
+ certificate: "platform",
+ privileged: true,
+ srcs: [
+ "src/**/*.java",
+ ],
+
+ static_libs: [
+ "truth-prebuilt",
+ "androidx.test.core",
+ "androidx.test.runner",
+ "androidx.test.rules",
+ "androidx.test.ext.junit",
+ ],
+
+ test_suites: ["device-tests"],
+
+ instrumentation_for: "Settings",
+}
diff --git a/tests/componenttests/AndroidManifest.xml b/tests/componenttests/AndroidManifest.xml
new file mode 100644
index 0000000..54ea374
--- /dev/null
+++ b/tests/componenttests/AndroidManifest.xml
@@ -0,0 +1,40 @@
+<?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">
+
+ <uses-permission android:name="android.permission.BLUETOOTH" />
+ <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
+ <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>
\ No newline at end of file
diff --git a/tests/componenttests/AndroidTest.xml b/tests/componenttests/AndroidTest.xml
new file mode 100644
index 0000000..ea7ac06
--- /dev/null
+++ b/tests/componenttests/AndroidTest.xml
@@ -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>
diff --git a/tests/componenttests/OWNERS b/tests/componenttests/OWNERS
new file mode 100644
index 0000000..51746f0
--- /dev/null
+++ b/tests/componenttests/OWNERS
@@ -0,0 +1,3 @@
+# People who can approve changes for submission
+jyhsu@google.com
+syaoranx@google.com
\ No newline at end of file
diff --git a/tests/componenttests/src/com/android/settings/fuelgauge/batterysaver/BatterySaverButtonPreferenceControllerComponentTest.java b/tests/componenttests/src/com/android/settings/fuelgauge/batterysaver/BatterySaverButtonPreferenceControllerComponentTest.java
new file mode 100644
index 0000000..30fcbf5
--- /dev/null
+++ b/tests/componenttests/src/com/android/settings/fuelgauge/batterysaver/BatterySaverButtonPreferenceControllerComponentTest.java
@@ -0,0 +1,143 @@
+/*
+ * 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.Instrumentation;
+import android.content.Context;
+import android.content.Intent;
+import android.os.PowerManager;
+import android.provider.Settings;
+import android.util.Log;
+import android.widget.Button;
+
+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.R;
+import com.android.settings.Settings.BatterySaverSettingsActivity;
+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;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class BatterySaverButtonPreferenceControllerComponentTest {
+ private static final String TAG =
+ BatterySaverButtonPreferenceControllerComponentTest.class.getSimpleName();
+ private Instrumentation mInstrumentation = InstrumentationRegistry.getInstrumentation();
+ private 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");
+ }
+
+ @Test
+ public void test_check_battery_saver_button() throws Exception {
+ ActivityScenario scenario = rule.getScenario();
+ scenario.onActivity(activity -> {
+ final Button button = activity.findViewById(R.id.state_on_button);
+ UiUtils.waitUntilCondition(3000, () -> button.isEnabled());
+ button.callOnClick();
+ checkPowerSaverMode(true);
+
+ Button offButton = activity.findViewById(R.id.state_off_button);
+ offButton.callOnClick();
+ checkPowerSaverMode(false);
+ });
+
+ //Ideally, we should be able to also create BatteryTipPreferenceController and verify that
+ //it is showing battery saver on. Unfortunately, that part of code is tightly coupled with
+ //UI, and it's not possible to retrieve that string without reaching very deep into the
+ //codes and become very tightly coupled with any future changes. That is not what component
+ //tests should do, so either we'll need to do this through UI with another ActivityScenario,
+ //or the code needs to be refactored to be less coupled with UI.
+ }
+
+ @Test
+ public void test_battery_saver_button_changes_when_framework_setting_change() throws Exception {
+ ActivityScenario scenario = rule.getScenario();
+ scenario.onActivity(activity -> {
+ Button buttonOn = activity.findViewById(R.id.state_on_button);
+ Button buttonOff = activity.findViewById(R.id.state_off_button);
+ assertThat(buttonOn.isVisibleToUser()).isEqualTo(true);
+ assertThat(buttonOff.isVisibleToUser()).isEqualTo(false);
+ });
+
+ mManager.setPowerSaveModeEnabled(true);
+ scenario.recreate();
+ scenario.onActivity(activity -> {
+ Button buttonOn = activity.findViewById(R.id.state_on_button);
+ Button buttonOff = activity.findViewById(R.id.state_off_button);
+ assertThat(buttonOn.isVisibleToUser()).isEqualTo(false);
+ assertThat(buttonOff.isVisibleToUser()).isEqualTo(true);
+ });
+
+ mManager.setPowerSaveModeEnabled(false);
+ scenario.recreate();
+ scenario.onActivity(activity -> {
+ Button buttonOn = activity.findViewById(R.id.state_on_button);
+ Button buttonOff = activity.findViewById(R.id.state_off_button);
+ assertThat(buttonOn.isVisibleToUser()).isEqualTo(true);
+ assertThat(buttonOff.isVisibleToUser()).isEqualTo(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();
+ }
+}
diff --git a/tests/componenttests/src/com/android/settings/privacy/EnabledContentCapturePreferenceControllerComponentTest.java b/tests/componenttests/src/com/android/settings/privacy/EnabledContentCapturePreferenceControllerComponentTest.java
new file mode 100644
index 0000000..aba6f8f
--- /dev/null
+++ b/tests/componenttests/src/com/android/settings/privacy/EnabledContentCapturePreferenceControllerComponentTest.java
@@ -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();
+ }
+}
diff --git a/tests/componenttests/src/com/android/settings/testutils/AdbUtils.java b/tests/componenttests/src/com/android/settings/testutils/AdbUtils.java
new file mode 100644
index 0000000..08eb47a
--- /dev/null
+++ b/tests/componenttests/src/com/android/settings/testutils/AdbUtils.java
@@ -0,0 +1,62 @@
+/*
+ * 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 android.text.TextUtils;
+import android.util.Log;
+
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import java.io.BufferedReader;
+import java.io.InputStreamReader;
+import java.nio.charset.StandardCharsets;
+import java.util.Optional;
+
+public class AdbUtils {
+ 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)) {
+ try (ParcelFileDescriptor.AutoCloseInputStream in =
+ new ParcelFileDescriptor.AutoCloseInputStream(
+ InstrumentationRegistry.getInstrumentation()
+ .getUiAutomation()
+ .executeShellCommand(command))) {
+ try (BufferedReader br =
+ new BufferedReader(
+ new InputStreamReader(in, StandardCharsets.UTF_8))) {
+ Optional<String> resultOptional = br.lines().filter(line -> {
+ Log.d(logTag, line);
+ return TextUtils.isEmpty(prefix) || line.contains(prefix);
+ }).findFirst();
+ String result = resultOptional.get();
+ if (result.contains(target)) {
+ return true;
+ } else {
+ Thread.sleep(100);
+ }
+ }
+ } catch (Exception e) {
+ throw e;
+ }
+ }
+
+ return false;
+ }
+}
diff --git a/tests/componenttests/src/com/android/settings/testutils/CommonUtils.java b/tests/componenttests/src/com/android/settings/testutils/CommonUtils.java
new file mode 100644
index 0000000..cbfe245
--- /dev/null
+++ b/tests/componenttests/src/com/android/settings/testutils/CommonUtils.java
@@ -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.testutils;
+
+import android.app.Activity;
+import android.graphics.Bitmap;
+import android.os.Environment;
+import android.util.Log;
+import android.view.View;
+
+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();
+
+ 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) {
+ 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);
+ }
+ return true;
+ }
+ } catch (Exception e) {
+ Log.d(TAG, e.getMessage());
+ return false;
+ } finally {
+ if (null != connection) {
+ connection.disconnect();
+ }
+ }
+
+ return false;
+ }
+
+}
diff --git a/tests/componenttests/src/com/android/settings/testutils/Constants.java b/tests/componenttests/src/com/android/settings/testutils/Constants.java
new file mode 100644
index 0000000..5e32f87
--- /dev/null
+++ b/tests/componenttests/src/com/android/settings/testutils/Constants.java
@@ -0,0 +1,23 @@
+/*
+ * 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;
+}
diff --git a/tests/componenttests/src/com/android/settings/testutils/UiUtils.java b/tests/componenttests/src/com/android/settings/testutils/UiUtils.java
new file mode 100644
index 0000000..a482add
--- /dev/null
+++ b/tests/componenttests/src/com/android/settings/testutils/UiUtils.java
@@ -0,0 +1,58 @@
+/*
+ * 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 androidx.test.platform.app.InstrumentationRegistry;
+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 {
+
+ public static void 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;
+ }
+ } catch (NullPointerException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+
+ public static boolean waitForActivitiesInStage(long timeoutInMillis, Stage stage) {
+ final Collection<Activity> activities = new ArrayList<>();
+ waitUntilCondition(Constants.ACTIVITY_LAUNCH_WAIT_TIMEOUT, () -> {
+ InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> activities.addAll(
+ ActivityLifecycleMonitorRegistry.getInstance().getActivitiesInStage(
+ Stage.RESUMED)));
+ return activities.size() > 0;
+ });
+
+ return activities.size() > 0;
+ }
+}
diff --git a/tests/componenttests/src/com/android/settings/wifi/WifiSettings2ActivityTest.java b/tests/componenttests/src/com/android/settings/wifi/WifiSettings2ActivityTest.java
new file mode 100644
index 0000000..aa6b252
--- /dev/null
+++ b/tests/componenttests/src/com/android/settings/wifi/WifiSettings2ActivityTest.java
@@ -0,0 +1,125 @@
+/*
+ * 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.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
+ 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();
+ }
+}
diff --git a/tests/robotests/Android.bp b/tests/robotests/Android.bp
index c8c6c38..f6ad049 100644
--- a/tests/robotests/Android.bp
+++ b/tests/robotests/Android.bp
@@ -1,4 +1,4 @@
-//############################################################
+ //############################################################
// Build SettingsRoboTestStub.apk which includes test-only resources.#
//############################################################