From 9c8e6fb68f513f84db59ba8013ae6890d92fc498 Mon Sep 17 00:00:00 2001 From: Sundeep Ghuman Date: Wed, 24 Jan 2018 14:39:19 -0800 Subject: [PATCH 01/11] Move AccessPointPreference.generateApKey. Move logic into AccessPoint.java. Bug: 64989100 Test: runtest --path tests/unit/src/com/android/settings/wifi/WifiSettingsUiTest.java Change-Id: I822a9675263191f22e84233bf2f83a610375a815 --- .../android/settings/wifi/SavedAccessPointsWifiSettings.java | 2 +- src/com/android/settings/wifi/WifiSettings.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/com/android/settings/wifi/SavedAccessPointsWifiSettings.java b/src/com/android/settings/wifi/SavedAccessPointsWifiSettings.java index 9f52159796f..3079f8d8576 100644 --- a/src/com/android/settings/wifi/SavedAccessPointsWifiSettings.java +++ b/src/com/android/settings/wifi/SavedAccessPointsWifiSettings.java @@ -161,7 +161,7 @@ public class SavedAccessPointsWifiSettings extends SettingsPreferenceFragment final int accessPointsSize = accessPoints.size(); for (int i = 0; i < accessPointsSize; ++i) { AccessPoint ap = accessPoints.get(i); - String key = AccessPointPreference.generatePreferenceKey(ap); + String key = ap.getKey(); LongPressAccessPointPreference preference = (LongPressAccessPointPreference) getCachedPreference(key); if (preference == null) { diff --git a/src/com/android/settings/wifi/WifiSettings.java b/src/com/android/settings/wifi/WifiSettings.java index 73f17f7e8f6..74fe8810ea6 100644 --- a/src/com/android/settings/wifi/WifiSettings.java +++ b/src/com/android/settings/wifi/WifiSettings.java @@ -768,7 +768,7 @@ public class WifiSettings extends RestrictedSettingsFragment AccessPoint accessPoint = accessPoints.get(index); // Ignore access points that are out of range. if (accessPoint.isReachable()) { - String key = AccessPointPreference.generatePreferenceKey(accessPoint); + String key = accessPoint.getKey(); hasAvailableAccessPoints = true; LongPressAccessPointPreference pref = (LongPressAccessPointPreference) getCachedPreference(key); From b8b2e51e8de8e41f9962260918c47459911a0a4a Mon Sep 17 00:00:00 2001 From: Sudheer Shanka Date: Tue, 23 Jan 2018 01:46:53 -0800 Subject: [PATCH 02/11] Add policy transparency for metered data related settings. With API Dpm.setMeteredDataDisabled, admins can restrict some packages from accessing metered data and when admin does restrict packages, user settings to enable usage of mobile data in background or allow unrestricted access during data saver mode are not relevant. Add policy transparency to these settings so that user knows that admin disabled them. Bug: 63700027 Test: make RunSettingsRoboTests Test: manual Change-Id: I450f7a91356ed8fb33f464620c73fa9407a1ff83 --- res/xml/app_data_usage.xml | 14 ++- .../settings/datausage/AppDataUsage.java | 18 +++- .../datausage/UnrestrictedDataAccess.java | 55 ++++++++++- .../settings/datausage/AppDataUsageTest.java | 39 +++++++- .../datausage/UnrestrictedDataAccessTest.java | 97 ++++++++++++++++++- .../shadow/ShadowRestrictedLockUtils.java | 65 +++++++++++++ 6 files changed, 267 insertions(+), 21 deletions(-) create mode 100644 tests/robotests/src/com/android/settings/testutils/shadow/ShadowRestrictedLockUtils.java diff --git a/res/xml/app_data_usage.xml b/res/xml/app_data_usage.xml index 3e94135fb4b..a4b215980aa 100644 --- a/res/xml/app_data_usage.xml +++ b/res/xml/app_data_usage.xml @@ -16,6 +16,8 @@ - + android:summary="@string/data_usage_app_restrict_background_summary" + settings:useAdditionalSummary="true" + settings:restrictedSwitchSummary="@string/disabled_by_admin" /> - + android:summary="@string/unrestricted_app_summary" + settings:useAdditionalSummary="true" + settings:restrictedSwitchSummary="@string/disabled_by_admin" /> diff --git a/src/com/android/settings/datausage/AppDataUsage.java b/src/com/android/settings/datausage/AppDataUsage.java index 5470e6372db..a0d0ec03551 100644 --- a/src/com/android/settings/datausage/AppDataUsage.java +++ b/src/com/android/settings/datausage/AppDataUsage.java @@ -33,7 +33,6 @@ import android.os.Bundle; import android.os.RemoteException; import android.os.UserHandle; import android.support.annotation.VisibleForTesting; -import android.support.v14.preference.SwitchPreference; import android.support.v7.preference.Preference; import android.support.v7.preference.PreferenceCategory; import android.text.format.Formatter; @@ -48,6 +47,9 @@ import com.android.settings.R; import com.android.settings.applications.AppInfoBase; import com.android.settings.widget.EntityHeaderController; import com.android.settingslib.AppItem; +import com.android.settingslib.RestrictedLockUtils; +import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin; +import com.android.settingslib.RestrictedSwitchPreference; import com.android.settingslib.net.ChartData; import com.android.settingslib.net.ChartDataLoader; import com.android.settingslib.net.UidDetail; @@ -80,7 +82,7 @@ public class AppDataUsage extends DataUsageBase implements Preference.OnPreferen private Preference mForegroundUsage; private Preference mBackgroundUsage; private Preference mAppSettings; - private SwitchPreference mRestrictBackground; + private RestrictedSwitchPreference mRestrictBackground; private PreferenceCategory mAppList; private Drawable mIcon; @@ -97,7 +99,7 @@ public class AppDataUsage extends DataUsageBase implements Preference.OnPreferen private AppItem mAppItem; private Intent mAppSettingsIntent; private SpinnerPreference mCycle; - private SwitchPreference mUnrestrictedData; + private RestrictedSwitchPreference mUnrestrictedData; private DataSaverBackend mDataSaverBackend; @Override @@ -160,9 +162,11 @@ public class AppDataUsage extends DataUsageBase implements Preference.OnPreferen removePreference(KEY_UNRESTRICTED_DATA); removePreference(KEY_RESTRICT_BACKGROUND); } else { - mRestrictBackground = (SwitchPreference) findPreference(KEY_RESTRICT_BACKGROUND); + mRestrictBackground = (RestrictedSwitchPreference) findPreference( + KEY_RESTRICT_BACKGROUND); mRestrictBackground.setOnPreferenceChangeListener(this); - mUnrestrictedData = (SwitchPreference) findPreference(KEY_UNRESTRICTED_DATA); + mUnrestrictedData = (RestrictedSwitchPreference) findPreference( + KEY_UNRESTRICTED_DATA); mUnrestrictedData.setOnPreferenceChangeListener(this); } mDataSaverBackend = new DataSaverBackend(getContext()); @@ -261,8 +265,11 @@ public class AppDataUsage extends DataUsageBase implements Preference.OnPreferen } private void updatePrefs(boolean restrictBackground, boolean unrestrictData) { + final EnforcedAdmin admin = RestrictedLockUtils.checkIfMeteredDataRestricted( + getContext(), mPackageName, UserHandle.getUserId(mAppItem.key)); if (mRestrictBackground != null) { mRestrictBackground.setChecked(!restrictBackground); + mRestrictBackground.setDisabledByAdmin(admin); } if (mUnrestrictedData != null) { if (restrictBackground) { @@ -270,6 +277,7 @@ public class AppDataUsage extends DataUsageBase implements Preference.OnPreferen } else { mUnrestrictedData.setVisible(true); mUnrestrictedData.setChecked(unrestrictData); + mUnrestrictedData.setDisabledByAdmin(admin); } } } diff --git a/src/com/android/settings/datausage/UnrestrictedDataAccess.java b/src/com/android/settings/datausage/UnrestrictedDataAccess.java index e8a7bbfa2f9..cff4a502147 100644 --- a/src/com/android/settings/datausage/UnrestrictedDataAccess.java +++ b/src/com/android/settings/datausage/UnrestrictedDataAccess.java @@ -14,6 +14,8 @@ package com.android.settings.datausage; +import static com.android.settingslib.RestrictedLockUtils.checkIfMeteredDataRestricted; + import android.app.Application; import android.content.Context; import android.os.Bundle; @@ -37,6 +39,8 @@ import com.android.settings.core.FeatureFlags; import com.android.settings.datausage.AppStateDataUsageBridge.DataUsageState; import com.android.settings.overlay.FeatureFactory; import com.android.settings.widget.AppSwitchPreference; +import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin; +import com.android.settingslib.RestrictedPreferenceHelper; import com.android.settingslib.applications.ApplicationsState; import com.android.settingslib.applications.ApplicationsState.AppEntry; import com.android.settingslib.applications.ApplicationsState.AppFilter; @@ -172,6 +176,8 @@ public class UnrestrictedDataAccess extends SettingsPreferenceFragment preference.setOnPreferenceChangeListener(this); getPreferenceScreen().addPreference(preference); } else { + preference.setDisabledByAdmin(checkIfMeteredDataRestricted(getContext(), + entry.info.packageName, UserHandle.getUserId(entry.info.uid))); preference.reuse(); } preference.setOrder(i); @@ -242,16 +248,22 @@ public class UnrestrictedDataAccess extends SettingsPreferenceFragment return app != null && UserHandle.isApp(app.info.uid); } - private class AccessPreference extends AppSwitchPreference + @VisibleForTesting + class AccessPreference extends AppSwitchPreference implements DataSaverBackend.Listener { private final AppEntry mEntry; private final DataUsageState mState; + private final RestrictedPreferenceHelper mHelper; public AccessPreference(final Context context, AppEntry entry) { super(context); + setWidgetLayoutResource(R.layout.restricted_switch_widget); + mHelper = new RestrictedPreferenceHelper(context, this, null); mEntry = entry; mState = (DataUsageState) mEntry.extraInfo; mEntry.ensureLabel(getContext()); + setDisabledByAdmin(checkIfMeteredDataRestricted(context, entry.info.packageName, + UserHandle.getUserId(entry.info.uid))); setState(); if (mEntry.icon != null) { setIcon(mEntry.icon); @@ -291,12 +303,21 @@ public class UnrestrictedDataAccess extends SettingsPreferenceFragment } } + @Override + public void performClick() { + if (!mHelper.performClick()) { + super.performClick(); + } + } + // Sets UI state based on whitelist/blacklist status. private void setState() { setTitle(mEntry.label); if (mState != null) { setChecked(mState.isDataSaverWhitelisted); - if (mState.isDataSaverBlacklisted) { + if (isDisabledByAdmin()) { + setSummary(R.string.disabled_by_admin); + } else if (mState.isDataSaverBlacklisted) { setSummary(R.string.restrict_background_blacklisted); } else { setSummary(""); @@ -323,10 +344,21 @@ public class UnrestrictedDataAccess extends SettingsPreferenceFragment } }); } - holder.findViewById(android.R.id.widget_frame) - .setVisibility(mState != null && mState.isDataSaverBlacklisted - ? View.INVISIBLE : View.VISIBLE); + final boolean disabledByAdmin = isDisabledByAdmin(); + final View widgetFrame = holder.findViewById(android.R.id.widget_frame); + if (disabledByAdmin) { + widgetFrame.setVisibility(View.VISIBLE); + } else { + widgetFrame.setVisibility(mState != null && mState.isDataSaverBlacklisted + ? View.INVISIBLE : View.VISIBLE); + } super.onBindViewHolder(holder); + + mHelper.onBindViewHolder(holder); + holder.findViewById(R.id.restricted_icon).setVisibility( + disabledByAdmin ? View.VISIBLE : View.GONE); + holder.findViewById(android.R.id.switch_widget).setVisibility( + disabledByAdmin ? View.GONE : View.VISIBLE); } @Override @@ -348,6 +380,19 @@ public class UnrestrictedDataAccess extends SettingsPreferenceFragment reuse(); } } + + public void setDisabledByAdmin(EnforcedAdmin admin) { + mHelper.setDisabledByAdmin(admin); + } + + public boolean isDisabledByAdmin() { + return mHelper.isDisabledByAdmin(); + } + + @VisibleForTesting + public AppEntry getEntryForTest() { + return mEntry; + } } } diff --git a/tests/robotests/src/com/android/settings/datausage/AppDataUsageTest.java b/tests/robotests/src/com/android/settings/datausage/AppDataUsageTest.java index 7cd09dec861..58643b6560f 100644 --- a/tests/robotests/src/com/android/settings/datausage/AppDataUsageTest.java +++ b/tests/robotests/src/com/android/settings/datausage/AppDataUsageTest.java @@ -29,8 +29,8 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.content.pm.PackageManager; +import android.net.NetworkPolicyManager; import android.os.Bundle; -import android.support.v14.preference.SwitchPreference; import android.support.v7.preference.PreferenceManager; import android.support.v7.preference.PreferenceScreen; import android.util.ArraySet; @@ -40,8 +40,11 @@ import com.android.settings.TestConfig; import com.android.settings.testutils.FakeFeatureFactory; import com.android.settings.testutils.SettingsRobolectricTestRunner; import com.android.settings.testutils.shadow.ShadowEntityHeaderController; +import com.android.settings.testutils.shadow.ShadowRestrictedLockUtils; import com.android.settings.widget.EntityHeaderController; import com.android.settingslib.AppItem; +import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin; +import com.android.settingslib.RestrictedSwitchPreference; import com.android.settingslib.wrapper.PackageManagerWrapper; import org.junit.After; @@ -57,7 +60,10 @@ import org.robolectric.util.ReflectionHelpers; @RunWith(SettingsRobolectricTestRunner.class) @Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION, - shadows = ShadowEntityHeaderController.class) + shadows = { + ShadowEntityHeaderController.class, + ShadowRestrictedLockUtils.class + }) public class AppDataUsageTest { @Mock(answer = Answers.RETURNS_DEEP_STUBS) @@ -134,7 +140,7 @@ public class AppDataUsageTest { public void changePreference_backgroundData_shouldUpdateUI() { mFragment = spy(new AppDataUsage()); final AppItem appItem = new AppItem(123456789); - final SwitchPreference pref = mock(SwitchPreference.class); + final RestrictedSwitchPreference pref = mock(RestrictedSwitchPreference.class); final DataSaverBackend dataSaverBackend = mock(DataSaverBackend.class); ReflectionHelpers.setField(mFragment, "mAppItem", appItem); ReflectionHelpers.setField(mFragment, "mRestrictBackground", pref); @@ -146,4 +152,31 @@ public class AppDataUsageTest { verify(mFragment).updatePrefs(); } + + @Test + public void updatePrefs_restrictedByAdmin_shouldDisablePreference() { + mFragment = spy(new AppDataUsage()); + final int testUid = 123123; + final AppItem appItem = new AppItem(testUid); + final RestrictedSwitchPreference restrictBackgroundPref + = mock(RestrictedSwitchPreference.class); + final RestrictedSwitchPreference unrestrictedDataPref + = mock(RestrictedSwitchPreference.class); + final DataSaverBackend dataSaverBackend = mock(DataSaverBackend.class); + final NetworkPolicyManager networkPolicyManager = mock(NetworkPolicyManager.class); + ReflectionHelpers.setField(mFragment, "mAppItem", appItem); + ReflectionHelpers.setField(mFragment, "mRestrictBackground", restrictBackgroundPref); + ReflectionHelpers.setField(mFragment, "mUnrestrictedData", unrestrictedDataPref); + ReflectionHelpers.setField(mFragment, "mDataSaverBackend", dataSaverBackend); + ReflectionHelpers.setField(mFragment.services, "mPolicyManager", networkPolicyManager); + + ShadowRestrictedLockUtils.setRestricted(true); + doReturn(NetworkPolicyManager.POLICY_NONE).when(networkPolicyManager) + .getUidPolicy(testUid); + + mFragment.updatePrefs(); + + verify(restrictBackgroundPref).setDisabledByAdmin(any(EnforcedAdmin.class)); + verify(unrestrictedDataPref).setDisabledByAdmin(any(EnforcedAdmin.class)); + } } diff --git a/tests/robotests/src/com/android/settings/datausage/UnrestrictedDataAccessTest.java b/tests/robotests/src/com/android/settings/datausage/UnrestrictedDataAccessTest.java index 53cb7edd25e..fff879f9f11 100644 --- a/tests/robotests/src/com/android/settings/datausage/UnrestrictedDataAccessTest.java +++ b/tests/robotests/src/com/android/settings/datausage/UnrestrictedDataAccessTest.java @@ -16,41 +16,68 @@ package com.android.settings.datausage; import static com.google.common.truth.Truth.assertThat; + +import static org.junit.Assert.fail; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.nullable; import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; import android.content.Context; import android.content.pm.ApplicationInfo; import android.os.Process; +import android.support.v7.preference.PreferenceManager; +import android.support.v7.preference.PreferenceScreen; import com.android.internal.logging.nano.MetricsProto; +import com.android.settings.R; import com.android.settings.TestConfig; +import com.android.settings.datausage.AppStateDataUsageBridge.DataUsageState; +import com.android.settings.datausage.UnrestrictedDataAccess.AccessPreference; import com.android.settings.testutils.FakeFeatureFactory; import com.android.settings.testutils.SettingsRobolectricTestRunner; -import com.android.settingslib.applications.ApplicationsState; +import com.android.settings.testutils.shadow.ShadowRestrictedLockUtils; +import com.android.settingslib.applications.ApplicationsState.AppEntry; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import org.robolectric.RuntimeEnvironment; import org.robolectric.annotation.Config; +import org.robolectric.util.ReflectionHelpers; + +import java.util.ArrayList; @RunWith(SettingsRobolectricTestRunner.class) -@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION) +@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION, + shadows = { + ShadowRestrictedLockUtils.class + }) public class UnrestrictedDataAccessTest { @Mock - private ApplicationsState.AppEntry mAppEntry; + private AppEntry mAppEntry; private UnrestrictedDataAccess mFragment; private FakeFeatureFactory mFeatureFactory; + @Mock + private PreferenceScreen mPreferenceScreen; + @Mock + private PreferenceManager mPreferenceManager; + @Mock + private DataSaverBackend mDataSaverBackend; @Before public void setUp() { MockitoAnnotations.initMocks(this); mFeatureFactory = FakeFeatureFactory.setupForTest(); - mFragment = new UnrestrictedDataAccess(); + mFragment = spy(new UnrestrictedDataAccess()); } @Test @@ -80,4 +107,66 @@ public class UnrestrictedDataAccessTest { eq(MetricsProto.MetricsEvent.APP_SPECIAL_PERMISSION_UNL_DATA_DENY), eq("app")); } + @Test + public void testOnRebuildComplete_restricted_shouldBeDisabled() { + final Context context = RuntimeEnvironment.application; + doReturn(context).when(mFragment).getContext(); + doReturn(context).when(mPreferenceManager).getContext(); + doReturn(true).when(mFragment).shouldAddPreference(any(AppEntry.class)); + doNothing().when(mFragment).setLoading(anyBoolean(), anyBoolean()); + doReturn(mPreferenceScreen).when(mFragment).getPreferenceScreen(); + doReturn(mPreferenceManager).when(mFragment).getPreferenceManager(); + ReflectionHelpers.setField(mFragment, "mDataSaverBackend", mDataSaverBackend); + + final String testPkg1 = "com.example.one"; + final String testPkg2 = "com.example.two"; + ShadowRestrictedLockUtils.setRestrictedPkgs(testPkg2); + + doAnswer((invocation) -> { + final AccessPreference preference = invocation.getArgument(0); + final AppEntry entry = preference.getEntryForTest(); + // Verify preference is disabled by admin and the summary is changed accordingly. + if (testPkg1.equals(entry.info.packageName)) { + assertThat(preference.isDisabledByAdmin()).isFalse(); + assertThat(preference.getSummary()).isEqualTo(""); + } else if (testPkg2.equals(entry.info.packageName)) { + assertThat(preference.isDisabledByAdmin()).isTrue(); + assertThat(preference.getSummary()).isEqualTo( + context.getString(R.string.disabled_by_admin)); + } + assertThat(preference.isChecked()).isFalse(); + preference.performClick(); + // Verify that when the preference is clicked, support details intent is launched + // if the preference is disabled by admin, otherwise the switch is toggled. + if (testPkg1.equals(entry.info.packageName)) { + assertThat(preference.isChecked()).isTrue(); + assertThat(ShadowRestrictedLockUtils.hasAdminSupportDetailsIntentLaunched()) + .isFalse(); + } else if (testPkg2.equals(entry.info.packageName)) { + assertThat(preference.isChecked()).isFalse(); + assertThat(ShadowRestrictedLockUtils.hasAdminSupportDetailsIntentLaunched()) + .isTrue(); + } + ShadowRestrictedLockUtils.clearAdminSupportDetailsIntentLaunch(); + return null; + }).when(mPreferenceScreen).addPreference(any(AccessPreference.class)); + mFragment.onRebuildComplete(createAppEntries(testPkg1, testPkg2)); + } + + private ArrayList createAppEntries(String... packageNames) { + final ArrayList appEntries = new ArrayList<>(); + for (int i = 0; i < packageNames.length; ++i) { + final ApplicationInfo info = new ApplicationInfo(); + info.packageName = packageNames[i]; + info.uid = Process.FIRST_APPLICATION_UID + i; + info.sourceDir = info.packageName; + final AppEntry appEntry = spy(new AppEntry(RuntimeEnvironment.application, + info, i)); + appEntry.extraInfo = new DataUsageState(false, false); + doNothing().when(appEntry).ensureLabel(any(Context.class)); + ReflectionHelpers.setField(appEntry, "info", info); + appEntries.add(appEntry); + } + return appEntries; + } } diff --git a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowRestrictedLockUtils.java b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowRestrictedLockUtils.java new file mode 100644 index 00000000000..afede1a200e --- /dev/null +++ b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowRestrictedLockUtils.java @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2018 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.shadow; + +import android.content.Context; + +import com.android.internal.util.ArrayUtils; +import com.android.settingslib.RestrictedLockUtils; +import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin; + +import org.robolectric.annotation.Implementation; +import org.robolectric.annotation.Implements; + +@Implements(RestrictedLockUtils.class) +public class ShadowRestrictedLockUtils { + private static boolean isRestricted; + private static String[] restrictedPkgs; + private static boolean adminSupportDetailsIntentLaunched; + + @Implementation + public static RestrictedLockUtils.EnforcedAdmin checkIfMeteredDataRestricted(Context context, + String packageName, int userId) { + if (isRestricted) { + return new EnforcedAdmin(); + } + if (ArrayUtils.contains(restrictedPkgs, packageName)) { + return new EnforcedAdmin(); + } + return null; + } + + @Implementation + public static void sendShowAdminSupportDetailsIntent(Context context, EnforcedAdmin admin) { + adminSupportDetailsIntentLaunched = true; + } + + public static boolean hasAdminSupportDetailsIntentLaunched() { + return adminSupportDetailsIntentLaunched; + } + + public static void clearAdminSupportDetailsIntentLaunch() { + adminSupportDetailsIntentLaunched = false; + } + + public static void setRestricted(boolean restricted) { + isRestricted = restricted; + } + + public static void setRestrictedPkgs(String... pkgs) { + restrictedPkgs = pkgs; + } +} From d341d86850e6f866ceac811ec1acb3e116dfc08e Mon Sep 17 00:00:00 2001 From: Salvador Martinez Date: Fri, 26 Jan 2018 17:10:16 -0800 Subject: [PATCH 03/11] Readd needed string This string was needed by a utility class and so it needs to be readded. Test: In sister CL Bug: 72200354 Change-Id: I87f6be7c40d16c669bb2347c90e79fc3ccdf7183 --- res/values/strings.xml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/res/values/strings.xml b/res/values/strings.xml index fe1783ba9c4..4dc88d4a909 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -8780,6 +8780,9 @@ Surface Trace + + %1$s - %2$s + Work profile settings From 484087c181cedb5a6418c8c10f81a36eaa49420f Mon Sep 17 00:00:00 2001 From: Jin Dong Date: Fri, 22 Dec 2017 17:49:23 +0800 Subject: [PATCH 04/11] Fix memory leak of DataSaverPreference When DataSaverPreference is shown repeatedly, memory leak happens since DataSaverBackend.Listener is not removed on onDetached(). TEST: Repeat enter and exit "Data usage" for several times and check if the count of activity is not increasing. Bug: 72581115 Change-Id: Ic4a72de049bb87f1e522fe46dd0fb4bb58ed65a5 --- src/com/android/settings/datausage/DataSaverPreference.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/com/android/settings/datausage/DataSaverPreference.java b/src/com/android/settings/datausage/DataSaverPreference.java index 13ef9d7c4f5..f1f648a37a2 100644 --- a/src/com/android/settings/datausage/DataSaverPreference.java +++ b/src/com/android/settings/datausage/DataSaverPreference.java @@ -37,7 +37,7 @@ public class DataSaverPreference extends Preference implements DataSaverBackend. @Override public void onDetached() { super.onDetached(); - mDataSaverBackend.addListener(this); + mDataSaverBackend.remListener(this); } @Override From 7576e726f9ed8eb8e0229e2b89228c5dacc3f6ea Mon Sep 17 00:00:00 2001 From: Fan Zhang Date: Mon, 29 Jan 2018 09:53:26 -0800 Subject: [PATCH 05/11] Fix settings ui tests in abvt suite Change-Id: I77a262c473b2dfe09c3dabf8e07525fa17815b35 Fixes: 72608407 Test: atest --- tests/uitests/Android.mk | 16 +- .../settings/ui/AboutPhoneSettingsTests.java | 162 ++-- .../settings/ui/HomepageDisplayTests.java | 10 +- ...irelessNetworkSettingsAdditionalTests.java | 766 ++++++++++++++++++ .../ui/WirelessNetworkSettingsTests.java | 745 ++--------------- 5 files changed, 875 insertions(+), 824 deletions(-) create mode 100644 tests/uitests/src/com/android/settings/ui/WirelessNetworkSettingsAdditionalTests.java diff --git a/tests/uitests/Android.mk b/tests/uitests/Android.mk index 870f59c17bd..d52911deefe 100644 --- a/tests/uitests/Android.mk +++ b/tests/uitests/Android.mk @@ -19,16 +19,22 @@ LOCAL_PACKAGE_NAME := SettingsUITests LOCAL_COMPATIBILITY_SUITE := device-tests LOCAL_SRC_FILES := $(call all-java-files-under, src) LOCAL_MODULE_TAGS := tests -LOCAL_JAVA_LIBRARIES := android.test.runner android.test.base + +LOCAL_JAVA_LIBRARIES := \ + android.test.runner \ + android.test.base + LOCAL_STATIC_JAVA_LIBRARIES := \ + android-support-test \ app-helpers-core \ launcher-helper-lib \ - settings-helper \ - timeresult-helper-lib \ - ub-uiautomator \ - sysui-helper \ metrics-helper-lib \ platform-test-annotations \ + settings-helper \ + sysui-helper \ + timeresult-helper-lib \ + truth-prebuilt \ + ub-uiautomator \ #LOCAL_SDK_VERSION := current diff --git a/tests/uitests/src/com/android/settings/ui/AboutPhoneSettingsTests.java b/tests/uitests/src/com/android/settings/ui/AboutPhoneSettingsTests.java index 57f9bc2aedd..b92a70773f5 100644 --- a/tests/uitests/src/com/android/settings/ui/AboutPhoneSettingsTests.java +++ b/tests/uitests/src/com/android/settings/ui/AboutPhoneSettingsTests.java @@ -16,57 +16,55 @@ package com.android.settings.ui; +import static com.android.settings.ui.testutils.SettingsTestUtils.SETTINGS_PACKAGE; +import static com.google.common.truth.Truth.assertThat; +import static com.google.common.truth.Truth.assertWithMessage; + +import android.app.Instrumentation; import android.content.Intent; import android.os.RemoteException; import android.provider.Settings; +import android.support.test.InstrumentationRegistry; +import android.support.test.filters.SmallTest; +import android.support.test.runner.AndroidJUnit4; import android.support.test.uiautomator.By; import android.support.test.uiautomator.Direction; import android.support.test.uiautomator.UiDevice; import android.support.test.uiautomator.UiObject2; import android.support.test.uiautomator.Until; -import android.test.InstrumentationTestCase; -import android.test.suitebuilder.annotation.MediumTest; -import android.test.suitebuilder.annotation.Suppress; import android.text.TextUtils; -import android.util.Log; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; import java.util.ArrayList; import java.util.Arrays; import java.util.Iterator; /** Verifies basic functionality of the About Phone screen */ -public class AboutPhoneSettingsTests extends InstrumentationTestCase { - private static final boolean LOCAL_LOGV = false; - private static final String TAG = "AboutPhoneSettingsTest"; +@RunWith(AndroidJUnit4.class) +@SmallTest +public class AboutPhoneSettingsTests { private static final int TIMEOUT = 2000; - private static final String SETTINGS_PACKAGE = "com.android.settings"; - - private UiDevice mDevice; // TODO: retrieve using name/ids from com.android.settings package private static final String[] sResourceTexts = { - "Status", - "Legal information", - "Regulatory labels", - "Model", - "Android version", - "Android security patch level", - "Baseband version", - "Kernel version", - "Build number" + "Phone number", + "SIM status", + "Model & hardware", + "MEID", + "Android version" }; - private static final String[] sClickableResourceTexts = { - "Status", "Legal information", "Regulatory labels", - }; + private UiDevice mDevice; + private Instrumentation mInstrumentation; - @Override + @Before public void setUp() throws Exception { - if (LOCAL_LOGV) { - Log.d(TAG, "-------"); - } - super.setUp(); - mDevice = UiDevice.getInstance(getInstrumentation()); + mInstrumentation = InstrumentationRegistry.getInstrumentation(); + mDevice = UiDevice.getInstance(mInstrumentation); try { mDevice.setOrientationNatural(); } catch (RemoteException e) { @@ -82,84 +80,40 @@ public class AboutPhoneSettingsTests extends InstrumentationTestCase { UiObject2 view = mDevice.wait( Until.findObject(By.res(SETTINGS_PACKAGE + ":id/main_content")), TIMEOUT); - assertNotNull("Could not find main About Phone screen", view); + assertThat(view).isNotNull(); view.scroll(Direction.UP, 1.0f); } - @Override - protected void tearDown() throws Exception { + @After + public void tearDown() throws Exception { // Adding an extra pressBack so we exit About Phone Settings // and finish the test cleanly mDevice.pressBack(); mDevice.pressHome(); // finish settings activity mDevice.waitForIdle(TIMEOUT * 2); // give UI time to finish animating - super.tearDown(); + } + + @Test + public void testAllMenuEntriesExist() throws Exception { + searchForItemsAndTakeAction(mDevice, sResourceTexts); } private void launchAboutPhoneSettings(String aboutSetting) throws Exception { Intent aboutIntent = new Intent(aboutSetting); aboutIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - getInstrumentation().getContext().startActivity(aboutIntent); - } - - /** - * Callable actions that can be taken when a UIObject2 is found - * - * @param device The current UiDevice - * @param item The UiObject2 that was found and can be acted on - * - * @return {@code true} if the call was successful, and {@code false} otherwise - */ - public interface UIObject2Callback { - boolean call(UiDevice device, UiObject2 item) throws Exception; - } - - /** - * Clicks the given item and then presses the Back button - * - *

Used to test whether a given UiObject2 can be successfully clicked. - * Presses Back to restore state to the previous screen. - * - * @param device The device that can be used to press Back - * @param item The item to click - * - * @return {@code true} if clicking the item succeeded, and {@code false} otherwise - */ - public class UiObject2Clicker implements UIObject2Callback { - public boolean call(UiDevice device, UiObject2 item) throws Exception { - item.click(); - Thread.sleep(TIMEOUT * 2); // give UI time to finish animating - boolean pressWorked = device.pressBack(); - Thread.sleep(TIMEOUT * 2); - return pressWorked; - } + InstrumentationRegistry.getTargetContext().startActivity(aboutIntent); } /** * Removes items found in the view and optionally takes some action. - * - * @param device The current UiDevice - * @param itemsLeftToFind The items to search for in the current view - * @param action Action to call on each item that is found; pass {@code null} to take no action */ - private void removeItemsAndTakeAction( - UiDevice device, ArrayList itemsLeftToFind, UIObject2Callback action) throws Exception { + private void removeItemsAndTakeAction(UiDevice device, ArrayList itemsLeftToFind) + throws Exception { for (Iterator iterator = itemsLeftToFind.iterator(); iterator.hasNext(); ) { String itemText = iterator.next(); UiObject2 item = device.wait(Until.findObject(By.text(itemText)), TIMEOUT); if (item != null) { - if (LOCAL_LOGV) { - Log.d(TAG, itemText + " is present"); - } iterator.remove(); - if (action != null) { - boolean success = action.call(device, item); - assertTrue("Calling action after " + itemText + " did not work", success); - } - } else { - if (LOCAL_LOGV) { - Log.d(TAG, "Could not find " + itemText); - } } } } @@ -169,25 +123,18 @@ public class AboutPhoneSettingsTests extends InstrumentationTestCase { * *

Will scroll down the screen until it has found all elements or reached the bottom. * This allows elements to be found and acted on even if they change order. - * - * @param device The current UiDevice - * @param itemsToFind The items to search for in the current view - * @param action Action to call on each item that is found; pass {@code null} to take no action */ - public void searchForItemsAndTakeAction(UiDevice device, String[] itemsToFind, UIObject2Callback action) + private void searchForItemsAndTakeAction(UiDevice device, String[] itemsToFind) throws Exception { - ArrayList itemsLeftToFind = new ArrayList(Arrays.asList(itemsToFind)); - assertFalse( - "There must be at least one item to search for on the screen!", - itemsLeftToFind.isEmpty()); + ArrayList itemsLeftToFind = new ArrayList<>(Arrays.asList(itemsToFind)); + assertWithMessage("There must be at least one item to search for on the screen!") + .that(itemsLeftToFind) + .isNotEmpty(); - if (LOCAL_LOGV) { - Log.d(TAG, "items: " + TextUtils.join(", ", itemsLeftToFind)); - } boolean canScrollDown = true; while (canScrollDown && !itemsLeftToFind.isEmpty()) { - removeItemsAndTakeAction(device, itemsLeftToFind, action); + removeItemsAndTakeAction(device, itemsLeftToFind); // when we've finished searching the current view, scroll down UiObject2 view = @@ -201,24 +148,11 @@ public class AboutPhoneSettingsTests extends InstrumentationTestCase { } } // check the last items once we have reached the bottom of the view - removeItemsAndTakeAction(device, itemsLeftToFind, action); + removeItemsAndTakeAction(device, itemsLeftToFind); - assertTrue( - "The following items were not found on the screen: " - + TextUtils.join(", ", itemsLeftToFind), - itemsLeftToFind.isEmpty()); - } - - @MediumTest // UI interaction - public void testAllMenuEntriesExist() throws Exception { - searchForItemsAndTakeAction(mDevice, sResourceTexts, null); - } - - // Suppressing this test as it might be causing other test failures - // Will verify that this test is the cause before proceeding with solution - @Suppress - @MediumTest // UI interaction - public void testClickableEntriesCanBeClicked() throws Exception { - searchForItemsAndTakeAction(mDevice, sClickableResourceTexts, new UiObject2Clicker()); + assertWithMessage("The following items were not found on the screen: " + + TextUtils.join(", ", itemsLeftToFind)) + .that(itemsLeftToFind) + .isEmpty(); } } diff --git a/tests/uitests/src/com/android/settings/ui/HomepageDisplayTests.java b/tests/uitests/src/com/android/settings/ui/HomepageDisplayTests.java index 7931d30edd2..3b7b006e628 100644 --- a/tests/uitests/src/com/android/settings/ui/HomepageDisplayTests.java +++ b/tests/uitests/src/com/android/settings/ui/HomepageDisplayTests.java @@ -16,6 +16,9 @@ package com.android.settings.ui; +import static com.android.settings.ui.testutils.SettingsTestUtils.SETTINGS_PACKAGE; +import static com.android.settings.ui.testutils.SettingsTestUtils.TIMEOUT; + import android.os.RemoteException; import android.platform.test.annotations.Presubmit; import android.provider.Settings; @@ -36,9 +39,6 @@ import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import static com.android.settings.ui.testutils.SettingsTestUtils.SETTINGS_PACKAGE; -import static com.android.settings.ui.testutils.SettingsTestUtils.TIMEOUT; - @MediumTest @RunWith(AndroidJUnit4.class) public class HomepageDisplayTests { @@ -52,19 +52,17 @@ public class HomepageDisplayTests { "Sound", "Storage", "Security & location", - "Users & accounts", + "Accounts", "Accessibility", "System", "Support & tips" }; private UiDevice mDevice; - private SettingsHelper mSettingsHelper; @Before public void setUp() throws Exception { mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()); - mSettingsHelper = new SettingsHelper(); try { mDevice.setOrientationNatural(); } catch (RemoteException e) { diff --git a/tests/uitests/src/com/android/settings/ui/WirelessNetworkSettingsAdditionalTests.java b/tests/uitests/src/com/android/settings/ui/WirelessNetworkSettingsAdditionalTests.java new file mode 100644 index 00000000000..4ed2a1dd397 --- /dev/null +++ b/tests/uitests/src/com/android/settings/ui/WirelessNetworkSettingsAdditionalTests.java @@ -0,0 +1,766 @@ +/* + * Copyright (C) 2018 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.ui; + +import android.content.Context; +import android.net.wifi.WifiManager; +import android.os.RemoteException; +import android.platform.test.annotations.Presubmit; +import android.provider.Settings; +import android.support.test.uiautomator.By; +import android.support.test.uiautomator.BySelector; +import android.support.test.uiautomator.Direction; +import android.support.test.uiautomator.StaleObjectException; +import android.support.test.uiautomator.UiDevice; +import android.support.test.uiautomator.UiObject2; +import android.support.test.uiautomator.Until; +import android.system.helpers.CommandsHelper; +import android.system.helpers.SettingsHelper; +import android.test.InstrumentationTestCase; +import android.test.suitebuilder.annotation.MediumTest; +import android.test.suitebuilder.annotation.Suppress; +import android.util.Log; + +/** + * Additional tests for Wifi Settings. + */ +public class WirelessNetworkSettingsAdditionalTests extends InstrumentationTestCase { + // These back button presses are performed in tearDown() to exit Wifi + // Settings sub-menus that a test might finish in. This number should be + // high enough to account for the deepest sub-menu a test might enter. + private static final int NUM_BACK_BUTTON_PRESSES = 5; + private static final int TIMEOUT = 2000; + private static final int SLEEP_TIME = 500; + private static final String AIRPLANE_MODE_BROADCAST = + "am broadcast -a android.intent.action.AIRPLANE_MODE"; + private static final String TAG="WirelessNetworkSettingsTests"; + + // Note: The values of these variables might affect flakiness in tests that involve + // scrolling. Adjust where necessary. + private static final float SCROLL_UP_PERCENT = 10.0f; + private static final float SCROLL_DOWN_PERCENT = 0.5f; + private static final int MAX_SCROLL_ATTEMPTS = 10; + private static final int MAX_ADD_NETWORK_BUTTON_ATTEMPTS = 3; + private static final int SCROLL_SPEED = 2000; + + private static final String TEST_SSID = "testSsid"; + private static final String TEST_PW_GE_8_CHAR = "testPasswordGreaterThan8Char"; + private static final String TEST_PW_LT_8_CHAR = "lt8Char"; + private static final String TEST_DOMAIN = "testDomain.com"; + + private static final String SETTINGS_PACKAGE = "com.android.settings"; + + private static final String CHECKBOX_CLASS = "android.widget.CheckBox"; + private static final String SPINNER_CLASS = "android.widget.Spinner"; + private static final String EDIT_TEXT_CLASS = "android.widget.EditText"; + private static final String SCROLLVIEW_CLASS = "android.widget.ScrollView"; + private static final String LISTVIEW_CLASS = "android.widget.ListView"; + + private static final String ADD_NETWORK_MENU_CANCEL_BUTTON_TEXT = "CANCEL"; + private static final String ADD_NETWORK_MENU_SAVE_BUTTON_TEXT = "SAVE"; + private static final String ADD_NETWORK_PREFERENCE_TEXT = "Add network"; + private static final String CONFIGURE_WIFI_PREFERENCE_TEXT = "Wi‑Fi preferences"; + private static final String CONFIGURE_WIFI_ADVANCED_PREFERENCE_TEXT = "Advanced"; + private static final String CACERT_MENU_PLEASE_SELECT_TEXT = "Please select"; + private static final String CACERT_MENU_USE_SYSTEM_CERTS_TEXT = "Use system certificates"; + private static final String CACERT_MENU_DO_NOT_VALIDATE_TEXT = "Do not validate"; + private static final String USERCERT_MENU_PLEASE_SELECT_TEXT = "Please select"; + private static final String USERCERT_MENU_DO_NOT_PROVIDE_TEXT = "Do not provide"; + private static final String SECURITY_OPTION_NONE_TEXT = "None"; + private static final String SECURITY_OPTION_WEP_TEXT = "WEP"; + private static final String SECURITY_OPTION_PSK_TEXT = "WPA/WPA2 PSK"; + private static final String SECURITY_OPTION_EAP_TEXT = "802.1x EAP"; + private static final String EAP_METHOD_PEAP_TEXT = "PEAP"; + private static final String EAP_METHOD_TLS_TEXT = "TLS"; + private static final String EAP_METHOD_TTLS_TEXT = "TTLS"; + private static final String EAP_METHOD_PWD_TEXT = "PWD"; + private static final String EAP_METHOD_SIM_TEXT = "SIM"; + private static final String EAP_METHOD_AKA_TEXT = "AKA"; + private static final String EAP_METHOD_AKA_PRIME_TEXT = "AKA'"; + private static final String PHASE2_MENU_NONE_TEXT = "None"; + private static final String PHASE2_MENU_MSCHAPV2_TEXT = "MSCHAPV2"; + private static final String PHASE2_MENU_GTC_TEXT = "GTC"; + + private static final String ADD_NETWORK_MENU_ADV_TOGGLE_RES_ID = "wifi_advanced_togglebox"; + private static final String ADD_NETWORK_MENU_IP_SETTINGS_RES_ID = "ip_settings"; + private static final String ADD_NETWORK_MENU_PROXY_SETTINGS_RES_ID = "proxy_settings"; + private static final String ADD_NETWORK_MENU_SECURITY_OPTION_RES_ID = "security"; + private static final String ADD_NETWORK_MENU_EAP_METHOD_RES_ID = "method"; + private static final String ADD_NETWORK_MENU_SSID_RES_ID = "ssid"; + private static final String ADD_NETWORK_MENU_PHASE2_RES_ID = "phase2"; + private static final String ADD_NETWORK_MENU_CACERT_RES_ID = "ca_cert"; + private static final String ADD_NETWORK_MENU_USERCERT_RES_ID = "user_cert"; + private static final String ADD_NETWORK_MENU_NO_DOMAIN_WARNING_RES_ID = "no_domain_warning"; + private static final String ADD_NETWORK_MENU_NO_CACERT_WARNING_RES_ID = "no_ca_cert_warning"; + private static final String ADD_NETWORK_MENU_DOMAIN_LAYOUT_RES_ID = "l_domain"; + private static final String ADD_NETWORK_MENU_DOMAIN_RES_ID = "domain"; + private static final String ADD_NETWORK_MENU_IDENTITY_LAYOUT_RES_ID = "l_identity"; + private static final String ADD_NETWORK_MENU_ANONYMOUS_LAYOUT_RES_ID = "l_anonymous"; + private static final String ADD_NETWORK_MENU_PASSWORD_LAYOUT_RES_ID = "password_layout"; + private static final String ADD_NETWORK_MENU_SHOW_PASSWORD_LAYOUT_RES_ID = + "show_password_layout"; + private static final String ADD_NETWORK_MENU_PASSWORD_RES_ID = "password"; + + private static final BySelector ADD_NETWORK_MENU_SCROLLABLE_BY_SELECTOR = + By.scrollable(true).clazz(SCROLLVIEW_CLASS); + private static final BySelector SPINNER_OPTIONS_SCROLLABLE_BY_SELECTOR = + By.scrollable(true).clazz(LISTVIEW_CLASS); + + private UiDevice mDevice; + private CommandsHelper mCommandsHelper; + + @Override + public void setUp() throws Exception { + super.setUp(); + mDevice = UiDevice.getInstance(getInstrumentation()); + try { + mDevice.setOrientationNatural(); + } catch (RemoteException e) { + throw new RuntimeException("failed to freeze device orientation", e); + } + // Ensure airplane mode is OFF so that wifi can be enabled using WiFiManager. + Settings.Global.putString(getInstrumentation().getContext().getContentResolver(), + Settings.Global.AIRPLANE_MODE_ON, "0"); + Log.d(TAG, "sending airplane mode broadcast to device"); + mCommandsHelper = CommandsHelper.getInstance(); + mCommandsHelper.executeShellCommand(AIRPLANE_MODE_BROADCAST); + } + + @Override + protected void tearDown() throws Exception { + // Exit all settings sub-menus. + for (int i = 0; i < NUM_BACK_BUTTON_PRESSES; ++i) { + mDevice.pressBack(); + } + mDevice.pressHome(); + super.tearDown(); + } + + @MediumTest + public void testWifiMenuLoadConfigure() throws Exception { + loadWiFiConfigureMenu(); + Thread.sleep(SLEEP_TIME); + UiObject2 configureWiFiHeading = mDevice.wait(Until.findObject + (By.text(CONFIGURE_WIFI_PREFERENCE_TEXT)), TIMEOUT); + assertNotNull("Configure WiFi menu has not loaded correctly", configureWiFiHeading); + } + + @MediumTest + public void testNetworkNotificationsOn() throws Exception { + verifyNetworkNotificationsOnOrOff(true); + } + + @MediumTest + public void testNetworkNotificationsOff() throws Exception { + verifyNetworkNotificationsOnOrOff(false); + } + + @MediumTest + public void testAddNetworkMenu_Default() throws Exception { + loadAddNetworkMenu(); + + // Submit button should be disabled by default, while cancel button should be enabled. + assertFalse(mDevice.wait(Until.findObject( + By.text(ADD_NETWORK_MENU_SAVE_BUTTON_TEXT)), TIMEOUT).isEnabled()); + assertTrue(mDevice.wait(Until.findObject( + By.text(ADD_NETWORK_MENU_CANCEL_BUTTON_TEXT)), TIMEOUT).isEnabled()); + + // Check that the SSID field is defaults to the hint. + assertEquals("Enter the SSID", mDevice.wait(Until.findObject(By + .res(SETTINGS_PACKAGE, ADD_NETWORK_MENU_SSID_RES_ID) + .clazz(EDIT_TEXT_CLASS)), TIMEOUT*2) + .getText()); + + // Check Security defaults to None. + assertEquals("None", mDevice.wait(Until.findObject(By + .res(SETTINGS_PACKAGE, ADD_NETWORK_MENU_SECURITY_OPTION_RES_ID) + .clazz(SPINNER_CLASS)), TIMEOUT) + .getChildren().get(0).getText()); + + // Check advanced options are collapsed by default. + assertFalse(mDevice.wait(Until.findObject(By + .res(SETTINGS_PACKAGE, ADD_NETWORK_MENU_ADV_TOGGLE_RES_ID) + .clazz(CHECKBOX_CLASS)), TIMEOUT).isChecked()); + + } + + @Suppress + @MediumTest + public void testAddNetworkMenu_Proxy() throws Exception { + loadAddNetworkMenu(); + + // Toggle advanced options. + mDevice.wait(Until.findObject(By + .res(SETTINGS_PACKAGE, ADD_NETWORK_MENU_ADV_TOGGLE_RES_ID) + .clazz(CHECKBOX_CLASS)), TIMEOUT).click(); + + // Verify Proxy defaults to None. + BySelector proxySettingsBySelector = + By.res(SETTINGS_PACKAGE, ADD_NETWORK_MENU_PROXY_SETTINGS_RES_ID) + .clazz(SPINNER_CLASS); + findOrScrollToObject(ADD_NETWORK_MENU_SCROLLABLE_BY_SELECTOR, proxySettingsBySelector); + assertEquals("None", mDevice.wait(Until.findObject(proxySettingsBySelector), TIMEOUT) + .getChildren().get(0).getText()); + + // Verify that Proxy Manual fields appear. + findOrScrollToObject(ADD_NETWORK_MENU_SCROLLABLE_BY_SELECTOR, proxySettingsBySelector); + mDevice.wait(Until.findObject(proxySettingsBySelector), TIMEOUT).click(); + mDevice.wait(Until.findObject(By.text("Manual")), TIMEOUT).click(); + findOrScrollToObject(ADD_NETWORK_MENU_SCROLLABLE_BY_SELECTOR, + By.res(SETTINGS_PACKAGE, "proxy_warning_limited_support")); + findOrScrollToObject(ADD_NETWORK_MENU_SCROLLABLE_BY_SELECTOR, + By.res(SETTINGS_PACKAGE, "proxy_hostname")); + findOrScrollToObject(ADD_NETWORK_MENU_SCROLLABLE_BY_SELECTOR, + By.res(SETTINGS_PACKAGE, "proxy_exclusionlist")); + + // Verify that Proxy Auto-Config options appear. + findOrScrollToObject(ADD_NETWORK_MENU_SCROLLABLE_BY_SELECTOR, proxySettingsBySelector); + mDevice.wait(Until.findObject(proxySettingsBySelector), TIMEOUT).click(); + mDevice.wait(Until.findObject(By.text("Proxy Auto-Config")), TIMEOUT).click(); + findOrScrollToObject(ADD_NETWORK_MENU_SCROLLABLE_BY_SELECTOR, + By.res(SETTINGS_PACKAGE, "proxy_pac")); + } + + @Suppress + @MediumTest + public void testAddNetworkMenu_IpSettings() throws Exception { + loadAddNetworkMenu(); + + // Toggle advanced options. + mDevice.wait(Until.findObject(By + .res(SETTINGS_PACKAGE, ADD_NETWORK_MENU_ADV_TOGGLE_RES_ID) + .clazz(CHECKBOX_CLASS)), TIMEOUT).click(); + + // Verify IP settings defaults to DHCP. + BySelector ipSettingsBySelector = + By.res(SETTINGS_PACKAGE, ADD_NETWORK_MENU_IP_SETTINGS_RES_ID).clazz(SPINNER_CLASS); + findOrScrollToObject(ADD_NETWORK_MENU_SCROLLABLE_BY_SELECTOR, ipSettingsBySelector); + assertEquals("DHCP", mDevice.wait(Until.findObject(ipSettingsBySelector), TIMEOUT) + .getChildren().get(0).getText()); + + // Verify that Static IP settings options appear. + findOrScrollToObject(ADD_NETWORK_MENU_SCROLLABLE_BY_SELECTOR, ipSettingsBySelector).click(); + mDevice.wait(Until.findObject(By.text("Static")), TIMEOUT).click(); + findOrScrollToObject(ADD_NETWORK_MENU_SCROLLABLE_BY_SELECTOR, + By.res(SETTINGS_PACKAGE, "ipaddress")); + findOrScrollToObject(ADD_NETWORK_MENU_SCROLLABLE_BY_SELECTOR, + By.res(SETTINGS_PACKAGE, "gateway")); + findOrScrollToObject(ADD_NETWORK_MENU_SCROLLABLE_BY_SELECTOR, + By.res(SETTINGS_PACKAGE, "network_prefix_length")); + findOrScrollToObject(ADD_NETWORK_MENU_SCROLLABLE_BY_SELECTOR, + By.res(SETTINGS_PACKAGE, "dns1")); + findOrScrollToObject(ADD_NETWORK_MENU_SCROLLABLE_BY_SELECTOR, + By.res(SETTINGS_PACKAGE, "dns2")); + } + + @Suppress + @MediumTest + public void testPhase2Settings() throws Exception { + loadAddNetworkMenu(); + selectSecurityOption(SECURITY_OPTION_EAP_TEXT); + + BySelector phase2SettingsBySelector = + By.res(SETTINGS_PACKAGE, ADD_NETWORK_MENU_PHASE2_RES_ID).clazz(SPINNER_CLASS); + findOrScrollToObject(ADD_NETWORK_MENU_SCROLLABLE_BY_SELECTOR, phase2SettingsBySelector); + assertEquals(PHASE2_MENU_NONE_TEXT, mDevice.wait(Until + .findObject(phase2SettingsBySelector), TIMEOUT).getChildren().get(0).getText()); + mDevice.wait(Until.findObject(phase2SettingsBySelector), TIMEOUT).click(); + Thread.sleep(SLEEP_TIME); + + // Verify Phase 2 authentication spinner options. + assertNotNull(mDevice.wait(Until.findObject(By.text(PHASE2_MENU_NONE_TEXT)), TIMEOUT)); + assertNotNull(mDevice.wait(Until.findObject(By.text(PHASE2_MENU_MSCHAPV2_TEXT)), TIMEOUT)); + assertNotNull(mDevice.wait(Until.findObject(By.text(PHASE2_MENU_GTC_TEXT)), TIMEOUT)); + } + + @Suppress + @MediumTest + public void testCaCertSettings() throws Exception { + loadAddNetworkMenu(); + selectSecurityOption(SECURITY_OPTION_EAP_TEXT); + + BySelector caCertSettingsBySelector = + By.res(SETTINGS_PACKAGE, ADD_NETWORK_MENU_CACERT_RES_ID).clazz(SPINNER_CLASS); + findOrScrollToObject(ADD_NETWORK_MENU_SCROLLABLE_BY_SELECTOR, caCertSettingsBySelector); + assertEquals(CACERT_MENU_PLEASE_SELECT_TEXT, mDevice.wait(Until + .findObject(caCertSettingsBySelector), TIMEOUT).getChildren().get(0).getText()); + mDevice.wait(Until.findObject(caCertSettingsBySelector), TIMEOUT).click(); + Thread.sleep(SLEEP_TIME); + + // Verify CA certificate spinner options. + assertNotNull(mDevice.wait(Until.findObject( + By.text(CACERT_MENU_PLEASE_SELECT_TEXT)), TIMEOUT)); + assertNotNull(mDevice.wait(Until.findObject( + By.text(CACERT_MENU_USE_SYSTEM_CERTS_TEXT)), TIMEOUT)); + assertNotNull(mDevice.wait(Until.findObject( + By.text(CACERT_MENU_DO_NOT_VALIDATE_TEXT)), TIMEOUT)); + + // Verify that a domain field and warning appear when the user selects the + // "Use system certificates" option. + mDevice.wait(Until.findObject(By.text(CACERT_MENU_USE_SYSTEM_CERTS_TEXT)), TIMEOUT).click(); + findOrScrollToObject(ADD_NETWORK_MENU_SCROLLABLE_BY_SELECTOR, + By.res(SETTINGS_PACKAGE, ADD_NETWORK_MENU_DOMAIN_LAYOUT_RES_ID)); + findOrScrollToObject(ADD_NETWORK_MENU_SCROLLABLE_BY_SELECTOR, + By.res(SETTINGS_PACKAGE, ADD_NETWORK_MENU_NO_DOMAIN_WARNING_RES_ID)); + + // Verify that a warning appears when the user chooses the "Do Not Validate" option. + mDevice.wait(Until.findObject(caCertSettingsBySelector), TIMEOUT).click(); + mDevice.wait(Until.findObject(By.text(CACERT_MENU_DO_NOT_VALIDATE_TEXT)), TIMEOUT).click(); + findOrScrollToObject(ADD_NETWORK_MENU_SCROLLABLE_BY_SELECTOR, + By.res(SETTINGS_PACKAGE, ADD_NETWORK_MENU_NO_CACERT_WARNING_RES_ID)); + } + + @Suppress + @MediumTest + public void testAddNetwork_NoSecurity() throws Exception { + loadAddNetworkMenu(); + selectSecurityOption(SECURITY_OPTION_NONE_TEXT); + + // Entering an SSID is enough to enable the submit button. // TODO THIS GUY + enterSSID(TEST_SSID); + assertTrue(mDevice.wait(Until + .findObject(By.text(ADD_NETWORK_MENU_SAVE_BUTTON_TEXT)), TIMEOUT).isEnabled()); + } + + @Suppress + @MediumTest + public void testAddNetwork_WEP() throws Exception { + loadAddNetworkMenu(); + selectSecurityOption(SECURITY_OPTION_WEP_TEXT); + assertFalse(mDevice.wait(Until.findObject( + By.text(ADD_NETWORK_MENU_SAVE_BUTTON_TEXT)), TIMEOUT).isEnabled()); + + // Verify that WEP fields appear. + findOrScrollToObject(ADD_NETWORK_MENU_SCROLLABLE_BY_SELECTOR, + By.res(SETTINGS_PACKAGE, ADD_NETWORK_MENU_PASSWORD_LAYOUT_RES_ID)); + findOrScrollToObject(ADD_NETWORK_MENU_SCROLLABLE_BY_SELECTOR, + By.res(SETTINGS_PACKAGE, ADD_NETWORK_MENU_SHOW_PASSWORD_LAYOUT_RES_ID)); + + // Entering an SSID alone does not enable the submit button. + enterSSID(TEST_SSID); + assertFalse(mDevice.wait(Until.findObject( + By.text(ADD_NETWORK_MENU_SAVE_BUTTON_TEXT)), TIMEOUT).isEnabled()); + + // Submit button is only enabled after a password is entered. + enterPassword(TEST_PW_GE_8_CHAR); + assertTrue(mDevice.wait(Until + .findObject(By.text(ADD_NETWORK_MENU_SAVE_BUTTON_TEXT)), TIMEOUT).isEnabled()); + } + + @Suppress + @MediumTest + public void testAddNetwork_PSK() throws Exception { + loadAddNetworkMenu(); + selectSecurityOption(SECURITY_OPTION_PSK_TEXT); + assertFalse(mDevice.wait(Until.findObject( + By.text(ADD_NETWORK_MENU_SAVE_BUTTON_TEXT)), TIMEOUT).isEnabled()); + + // Verify that PSK fields appear. + findOrScrollToObject(ADD_NETWORK_MENU_SCROLLABLE_BY_SELECTOR, + By.res(SETTINGS_PACKAGE, ADD_NETWORK_MENU_PASSWORD_LAYOUT_RES_ID)); + findOrScrollToObject(ADD_NETWORK_MENU_SCROLLABLE_BY_SELECTOR, + By.res(SETTINGS_PACKAGE, ADD_NETWORK_MENU_SHOW_PASSWORD_LAYOUT_RES_ID)); + + // Entering an SSID alone does not enable the submit button. + enterSSID(TEST_SSID); + assertFalse(mDevice.wait(Until.findObject( + By.text(ADD_NETWORK_MENU_SAVE_BUTTON_TEXT)), TIMEOUT).isEnabled()); + + // Entering an password that is too short does not enable submit button. + enterPassword(TEST_PW_LT_8_CHAR); + assertFalse(mDevice.wait(Until.findObject( + By.text(ADD_NETWORK_MENU_SAVE_BUTTON_TEXT)), TIMEOUT).isEnabled()); + + // Submit button is only enabled after a password of valid length is entered. + enterPassword(TEST_PW_GE_8_CHAR); + assertTrue(mDevice.wait(Until.findObject( + By.text(ADD_NETWORK_MENU_SAVE_BUTTON_TEXT)), TIMEOUT).isEnabled()); + } + + @Suppress + @MediumTest + public void testAddNetwork_EAP_PEAP() throws Exception { + loadAddNetworkMenu(); + selectSecurityOption(SECURITY_OPTION_EAP_TEXT); + assertFalse(mDevice.wait(Until.findObject( + By.text(ADD_NETWORK_MENU_SAVE_BUTTON_TEXT)), TIMEOUT).isEnabled()); + + selectEAPMethod(EAP_METHOD_PEAP_TEXT); + + // Verify that EAP-PEAP fields appear. + findOrScrollToObject(ADD_NETWORK_MENU_SCROLLABLE_BY_SELECTOR, + By.res(SETTINGS_PACKAGE, ADD_NETWORK_MENU_PHASE2_RES_ID)); + findOrScrollToObject(ADD_NETWORK_MENU_SCROLLABLE_BY_SELECTOR, + By.res(SETTINGS_PACKAGE, ADD_NETWORK_MENU_CACERT_RES_ID)); + findOrScrollToObject(ADD_NETWORK_MENU_SCROLLABLE_BY_SELECTOR, + By.res(SETTINGS_PACKAGE, ADD_NETWORK_MENU_IDENTITY_LAYOUT_RES_ID)); + findOrScrollToObject(ADD_NETWORK_MENU_SCROLLABLE_BY_SELECTOR, + By.res(SETTINGS_PACKAGE, ADD_NETWORK_MENU_ANONYMOUS_LAYOUT_RES_ID)); + findOrScrollToObject(ADD_NETWORK_MENU_SCROLLABLE_BY_SELECTOR, + By.res(SETTINGS_PACKAGE, ADD_NETWORK_MENU_PASSWORD_LAYOUT_RES_ID)); + findOrScrollToObject(ADD_NETWORK_MENU_SCROLLABLE_BY_SELECTOR, + By.res(SETTINGS_PACKAGE, ADD_NETWORK_MENU_SHOW_PASSWORD_LAYOUT_RES_ID)); + + // Entering an SSID alone does not enable the submit button. + enterSSID(TEST_SSID); + assertFalse(mDevice.wait(Until.findObject( + By.text(ADD_NETWORK_MENU_SAVE_BUTTON_TEXT)), TIMEOUT).isEnabled()); + + verifyCaCertificateSubmitConditions(); + } + + @Suppress + @MediumTest + public void testAddNetwork_EAP_TLS() throws Exception { + loadAddNetworkMenu(); + selectSecurityOption(SECURITY_OPTION_EAP_TEXT); + assertFalse(mDevice.wait(Until.findObject( + By.text(ADD_NETWORK_MENU_SAVE_BUTTON_TEXT)), TIMEOUT).isEnabled()); + + selectEAPMethod(EAP_METHOD_TLS_TEXT); + + // Verify that EAP-TLS fields appear. + findOrScrollToObject(ADD_NETWORK_MENU_SCROLLABLE_BY_SELECTOR, + By.res(SETTINGS_PACKAGE, ADD_NETWORK_MENU_CACERT_RES_ID)); + findOrScrollToObject(ADD_NETWORK_MENU_SCROLLABLE_BY_SELECTOR, + By.res(SETTINGS_PACKAGE, ADD_NETWORK_MENU_USERCERT_RES_ID)); + findOrScrollToObject(ADD_NETWORK_MENU_SCROLLABLE_BY_SELECTOR, + By.res(SETTINGS_PACKAGE, ADD_NETWORK_MENU_IDENTITY_LAYOUT_RES_ID)); + + // Entering an SSID alone does not enable the submit button. + enterSSID(TEST_SSID); + assertFalse(mDevice.wait(Until.findObject( + By.text(ADD_NETWORK_MENU_SAVE_BUTTON_TEXT)), TIMEOUT).isEnabled()); + + // Selecting the User certificate "Do not provide" option alone does not enable the submit + // button. + selectUserCertificateOption(USERCERT_MENU_DO_NOT_PROVIDE_TEXT); + assertFalse(mDevice.wait(Until.findObject( + By.text(ADD_NETWORK_MENU_SAVE_BUTTON_TEXT)), TIMEOUT).isEnabled()); + + verifyCaCertificateSubmitConditions(); + } + + @Suppress + @MediumTest + public void testAddNetwork_EAP_TTLS() throws Exception { + loadAddNetworkMenu(); + selectSecurityOption(SECURITY_OPTION_EAP_TEXT); + assertFalse(mDevice.wait(Until.findObject( + By.text(ADD_NETWORK_MENU_SAVE_BUTTON_TEXT)), TIMEOUT).isEnabled()); + + selectEAPMethod(EAP_METHOD_TTLS_TEXT); + + // Verify that EAP-TLS fields appear. + findOrScrollToObject(ADD_NETWORK_MENU_SCROLLABLE_BY_SELECTOR, + By.res(SETTINGS_PACKAGE, ADD_NETWORK_MENU_PHASE2_RES_ID)); + findOrScrollToObject(ADD_NETWORK_MENU_SCROLLABLE_BY_SELECTOR, + By.res(SETTINGS_PACKAGE, ADD_NETWORK_MENU_CACERT_RES_ID)); + findOrScrollToObject(ADD_NETWORK_MENU_SCROLLABLE_BY_SELECTOR, + By.res(SETTINGS_PACKAGE, ADD_NETWORK_MENU_IDENTITY_LAYOUT_RES_ID)); + findOrScrollToObject(ADD_NETWORK_MENU_SCROLLABLE_BY_SELECTOR, + By.res(SETTINGS_PACKAGE, ADD_NETWORK_MENU_ANONYMOUS_LAYOUT_RES_ID)); + findOrScrollToObject(ADD_NETWORK_MENU_SCROLLABLE_BY_SELECTOR, + By.res(SETTINGS_PACKAGE, ADD_NETWORK_MENU_PASSWORD_LAYOUT_RES_ID)); + + // Entering an SSID alone does not enable the submit button. + enterSSID(TEST_SSID); + assertFalse(mDevice.wait(Until.findObject( + By.text(ADD_NETWORK_MENU_SAVE_BUTTON_TEXT)), TIMEOUT).isEnabled()); + + verifyCaCertificateSubmitConditions(); + } + + @Suppress + @MediumTest + public void testAddNetwork_EAP_PWD() throws Exception { + loadAddNetworkMenu(); + selectSecurityOption(SECURITY_OPTION_EAP_TEXT); + assertFalse(mDevice.wait(Until.findObject( + By.text(ADD_NETWORK_MENU_SAVE_BUTTON_TEXT)), TIMEOUT).isEnabled()); + + selectEAPMethod(EAP_METHOD_PWD_TEXT); + + // Verify that EAP-TLS fields appear. + findOrScrollToObject(ADD_NETWORK_MENU_SCROLLABLE_BY_SELECTOR, + By.res(SETTINGS_PACKAGE, ADD_NETWORK_MENU_IDENTITY_LAYOUT_RES_ID)); + findOrScrollToObject(ADD_NETWORK_MENU_SCROLLABLE_BY_SELECTOR, + By.res(SETTINGS_PACKAGE, ADD_NETWORK_MENU_PASSWORD_LAYOUT_RES_ID)); + + // Entering an SSID alone enables the submit button. + enterSSID(TEST_SSID); + assertTrue(mDevice.wait(Until.findObject( + By.text(ADD_NETWORK_MENU_SAVE_BUTTON_TEXT)), TIMEOUT).isEnabled()); + } + + @Suppress + @MediumTest + public void testAddNetwork_EAP_SIM() throws Exception { + loadAddNetworkMenu(); + selectSecurityOption(SECURITY_OPTION_EAP_TEXT); + assertFalse(mDevice.wait(Until.findObject( + By.text(ADD_NETWORK_MENU_SAVE_BUTTON_TEXT)), TIMEOUT).isEnabled()); + + selectEAPMethod(EAP_METHOD_SIM_TEXT); + + // Entering an SSID alone enables the submit button. + enterSSID(TEST_SSID); + assertTrue(mDevice.wait(Until.findObject( + By.text(ADD_NETWORK_MENU_SAVE_BUTTON_TEXT)), TIMEOUT).isEnabled()); + } + + @Suppress + @MediumTest + public void testAddNetwork_EAP_AKA() throws Exception { + loadAddNetworkMenu(); + selectSecurityOption(SECURITY_OPTION_EAP_TEXT); + assertFalse(mDevice.wait(Until.findObject( + By.text(ADD_NETWORK_MENU_SAVE_BUTTON_TEXT)), TIMEOUT).isEnabled()); + + selectEAPMethod(EAP_METHOD_AKA_TEXT); + + // Entering an SSID alone enables the submit button. + enterSSID(TEST_SSID); + assertTrue(mDevice.wait(Until.findObject( + By.text(ADD_NETWORK_MENU_SAVE_BUTTON_TEXT)), TIMEOUT).isEnabled()); + } + + @Suppress + @MediumTest + public void testAddNetwork_EAP_AKA_PRIME() throws Exception { + loadAddNetworkMenu(); + selectSecurityOption(SECURITY_OPTION_EAP_TEXT); + assertFalse(mDevice.wait(Until.findObject( + By.text(ADD_NETWORK_MENU_SAVE_BUTTON_TEXT)), TIMEOUT).isEnabled()); + + selectEAPMethod(EAP_METHOD_AKA_PRIME_TEXT); + + // Entering an SSID alone enables the submit button. + enterSSID(TEST_SSID); + assertTrue(mDevice.wait(Until.findObject( + By.text(ADD_NETWORK_MENU_SAVE_BUTTON_TEXT)), TIMEOUT).isEnabled()); + } + + private void verifyKeepWiFiOnDuringSleep(String settingToBeVerified, int settingValue) + throws Exception { + loadWiFiConfigureMenu(); + mDevice.wait(Until.findObject(By.text("Keep Wi‑Fi on during sleep")), TIMEOUT) + .click(); + mDevice.wait(Until.findObject(By.clazz("android.widget.CheckedTextView") + .text(settingToBeVerified)), TIMEOUT).click(); + Thread.sleep(SLEEP_TIME); + int keepWiFiOnSetting = + Settings.Global.getInt(getInstrumentation().getContext().getContentResolver(), + Settings.Global.WIFI_SLEEP_POLICY); + assertEquals(settingValue, keepWiFiOnSetting); + } + + private void verifyNetworkNotificationsOnOrOff(boolean verifyOn) + throws Exception { + // Enable network recommendations to enable the toggle switch for Network + // notifications + Settings.Global.putString(getInstrumentation().getContext().getContentResolver(), + Settings.Global.NETWORK_RECOMMENDATIONS_ENABLED, "1"); + if (verifyOn) { + Settings.Global.putString(getInstrumentation().getContext().getContentResolver(), + Settings.Global.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON, "0"); + } + else { + Settings.Global.putString(getInstrumentation().getContext().getContentResolver(), + Settings.Global.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON, "1"); + } + loadWiFiConfigureMenu(); + mDevice.wait(Until.findObject(By.text("Open network notification")), TIMEOUT) + .click(); + Thread.sleep(SLEEP_TIME); + String wifiNotificationValue = + Settings.Global.getString(getInstrumentation().getContext().getContentResolver(), + Settings.Global.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON); + if (verifyOn) { + assertEquals("1", wifiNotificationValue); + } + else { + assertEquals("0", wifiNotificationValue); + } + } + + private void verifyWiFiOnOrOff(boolean verifyOn) throws Exception { + String switchText = "On"; + if (verifyOn) { + switchText = "Off"; + } + loadWiFiSettingsPage(!verifyOn); + mDevice.wait(Until + .findObject(By.res(SETTINGS_PACKAGE, "switch_bar").text(switchText)), TIMEOUT) + .click(); + Thread.sleep(SLEEP_TIME); + String wifiValue = + Settings.Global.getString(getInstrumentation().getContext().getContentResolver(), + Settings.Global.WIFI_ON); + if (verifyOn) { + // 1 is Enabled, 2 is Enabled while airplane mode is ON. + assertTrue(wifiValue.equals("1") || wifiValue.equals("2")); + } + else { + assertEquals("0", wifiValue); + } + } + + private void verifyCaCertificateSubmitConditions() throws Exception { + // Selecting the CA certificate "Do not validate" option enables the submit button. + selectCaCertificateOption(CACERT_MENU_DO_NOT_VALIDATE_TEXT); + assertTrue(mDevice.wait(Until.findObject( + By.text(ADD_NETWORK_MENU_SAVE_BUTTON_TEXT)), TIMEOUT).isEnabled()); + + // However, selecting the CA certificate "Use system certificates option" is not enough to + // enable the submit button. + selectCaCertificateOption(CACERT_MENU_USE_SYSTEM_CERTS_TEXT); + assertFalse(mDevice.wait(Until.findObject( + By.text(ADD_NETWORK_MENU_SAVE_BUTTON_TEXT)), TIMEOUT).isEnabled()); + + // Submit button is only enabled after a domain is entered as well. + enterDomain(TEST_DOMAIN); + assertTrue(mDevice.wait(Until.findObject( + By.text(ADD_NETWORK_MENU_SAVE_BUTTON_TEXT)), TIMEOUT).isEnabled()); + } + + private void loadWiFiSettingsPage(boolean wifiEnabled) throws Exception { + WifiManager wifiManager = (WifiManager)getInstrumentation().getContext() + .getSystemService(Context.WIFI_SERVICE); + wifiManager.setWifiEnabled(wifiEnabled); + SettingsHelper.launchSettingsPage(getInstrumentation().getContext(), + Settings.ACTION_WIFI_SETTINGS); + } + + private void loadWiFiConfigureMenu() throws Exception { + loadWiFiSettingsPage(false); + Thread.sleep(TIMEOUT); + mDevice.wait(Until.findObject(By.text(CONFIGURE_WIFI_PREFERENCE_TEXT)), TIMEOUT).click(); + mDevice.wait(Until.findObject( + By.text(CONFIGURE_WIFI_ADVANCED_PREFERENCE_TEXT)), TIMEOUT).click(); + } + + private void loadAddNetworkMenu() throws Exception { + loadWiFiSettingsPage(true); + for (int attempts = 0; attempts < MAX_ADD_NETWORK_BUTTON_ATTEMPTS; ++attempts) { + try { + findOrScrollToObject(By.scrollable(true), By.text(ADD_NETWORK_PREFERENCE_TEXT)) + .click(); + } catch (StaleObjectException e) { + // The network list might have been updated between when the Add network button was + // found, and when it UI automator attempted to click on it. Retry. + continue; + } + // If we get here, we successfully clicked on the Add network button, so we are done. + Thread.sleep(SLEEP_TIME*5); + return; + } + + fail("Failed to load Add Network Menu after " + MAX_ADD_NETWORK_BUTTON_ATTEMPTS + + " retries"); + } + + private void selectSecurityOption(String securityOption) throws Exception { + // We might not need to scroll to the security options if not enough add network menu + // options are visible. + findOrScrollToObject(ADD_NETWORK_MENU_SCROLLABLE_BY_SELECTOR, + By.res(SETTINGS_PACKAGE, ADD_NETWORK_MENU_SECURITY_OPTION_RES_ID) + .clazz(SPINNER_CLASS)).click(); + Thread.sleep(SLEEP_TIME); + mDevice.wait(Until.findObject(By.text(securityOption)), TIMEOUT).click(); + } + + private void selectEAPMethod(String eapMethod) throws Exception { + findOrScrollToObject(ADD_NETWORK_MENU_SCROLLABLE_BY_SELECTOR, + By.res(SETTINGS_PACKAGE, ADD_NETWORK_MENU_EAP_METHOD_RES_ID).clazz(SPINNER_CLASS)) + .click(); + Thread.sleep(SLEEP_TIME); + findOrScrollToObject(SPINNER_OPTIONS_SCROLLABLE_BY_SELECTOR, By.text(eapMethod)).click(); + } + + private void selectUserCertificateOption(String userCertificateOption) throws Exception { + findOrScrollToObject(ADD_NETWORK_MENU_SCROLLABLE_BY_SELECTOR, + By.res(SETTINGS_PACKAGE, ADD_NETWORK_MENU_USERCERT_RES_ID).clazz(SPINNER_CLASS)) + .click(); + mDevice.wait(Until.findObject(By.text(userCertificateOption)), TIMEOUT).click(); + } + + private void selectCaCertificateOption(String caCertificateOption) throws Exception { + findOrScrollToObject(ADD_NETWORK_MENU_SCROLLABLE_BY_SELECTOR, + By.res(SETTINGS_PACKAGE, ADD_NETWORK_MENU_CACERT_RES_ID).clazz(SPINNER_CLASS)) + .click(); + mDevice.wait(Until.findObject(By.text(caCertificateOption)), TIMEOUT).click(); + } + + private void enterSSID(String ssid) throws Exception { + // We might not need to scroll to the SSID option if not enough add network menu options + // are visible. + findOrScrollToObject(ADD_NETWORK_MENU_SCROLLABLE_BY_SELECTOR, + By.res(SETTINGS_PACKAGE, ADD_NETWORK_MENU_SSID_RES_ID).clazz(EDIT_TEXT_CLASS)) + .setText(ssid); + } + + private void enterPassword(String password) throws Exception { + findOrScrollToObject(ADD_NETWORK_MENU_SCROLLABLE_BY_SELECTOR, + By.res(SETTINGS_PACKAGE, ADD_NETWORK_MENU_PASSWORD_RES_ID).clazz(EDIT_TEXT_CLASS)) + .setText(password); + } + + private void enterDomain(String domain) throws Exception { + findOrScrollToObject(ADD_NETWORK_MENU_SCROLLABLE_BY_SELECTOR, + By.res(SETTINGS_PACKAGE, ADD_NETWORK_MENU_DOMAIN_RES_ID)).setText(domain); + } + + // Use this if the UI object might or might not need to be scrolled to. + private UiObject2 findOrScrollToObject(BySelector scrollableSelector, BySelector objectSelector) + throws Exception { + UiObject2 object = mDevice.wait(Until.findObject(objectSelector), TIMEOUT); + if (object == null) { + object = scrollToObject(scrollableSelector, objectSelector); + } + return object; + } + + private UiObject2 scrollToObject(BySelector scrollableSelector, BySelector objectSelector) + throws Exception { + UiObject2 scrollable = mDevice.wait(Until.findObject(scrollableSelector), TIMEOUT); + if (scrollable == null) { + fail("Could not find scrollable UI object identified by " + scrollableSelector); + } + UiObject2 found = null; + // Scroll all the way up first, then all the way down. + while (true) { + // Optimization: terminate if we find the object while scrolling up to reset, so + // we save the time spent scrolling down again. + boolean canScrollAgain = scrollable.scroll(Direction.UP, SCROLL_UP_PERCENT, + SCROLL_SPEED); + found = mDevice.findObject(objectSelector); + if (found != null) return found; + if (!canScrollAgain) break; + } + for (int attempts = 0; found == null && attempts < MAX_SCROLL_ATTEMPTS; ++attempts) { + // Return value of UiObject2.scroll() is not reliable, so do not use it in loop + // condition, in case it causes this loop to terminate prematurely. + scrollable.scroll(Direction.DOWN, SCROLL_DOWN_PERCENT, SCROLL_SPEED); + found = mDevice.findObject(objectSelector); + } + if (found == null) { + fail("Could not scroll to UI object identified by " + objectSelector); + } + return found; + } +} diff --git a/tests/uitests/src/com/android/settings/ui/WirelessNetworkSettingsTests.java b/tests/uitests/src/com/android/settings/ui/WirelessNetworkSettingsTests.java index 1e3b978c804..64fa5fd734e 100644 --- a/tests/uitests/src/com/android/settings/ui/WirelessNetworkSettingsTests.java +++ b/tests/uitests/src/com/android/settings/ui/WirelessNetworkSettingsTests.java @@ -16,762 +16,109 @@ package com.android.settings.ui; +import static com.android.settings.ui.testutils.SettingsTestUtils.SETTINGS_PACKAGE; +import static com.google.common.truth.Truth.assertThat; + import android.content.Context; -import android.content.Intent; import android.net.wifi.WifiManager; import android.os.RemoteException; import android.platform.test.annotations.Presubmit; import android.provider.Settings; +import android.support.test.InstrumentationRegistry; +import android.support.test.runner.AndroidJUnit4; +import android.support.test.uiautomator.By; +import android.support.test.uiautomator.UiDevice; +import android.support.test.uiautomator.Until; import android.system.helpers.CommandsHelper; import android.system.helpers.SettingsHelper; -import android.support.test.uiautomator.By; -import android.support.test.uiautomator.BySelector; -import android.support.test.uiautomator.Direction; -import android.support.test.uiautomator.StaleObjectException; -import android.support.test.uiautomator.UiDevice; -import android.support.test.uiautomator.UiObject2; -import android.support.test.uiautomator.Until; -import android.test.InstrumentationTestCase; import android.test.suitebuilder.annotation.MediumTest; -import android.test.suitebuilder.annotation.Suppress; import android.util.Log; -import junit.framework.AssertionFailedError; -public class WirelessNetworkSettingsTests extends InstrumentationTestCase { +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +/** + * Core tests for Wifi Settings. + */ +@RunWith(AndroidJUnit4.class) +@MediumTest +public class WirelessNetworkSettingsTests { // These back button presses are performed in tearDown() to exit Wifi // Settings sub-menus that a test might finish in. This number should be // high enough to account for the deepest sub-menu a test might enter. private static final int NUM_BACK_BUTTON_PRESSES = 5; - private static final int TIMEOUT = 2000; + private static final int TIMEOUT = 20000; private static final int SLEEP_TIME = 500; private static final String AIRPLANE_MODE_BROADCAST = "am broadcast -a android.intent.action.AIRPLANE_MODE"; - private static final String TAG="WirelessNetworkSettingsTests"; + private static final String TAG = "WirelessNetworkTests"; - // Note: The values of these variables might affect flakiness in tests that involve - // scrolling. Adjust where necessary. - private static final float SCROLL_UP_PERCENT = 10.0f; - private static final float SCROLL_DOWN_PERCENT = 0.5f; - private static final int MAX_SCROLL_ATTEMPTS = 10; - private static final int MAX_ADD_NETWORK_BUTTON_ATTEMPTS = 3; - private static final int SCROLL_SPEED = 2000; - - private static final String TEST_SSID = "testSsid"; - private static final String TEST_PW_GE_8_CHAR = "testPasswordGreaterThan8Char"; - private static final String TEST_PW_LT_8_CHAR = "lt8Char"; - private static final String TEST_DOMAIN = "testDomain.com"; - - private static final String SETTINGS_PACKAGE = "com.android.settings"; - - private static final String CHECKBOX_CLASS = "android.widget.CheckBox"; - private static final String SPINNER_CLASS = "android.widget.Spinner"; - private static final String EDIT_TEXT_CLASS = "android.widget.EditText"; - private static final String SCROLLVIEW_CLASS = "android.widget.ScrollView"; - private static final String LISTVIEW_CLASS = "android.widget.ListView"; - - private static final String ADD_NETWORK_MENU_CANCEL_BUTTON_TEXT = "CANCEL"; - private static final String ADD_NETWORK_MENU_SAVE_BUTTON_TEXT = "SAVE"; - private static final String ADD_NETWORK_PREFERENCE_TEXT = "Add network"; - private static final String CONFIGURE_WIFI_PREFERENCE_TEXT = "Wi‑Fi preferences"; - private static final String CONFIGURE_WIFI_ADVANCED_PREFERENCE_TEXT = "Advanced"; - private static final String CACERT_MENU_PLEASE_SELECT_TEXT = "Please select"; - private static final String CACERT_MENU_USE_SYSTEM_CERTS_TEXT = "Use system certificates"; - private static final String CACERT_MENU_DO_NOT_VALIDATE_TEXT = "Do not validate"; - private static final String USERCERT_MENU_PLEASE_SELECT_TEXT = "Please select"; - private static final String USERCERT_MENU_DO_NOT_PROVIDE_TEXT = "Do not provide"; - private static final String SECURITY_OPTION_NONE_TEXT = "None"; - private static final String SECURITY_OPTION_WEP_TEXT = "WEP"; - private static final String SECURITY_OPTION_PSK_TEXT = "WPA/WPA2 PSK"; - private static final String SECURITY_OPTION_EAP_TEXT = "802.1x EAP"; - private static final String EAP_METHOD_PEAP_TEXT = "PEAP"; - private static final String EAP_METHOD_TLS_TEXT = "TLS"; - private static final String EAP_METHOD_TTLS_TEXT = "TTLS"; - private static final String EAP_METHOD_PWD_TEXT = "PWD"; - private static final String EAP_METHOD_SIM_TEXT = "SIM"; - private static final String EAP_METHOD_AKA_TEXT = "AKA"; - private static final String EAP_METHOD_AKA_PRIME_TEXT = "AKA'"; - private static final String PHASE2_MENU_NONE_TEXT = "None"; - private static final String PHASE2_MENU_MSCHAPV2_TEXT = "MSCHAPV2"; - private static final String PHASE2_MENU_GTC_TEXT = "GTC"; - - private static final String ADD_NETWORK_MENU_ADV_TOGGLE_RES_ID = "wifi_advanced_togglebox"; - private static final String ADD_NETWORK_MENU_IP_SETTINGS_RES_ID = "ip_settings"; - private static final String ADD_NETWORK_MENU_PROXY_SETTINGS_RES_ID = "proxy_settings"; - private static final String ADD_NETWORK_MENU_SECURITY_OPTION_RES_ID = "security"; - private static final String ADD_NETWORK_MENU_EAP_METHOD_RES_ID = "method"; - private static final String ADD_NETWORK_MENU_SSID_RES_ID = "ssid"; - private static final String ADD_NETWORK_MENU_PHASE2_RES_ID = "phase2"; - private static final String ADD_NETWORK_MENU_CACERT_RES_ID = "ca_cert"; - private static final String ADD_NETWORK_MENU_USERCERT_RES_ID = "user_cert"; - private static final String ADD_NETWORK_MENU_NO_DOMAIN_WARNING_RES_ID = "no_domain_warning"; - private static final String ADD_NETWORK_MENU_NO_CACERT_WARNING_RES_ID = "no_ca_cert_warning"; - private static final String ADD_NETWORK_MENU_DOMAIN_LAYOUT_RES_ID = "l_domain"; - private static final String ADD_NETWORK_MENU_DOMAIN_RES_ID = "domain"; - private static final String ADD_NETWORK_MENU_IDENTITY_LAYOUT_RES_ID = "l_identity"; - private static final String ADD_NETWORK_MENU_ANONYMOUS_LAYOUT_RES_ID = "l_anonymous"; - private static final String ADD_NETWORK_MENU_PASSWORD_LAYOUT_RES_ID = "password_layout"; - private static final String ADD_NETWORK_MENU_SHOW_PASSWORD_LAYOUT_RES_ID = - "show_password_layout"; - private static final String ADD_NETWORK_MENU_PASSWORD_RES_ID = "password"; - - private static final BySelector ADD_NETWORK_MENU_SCROLLABLE_BY_SELECTOR = - By.scrollable(true).clazz(SCROLLVIEW_CLASS); - private static final BySelector SPINNER_OPTIONS_SCROLLABLE_BY_SELECTOR = - By.scrollable(true).clazz(LISTVIEW_CLASS); private UiDevice mDevice; private CommandsHelper mCommandsHelper; - @Override + @Before public void setUp() throws Exception { - super.setUp(); - mDevice = UiDevice.getInstance(getInstrumentation()); + + mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()); try { mDevice.setOrientationNatural(); } catch (RemoteException e) { throw new RuntimeException("failed to freeze device orientation", e); } // Ensure airplane mode is OFF so that wifi can be enabled using WiFiManager. - Settings.Global.putString(getInstrumentation().getContext().getContentResolver(), + Settings.Global.putString(InstrumentationRegistry.getTargetContext().getContentResolver(), Settings.Global.AIRPLANE_MODE_ON, "0"); + Log.d(TAG, "sending airplane mode broadcast to device"); - mCommandsHelper = CommandsHelper.getInstance(); + mCommandsHelper = CommandsHelper.getInstance(InstrumentationRegistry.getInstrumentation()); mCommandsHelper.executeShellCommand(AIRPLANE_MODE_BROADCAST); } - @Override - protected void tearDown() throws Exception { + @After + public void tearDown() { // Exit all settings sub-menus. for (int i = 0; i < NUM_BACK_BUTTON_PRESSES; ++i) { mDevice.pressBack(); } mDevice.pressHome(); - super.tearDown(); } @Presubmit - @MediumTest + @Test public void testWiFiEnabled() throws Exception { verifyWiFiOnOrOff(true); } @Presubmit - @MediumTest + @Test public void testWiFiDisabled() throws Exception { verifyWiFiOnOrOff(false); } - @MediumTest - public void testWifiMenuLoadConfigure() throws Exception { - loadWiFiConfigureMenu(); - Thread.sleep(SLEEP_TIME); - UiObject2 configureWiFiHeading = mDevice.wait(Until.findObject - (By.text(CONFIGURE_WIFI_PREFERENCE_TEXT)), TIMEOUT); - assertNotNull("Configure WiFi menu has not loaded correctly", configureWiFiHeading); - } - - @MediumTest - public void testNetworkNotificationsOn() throws Exception { - verifyNetworkNotificationsOnOrOff(true); - } - - @MediumTest - public void testNetworkNotificationsOff() throws Exception { - verifyNetworkNotificationsOnOrOff(false); - } - - @MediumTest - public void testAddNetworkMenu_Default() throws Exception { - loadAddNetworkMenu(); - - // Submit button should be disabled by default, while cancel button should be enabled. - assertFalse(mDevice.wait(Until.findObject( - By.text(ADD_NETWORK_MENU_SAVE_BUTTON_TEXT)), TIMEOUT).isEnabled()); - assertTrue(mDevice.wait(Until.findObject( - By.text(ADD_NETWORK_MENU_CANCEL_BUTTON_TEXT)), TIMEOUT).isEnabled()); - - // Check that the SSID field is defaults to the hint. - assertEquals("Enter the SSID", mDevice.wait(Until.findObject(By - .res(SETTINGS_PACKAGE, ADD_NETWORK_MENU_SSID_RES_ID) - .clazz(EDIT_TEXT_CLASS)), TIMEOUT*2) - .getText()); - - // Check Security defaults to None. - assertEquals("None", mDevice.wait(Until.findObject(By - .res(SETTINGS_PACKAGE, ADD_NETWORK_MENU_SECURITY_OPTION_RES_ID) - .clazz(SPINNER_CLASS)), TIMEOUT) - .getChildren().get(0).getText()); - - // Check advanced options are collapsed by default. - assertFalse(mDevice.wait(Until.findObject(By - .res(SETTINGS_PACKAGE, ADD_NETWORK_MENU_ADV_TOGGLE_RES_ID) - .clazz(CHECKBOX_CLASS)), TIMEOUT).isChecked()); - - } - - @Suppress - @MediumTest - public void testAddNetworkMenu_Proxy() throws Exception { - loadAddNetworkMenu(); - - // Toggle advanced options. - mDevice.wait(Until.findObject(By - .res(SETTINGS_PACKAGE, ADD_NETWORK_MENU_ADV_TOGGLE_RES_ID) - .clazz(CHECKBOX_CLASS)), TIMEOUT).click(); - - // Verify Proxy defaults to None. - BySelector proxySettingsBySelector = - By.res(SETTINGS_PACKAGE, ADD_NETWORK_MENU_PROXY_SETTINGS_RES_ID) - .clazz(SPINNER_CLASS); - findOrScrollToObject(ADD_NETWORK_MENU_SCROLLABLE_BY_SELECTOR, proxySettingsBySelector); - assertEquals("None", mDevice.wait(Until.findObject(proxySettingsBySelector), TIMEOUT) - .getChildren().get(0).getText()); - - // Verify that Proxy Manual fields appear. - findOrScrollToObject(ADD_NETWORK_MENU_SCROLLABLE_BY_SELECTOR, proxySettingsBySelector); - mDevice.wait(Until.findObject(proxySettingsBySelector), TIMEOUT).click(); - mDevice.wait(Until.findObject(By.text("Manual")), TIMEOUT).click(); - findOrScrollToObject(ADD_NETWORK_MENU_SCROLLABLE_BY_SELECTOR, - By.res(SETTINGS_PACKAGE, "proxy_warning_limited_support")); - findOrScrollToObject(ADD_NETWORK_MENU_SCROLLABLE_BY_SELECTOR, - By.res(SETTINGS_PACKAGE, "proxy_hostname")); - findOrScrollToObject(ADD_NETWORK_MENU_SCROLLABLE_BY_SELECTOR, - By.res(SETTINGS_PACKAGE, "proxy_exclusionlist")); - - // Verify that Proxy Auto-Config options appear. - findOrScrollToObject(ADD_NETWORK_MENU_SCROLLABLE_BY_SELECTOR, proxySettingsBySelector); - mDevice.wait(Until.findObject(proxySettingsBySelector), TIMEOUT).click(); - mDevice.wait(Until.findObject(By.text("Proxy Auto-Config")), TIMEOUT).click(); - findOrScrollToObject(ADD_NETWORK_MENU_SCROLLABLE_BY_SELECTOR, - By.res(SETTINGS_PACKAGE, "proxy_pac")); - } - - @Suppress - @MediumTest - public void testAddNetworkMenu_IpSettings() throws Exception { - loadAddNetworkMenu(); - - // Toggle advanced options. - mDevice.wait(Until.findObject(By - .res(SETTINGS_PACKAGE, ADD_NETWORK_MENU_ADV_TOGGLE_RES_ID) - .clazz(CHECKBOX_CLASS)), TIMEOUT).click(); - - // Verify IP settings defaults to DHCP. - BySelector ipSettingsBySelector = - By.res(SETTINGS_PACKAGE, ADD_NETWORK_MENU_IP_SETTINGS_RES_ID).clazz(SPINNER_CLASS); - findOrScrollToObject(ADD_NETWORK_MENU_SCROLLABLE_BY_SELECTOR, ipSettingsBySelector); - assertEquals("DHCP", mDevice.wait(Until.findObject(ipSettingsBySelector), TIMEOUT) - .getChildren().get(0).getText()); - - // Verify that Static IP settings options appear. - findOrScrollToObject(ADD_NETWORK_MENU_SCROLLABLE_BY_SELECTOR, ipSettingsBySelector).click(); - mDevice.wait(Until.findObject(By.text("Static")), TIMEOUT).click(); - findOrScrollToObject(ADD_NETWORK_MENU_SCROLLABLE_BY_SELECTOR, - By.res(SETTINGS_PACKAGE, "ipaddress")); - findOrScrollToObject(ADD_NETWORK_MENU_SCROLLABLE_BY_SELECTOR, - By.res(SETTINGS_PACKAGE, "gateway")); - findOrScrollToObject(ADD_NETWORK_MENU_SCROLLABLE_BY_SELECTOR, - By.res(SETTINGS_PACKAGE, "network_prefix_length")); - findOrScrollToObject(ADD_NETWORK_MENU_SCROLLABLE_BY_SELECTOR, - By.res(SETTINGS_PACKAGE, "dns1")); - findOrScrollToObject(ADD_NETWORK_MENU_SCROLLABLE_BY_SELECTOR, - By.res(SETTINGS_PACKAGE, "dns2")); - } - - @Suppress - @MediumTest - public void testPhase2Settings() throws Exception { - loadAddNetworkMenu(); - selectSecurityOption(SECURITY_OPTION_EAP_TEXT); - - BySelector phase2SettingsBySelector = - By.res(SETTINGS_PACKAGE, ADD_NETWORK_MENU_PHASE2_RES_ID).clazz(SPINNER_CLASS); - findOrScrollToObject(ADD_NETWORK_MENU_SCROLLABLE_BY_SELECTOR, phase2SettingsBySelector); - assertEquals(PHASE2_MENU_NONE_TEXT, mDevice.wait(Until - .findObject(phase2SettingsBySelector), TIMEOUT).getChildren().get(0).getText()); - mDevice.wait(Until.findObject(phase2SettingsBySelector), TIMEOUT).click(); - Thread.sleep(SLEEP_TIME); - - // Verify Phase 2 authentication spinner options. - assertNotNull(mDevice.wait(Until.findObject(By.text(PHASE2_MENU_NONE_TEXT)), TIMEOUT)); - assertNotNull(mDevice.wait(Until.findObject(By.text(PHASE2_MENU_MSCHAPV2_TEXT)), TIMEOUT)); - assertNotNull(mDevice.wait(Until.findObject(By.text(PHASE2_MENU_GTC_TEXT)), TIMEOUT)); - } - - @Suppress - @MediumTest - public void testCaCertSettings() throws Exception { - loadAddNetworkMenu(); - selectSecurityOption(SECURITY_OPTION_EAP_TEXT); - - BySelector caCertSettingsBySelector = - By.res(SETTINGS_PACKAGE, ADD_NETWORK_MENU_CACERT_RES_ID).clazz(SPINNER_CLASS); - findOrScrollToObject(ADD_NETWORK_MENU_SCROLLABLE_BY_SELECTOR, caCertSettingsBySelector); - assertEquals(CACERT_MENU_PLEASE_SELECT_TEXT, mDevice.wait(Until - .findObject(caCertSettingsBySelector), TIMEOUT).getChildren().get(0).getText()); - mDevice.wait(Until.findObject(caCertSettingsBySelector), TIMEOUT).click(); - Thread.sleep(SLEEP_TIME); - - // Verify CA certificate spinner options. - assertNotNull(mDevice.wait(Until.findObject( - By.text(CACERT_MENU_PLEASE_SELECT_TEXT)), TIMEOUT)); - assertNotNull(mDevice.wait(Until.findObject( - By.text(CACERT_MENU_USE_SYSTEM_CERTS_TEXT)), TIMEOUT)); - assertNotNull(mDevice.wait(Until.findObject( - By.text(CACERT_MENU_DO_NOT_VALIDATE_TEXT)), TIMEOUT)); - - // Verify that a domain field and warning appear when the user selects the - // "Use system certificates" option. - mDevice.wait(Until.findObject(By.text(CACERT_MENU_USE_SYSTEM_CERTS_TEXT)), TIMEOUT).click(); - findOrScrollToObject(ADD_NETWORK_MENU_SCROLLABLE_BY_SELECTOR, - By.res(SETTINGS_PACKAGE, ADD_NETWORK_MENU_DOMAIN_LAYOUT_RES_ID)); - findOrScrollToObject(ADD_NETWORK_MENU_SCROLLABLE_BY_SELECTOR, - By.res(SETTINGS_PACKAGE, ADD_NETWORK_MENU_NO_DOMAIN_WARNING_RES_ID)); - - // Verify that a warning appears when the user chooses the "Do Not Validate" option. - mDevice.wait(Until.findObject(caCertSettingsBySelector), TIMEOUT).click(); - mDevice.wait(Until.findObject(By.text(CACERT_MENU_DO_NOT_VALIDATE_TEXT)), TIMEOUT).click(); - findOrScrollToObject(ADD_NETWORK_MENU_SCROLLABLE_BY_SELECTOR, - By.res(SETTINGS_PACKAGE, ADD_NETWORK_MENU_NO_CACERT_WARNING_RES_ID)); - } - - @Suppress - @MediumTest - public void testAddNetwork_NoSecurity() throws Exception { - loadAddNetworkMenu(); - selectSecurityOption(SECURITY_OPTION_NONE_TEXT); - - // Entering an SSID is enough to enable the submit button. // TODO THIS GUY - enterSSID(TEST_SSID); - assertTrue(mDevice.wait(Until - .findObject(By.text(ADD_NETWORK_MENU_SAVE_BUTTON_TEXT)), TIMEOUT).isEnabled()); - } - - @Suppress - @MediumTest - public void testAddNetwork_WEP() throws Exception { - loadAddNetworkMenu(); - selectSecurityOption(SECURITY_OPTION_WEP_TEXT); - assertFalse(mDevice.wait(Until.findObject( - By.text(ADD_NETWORK_MENU_SAVE_BUTTON_TEXT)), TIMEOUT).isEnabled()); - - // Verify that WEP fields appear. - findOrScrollToObject(ADD_NETWORK_MENU_SCROLLABLE_BY_SELECTOR, - By.res(SETTINGS_PACKAGE, ADD_NETWORK_MENU_PASSWORD_LAYOUT_RES_ID)); - findOrScrollToObject(ADD_NETWORK_MENU_SCROLLABLE_BY_SELECTOR, - By.res(SETTINGS_PACKAGE, ADD_NETWORK_MENU_SHOW_PASSWORD_LAYOUT_RES_ID)); - - // Entering an SSID alone does not enable the submit button. - enterSSID(TEST_SSID); - assertFalse(mDevice.wait(Until.findObject( - By.text(ADD_NETWORK_MENU_SAVE_BUTTON_TEXT)), TIMEOUT).isEnabled()); - - // Submit button is only enabled after a password is entered. - enterPassword(TEST_PW_GE_8_CHAR); - assertTrue(mDevice.wait(Until - .findObject(By.text(ADD_NETWORK_MENU_SAVE_BUTTON_TEXT)), TIMEOUT).isEnabled()); - } - - @Suppress - @MediumTest - public void testAddNetwork_PSK() throws Exception { - loadAddNetworkMenu(); - selectSecurityOption(SECURITY_OPTION_PSK_TEXT); - assertFalse(mDevice.wait(Until.findObject( - By.text(ADD_NETWORK_MENU_SAVE_BUTTON_TEXT)), TIMEOUT).isEnabled()); - - // Verify that PSK fields appear. - findOrScrollToObject(ADD_NETWORK_MENU_SCROLLABLE_BY_SELECTOR, - By.res(SETTINGS_PACKAGE, ADD_NETWORK_MENU_PASSWORD_LAYOUT_RES_ID)); - findOrScrollToObject(ADD_NETWORK_MENU_SCROLLABLE_BY_SELECTOR, - By.res(SETTINGS_PACKAGE, ADD_NETWORK_MENU_SHOW_PASSWORD_LAYOUT_RES_ID)); - - // Entering an SSID alone does not enable the submit button. - enterSSID(TEST_SSID); - assertFalse(mDevice.wait(Until.findObject( - By.text(ADD_NETWORK_MENU_SAVE_BUTTON_TEXT)), TIMEOUT).isEnabled()); - - // Entering an password that is too short does not enable submit button. - enterPassword(TEST_PW_LT_8_CHAR); - assertFalse(mDevice.wait(Until.findObject( - By.text(ADD_NETWORK_MENU_SAVE_BUTTON_TEXT)), TIMEOUT).isEnabled()); - - // Submit button is only enabled after a password of valid length is entered. - enterPassword(TEST_PW_GE_8_CHAR); - assertTrue(mDevice.wait(Until.findObject( - By.text(ADD_NETWORK_MENU_SAVE_BUTTON_TEXT)), TIMEOUT).isEnabled()); - } - - @Suppress - @MediumTest - public void testAddNetwork_EAP_PEAP() throws Exception { - loadAddNetworkMenu(); - selectSecurityOption(SECURITY_OPTION_EAP_TEXT); - assertFalse(mDevice.wait(Until.findObject( - By.text(ADD_NETWORK_MENU_SAVE_BUTTON_TEXT)), TIMEOUT).isEnabled()); - - selectEAPMethod(EAP_METHOD_PEAP_TEXT); - - // Verify that EAP-PEAP fields appear. - findOrScrollToObject(ADD_NETWORK_MENU_SCROLLABLE_BY_SELECTOR, - By.res(SETTINGS_PACKAGE, ADD_NETWORK_MENU_PHASE2_RES_ID)); - findOrScrollToObject(ADD_NETWORK_MENU_SCROLLABLE_BY_SELECTOR, - By.res(SETTINGS_PACKAGE, ADD_NETWORK_MENU_CACERT_RES_ID)); - findOrScrollToObject(ADD_NETWORK_MENU_SCROLLABLE_BY_SELECTOR, - By.res(SETTINGS_PACKAGE, ADD_NETWORK_MENU_IDENTITY_LAYOUT_RES_ID)); - findOrScrollToObject(ADD_NETWORK_MENU_SCROLLABLE_BY_SELECTOR, - By.res(SETTINGS_PACKAGE, ADD_NETWORK_MENU_ANONYMOUS_LAYOUT_RES_ID)); - findOrScrollToObject(ADD_NETWORK_MENU_SCROLLABLE_BY_SELECTOR, - By.res(SETTINGS_PACKAGE, ADD_NETWORK_MENU_PASSWORD_LAYOUT_RES_ID)); - findOrScrollToObject(ADD_NETWORK_MENU_SCROLLABLE_BY_SELECTOR, - By.res(SETTINGS_PACKAGE, ADD_NETWORK_MENU_SHOW_PASSWORD_LAYOUT_RES_ID)); - - // Entering an SSID alone does not enable the submit button. - enterSSID(TEST_SSID); - assertFalse(mDevice.wait(Until.findObject( - By.text(ADD_NETWORK_MENU_SAVE_BUTTON_TEXT)), TIMEOUT).isEnabled()); - - verifyCaCertificateSubmitConditions(); - } - - @Suppress - @MediumTest - public void testAddNetwork_EAP_TLS() throws Exception { - loadAddNetworkMenu(); - selectSecurityOption(SECURITY_OPTION_EAP_TEXT); - assertFalse(mDevice.wait(Until.findObject( - By.text(ADD_NETWORK_MENU_SAVE_BUTTON_TEXT)), TIMEOUT).isEnabled()); - - selectEAPMethod(EAP_METHOD_TLS_TEXT); - - // Verify that EAP-TLS fields appear. - findOrScrollToObject(ADD_NETWORK_MENU_SCROLLABLE_BY_SELECTOR, - By.res(SETTINGS_PACKAGE, ADD_NETWORK_MENU_CACERT_RES_ID)); - findOrScrollToObject(ADD_NETWORK_MENU_SCROLLABLE_BY_SELECTOR, - By.res(SETTINGS_PACKAGE, ADD_NETWORK_MENU_USERCERT_RES_ID)); - findOrScrollToObject(ADD_NETWORK_MENU_SCROLLABLE_BY_SELECTOR, - By.res(SETTINGS_PACKAGE, ADD_NETWORK_MENU_IDENTITY_LAYOUT_RES_ID)); - - // Entering an SSID alone does not enable the submit button. - enterSSID(TEST_SSID); - assertFalse(mDevice.wait(Until.findObject( - By.text(ADD_NETWORK_MENU_SAVE_BUTTON_TEXT)), TIMEOUT).isEnabled()); - - // Selecting the User certificate "Do not provide" option alone does not enable the submit - // button. - selectUserCertificateOption(USERCERT_MENU_DO_NOT_PROVIDE_TEXT); - assertFalse(mDevice.wait(Until.findObject( - By.text(ADD_NETWORK_MENU_SAVE_BUTTON_TEXT)), TIMEOUT).isEnabled()); - - verifyCaCertificateSubmitConditions(); - } - - @Suppress - @MediumTest - public void testAddNetwork_EAP_TTLS() throws Exception { - loadAddNetworkMenu(); - selectSecurityOption(SECURITY_OPTION_EAP_TEXT); - assertFalse(mDevice.wait(Until.findObject( - By.text(ADD_NETWORK_MENU_SAVE_BUTTON_TEXT)), TIMEOUT).isEnabled()); - - selectEAPMethod(EAP_METHOD_TTLS_TEXT); - - // Verify that EAP-TLS fields appear. - findOrScrollToObject(ADD_NETWORK_MENU_SCROLLABLE_BY_SELECTOR, - By.res(SETTINGS_PACKAGE, ADD_NETWORK_MENU_PHASE2_RES_ID)); - findOrScrollToObject(ADD_NETWORK_MENU_SCROLLABLE_BY_SELECTOR, - By.res(SETTINGS_PACKAGE, ADD_NETWORK_MENU_CACERT_RES_ID)); - findOrScrollToObject(ADD_NETWORK_MENU_SCROLLABLE_BY_SELECTOR, - By.res(SETTINGS_PACKAGE, ADD_NETWORK_MENU_IDENTITY_LAYOUT_RES_ID)); - findOrScrollToObject(ADD_NETWORK_MENU_SCROLLABLE_BY_SELECTOR, - By.res(SETTINGS_PACKAGE, ADD_NETWORK_MENU_ANONYMOUS_LAYOUT_RES_ID)); - findOrScrollToObject(ADD_NETWORK_MENU_SCROLLABLE_BY_SELECTOR, - By.res(SETTINGS_PACKAGE, ADD_NETWORK_MENU_PASSWORD_LAYOUT_RES_ID)); - - // Entering an SSID alone does not enable the submit button. - enterSSID(TEST_SSID); - assertFalse(mDevice.wait(Until.findObject( - By.text(ADD_NETWORK_MENU_SAVE_BUTTON_TEXT)), TIMEOUT).isEnabled()); - - verifyCaCertificateSubmitConditions(); - } - - @Suppress - @MediumTest - public void testAddNetwork_EAP_PWD() throws Exception { - loadAddNetworkMenu(); - selectSecurityOption(SECURITY_OPTION_EAP_TEXT); - assertFalse(mDevice.wait(Until.findObject( - By.text(ADD_NETWORK_MENU_SAVE_BUTTON_TEXT)), TIMEOUT).isEnabled()); - - selectEAPMethod(EAP_METHOD_PWD_TEXT); - - // Verify that EAP-TLS fields appear. - findOrScrollToObject(ADD_NETWORK_MENU_SCROLLABLE_BY_SELECTOR, - By.res(SETTINGS_PACKAGE, ADD_NETWORK_MENU_IDENTITY_LAYOUT_RES_ID)); - findOrScrollToObject(ADD_NETWORK_MENU_SCROLLABLE_BY_SELECTOR, - By.res(SETTINGS_PACKAGE, ADD_NETWORK_MENU_PASSWORD_LAYOUT_RES_ID)); - - // Entering an SSID alone enables the submit button. - enterSSID(TEST_SSID); - assertTrue(mDevice.wait(Until.findObject( - By.text(ADD_NETWORK_MENU_SAVE_BUTTON_TEXT)), TIMEOUT).isEnabled()); - } - - @Suppress - @MediumTest - public void testAddNetwork_EAP_SIM() throws Exception { - loadAddNetworkMenu(); - selectSecurityOption(SECURITY_OPTION_EAP_TEXT); - assertFalse(mDevice.wait(Until.findObject( - By.text(ADD_NETWORK_MENU_SAVE_BUTTON_TEXT)), TIMEOUT).isEnabled()); - - selectEAPMethod(EAP_METHOD_SIM_TEXT); - - // Entering an SSID alone enables the submit button. - enterSSID(TEST_SSID); - assertTrue(mDevice.wait(Until.findObject( - By.text(ADD_NETWORK_MENU_SAVE_BUTTON_TEXT)), TIMEOUT).isEnabled()); - } - - @Suppress - @MediumTest - public void testAddNetwork_EAP_AKA() throws Exception { - loadAddNetworkMenu(); - selectSecurityOption(SECURITY_OPTION_EAP_TEXT); - assertFalse(mDevice.wait(Until.findObject( - By.text(ADD_NETWORK_MENU_SAVE_BUTTON_TEXT)), TIMEOUT).isEnabled()); - - selectEAPMethod(EAP_METHOD_AKA_TEXT); - - // Entering an SSID alone enables the submit button. - enterSSID(TEST_SSID); - assertTrue(mDevice.wait(Until.findObject( - By.text(ADD_NETWORK_MENU_SAVE_BUTTON_TEXT)), TIMEOUT).isEnabled()); - } - - @Suppress - @MediumTest - public void testAddNetwork_EAP_AKA_PRIME() throws Exception { - loadAddNetworkMenu(); - selectSecurityOption(SECURITY_OPTION_EAP_TEXT); - assertFalse(mDevice.wait(Until.findObject( - By.text(ADD_NETWORK_MENU_SAVE_BUTTON_TEXT)), TIMEOUT).isEnabled()); - - selectEAPMethod(EAP_METHOD_AKA_PRIME_TEXT); - - // Entering an SSID alone enables the submit button. - enterSSID(TEST_SSID); - assertTrue(mDevice.wait(Until.findObject( - By.text(ADD_NETWORK_MENU_SAVE_BUTTON_TEXT)), TIMEOUT).isEnabled()); - } - - private void verifyKeepWiFiOnDuringSleep(String settingToBeVerified, int settingValue) - throws Exception { - loadWiFiConfigureMenu(); - mDevice.wait(Until.findObject(By.text("Keep Wi‑Fi on during sleep")), TIMEOUT) - .click(); - mDevice.wait(Until.findObject(By.clazz("android.widget.CheckedTextView") - .text(settingToBeVerified)), TIMEOUT).click(); - Thread.sleep(SLEEP_TIME); - int keepWiFiOnSetting = - Settings.Global.getInt(getInstrumentation().getContext().getContentResolver(), - Settings.Global.WIFI_SLEEP_POLICY); - assertEquals(settingValue, keepWiFiOnSetting); - } - - private void verifyNetworkNotificationsOnOrOff(boolean verifyOn) - throws Exception { - // Enable network recommendations to enable the toggle switch for Network - // notifications - Settings.Global.putString(getInstrumentation().getContext().getContentResolver(), - Settings.Global.NETWORK_RECOMMENDATIONS_ENABLED, "1"); - if (verifyOn) { - Settings.Global.putString(getInstrumentation().getContext().getContentResolver(), - Settings.Global.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON, "0"); - } - else { - Settings.Global.putString(getInstrumentation().getContext().getContentResolver(), - Settings.Global.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON, "1"); - } - loadWiFiConfigureMenu(); - mDevice.wait(Until.findObject(By.text("Open network notification")), TIMEOUT) - .click(); - Thread.sleep(SLEEP_TIME); - String wifiNotificationValue = - Settings.Global.getString(getInstrumentation().getContext().getContentResolver(), - Settings.Global.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON); - if (verifyOn) { - assertEquals("1", wifiNotificationValue); - } - else { - assertEquals("0", wifiNotificationValue); - } - } - private void verifyWiFiOnOrOff(boolean verifyOn) throws Exception { - String switchText = "On"; - if (verifyOn) { - switchText = "Off"; - } - loadWiFiSettingsPage(!verifyOn); - mDevice.wait(Until - .findObject(By.res(SETTINGS_PACKAGE, "switch_bar").text(switchText)), TIMEOUT) - .click(); - Thread.sleep(SLEEP_TIME); - String wifiValue = - Settings.Global.getString(getInstrumentation().getContext().getContentResolver(), - Settings.Global.WIFI_ON); - if (verifyOn) { - // 1 is Enabled, 2 is Enabled while airplane mode is ON. - assertTrue(wifiValue.equals("1") || wifiValue.equals("2")); - } - else { - assertEquals("0", wifiValue); - } - } - - private void verifyCaCertificateSubmitConditions() throws Exception { - // Selecting the CA certificate "Do not validate" option enables the submit button. - selectCaCertificateOption(CACERT_MENU_DO_NOT_VALIDATE_TEXT); - assertTrue(mDevice.wait(Until.findObject( - By.text(ADD_NETWORK_MENU_SAVE_BUTTON_TEXT)), TIMEOUT).isEnabled()); - - // However, selecting the CA certificate "Use system certificates option" is not enough to - // enable the submit button. - selectCaCertificateOption(CACERT_MENU_USE_SYSTEM_CERTS_TEXT); - assertFalse(mDevice.wait(Until.findObject( - By.text(ADD_NETWORK_MENU_SAVE_BUTTON_TEXT)), TIMEOUT).isEnabled()); - - // Submit button is only enabled after a domain is entered as well. - enterDomain(TEST_DOMAIN); - assertTrue(mDevice.wait(Until.findObject( - By.text(ADD_NETWORK_MENU_SAVE_BUTTON_TEXT)), TIMEOUT).isEnabled()); + loadWiFiSettingsPage(!verifyOn); + mDevice.wait(Until.findObject(By.res(SETTINGS_PACKAGE, "switch_widget")), TIMEOUT) + .click(); + Thread.sleep(SLEEP_TIME); + final String wifiValue = Settings.Global.getString( + InstrumentationRegistry.getTargetContext().getContentResolver(), + Settings.Global.WIFI_ON); + if (verifyOn) { + // 1 is Enabled, 2 is Enabled while airplane mode is ON. + assertThat(wifiValue).isAnyOf("1", "2"); + } else { + assertThat(wifiValue).isEqualTo("0"); + } } private void loadWiFiSettingsPage(boolean wifiEnabled) throws Exception { - WifiManager wifiManager = (WifiManager)getInstrumentation().getContext() + WifiManager wifiManager = (WifiManager) InstrumentationRegistry.getTargetContext() .getSystemService(Context.WIFI_SERVICE); wifiManager.setWifiEnabled(wifiEnabled); - SettingsHelper.launchSettingsPage(getInstrumentation().getContext(), + SettingsHelper.launchSettingsPage(InstrumentationRegistry.getTargetContext(), Settings.ACTION_WIFI_SETTINGS); } - - private void loadWiFiConfigureMenu() throws Exception { - loadWiFiSettingsPage(false); - Thread.sleep(TIMEOUT); - mDevice.wait(Until.findObject(By.text(CONFIGURE_WIFI_PREFERENCE_TEXT)), TIMEOUT).click(); - mDevice.wait(Until.findObject( - By.text(CONFIGURE_WIFI_ADVANCED_PREFERENCE_TEXT)), TIMEOUT).click(); - } - - private void loadAddNetworkMenu() throws Exception { - loadWiFiSettingsPage(true); - for (int attempts = 0; attempts < MAX_ADD_NETWORK_BUTTON_ATTEMPTS; ++attempts) { - try { - findOrScrollToObject(By.scrollable(true), By.text(ADD_NETWORK_PREFERENCE_TEXT)) - .click(); - } catch (StaleObjectException e) { - // The network list might have been updated between when the Add network button was - // found, and when it UI automator attempted to click on it. Retry. - continue; - } - // If we get here, we successfully clicked on the Add network button, so we are done. - Thread.sleep(SLEEP_TIME*5); - return; - } - - fail("Failed to load Add Network Menu after " + MAX_ADD_NETWORK_BUTTON_ATTEMPTS - + " retries"); - } - - private void selectSecurityOption(String securityOption) throws Exception { - // We might not need to scroll to the security options if not enough add network menu - // options are visible. - findOrScrollToObject(ADD_NETWORK_MENU_SCROLLABLE_BY_SELECTOR, - By.res(SETTINGS_PACKAGE, ADD_NETWORK_MENU_SECURITY_OPTION_RES_ID) - .clazz(SPINNER_CLASS)).click(); - Thread.sleep(SLEEP_TIME); - mDevice.wait(Until.findObject(By.text(securityOption)), TIMEOUT).click(); - } - - private void selectEAPMethod(String eapMethod) throws Exception { - findOrScrollToObject(ADD_NETWORK_MENU_SCROLLABLE_BY_SELECTOR, - By.res(SETTINGS_PACKAGE, ADD_NETWORK_MENU_EAP_METHOD_RES_ID).clazz(SPINNER_CLASS)) - .click(); - Thread.sleep(SLEEP_TIME); - findOrScrollToObject(SPINNER_OPTIONS_SCROLLABLE_BY_SELECTOR, By.text(eapMethod)).click(); - } - - private void selectUserCertificateOption(String userCertificateOption) throws Exception { - findOrScrollToObject(ADD_NETWORK_MENU_SCROLLABLE_BY_SELECTOR, - By.res(SETTINGS_PACKAGE, ADD_NETWORK_MENU_USERCERT_RES_ID).clazz(SPINNER_CLASS)) - .click(); - mDevice.wait(Until.findObject(By.text(userCertificateOption)), TIMEOUT).click(); - } - - private void selectCaCertificateOption(String caCertificateOption) throws Exception { - findOrScrollToObject(ADD_NETWORK_MENU_SCROLLABLE_BY_SELECTOR, - By.res(SETTINGS_PACKAGE, ADD_NETWORK_MENU_CACERT_RES_ID).clazz(SPINNER_CLASS)) - .click(); - mDevice.wait(Until.findObject(By.text(caCertificateOption)), TIMEOUT).click(); - } - - private void enterSSID(String ssid) throws Exception { - // We might not need to scroll to the SSID option if not enough add network menu options - // are visible. - findOrScrollToObject(ADD_NETWORK_MENU_SCROLLABLE_BY_SELECTOR, - By.res(SETTINGS_PACKAGE, ADD_NETWORK_MENU_SSID_RES_ID).clazz(EDIT_TEXT_CLASS)) - .setText(ssid); - } - - private void enterPassword(String password) throws Exception { - findOrScrollToObject(ADD_NETWORK_MENU_SCROLLABLE_BY_SELECTOR, - By.res(SETTINGS_PACKAGE, ADD_NETWORK_MENU_PASSWORD_RES_ID).clazz(EDIT_TEXT_CLASS)) - .setText(password); - } - - private void enterDomain(String domain) throws Exception { - findOrScrollToObject(ADD_NETWORK_MENU_SCROLLABLE_BY_SELECTOR, - By.res(SETTINGS_PACKAGE, ADD_NETWORK_MENU_DOMAIN_RES_ID)).setText(domain); - } - - // Use this if the UI object might or might not need to be scrolled to. - private UiObject2 findOrScrollToObject(BySelector scrollableSelector, BySelector objectSelector) - throws Exception { - UiObject2 object = mDevice.wait(Until.findObject(objectSelector), TIMEOUT); - if (object == null) { - object = scrollToObject(scrollableSelector, objectSelector); - } - return object; - } - - private UiObject2 scrollToObject(BySelector scrollableSelector, BySelector objectSelector) - throws Exception { - UiObject2 scrollable = mDevice.wait(Until.findObject(scrollableSelector), TIMEOUT); - if (scrollable == null) { - fail("Could not find scrollable UI object identified by " + scrollableSelector); - } - UiObject2 found = null; - // Scroll all the way up first, then all the way down. - while (true) { - // Optimization: terminate if we find the object while scrolling up to reset, so - // we save the time spent scrolling down again. - boolean canScrollAgain = scrollable.scroll(Direction.UP, SCROLL_UP_PERCENT, - SCROLL_SPEED); - found = mDevice.findObject(objectSelector); - if (found != null) return found; - if (!canScrollAgain) break; - } - for (int attempts = 0; found == null && attempts < MAX_SCROLL_ATTEMPTS; ++attempts) { - // Return value of UiObject2.scroll() is not reliable, so do not use it in loop - // condition, in case it causes this loop to terminate prematurely. - scrollable.scroll(Direction.DOWN, SCROLL_DOWN_PERCENT, SCROLL_SPEED); - found = mDevice.findObject(objectSelector); - } - if (found == null) { - fail("Could not scroll to UI object identified by " + objectSelector); - } - return found; - } } From 409eab14de3767aeb0d80885cadef32ef257f233 Mon Sep 17 00:00:00 2001 From: Fan Zhang Date: Mon, 29 Jan 2018 11:23:52 -0800 Subject: [PATCH 06/11] Fix shortcut icon in launcher When building icon for shortcut, check if the icon is LayerDrawable. - If yes, only take the second layer (foreground). Also move the class to shortcut package Change-Id: I3513dbeb6509f11aa70ab3230d441e268ca9356d Fixes: 72553870 Test: atest --- AndroidManifest.xml | 2 +- .../android/settings/SettingsInitialize.java | 2 ++ .../LocaleDragAndDropAdapter.java | 2 +- .../{ => shortcut}/CreateShortcut.java | 18 ++++++++---- .../{ => shortcut}/CreateShortcutTest.java | 28 +++++++++---------- 5 files changed, 31 insertions(+), 21 deletions(-) rename src/com/android/settings/{ => shortcut}/CreateShortcut.java (92%) rename tests/unit/src/com/android/settings/{ => shortcut}/CreateShortcutTest.java (90%) diff --git a/AndroidManifest.xml b/AndroidManifest.xml index 2e511084b51..d637ac7da21 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -146,7 +146,7 @@ android:parentActivityName="Settings"> - diff --git a/src/com/android/settings/SettingsInitialize.java b/src/com/android/settings/SettingsInitialize.java index 6b15770a96e..9f2bdcc6fcf 100644 --- a/src/com/android/settings/SettingsInitialize.java +++ b/src/com/android/settings/SettingsInitialize.java @@ -34,6 +34,8 @@ import static android.content.pm.PackageManager.GET_META_DATA; import static android.content.pm.PackageManager.GET_RESOLVED_FILTER; import static android.content.pm.PackageManager.MATCH_DISABLED_COMPONENTS; +import com.android.settings.shortcut.CreateShortcut; + /** * Listens to {@link Intent.ACTION_PRE_BOOT_COMPLETED} and {@link Intent.ACTION_USER_INITIALIZED} * performs setup steps for a managed profile (disables the launcher icon of the Settings app, diff --git a/src/com/android/settings/localepicker/LocaleDragAndDropAdapter.java b/src/com/android/settings/localepicker/LocaleDragAndDropAdapter.java index 1d21c123c9e..0d8cbaf1166 100644 --- a/src/com/android/settings/localepicker/LocaleDragAndDropAdapter.java +++ b/src/com/android/settings/localepicker/LocaleDragAndDropAdapter.java @@ -34,7 +34,7 @@ import android.widget.CompoundButton; import com.android.internal.app.LocalePicker; import com.android.internal.app.LocaleStore; -import com.android.settings.CreateShortcut; +import com.android.settings.shortcut.CreateShortcut; import com.android.settings.R; import java.text.NumberFormat; diff --git a/src/com/android/settings/CreateShortcut.java b/src/com/android/settings/shortcut/CreateShortcut.java similarity index 92% rename from src/com/android/settings/CreateShortcut.java rename to src/com/android/settings/shortcut/CreateShortcut.java index 8bc801b99c3..2bd9b761255 100644 --- a/src/com/android/settings/CreateShortcut.java +++ b/src/com/android/settings/shortcut/CreateShortcut.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.settings; +package com.android.settings.shortcut; import android.app.LauncherActivity; import android.content.ComponentName; @@ -28,7 +28,9 @@ import android.content.pm.ShortcutManager; import android.graphics.Bitmap; import android.graphics.Bitmap.Config; import android.graphics.Canvas; +import android.graphics.drawable.Drawable; import android.graphics.drawable.Icon; +import android.graphics.drawable.LayerDrawable; import android.net.ConnectivityManager; import android.os.AsyncTask; import android.support.annotation.VisibleForTesting; @@ -40,6 +42,7 @@ import android.widget.ImageView; import android.widget.ListView; import com.android.internal.logging.nano.MetricsProto; +import com.android.settings.R; import com.android.settings.Settings.TetherSettingsActivity; import com.android.settings.overlay.FeatureFactory; @@ -65,7 +68,8 @@ public class CreateShortcut extends LauncherActivity { finish(); } - protected Intent createResultIntent(Intent shortcutIntent, ResolveInfo resolveInfo, + @VisibleForTesting + Intent createResultIntent(Intent shortcutIntent, ResolveInfo resolveInfo, CharSequence label) { shortcutIntent.setFlags(Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED); ShortcutManager sm = getSystemService(ShortcutManager.class); @@ -94,8 +98,8 @@ public class CreateShortcut extends LauncherActivity { if (activityInfo.icon != 0) { intent.putExtra(Intent.EXTRA_SHORTCUT_ICON, createIcon(activityInfo.icon, - R.layout.shortcut_badge, - getResources().getDimensionPixelSize(R.dimen.shortcut_size))); + R.layout.shortcut_badge, + getResources().getDimensionPixelSize(R.dimen.shortcut_size))); } return intent; } @@ -112,7 +116,11 @@ public class CreateShortcut extends LauncherActivity { private Bitmap createIcon(int resource, int layoutRes, int size) { Context context = new ContextThemeWrapper(this, android.R.style.Theme_Material); View view = LayoutInflater.from(context).inflate(layoutRes, null); - ((ImageView) view.findViewById(android.R.id.icon)).setImageResource(resource); + Drawable iconDrawable = getDrawable(resource); + if (iconDrawable instanceof LayerDrawable) { + iconDrawable = ((LayerDrawable) iconDrawable).getDrawable(1); + } + ((ImageView) view.findViewById(android.R.id.icon)).setImageDrawable(iconDrawable); int spec = MeasureSpec.makeMeasureSpec(size, MeasureSpec.EXACTLY); view.measure(spec, spec); diff --git a/tests/unit/src/com/android/settings/CreateShortcutTest.java b/tests/unit/src/com/android/settings/shortcut/CreateShortcutTest.java similarity index 90% rename from tests/unit/src/com/android/settings/CreateShortcutTest.java rename to tests/unit/src/com/android/settings/shortcut/CreateShortcutTest.java index 4ae9bd7997c..5ec008b3d5d 100644 --- a/tests/unit/src/com/android/settings/CreateShortcutTest.java +++ b/tests/unit/src/com/android/settings/shortcut/CreateShortcutTest.java @@ -14,12 +14,10 @@ * limitations under the License. */ -package com.android.settings; +package com.android.settings.shortcut; import static android.support.test.espresso.Espresso.onView; import static android.support.test.espresso.assertion.ViewAssertions.doesNotExist; -import static android.support.test.espresso.matcher.ViewMatchers.withText; - import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.mockito.Mockito.any; @@ -39,9 +37,13 @@ import android.content.pm.ResolveInfo; import android.content.pm.ShortcutInfo; import android.content.pm.ShortcutManager; import android.support.test.InstrumentationRegistry; +import android.support.test.espresso.matcher.ViewMatchers; import android.support.test.filters.SmallTest; import android.support.test.runner.AndroidJUnit4; +import com.android.settings.R; +import com.android.settings.Settings; + import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -55,12 +57,6 @@ import java.util.List; /** * Tests for {@link CreateShortcutTest} - * - m SettingsTests && - adb install \ - -r -g ${ANDROID_PRODUCT_OUT}/data/app/SettingsTests/SettingsTests.apk && - adb shell am instrument -e class com.android.settings.CreateShortcutTest \ - -w com.android.settings.tests/android.support.test.runner.AndroidJUnitRunner */ @RunWith(AndroidJUnit4.class) @SmallTest @@ -71,8 +67,10 @@ public class CreateShortcutTest { private Instrumentation mInstrumentation; private Context mContext; - @Mock ShortcutManager mShortcutManager; - @Captor ArgumentCaptor> mListCaptor; + @Mock + ShortcutManager mShortcutManager; + @Captor + ArgumentCaptor> mListCaptor; @Before public void setup() { @@ -84,15 +82,17 @@ public class CreateShortcutTest { @Test public void test_layoutDoesNotHaveCancelButton() { mInstrumentation.startActivitySync(new Intent(Intent.ACTION_CREATE_SHORTCUT) - .setClassName(mContext, CreateShortcut.class.getName())); - onView(withText(R.string.cancel)).check(doesNotExist()); + .setClassName(mContext, CreateShortcut.class.getName()) + .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)); + onView(ViewMatchers.withText(R.string.cancel)).check(doesNotExist()); } @Test public void createResultIntent() { CreateShortcut orgActivity = (CreateShortcut) mInstrumentation.startActivitySync( new Intent(Intent.ACTION_CREATE_SHORTCUT) - .setClassName(mContext, CreateShortcut.class.getName())); + .setClassName(mContext, CreateShortcut.class.getName()) + .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)); CreateShortcut activity = spy(orgActivity); doReturn(mShortcutManager).when(activity).getSystemService(eq(Context.SHORTCUT_SERVICE)); From 73dc479ab5fbb66e31343c043ebf350c251d79f5 Mon Sep 17 00:00:00 2001 From: Fan Zhang Date: Mon, 29 Jan 2018 12:06:58 -0800 Subject: [PATCH 07/11] Remove security settings v1 code Change-Id: I958ed1588009b91f64cd8ecb98208e72a891903e Fixes: 32953042 Test: robotests --- AndroidManifest.xml | 40 +- ...v2.xml => security_dashboard_settings.xml} | 0 res/xml/security_settings.xml | 24 - res/xml/security_settings_chooser.xml | 39 - res/xml/security_settings_lockscreen.xml | 35 - .../security_settings_lockscreen_profile.xml | 29 - res/xml/security_settings_misc.xml | 88 -- res/xml/security_settings_password.xml | 38 - .../security_settings_password_profile.xml | 29 - res/xml/security_settings_pattern.xml | 38 - res/xml/security_settings_pattern_profile.xml | 33 - res/xml/security_settings_pin.xml | 37 - res/xml/security_settings_pin_profile.xml | 29 - res/xml/security_settings_profile.xml | 27 - res/xml/security_settings_status.xml | 24 - res/xml/security_settings_unification.xml | 27 - src/com/android/settings/Settings.java | 3 +- .../android/settings/SettingsActivity.java | 14 - .../android/settings/core/FeatureFlags.java | 1 - .../core/gateway/SettingsGateway.java | 5 +- .../dashboard/DashboardFragmentRegistry.java | 4 +- .../fingerprint/FingerprintSettings.java | 46 - .../password/ManagedLockPasswordProvider.java | 11 - .../search/SearchIndexableResourcesImpl.java | 6 +- ...ProfileScreenLockPreferenceController.java | 5 +- .../ChangeScreenLockPreferenceController.java | 6 +- .../LockUnificationPreferenceController.java | 15 +- .../security/SecurityFeatureProvider.java | 12 - .../security/SecurityFeatureProviderImpl.java | 163 --- .../settings/security/SecuritySettings.java | 1026 ++--------------- .../settings/security/SecuritySettingsV2.java | 188 --- .../UnificationConfirmationDialog.java | 6 +- .../TrustAgentListPreferenceController.java | 8 +- ...ther_not_in_search_index_provider_registry | 3 +- .../core/XmlControllerAttributeTest.java | 18 +- ...ckUnificationPreferenceControllerTest.java | 2 +- .../SecurityFeatureProviderImplTest.java | 169 +-- .../security/SecuritySettingsTest.java | 136 +-- .../security/SecuritySettingsV2Test.java | 99 -- ...rustAgentListPreferenceControllerTest.java | 4 +- .../ui/SecuritySettingsLaunchTest.java | 2 +- 41 files changed, 198 insertions(+), 2291 deletions(-) rename res/xml/{security_settings_v2.xml => security_dashboard_settings.xml} (100%) delete mode 100644 res/xml/security_settings.xml delete mode 100644 res/xml/security_settings_chooser.xml delete mode 100644 res/xml/security_settings_lockscreen.xml delete mode 100644 res/xml/security_settings_lockscreen_profile.xml delete mode 100644 res/xml/security_settings_misc.xml delete mode 100644 res/xml/security_settings_password.xml delete mode 100644 res/xml/security_settings_password_profile.xml delete mode 100644 res/xml/security_settings_pattern.xml delete mode 100644 res/xml/security_settings_pattern_profile.xml delete mode 100644 res/xml/security_settings_pin.xml delete mode 100644 res/xml/security_settings_pin_profile.xml delete mode 100644 res/xml/security_settings_profile.xml delete mode 100644 res/xml/security_settings_status.xml delete mode 100644 res/xml/security_settings_unification.xml delete mode 100644 src/com/android/settings/security/SecuritySettingsV2.java delete mode 100644 tests/robotests/src/com/android/settings/security/SecuritySettingsV2Test.java diff --git a/AndroidManifest.xml b/AndroidManifest.xml index 2e511084b51..0ddaa0615bf 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -1279,7 +1279,7 @@ android:value="true" /> - - - - - - - - - - - - - - - - - - - - + android:parentActivityName=".Settings$SecurityDashboardActivity"> @@ -1436,7 +1404,7 @@ + android:parentActivityName=".Settings$SecurityDashboardActivity"> @@ -1574,7 +1542,7 @@ + android:parentActivityName=".Settings$SecurityDashboardActivity"> diff --git a/res/xml/security_settings_v2.xml b/res/xml/security_dashboard_settings.xml similarity index 100% rename from res/xml/security_settings_v2.xml rename to res/xml/security_dashboard_settings.xml diff --git a/res/xml/security_settings.xml b/res/xml/security_settings.xml deleted file mode 100644 index 31f2334d914..00000000000 --- a/res/xml/security_settings.xml +++ /dev/null @@ -1,24 +0,0 @@ - - - - - - diff --git a/res/xml/security_settings_chooser.xml b/res/xml/security_settings_chooser.xml deleted file mode 100644 index 360e6200e22..00000000000 --- a/res/xml/security_settings_chooser.xml +++ /dev/null @@ -1,39 +0,0 @@ - - - - - - - - - - - - - - diff --git a/res/xml/security_settings_lockscreen.xml b/res/xml/security_settings_lockscreen.xml deleted file mode 100644 index 56410fb5baf..00000000000 --- a/res/xml/security_settings_lockscreen.xml +++ /dev/null @@ -1,35 +0,0 @@ - - - - - - - - - - - - diff --git a/res/xml/security_settings_lockscreen_profile.xml b/res/xml/security_settings_lockscreen_profile.xml deleted file mode 100644 index a0c3f024912..00000000000 --- a/res/xml/security_settings_lockscreen_profile.xml +++ /dev/null @@ -1,29 +0,0 @@ - - - - - - - - diff --git a/res/xml/security_settings_misc.xml b/res/xml/security_settings_misc.xml deleted file mode 100644 index 730686cebd4..00000000000 --- a/res/xml/security_settings_misc.xml +++ /dev/null @@ -1,88 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/res/xml/security_settings_password.xml b/res/xml/security_settings_password.xml deleted file mode 100644 index 26077c7f508..00000000000 --- a/res/xml/security_settings_password.xml +++ /dev/null @@ -1,38 +0,0 @@ - - - - - - - - - - - - - - diff --git a/res/xml/security_settings_password_profile.xml b/res/xml/security_settings_password_profile.xml deleted file mode 100644 index 257b234c908..00000000000 --- a/res/xml/security_settings_password_profile.xml +++ /dev/null @@ -1,29 +0,0 @@ - - - - - - - - diff --git a/res/xml/security_settings_pattern.xml b/res/xml/security_settings_pattern.xml deleted file mode 100644 index 9b7482f8e5d..00000000000 --- a/res/xml/security_settings_pattern.xml +++ /dev/null @@ -1,38 +0,0 @@ - - - - - - - - - - - - - - diff --git a/res/xml/security_settings_pattern_profile.xml b/res/xml/security_settings_pattern_profile.xml deleted file mode 100644 index e095486560a..00000000000 --- a/res/xml/security_settings_pattern_profile.xml +++ /dev/null @@ -1,33 +0,0 @@ - - - - - - - - - - diff --git a/res/xml/security_settings_pin.xml b/res/xml/security_settings_pin.xml deleted file mode 100644 index 780ca193fd2..00000000000 --- a/res/xml/security_settings_pin.xml +++ /dev/null @@ -1,37 +0,0 @@ - - - - - - - - - - - - - - diff --git a/res/xml/security_settings_pin_profile.xml b/res/xml/security_settings_pin_profile.xml deleted file mode 100644 index 071b2f5a046..00000000000 --- a/res/xml/security_settings_pin_profile.xml +++ /dev/null @@ -1,29 +0,0 @@ - - - - - - - - diff --git a/res/xml/security_settings_profile.xml b/res/xml/security_settings_profile.xml deleted file mode 100644 index 9870e30799c..00000000000 --- a/res/xml/security_settings_profile.xml +++ /dev/null @@ -1,27 +0,0 @@ - - - - - - - - - - diff --git a/res/xml/security_settings_status.xml b/res/xml/security_settings_status.xml deleted file mode 100644 index 06930f94b43..00000000000 --- a/res/xml/security_settings_status.xml +++ /dev/null @@ -1,24 +0,0 @@ - - - - - - - - diff --git a/res/xml/security_settings_unification.xml b/res/xml/security_settings_unification.xml deleted file mode 100644 index b9c59e599f7..00000000000 --- a/res/xml/security_settings_unification.xml +++ /dev/null @@ -1,27 +0,0 @@ - - - - - - - - diff --git a/src/com/android/settings/Settings.java b/src/com/android/settings/Settings.java index 0b6fe89f7a3..b4908ddc706 100644 --- a/src/com/android/settings/Settings.java +++ b/src/com/android/settings/Settings.java @@ -67,8 +67,7 @@ public class Settings extends SettingsActivity { public static class AccessibilityInversionSettingsActivity extends SettingsActivity { /* empty */ } public static class AccessibilityContrastSettingsActivity extends SettingsActivity { /* empty */ } public static class AccessibilityDaltonizerSettingsActivity extends SettingsActivity { /* empty */ } - public static class SecuritySettingsActivity extends SettingsActivity { /* empty */ } - public static class SecuritySettingsActivityV2 extends SettingsActivity { /* empty */ } + public static class SecurityDashboardActivity extends SettingsActivity { /* empty */ } public static class UsageAccessSettingsActivity extends SettingsActivity { /* empty */ } public static class LocationSettingsActivity extends SettingsActivity { /* empty */ } public static class PrivacySettingsActivity extends SettingsActivity { /* empty */ } diff --git a/src/com/android/settings/SettingsActivity.java b/src/com/android/settings/SettingsActivity.java index d4584b7258e..3c18efb5f6b 100644 --- a/src/com/android/settings/SettingsActivity.java +++ b/src/com/android/settings/SettingsActivity.java @@ -802,20 +802,6 @@ public class SettingsActivity extends SettingsDrawerActivity !isConnectedDeviceV2Enabled && !UserManager.isDeviceInDemoMode(this) /* enabled */, isAdmin) || somethingChanged; - final boolean isSecurityV2Enabled = featureFactory.getSecurityFeatureProvider() - .isSecuritySettingsV2Enabled(this); - - // Enable new security page if v2 enabled - somethingChanged = setTileEnabled( - new ComponentName(packageName,Settings.SecuritySettingsActivityV2.class.getName()), - isSecurityV2Enabled, - isAdmin) || somethingChanged; - // Enable old security page if v2 disabled - somethingChanged = setTileEnabled( - new ComponentName(packageName,Settings.SecuritySettingsActivity.class.getName()), - !isSecurityV2Enabled, - isAdmin) || somethingChanged; - somethingChanged = setTileEnabled(new ComponentName(packageName, Settings.SimSettingsActivity.class.getName()), Utils.showSimCardTile(this), isAdmin) diff --git a/src/com/android/settings/core/FeatureFlags.java b/src/com/android/settings/core/FeatureFlags.java index e1636b4b63c..7505876b887 100644 --- a/src/com/android/settings/core/FeatureFlags.java +++ b/src/com/android/settings/core/FeatureFlags.java @@ -24,7 +24,6 @@ public class FeatureFlags { public static final String CONNECTED_DEVICE_V2 = "settings_connected_device_v2"; public static final String BATTERY_SETTINGS_V2 = "settings_battery_v2"; public static final String BATTERY_DISPLAY_APP_LIST = "settings_battery_display_app_list"; - public static final String SECURITY_SETTINGS_V2 = "settings_security_settings_v2"; public static final String ZONE_PICKER_V2 = "settings_zone_picker_v2"; public static final String SUGGESTION_UI_V2 = "settings_suggestion_ui_v2"; public static final String ABOUT_PHONE_V2 = "settings_about_phone_v2"; diff --git a/src/com/android/settings/core/gateway/SettingsGateway.java b/src/com/android/settings/core/gateway/SettingsGateway.java index ecf0584b18f..b07cf84774a 100644 --- a/src/com/android/settings/core/gateway/SettingsGateway.java +++ b/src/com/android/settings/core/gateway/SettingsGateway.java @@ -116,7 +116,6 @@ import com.android.settings.print.PrintSettingsFragment; import com.android.settings.security.CryptKeeperSettings; import com.android.settings.security.LockscreenDashboardFragment; import com.android.settings.security.SecuritySettings; -import com.android.settings.security.SecuritySettingsV2; import com.android.settings.sim.SimSettings; import com.android.settings.support.SupportDashboardActivity; import com.android.settings.system.ResetDashboardFragment; @@ -165,7 +164,6 @@ public class SettingsGateway { NotificationStation.class.getName(), LocationSettings.class.getName(), SecuritySettings.class.getName(), - SecuritySettingsV2.class.getName(), UsageAccessDetails.class.getName(), PrivacySettings.class.getName(), DeviceAdminSettings.class.getName(), @@ -271,8 +269,7 @@ public class SettingsGateway { Settings.PowerUsageSummaryActivity.class.getName(), Settings.PowerUsageSummaryLegacyActivity.class.getName(), Settings.AccountDashboardActivity.class.getName(), - Settings.SecuritySettingsActivity.class.getName(), - Settings.SecuritySettingsActivityV2.class.getName(), + Settings.SecurityDashboardActivity.class.getName(), Settings.AccessibilitySettingsActivity.class.getName(), Settings.SystemDashboardActivity.class.getName(), SupportDashboardActivity.class.getName(), diff --git a/src/com/android/settings/dashboard/DashboardFragmentRegistry.java b/src/com/android/settings/dashboard/DashboardFragmentRegistry.java index bb575ea4df1..275af3df7eb 100644 --- a/src/com/android/settings/dashboard/DashboardFragmentRegistry.java +++ b/src/com/android/settings/dashboard/DashboardFragmentRegistry.java @@ -33,7 +33,7 @@ import com.android.settings.network.NetworkDashboardFragment; import com.android.settings.notification.ConfigureNotificationSettings; import com.android.settings.notification.SoundSettings; import com.android.settings.security.LockscreenDashboardFragment; -import com.android.settings.security.SecuritySettingsV2; +import com.android.settings.security.SecuritySettings; import com.android.settings.system.SystemDashboardFragment; import com.android.settingslib.drawer.CategoryKey; @@ -77,7 +77,7 @@ public class DashboardFragmentRegistry { CategoryKey.CATEGORY_SOUND); PARENT_TO_CATEGORY_KEY_MAP.put(StorageDashboardFragment.class.getName(), CategoryKey.CATEGORY_STORAGE); - PARENT_TO_CATEGORY_KEY_MAP.put(SecuritySettingsV2.class.getName(), + PARENT_TO_CATEGORY_KEY_MAP.put(SecuritySettings.class.getName(), CategoryKey.CATEGORY_SECURITY); PARENT_TO_CATEGORY_KEY_MAP.put(AccountDetailDashboardFragment.class.getName(), CategoryKey.CATEGORY_ACCOUNT_DETAIL); diff --git a/src/com/android/settings/fingerprint/FingerprintSettings.java b/src/com/android/settings/fingerprint/FingerprintSettings.java index de7187c4ac4..caad9886664 100644 --- a/src/com/android/settings/fingerprint/FingerprintSettings.java +++ b/src/com/android/settings/fingerprint/FingerprintSettings.java @@ -35,7 +35,6 @@ import android.os.UserManager; import android.support.annotation.VisibleForTesting; import android.support.v7.preference.Preference; import android.support.v7.preference.Preference.OnPreferenceChangeListener; -import android.support.v7.preference.Preference.OnPreferenceClickListener; import android.support.v7.preference.PreferenceGroup; import android.support.v7.preference.PreferenceScreen; import android.support.v7.preference.PreferenceViewHolder; @@ -921,49 +920,4 @@ public class FingerprintSettings extends SubSettings { }); } } - - /** - * @deprecated in favor of new SecuritySettings. - */ - @Deprecated - public static Preference getFingerprintPreferenceForUser(Context context, final int userId) { - final FingerprintManager fpm = Utils.getFingerprintManagerOrNull(context); - if (fpm == null || !fpm.isHardwareDetected()) { - Log.v(TAG, "No fingerprint hardware detected!!"); - return null; - } - Preference fingerprintPreference = new Preference(context); - fingerprintPreference.setKey(KEY_FINGERPRINT_SETTINGS); - fingerprintPreference.setTitle(R.string.security_settings_fingerprint_preference_title); - final List items = fpm.getEnrolledFingerprints(userId); - final int fingerprintCount = items != null ? items.size() : 0; - final String clazz; - if (fingerprintCount > 0) { - fingerprintPreference.setSummary(context.getResources().getQuantityString( - R.plurals.security_settings_fingerprint_preference_summary, - fingerprintCount, fingerprintCount)); - clazz = FingerprintSettings.class.getName(); - } else { - fingerprintPreference.setSummary( - R.string.security_settings_fingerprint_preference_summary_none); - clazz = FingerprintEnrollIntroduction.class.getName(); - } - fingerprintPreference.setOnPreferenceClickListener(new OnPreferenceClickListener() { - @Override - public boolean onPreferenceClick(Preference preference) { - final Context context = preference.getContext(); - final UserManager userManager = UserManager.get(context); - if (Utils.startQuietModeDialogIfNecessary(context, userManager, - userId)) { - return false; - } - Intent intent = new Intent(); - intent.setClassName("com.android.settings", clazz); - intent.putExtra(Intent.EXTRA_USER_ID, userId); - context.startActivity(intent); - return true; - } - }); - return fingerprintPreference; - } } diff --git a/src/com/android/settings/password/ManagedLockPasswordProvider.java b/src/com/android/settings/password/ManagedLockPasswordProvider.java index 82135cf817d..5786a5afa09 100644 --- a/src/com/android/settings/password/ManagedLockPasswordProvider.java +++ b/src/com/android/settings/password/ManagedLockPasswordProvider.java @@ -54,17 +54,6 @@ public class ManagedLockPasswordProvider { */ CharSequence getPickerOptionTitle(boolean forFingerprint) { return ""; } - /** - * Gets resource id of the lock screen preference that should be displayed in security settings - * if the current password quality is set to - * {@link android.app.admin.DevicePolicyManager#PASSWORD_QUALITY_MANAGED}. - * @param forProfile Whether the settings are shown for a user profile rather than a user. - */ - public int getResIdForLockUnlockScreen(boolean forProfile) { - return forProfile ? R.xml.security_settings_password_profile - : R.xml.security_settings_password; - } - /** * Creates intent that should be launched when user chooses managed password in the lock * settings picker. diff --git a/src/com/android/settings/search/SearchIndexableResourcesImpl.java b/src/com/android/settings/search/SearchIndexableResourcesImpl.java index faa4b8c91d7..38dc15dc4d6 100644 --- a/src/com/android/settings/search/SearchIndexableResourcesImpl.java +++ b/src/com/android/settings/search/SearchIndexableResourcesImpl.java @@ -21,7 +21,6 @@ import android.support.annotation.VisibleForTesting; import com.android.settings.DateTimeSettings; import com.android.settings.DisplaySettings; import com.android.settings.LegalSettings; -import com.android.settings.deviceinfo.aboutphone.MyDeviceInfoFragment; import com.android.settings.accessibility.AccessibilitySettings; import com.android.settings.accessibility.AccessibilityShortcutPreferenceFragment; import com.android.settings.accessibility.MagnificationPreferenceFragment; @@ -42,6 +41,7 @@ import com.android.settings.development.DevelopmentSettingsDashboardFragment; import com.android.settings.deviceinfo.DeviceInfoSettings; import com.android.settings.deviceinfo.StorageDashboardFragment; import com.android.settings.deviceinfo.StorageSettings; +import com.android.settings.deviceinfo.aboutphone.MyDeviceInfoFragment; import com.android.settings.display.AmbientDisplaySettings; import com.android.settings.display.NightDisplaySettings; import com.android.settings.display.ScreenZoomSettings; @@ -75,7 +75,7 @@ import com.android.settings.print.PrintSettingsFragment; import com.android.settings.security.EncryptionAndCredential; import com.android.settings.security.LockscreenDashboardFragment; import com.android.settings.security.ScreenPinningSettings; -import com.android.settings.security.SecuritySettingsV2; +import com.android.settings.security.SecuritySettings; import com.android.settings.security.screenlock.ScreenLockSettings; import com.android.settings.sim.SimSettings; import com.android.settings.support.SupportDashboardActivity; @@ -132,7 +132,7 @@ public class SearchIndexableResourcesImpl implements SearchIndexableResources { addIndex(LanguageAndInputSettings.class); addIndex(LocationSettings.class); addIndex(ScanningSettings.class); - addIndex(SecuritySettingsV2.class); + addIndex(SecuritySettings.class); addIndex(ScreenLockSettings.class); addIndex(EncryptionAndCredential.class); addIndex(ScreenPinningSettings.class); diff --git a/src/com/android/settings/security/ChangeProfileScreenLockPreferenceController.java b/src/com/android/settings/security/ChangeProfileScreenLockPreferenceController.java index 9a33ec3deaf..91c4410f084 100644 --- a/src/com/android/settings/security/ChangeProfileScreenLockPreferenceController.java +++ b/src/com/android/settings/security/ChangeProfileScreenLockPreferenceController.java @@ -16,8 +16,7 @@ package com.android.settings.security; -import static com.android.settings.security - .SecuritySettingsV2.SET_OR_CHANGE_LOCK_METHOD_REQUEST_PROFILE; +import static com.android.settings.security.SecuritySettings.SET_OR_CHANGE_LOCK_METHOD_REQUEST_PROFILE; import android.app.admin.DevicePolicyManager; import android.content.Context; @@ -37,7 +36,7 @@ public class ChangeProfileScreenLockPreferenceController extends private static final String KEY_UNLOCK_SET_OR_CHANGE_PROFILE = "unlock_set_or_change_profile"; public ChangeProfileScreenLockPreferenceController(Context context, - SecuritySettingsV2 host) { + SecuritySettings host) { super(context, host); } diff --git a/src/com/android/settings/security/ChangeScreenLockPreferenceController.java b/src/com/android/settings/security/ChangeScreenLockPreferenceController.java index fdb93490a0c..10143d268fc 100644 --- a/src/com/android/settings/security/ChangeScreenLockPreferenceController.java +++ b/src/com/android/settings/security/ChangeScreenLockPreferenceController.java @@ -16,7 +16,7 @@ package com.android.settings.security; -import static com.android.settings.security.SecuritySettingsV2.SET_OR_CHANGE_LOCK_METHOD_REQUEST; +import static com.android.settings.security.SecuritySettings.SET_OR_CHANGE_LOCK_METHOD_REQUEST; import android.app.admin.DevicePolicyManager; import android.content.Context; @@ -45,7 +45,7 @@ public class ChangeScreenLockPreferenceController extends AbstractPreferenceCont private static final String KEY_UNLOCK_SET_OR_CHANGE = "unlock_set_or_change"; protected final DevicePolicyManager mDPM; - protected final SecuritySettingsV2 mHost; + protected final SecuritySettings mHost; protected final UserManager mUm; protected final LockPatternUtils mLockPatternUtils; @@ -54,7 +54,7 @@ public class ChangeScreenLockPreferenceController extends AbstractPreferenceCont protected RestrictedPreference mPreference; - public ChangeScreenLockPreferenceController(Context context, SecuritySettingsV2 host) { + public ChangeScreenLockPreferenceController(Context context, SecuritySettings host) { super(context); mUm = (UserManager) context.getSystemService(Context.USER_SERVICE); mDPM = (DevicePolicyManager) context.getSystemService(Context.DEVICE_POLICY_SERVICE); diff --git a/src/com/android/settings/security/LockUnificationPreferenceController.java b/src/com/android/settings/security/LockUnificationPreferenceController.java index 5486e2967e4..abbf2f4c116 100644 --- a/src/com/android/settings/security/LockUnificationPreferenceController.java +++ b/src/com/android/settings/security/LockUnificationPreferenceController.java @@ -16,11 +16,10 @@ package com.android.settings.security; -import static com.android.settings.security - .SecuritySettingsV2.SET_OR_CHANGE_LOCK_METHOD_REQUEST_PROFILE; -import static com.android.settings.security.SecuritySettingsV2.UNIFY_LOCK_CONFIRM_DEVICE_REQUEST; -import static com.android.settings.security.SecuritySettingsV2.UNIFY_LOCK_CONFIRM_PROFILE_REQUEST; -import static com.android.settings.security.SecuritySettingsV2.UNUNIFY_LOCK_CONFIRM_DEVICE_REQUEST; +import static com.android.settings.security.SecuritySettings.SET_OR_CHANGE_LOCK_METHOD_REQUEST_PROFILE; +import static com.android.settings.security.SecuritySettings.UNIFY_LOCK_CONFIRM_DEVICE_REQUEST; +import static com.android.settings.security.SecuritySettings.UNIFY_LOCK_CONFIRM_PROFILE_REQUEST; +import static com.android.settings.security.SecuritySettings.UNUNIFY_LOCK_CONFIRM_DEVICE_REQUEST; import android.app.Activity; import android.app.admin.DevicePolicyManager; @@ -53,7 +52,7 @@ public class LockUnificationPreferenceController extends AbstractPreferenceContr private final UserManager mUm; private final LockPatternUtils mLockPatternUtils; private final int mProfileChallengeUserId; - private final SecuritySettingsV2 mHost; + private final SecuritySettings mHost; private RestrictedSwitchPreference mUnifyProfile; @@ -67,7 +66,7 @@ public class LockUnificationPreferenceController extends AbstractPreferenceContr mUnifyProfile = (RestrictedSwitchPreference) screen.findPreference(KEY_UNIFICATION); } - public LockUnificationPreferenceController(Context context, SecuritySettingsV2 host) { + public LockUnificationPreferenceController(Context context, SecuritySettings host) { super(context); mHost = host; mUm = (UserManager) context.getSystemService(Context.USER_SERVICE); @@ -212,7 +211,7 @@ public class LockUnificationPreferenceController extends AbstractPreferenceContr mCurrentProfilePassword); mHost.startFragment(mHost, ChooseLockGeneric.ChooseLockGenericFragment.class.getName(), R.string.lock_settings_picker_title, - SecuritySettingsV2.SET_OR_CHANGE_LOCK_METHOD_REQUEST, null); + SecuritySettings.SET_OR_CHANGE_LOCK_METHOD_REQUEST, null); } } diff --git a/src/com/android/settings/security/SecurityFeatureProvider.java b/src/com/android/settings/security/SecurityFeatureProvider.java index 35ff586d1df..d533d1e5b10 100644 --- a/src/com/android/settings/security/SecurityFeatureProvider.java +++ b/src/com/android/settings/security/SecurityFeatureProvider.java @@ -17,26 +17,14 @@ package com.android.settings.security; import android.content.Context; -import android.support.v7.preference.PreferenceScreen; -import android.util.FeatureFlagUtils; import com.android.internal.widget.LockPatternUtils; -import com.android.settings.core.FeatureFlags; import com.android.settings.security.trustagent.TrustAgentManager; -import com.android.settingslib.drawer.DashboardCategory; /** FeatureProvider for security. */ public interface SecurityFeatureProvider { - default boolean isSecuritySettingsV2Enabled(Context context) { - return FeatureFlagUtils.isEnabled(context, FeatureFlags.SECURITY_SETTINGS_V2); - } - - /** Update preferences with data from associated tiles. */ - void updatePreferences(Context context, PreferenceScreen preferenceScreen, - DashboardCategory dashboardCategory); - /** Returns the {@link TrustAgentManager} bound to this {@link SecurityFeatureProvider}. */ TrustAgentManager getTrustAgentManager(); diff --git a/src/com/android/settings/security/SecurityFeatureProviderImpl.java b/src/com/android/settings/security/SecurityFeatureProviderImpl.java index 70b1ec10039..56a0884b5d5 100644 --- a/src/com/android/settings/security/SecurityFeatureProviderImpl.java +++ b/src/com/android/settings/security/SecurityFeatureProviderImpl.java @@ -17,28 +17,9 @@ package com.android.settings.security; import android.content.Context; -import android.content.IContentProvider; -import android.content.Intent; -import android.content.pm.PackageManager; -import android.content.res.Resources; -import android.graphics.drawable.Drawable; -import android.support.annotation.VisibleForTesting; -import android.support.v7.preference.Preference; -import android.support.v7.preference.PreferenceScreen; -import android.text.TextUtils; -import android.util.ArrayMap; -import android.util.Pair; import com.android.internal.widget.LockPatternUtils; -import com.android.settings.R; import com.android.settings.security.trustagent.TrustAgentManager; -import com.android.settingslib.drawer.DashboardCategory; -import com.android.settingslib.drawer.Tile; -import com.android.settingslib.drawer.TileUtils; -import com.android.settingslib.utils.ThreadUtils; - -import java.util.Map; -import java.util.TreeMap; /** Implementation for {@code SecurityFeatureProvider}. */ public class SecurityFeatureProviderImpl implements SecurityFeatureProvider { @@ -46,150 +27,6 @@ public class SecurityFeatureProviderImpl implements SecurityFeatureProvider { private TrustAgentManager mTrustAgentManager; private LockPatternUtils mLockPatternUtils; - @VisibleForTesting - static final Drawable DEFAULT_ICON = null; - - @VisibleForTesting - static Map> sIconCache = new TreeMap<>(); - - @VisibleForTesting - static Map sSummaryCache = new TreeMap<>(); - - /** Update preferences with data from associated tiles. */ - public void updatePreferences(final Context context, final PreferenceScreen preferenceScreen, - final DashboardCategory dashboardCategory) { - if (preferenceScreen == null) { - return; - } - int tilesCount = (dashboardCategory != null) ? dashboardCategory.getTilesCount() : 0; - if (tilesCount == 0) { - return; - } - - initPreferences(context, preferenceScreen, dashboardCategory); - - // Fetching the summary and icon from the provider introduces latency, so do this on a - // separate thread. - ThreadUtils.postOnBackgroundThread(() -> - updatePreferencesToRunOnWorkerThread(context, preferenceScreen, dashboardCategory)); - } - - @VisibleForTesting - static void initPreferences(Context context, PreferenceScreen preferenceScreen, - DashboardCategory dashboardCategory) { - int tilesCount = (dashboardCategory != null) ? dashboardCategory.getTilesCount() : 0; - for (int i = 0; i < tilesCount; i++) { - Tile tile = dashboardCategory.getTile(i); - // If the tile does not have a key or appropriate meta data, skip it. - if (TextUtils.isEmpty(tile.key) || (tile.metaData == null)) { - continue; - } - Preference matchingPref = preferenceScreen.findPreference(tile.key); - // If the tile does not have a matching preference, skip it. - if (matchingPref == null) { - continue; - } - // Either remove an icon by replacing them with nothing, or use the cached one since - // there is a delay in fetching the injected icon, and we don't want an inappropriate - // icon to be displayed while waiting for the injected icon. - final String iconUri = - tile.metaData.getString(TileUtils.META_DATA_PREFERENCE_ICON_URI, null); - Drawable drawable = DEFAULT_ICON; - if ((iconUri != null) && sIconCache.containsKey(iconUri)) { - Pair icon = sIconCache.get(iconUri); - try { - drawable = context.getPackageManager() - .getResourcesForApplication(icon.first /* package name */) - .getDrawable(icon.second /* res id */, - context.getTheme()); - } catch (PackageManager.NameNotFoundException e) { - // Ignore and just load the default icon. - } - } - matchingPref.setIcon(drawable); - // Either reserve room for the summary or load the cached one. This prevents the title - // from shifting when the final summary is injected. - final String summaryUri = - tile.metaData.getString(TileUtils.META_DATA_PREFERENCE_SUMMARY_URI, null); - String summary = context.getString(R.string.summary_placeholder); - if ((summaryUri != null) && sSummaryCache.containsKey(summaryUri)) { - summary = sSummaryCache.get(summaryUri); - } - matchingPref.setSummary(summary); - } - } - - @VisibleForTesting - void updatePreferencesToRunOnWorkerThread(Context context, PreferenceScreen preferenceScreen, - DashboardCategory dashboardCategory) { - - int tilesCount = (dashboardCategory != null) ? dashboardCategory.getTilesCount() : 0; - Map providerMap = new ArrayMap<>(); - for (int i = 0; i < tilesCount; i++) { - Tile tile = dashboardCategory.getTile(i); - // If the tile does not have a key or appropriate meta data, skip it. - if (TextUtils.isEmpty(tile.key) || (tile.metaData == null)) { - continue; - } - Preference matchingPref = preferenceScreen.findPreference(tile.key); - // If the tile does not have a matching preference, skip it. - if (matchingPref == null) { - continue; - } - // Check if the tile has content providers for dynamically updatable content. - final String iconUri = - tile.metaData.getString(TileUtils.META_DATA_PREFERENCE_ICON_URI, null); - final String summaryUri = - tile.metaData.getString(TileUtils.META_DATA_PREFERENCE_SUMMARY_URI, null); - if (!TextUtils.isEmpty(iconUri)) { - String packageName = null; - if (tile.intent != null) { - Intent intent = tile.intent; - if (!TextUtils.isEmpty(intent.getPackage())) { - packageName = intent.getPackage(); - } else if (intent.getComponent() != null) { - packageName = intent.getComponent().getPackageName(); - } - } - Pair icon = - TileUtils.getIconFromUri(context, packageName, iconUri, providerMap); - if (icon != null) { - sIconCache.put(iconUri, icon); - // Icon is only returned if the icon belongs to Settings or the target app. - // setIcon must be called on the UI thread. - ThreadUtils.postOnMainThread(() -> { - try { - matchingPref.setIcon(context.getPackageManager() - .getResourcesForApplication(icon.first /* package name */) - .getDrawable(icon.second /* res id */, - context.getTheme())); - } catch (PackageManager.NameNotFoundException - | Resources.NotFoundException e) { - // Intentionally ignored. If icon resources cannot be found, do not - // update. - } - }); - } - } - if (!TextUtils.isEmpty(summaryUri)) { - String summary = TileUtils.getTextFromUri(context, summaryUri, providerMap, - TileUtils.META_DATA_PREFERENCE_SUMMARY); - sSummaryCache.put(summaryUri, summary); - // setSummary must be called on UI thread. - ThreadUtils.postOnMainThread(() -> { - // Only update the summary if it has actually changed. - if (summary == null) { - if (matchingPref.getSummary() != null) { - matchingPref.setSummary(summary); - } - } else if (!summary.equals(matchingPref.getSummary())) { - matchingPref.setSummary(summary); - } - }); - } - } - } - @Override public TrustAgentManager getTrustAgentManager() { if (mTrustAgentManager == null) { diff --git a/src/com/android/settings/security/SecuritySettings.java b/src/com/android/settings/security/SecuritySettings.java index f099b44883f..df3b455f0a9 100644 --- a/src/com/android/settings/security/SecuritySettings.java +++ b/src/com/android/settings/security/SecuritySettings.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2007 The Android Open Source Project + * Copyright (C) 2018 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. @@ -13,744 +13,62 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.android.settings.security; -import static com.android.settingslib.RestrictedLockUtils.EnforcedAdmin; +import static com.android.settings.security.EncryptionStatusPreferenceController + .PREF_KEY_ENCRYPTION_SECURITY_PAGE; import android.app.Activity; -import android.app.AlertDialog; -import android.app.Dialog; -import android.app.FragmentManager; -import android.app.admin.DevicePolicyManager; import android.content.Context; -import android.content.DialogInterface; import android.content.Intent; -import android.content.res.Resources; import android.hardware.fingerprint.FingerprintManager; -import android.os.Bundle; -import android.os.PersistableBundle; -import android.os.UserHandle; -import android.os.UserManager; -import android.os.storage.StorageManager; import android.provider.SearchIndexableResource; -import android.provider.Settings; -import android.support.annotation.VisibleForTesting; -import android.support.v14.preference.SwitchPreference; -import android.support.v7.preference.Preference; -import android.support.v7.preference.Preference.OnPreferenceChangeListener; -import android.support.v7.preference.PreferenceGroup; -import android.support.v7.preference.PreferenceScreen; -import android.telephony.CarrierConfigManager; -import android.telephony.SubscriptionInfo; -import android.telephony.SubscriptionManager; -import android.telephony.TelephonyManager; -import android.text.TextUtils; -import com.android.internal.logging.nano.MetricsProto.MetricsEvent; -import com.android.internal.widget.LockPatternUtils; +import com.android.internal.logging.nano.MetricsProto; import com.android.settings.R; -import com.android.settings.SettingsPreferenceFragment; import com.android.settings.Utils; -import com.android.settings.core.instrumentation.InstrumentedDialogFragment; -import com.android.settings.dashboard.DashboardFeatureProvider; +import com.android.settings.dashboard.DashboardFragment; import com.android.settings.dashboard.SummaryLoader; import com.android.settings.enterprise.EnterprisePrivacyPreferenceController; import com.android.settings.enterprise.ManageDeviceAdminPreferenceController; -import com.android.settings.fingerprint.FingerprintSettings; +import com.android.settings.fingerprint.FingerprintProfileStatusPreferenceController; +import com.android.settings.fingerprint.FingerprintStatusPreferenceController; import com.android.settings.location.LocationPreferenceController; -import com.android.settings.notification.LockScreenNotificationPreferenceController; -import com.android.settings.overlay.FeatureFactory; -import com.android.settings.password.ChooseLockGeneric.ChooseLockGenericFragment; -import com.android.settings.password.ChooseLockSettingsHelper; -import com.android.settings.password.ManagedLockPasswordProvider; import com.android.settings.search.BaseSearchIndexProvider; -import com.android.settings.search.Indexable; -import com.android.settings.search.SearchIndexableRaw; -import com.android.settings.security.screenlock.ScreenLockSettings; -import com.android.settings.security.trustagent.TrustAgentManager; -import com.android.settings.security.trustagent.TrustAgentManager.TrustAgentComponentInfo; -import com.android.settings.widget.GearPreference; -import com.android.settingslib.RestrictedLockUtils; -import com.android.settingslib.RestrictedPreference; -import com.android.settingslib.RestrictedSwitchPreference; -import com.android.settingslib.drawer.CategoryKey; +import com.android.settings.security.screenlock.LockScreenPreferenceController; +import com.android.settings.security.trustagent.ManageTrustAgentsPreferenceController; +import com.android.settings.security.trustagent.TrustAgentListPreferenceController; +import com.android.settings.widget.PreferenceCategoryController; +import com.android.settingslib.core.AbstractPreferenceController; +import com.android.settingslib.core.lifecycle.Lifecycle; import java.util.ArrayList; import java.util.List; -/** - * Gesture lock pattern settings. - */ -public class SecuritySettings extends SettingsPreferenceFragment - implements OnPreferenceChangeListener, Indexable, - GearPreference.OnGearClickListener { +public class SecuritySettings extends DashboardFragment { private static final String TAG = "SecuritySettings"; - private static final String TRUST_AGENT_CLICK_INTENT = "trust_agent_click_intent"; - - // Lock Settings - private static final String KEY_UNLOCK_SET_OR_CHANGE = "unlock_set_or_change"; - private static final String KEY_UNLOCK_SET_OR_CHANGE_PROFILE = "unlock_set_or_change_profile"; - private static final String KEY_VISIBLE_PATTERN_PROFILE = "visiblepattern_profile"; - private static final String KEY_SECURITY_CATEGORY = "security_category"; - @VisibleForTesting - static final String KEY_MANAGE_TRUST_AGENTS = "manage_trust_agents"; - private static final String KEY_UNIFICATION = "unification"; - @VisibleForTesting - static final String KEY_LOCKSCREEN_PREFERENCES = "lockscreen_preferences"; - private static final String KEY_ENCRYPTION_AND_CREDENTIALS = "encryption_and_credential"; - private static final String KEY_LOCATION_SCANNING = "location_scanning"; - private static final String KEY_LOCATION = "location"; - - private static final int SET_OR_CHANGE_LOCK_METHOD_REQUEST = 123; - private static final int CHANGE_TRUST_AGENT_SETTINGS = 126; - private static final int SET_OR_CHANGE_LOCK_METHOD_REQUEST_PROFILE = 127; - private static final int UNIFY_LOCK_CONFIRM_DEVICE_REQUEST = 128; - private static final int UNIFY_LOCK_CONFIRM_PROFILE_REQUEST = 129; - private static final int UNUNIFY_LOCK_CONFIRM_DEVICE_REQUEST = 130; - private static final String TAG_UNIFICATION_DIALOG = "unification_dialog"; - - // Misc Settings - private static final String KEY_SIM_LOCK = "sim_lock_settings"; - private static final String KEY_SHOW_PASSWORD = "show_password"; - private static final String KEY_TRUST_AGENT = "trust_agent"; - private static final String KEY_SCREEN_PINNING = "screen_pinning_settings"; - - // Security status - private static final String KEY_SECURITY_STATUS = "security_status"; - private static final String SECURITY_STATUS_KEY_PREFIX = "security_status_"; - - // Device management settings - private static final String KEY_ENTERPRISE_PRIVACY = "enterprise_privacy"; - private static final String KEY_MANAGE_DEVICE_ADMIN = "manage_device_admin"; - - // These switch preferences need special handling since they're not all stored in Settings. - private static final String SWITCH_PREFERENCE_KEYS[] = { - KEY_SHOW_PASSWORD, KEY_UNIFICATION, KEY_VISIBLE_PATTERN_PROFILE - }; - - private static final int MY_USER_ID = UserHandle.myUserId(); - - private DashboardFeatureProvider mDashboardFeatureProvider; - private DevicePolicyManager mDPM; - private SecurityFeatureProvider mSecurityFeatureProvider; - private TrustAgentManager mTrustAgentManager; - private SubscriptionManager mSubscriptionManager; - private UserManager mUm; - - private ChooseLockSettingsHelper mChooseLockSettingsHelper; - private LockPatternUtils mLockPatternUtils; - private ManagedLockPasswordProvider mManagedPasswordProvider; - - private SwitchPreference mVisiblePatternProfile; - private RestrictedSwitchPreference mUnifyProfile; - - private SwitchPreference mShowPassword; - - private boolean mIsAdmin; - - private Intent mTrustAgentClickIntent; - - private int mProfileChallengeUserId; - - private String mCurrentDevicePassword; - private String mCurrentProfilePassword; - - private LocationPreferenceController mLocationcontroller; - private ManageDeviceAdminPreferenceController mManageDeviceAdminPreferenceController; - private EnterprisePrivacyPreferenceController mEnterprisePrivacyPreferenceController; + public static final int SET_OR_CHANGE_LOCK_METHOD_REQUEST = 123; + public static final int CHANGE_TRUST_AGENT_SETTINGS = 126; + public static final int SET_OR_CHANGE_LOCK_METHOD_REQUEST_PROFILE = 127; + public static final int UNIFY_LOCK_CONFIRM_DEVICE_REQUEST = 128; + public static final int UNIFY_LOCK_CONFIRM_PROFILE_REQUEST = 129; + public static final int UNUNIFY_LOCK_CONFIRM_DEVICE_REQUEST = 130; @Override public int getMetricsCategory() { - return MetricsEvent.SECURITY; + return MetricsProto.MetricsEvent.SECURITY; } @Override - public void onAttach(Context context) { - super.onAttach(context); - mLocationcontroller = new LocationPreferenceController(context, getLifecycle()); + protected int getPreferenceScreenResId() { + return R.xml.security_dashboard_settings; } @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - final Activity activity = getActivity(); - - mSubscriptionManager = SubscriptionManager.from(activity); - - mLockPatternUtils = new LockPatternUtils(activity); - - mManagedPasswordProvider = ManagedLockPasswordProvider.get(activity, MY_USER_ID); - - mDPM = (DevicePolicyManager)getSystemService(Context.DEVICE_POLICY_SERVICE); - - mUm = UserManager.get(activity); - - mChooseLockSettingsHelper = new ChooseLockSettingsHelper(activity); - - mDashboardFeatureProvider = FeatureFactory.getFactory(activity) - .getDashboardFeatureProvider(activity); - - mSecurityFeatureProvider = FeatureFactory.getFactory(activity).getSecurityFeatureProvider(); - - mTrustAgentManager = mSecurityFeatureProvider.getTrustAgentManager(); - - if (savedInstanceState != null - && savedInstanceState.containsKey(TRUST_AGENT_CLICK_INTENT)) { - mTrustAgentClickIntent = savedInstanceState.getParcelable(TRUST_AGENT_CLICK_INTENT); - } - - mManageDeviceAdminPreferenceController - = new ManageDeviceAdminPreferenceController(activity); - mEnterprisePrivacyPreferenceController - = new EnterprisePrivacyPreferenceController(activity); - } - - private static int getResIdForLockUnlockScreen(LockPatternUtils lockPatternUtils, - ManagedLockPasswordProvider managedPasswordProvider, int userId) { - final boolean isMyUser = userId == MY_USER_ID; - int resid = 0; - if (!lockPatternUtils.isSecure(userId)) { - if (!isMyUser) { - resid = R.xml.security_settings_lockscreen_profile; - } else if (lockPatternUtils.isLockScreenDisabled(userId)) { - resid = R.xml.security_settings_lockscreen; - } else { - resid = R.xml.security_settings_chooser; - } - } else { - switch (lockPatternUtils.getKeyguardStoredPasswordQuality(userId)) { - case DevicePolicyManager.PASSWORD_QUALITY_SOMETHING: - resid = isMyUser ? R.xml.security_settings_pattern - : R.xml.security_settings_pattern_profile; - break; - case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC: - case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX: - resid = isMyUser ? R.xml.security_settings_pin - : R.xml.security_settings_pin_profile; - break; - case DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC: - case DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC: - case DevicePolicyManager.PASSWORD_QUALITY_COMPLEX: - resid = isMyUser ? R.xml.security_settings_password - : R.xml.security_settings_password_profile; - break; - case DevicePolicyManager.PASSWORD_QUALITY_MANAGED: - resid = managedPasswordProvider.getResIdForLockUnlockScreen(!isMyUser); - break; - } - } - return resid; - } - - /** - * Important! - * - * Don't forget to update the SecuritySearchIndexProvider if you are doing any change in the - * logic or adding/removing preferences here. - */ - private PreferenceScreen createPreferenceHierarchy() { - PreferenceScreen root = getPreferenceScreen(); - if (root != null) { - root.removeAll(); - } - addPreferencesFromResource(R.xml.security_settings); - root = getPreferenceScreen(); - - // Add category for security status - addPreferencesFromResource(R.xml.security_settings_status); - - // Add options for lock/unlock screen - final int resid = getResIdForLockUnlockScreen(mLockPatternUtils, - mManagedPasswordProvider, MY_USER_ID); - addPreferencesFromResource(resid); - - // DO or PO installed in the user may disallow to change password. - disableIfPasswordQualityManaged(KEY_UNLOCK_SET_OR_CHANGE, MY_USER_ID); - - mProfileChallengeUserId = Utils.getManagedProfileId(mUm, MY_USER_ID); - if (mProfileChallengeUserId != UserHandle.USER_NULL - && mLockPatternUtils.isSeparateProfileChallengeAllowed(mProfileChallengeUserId)) { - addPreferencesFromResource(R.xml.security_settings_profile); - addPreferencesFromResource(R.xml.security_settings_unification); - final int profileResid = getResIdForLockUnlockScreen(mLockPatternUtils, - mManagedPasswordProvider, mProfileChallengeUserId); - addPreferencesFromResource(profileResid); - maybeAddFingerprintPreference(root, mProfileChallengeUserId); - if (!mLockPatternUtils.isSeparateProfileChallengeEnabled(mProfileChallengeUserId)) { - final Preference lockPreference = - root.findPreference(KEY_UNLOCK_SET_OR_CHANGE_PROFILE); - final String summary = getContext().getString( - R.string.lock_settings_profile_unified_summary); - lockPreference.setSummary(summary); - lockPreference.setEnabled(false); - // PO may disallow to change password for the profile, but screen lock and managed - // profile's lock is the same. Disable main "Screen lock" menu. - disableIfPasswordQualityManaged(KEY_UNLOCK_SET_OR_CHANGE, mProfileChallengeUserId); - } else { - // PO may disallow to change profile password, and the profile's password is - // separated from screen lock password. Disable profile specific "Screen lock" menu. - disableIfPasswordQualityManaged(KEY_UNLOCK_SET_OR_CHANGE_PROFILE, - mProfileChallengeUserId); - } - } - - Preference unlockSetOrChange = findPreference(KEY_UNLOCK_SET_OR_CHANGE); - if (unlockSetOrChange instanceof GearPreference) { - ((GearPreference) unlockSetOrChange).setOnGearClickListener(this); - } - - mIsAdmin = mUm.isAdminUser(); - - // Fingerprint and trust agents - int numberOfTrustAgent = 0; - PreferenceGroup securityCategory = (PreferenceGroup) - root.findPreference(KEY_SECURITY_CATEGORY); - if (securityCategory != null) { - maybeAddFingerprintPreference(securityCategory, UserHandle.myUserId()); - numberOfTrustAgent = addTrustAgentSettings(securityCategory); - setLockscreenPreferencesSummary(securityCategory); - } - - mVisiblePatternProfile = - (SwitchPreference) root.findPreference(KEY_VISIBLE_PATTERN_PROFILE); - mUnifyProfile = (RestrictedSwitchPreference) root.findPreference(KEY_UNIFICATION); - - // Append the rest of the settings - addPreferencesFromResource(R.xml.security_settings_misc); - - // Do not display SIM lock for devices without an Icc card - TelephonyManager tm = TelephonyManager.getDefault(); - CarrierConfigManager cfgMgr = (CarrierConfigManager) - getActivity().getSystemService(Context.CARRIER_CONFIG_SERVICE); - PersistableBundle b = cfgMgr.getConfig(); - if (!mIsAdmin || !isSimIccReady() || - b.getBoolean(CarrierConfigManager.KEY_HIDE_SIM_LOCK_SETTINGS_BOOL)) { - root.removePreference(root.findPreference(KEY_SIM_LOCK)); - } else { - // Disable SIM lock if there is no ready SIM card. - root.findPreference(KEY_SIM_LOCK).setEnabled(isSimReady()); - } - if (Settings.System.getInt(getContentResolver(), - Settings.System.LOCK_TO_APP_ENABLED, 0) != 0) { - root.findPreference(KEY_SCREEN_PINNING).setSummary( - getResources().getString(R.string.switch_on_text)); - } - - // Encryption status of device - if (LockPatternUtils.isDeviceEncryptionEnabled()) { - root.findPreference(KEY_ENCRYPTION_AND_CREDENTIALS).setSummary( - R.string.encryption_and_credential_settings_summary); - } else { - root.findPreference(KEY_ENCRYPTION_AND_CREDENTIALS).setSummary( - R.string.summary_placeholder); - } - - // Show password - mShowPassword = (SwitchPreference) root.findPreference(KEY_SHOW_PASSWORD); - - // Credential storage - final UserManager um = (UserManager) getActivity().getSystemService(Context.USER_SERVICE); - - // Advanced Security features - initTrustAgentPreference(root, numberOfTrustAgent); - - PreferenceGroup securityStatusPreferenceGroup = - (PreferenceGroup) root.findPreference(KEY_SECURITY_STATUS); - final List tilePrefs = mDashboardFeatureProvider.getPreferencesForCategory( - getActivity(), getPrefContext(), getMetricsCategory(), - CategoryKey.CATEGORY_SECURITY); - int numSecurityStatusPrefs = 0; - if (tilePrefs != null && !tilePrefs.isEmpty()) { - for (Preference preference : tilePrefs) { - if (!TextUtils.isEmpty(preference.getKey()) - && preference.getKey().startsWith(SECURITY_STATUS_KEY_PREFIX)) { - // Injected security status settings are placed under the Security status - // category. - securityStatusPreferenceGroup.addPreference(preference); - numSecurityStatusPrefs++; - } else { - // Other injected settings are placed under the Security preference screen. - root.addPreference(preference); - } - } - } - - if (numSecurityStatusPrefs == 0) { - root.removePreference(securityStatusPreferenceGroup); - } else if (numSecurityStatusPrefs > 0) { - // Update preference data with tile data. Security feature provider only updates the - // data if it actually needs to be changed. - mSecurityFeatureProvider.updatePreferences(getActivity(), root, - mDashboardFeatureProvider.getTilesForCategory( - CategoryKey.CATEGORY_SECURITY)); - } - - for (int i = 0; i < SWITCH_PREFERENCE_KEYS.length; i++) { - final Preference pref = findPreference(SWITCH_PREFERENCE_KEYS[i]); - if (pref != null) pref.setOnPreferenceChangeListener(this); - } - - mLocationcontroller.displayPreference(root); - mManageDeviceAdminPreferenceController.updateState( - root.findPreference(KEY_MANAGE_DEVICE_ADMIN)); - mEnterprisePrivacyPreferenceController.displayPreference(root); - final Preference enterprisePrivacyPreference = root.findPreference( - mEnterprisePrivacyPreferenceController.getPreferenceKey()); - mEnterprisePrivacyPreferenceController.updateState(enterprisePrivacyPreference); - - return root; - } - - @VisibleForTesting - void initTrustAgentPreference(PreferenceScreen root, int numberOfTrustAgent) { - Preference manageAgents = root.findPreference(KEY_MANAGE_TRUST_AGENTS); - if (manageAgents != null) { - if (!mLockPatternUtils.isSecure(MY_USER_ID)) { - manageAgents.setEnabled(false); - manageAgents.setSummary(R.string.disabled_because_no_backup_security); - } else if (numberOfTrustAgent > 0) { - manageAgents.setSummary(getActivity().getResources().getQuantityString( - R.plurals.manage_trust_agents_summary_on, - numberOfTrustAgent, numberOfTrustAgent)); - } else { - manageAgents.setSummary(R.string.manage_trust_agents_summary); - } - } - } - - @VisibleForTesting - void setLockscreenPreferencesSummary(PreferenceGroup group) { - final Preference lockscreenPreferences = group.findPreference(KEY_LOCKSCREEN_PREFERENCES); - if (lockscreenPreferences != null) { - lockscreenPreferences.setSummary( - LockScreenNotificationPreferenceController.getSummaryResource(getContext())); - } - } - - /* - * Sets the preference as disabled by admin if PASSWORD_QUALITY_MANAGED is set. - * The preference must be a RestrictedPreference. - */ - private void disableIfPasswordQualityManaged(String preferenceKey, int userId) { - final EnforcedAdmin admin = RestrictedLockUtils.checkIfPasswordQualityIsSet( - getActivity(), userId); - if (admin != null && mDPM.getPasswordQuality(admin.component, userId) == - DevicePolicyManager.PASSWORD_QUALITY_MANAGED) { - final RestrictedPreference pref = - (RestrictedPreference) getPreferenceScreen().findPreference(preferenceKey); - pref.setDisabledByAdmin(admin); - } - } - - private void maybeAddFingerprintPreference(PreferenceGroup securityCategory, int userId) { - Preference fingerprintPreference = - FingerprintSettings.getFingerprintPreferenceForUser( - securityCategory.getContext(), userId); - if (fingerprintPreference != null) { - securityCategory.addPreference(fingerprintPreference); - } - } - - // Return the number of trust agents being added - private int addTrustAgentSettings(PreferenceGroup securityCategory) { - final boolean hasSecurity = mLockPatternUtils.isSecure(MY_USER_ID); - final List agents = mTrustAgentManager.getActiveTrustAgents( - getActivity(), mLockPatternUtils); - for (TrustAgentComponentInfo agent : agents) { - final RestrictedPreference trustAgentPreference = - new RestrictedPreference(securityCategory.getContext()); - trustAgentPreference.setKey(KEY_TRUST_AGENT); - trustAgentPreference.setTitle(agent.title); - trustAgentPreference.setSummary(agent.summary); - // Create intent for this preference. - Intent intent = new Intent(); - intent.setComponent(agent.componentName); - intent.setAction(Intent.ACTION_MAIN); - trustAgentPreference.setIntent(intent); - // Add preference to the settings menu. - securityCategory.addPreference(trustAgentPreference); - - trustAgentPreference.setDisabledByAdmin(agent.admin); - if (!trustAgentPreference.isDisabledByAdmin() && !hasSecurity) { - trustAgentPreference.setEnabled(false); - trustAgentPreference.setSummary(R.string.disabled_because_no_backup_security); - } - } - return agents.size(); - } - - /* Return true if a there is a Slot that has Icc. - */ - private boolean isSimIccReady() { - TelephonyManager tm = TelephonyManager.getDefault(); - final List subInfoList = - mSubscriptionManager.getActiveSubscriptionInfoList(); - - if (subInfoList != null) { - for (SubscriptionInfo subInfo : subInfoList) { - if (tm.hasIccCard(subInfo.getSimSlotIndex())) { - return true; - } - } - } - - return false; - } - - /* Return true if a SIM is ready for locking. - * TODO: consider adding to TelephonyManager or SubscritpionManasger. - */ - private boolean isSimReady() { - int simState = TelephonyManager.SIM_STATE_UNKNOWN; - final List subInfoList = - mSubscriptionManager.getActiveSubscriptionInfoList(); - if (subInfoList != null) { - for (SubscriptionInfo subInfo : subInfoList) { - simState = TelephonyManager.getDefault().getSimState(subInfo.getSimSlotIndex()); - if((simState != TelephonyManager.SIM_STATE_ABSENT) && - (simState != TelephonyManager.SIM_STATE_UNKNOWN)){ - return true; - } - } - } - return false; - } - - @Override - public void onGearClick(GearPreference p) { - if (KEY_UNLOCK_SET_OR_CHANGE.equals(p.getKey())) { - startFragment(this, ScreenLockSettings.class.getName(), 0, 0, null); - } - } - - @Override - public void onSaveInstanceState(Bundle outState) { - super.onSaveInstanceState(outState); - if (mTrustAgentClickIntent != null) { - outState.putParcelable(TRUST_AGENT_CLICK_INTENT, mTrustAgentClickIntent); - } - } - - @Override - public void onResume() { - super.onResume(); - - // Make sure we reload the preference hierarchy since some of these settings - // depend on others... - createPreferenceHierarchy(); - - if (mVisiblePatternProfile != null) { - mVisiblePatternProfile.setChecked(mLockPatternUtils.isVisiblePatternEnabled( - mProfileChallengeUserId)); - } - - updateUnificationPreference(); - - if (mShowPassword != null) { - mShowPassword.setChecked(Settings.System.getInt(getContentResolver(), - Settings.System.TEXT_SHOW_PASSWORD, 1) != 0); - } - - mLocationcontroller.updateSummary(); - } - - @VisibleForTesting - void updateUnificationPreference() { - if (mUnifyProfile != null) { - final boolean separate = - mLockPatternUtils.isSeparateProfileChallengeEnabled(mProfileChallengeUserId); - mUnifyProfile.setChecked(!separate); - if (separate) { - mUnifyProfile.setDisabledByAdmin(RestrictedLockUtils.checkIfRestrictionEnforced( - getContext(), UserManager.DISALLOW_UNIFIED_PASSWORD, - mProfileChallengeUserId)); - } - } - } - - @Override - public boolean onPreferenceTreeClick(Preference preference) { - final String key = preference.getKey(); - if (KEY_UNLOCK_SET_OR_CHANGE.equals(key)) { - // TODO(b/35930129): Remove once existing password can be passed into vold directly. - // Currently we need this logic to ensure that the QUIET_MODE is off for any work - // profile with unified challenge on FBE-enabled devices. Otherwise, vold would not be - // able to complete the operation due to the lack of (old) encryption key. - if (mProfileChallengeUserId != UserHandle.USER_NULL - && !mLockPatternUtils.isSeparateProfileChallengeEnabled(mProfileChallengeUserId) - && StorageManager.isFileEncryptedNativeOnly()) { - if (Utils.startQuietModeDialogIfNecessary(this.getActivity(), mUm, - mProfileChallengeUserId)) { - return false; - } - } - startFragment(this, ChooseLockGenericFragment.class.getName(), - R.string.lock_settings_picker_title, SET_OR_CHANGE_LOCK_METHOD_REQUEST, null); - } else if (KEY_UNLOCK_SET_OR_CHANGE_PROFILE.equals(key)) { - if (Utils.startQuietModeDialogIfNecessary(this.getActivity(), mUm, - mProfileChallengeUserId)) { - return false; - } - Bundle extras = new Bundle(); - extras.putInt(Intent.EXTRA_USER_ID, mProfileChallengeUserId); - startFragment(this, ChooseLockGenericFragment.class.getName(), - R.string.lock_settings_picker_title_profile, - SET_OR_CHANGE_LOCK_METHOD_REQUEST_PROFILE, extras); - } else if (KEY_TRUST_AGENT.equals(key)) { - ChooseLockSettingsHelper helper = - new ChooseLockSettingsHelper(this.getActivity(), this); - mTrustAgentClickIntent = preference.getIntent(); - boolean confirmationLaunched = helper.launchConfirmationActivity( - CHANGE_TRUST_AGENT_SETTINGS, preference.getTitle()); - if (!confirmationLaunched&& mTrustAgentClickIntent != null) { - // If this returns false, it means no password confirmation is required. - startActivity(mTrustAgentClickIntent); - mTrustAgentClickIntent = null; - } - } else { - // If we didn't handle it, let preferences handle it. - return super.onPreferenceTreeClick(preference); - } - return true; - } - - /** - * see confirmPatternThenDisableAndClear - */ - @Override - public void onActivityResult(int requestCode, int resultCode, Intent data) { - super.onActivityResult(requestCode, resultCode, data); - if (requestCode == CHANGE_TRUST_AGENT_SETTINGS && resultCode == Activity.RESULT_OK) { - if (mTrustAgentClickIntent != null) { - startActivity(mTrustAgentClickIntent); - mTrustAgentClickIntent = null; - } - return; - } else if (requestCode == UNIFY_LOCK_CONFIRM_DEVICE_REQUEST - && resultCode == Activity.RESULT_OK) { - mCurrentDevicePassword = - data.getStringExtra(ChooseLockSettingsHelper.EXTRA_KEY_PASSWORD); - launchConfirmProfileLockForUnification(); - return; - } else if (requestCode == UNIFY_LOCK_CONFIRM_PROFILE_REQUEST - && resultCode == Activity.RESULT_OK) { - mCurrentProfilePassword = - data.getStringExtra(ChooseLockSettingsHelper.EXTRA_KEY_PASSWORD); - unifyLocks(); - return; - } else if (requestCode == UNUNIFY_LOCK_CONFIRM_DEVICE_REQUEST - && resultCode == Activity.RESULT_OK) { - ununifyLocks(); - return; - } - createPreferenceHierarchy(); - } - - private void launchConfirmDeviceLockForUnification() { - final String title = getActivity().getString( - R.string.unlock_set_unlock_launch_picker_title); - final ChooseLockSettingsHelper helper = - new ChooseLockSettingsHelper(getActivity(), this); - if (!helper.launchConfirmationActivity( - UNIFY_LOCK_CONFIRM_DEVICE_REQUEST, title, true, MY_USER_ID)) { - launchConfirmProfileLockForUnification(); - } - } - - private void launchConfirmProfileLockForUnification() { - final String title = getActivity().getString( - R.string.unlock_set_unlock_launch_picker_title_profile); - final ChooseLockSettingsHelper helper = - new ChooseLockSettingsHelper(getActivity(), this); - if (!helper.launchConfirmationActivity( - UNIFY_LOCK_CONFIRM_PROFILE_REQUEST, title, true, mProfileChallengeUserId)) { - unifyLocks(); - createPreferenceHierarchy(); - } - } - - private void unifyLocks() { - int profileQuality = - mLockPatternUtils.getKeyguardStoredPasswordQuality(mProfileChallengeUserId); - if (profileQuality == DevicePolicyManager.PASSWORD_QUALITY_SOMETHING) { - mLockPatternUtils.saveLockPattern( - LockPatternUtils.stringToPattern(mCurrentProfilePassword), - mCurrentDevicePassword, MY_USER_ID); - } else { - mLockPatternUtils.saveLockPassword( - mCurrentProfilePassword, mCurrentDevicePassword, - profileQuality, MY_USER_ID); - } - mLockPatternUtils.setSeparateProfileChallengeEnabled(mProfileChallengeUserId, false, - mCurrentProfilePassword); - final boolean profilePatternVisibility = - mLockPatternUtils.isVisiblePatternEnabled(mProfileChallengeUserId); - mLockPatternUtils.setVisiblePatternEnabled(profilePatternVisibility, MY_USER_ID); - mCurrentDevicePassword = null; - mCurrentProfilePassword = null; - } - - private void unifyUncompliantLocks() { - mLockPatternUtils.setSeparateProfileChallengeEnabled(mProfileChallengeUserId, false, - mCurrentProfilePassword); - startFragment(this, ChooseLockGenericFragment.class.getName(), - R.string.lock_settings_picker_title, SET_OR_CHANGE_LOCK_METHOD_REQUEST, null); - } - - private void ununifyLocks() { - Bundle extras = new Bundle(); - extras.putInt(Intent.EXTRA_USER_ID, mProfileChallengeUserId); - startFragment(this, - ChooseLockGenericFragment.class.getName(), - R.string.lock_settings_picker_title_profile, - SET_OR_CHANGE_LOCK_METHOD_REQUEST_PROFILE, extras); - } - - @Override - public boolean onPreferenceChange(Preference preference, Object value) { - boolean result = true; - final String key = preference.getKey(); - final LockPatternUtils lockPatternUtils = mChooseLockSettingsHelper.utils(); - if (KEY_VISIBLE_PATTERN_PROFILE.equals(key)) { - if (Utils.startQuietModeDialogIfNecessary(this.getActivity(), mUm, - mProfileChallengeUserId)) { - return false; - } - lockPatternUtils.setVisiblePatternEnabled((Boolean) value, mProfileChallengeUserId); - } else if (KEY_UNIFICATION.equals(key)) { - if (Utils.startQuietModeDialogIfNecessary(this.getActivity(), mUm, - mProfileChallengeUserId)) { - return false; - } - if ((Boolean) value) { - final boolean compliantForDevice = - (mLockPatternUtils.getKeyguardStoredPasswordQuality(mProfileChallengeUserId) - >= DevicePolicyManager.PASSWORD_QUALITY_SOMETHING - && mLockPatternUtils.isSeparateProfileChallengeAllowedToUnify( - mProfileChallengeUserId)); - UnificationConfirmationDialog dialog = - UnificationConfirmationDialog.newIntance(compliantForDevice); - dialog.show(getChildFragmentManager(), TAG_UNIFICATION_DIALOG); - } else { - final String title = getActivity().getString( - R.string.unlock_set_unlock_launch_picker_title); - final ChooseLockSettingsHelper helper = - new ChooseLockSettingsHelper(getActivity(), this); - if(!helper.launchConfirmationActivity( - UNUNIFY_LOCK_CONFIRM_DEVICE_REQUEST, title, true, MY_USER_ID)) { - ununifyLocks(); - } - } - } else if (KEY_SHOW_PASSWORD.equals(key)) { - Settings.System.putInt(getContentResolver(), Settings.System.TEXT_SHOW_PASSWORD, - ((Boolean) value) ? 1 : 0); - lockPatternUtils.setVisiblePasswordEnabled((Boolean) value, MY_USER_ID); - } - return result; + protected String getLogTag() { + return TAG; } @Override @@ -758,206 +76,95 @@ public class SecuritySettings extends SettingsPreferenceFragment return R.string.help_url_security; } + @Override + protected List getPreferenceControllers(Context context) { + return buildPreferenceControllers(context, getLifecycle(), this /* host*/); + } + + /** + * see confirmPatternThenDisableAndClear + */ + @Override + public void onActivityResult(int requestCode, int resultCode, Intent data) { + if (getPreferenceController(TrustAgentListPreferenceController.class) + .handleActivityResult(requestCode, resultCode)) { + return; + } + if (getPreferenceController(LockUnificationPreferenceController.class) + .handleActivityResult(requestCode, resultCode, data)) { + return; + } + super.onActivityResult(requestCode, resultCode, data); + } + + void launchConfirmDeviceLockForUnification() { + getPreferenceController(LockUnificationPreferenceController.class) + .launchConfirmDeviceLockForUnification(); + } + + void unifyUncompliantLocks() { + getPreferenceController(LockUnificationPreferenceController.class).unifyUncompliantLocks(); + } + + void updateUnificationPreference() { + getPreferenceController(LockUnificationPreferenceController.class).updateState(null); + } + + private static List buildPreferenceControllers(Context context, + Lifecycle lifecycle, SecuritySettings host) { + final List controllers = new ArrayList<>(); + controllers.add(new LocationPreferenceController(context, lifecycle)); + controllers.add(new ManageDeviceAdminPreferenceController(context)); + controllers.add(new EnterprisePrivacyPreferenceController(context)); + controllers.add(new ManageTrustAgentsPreferenceController(context)); + controllers.add(new ScreenPinningPreferenceController(context)); + controllers.add(new SimLockPreferenceController(context)); + controllers.add(new ShowPasswordPreferenceController(context)); + controllers.add(new FingerprintStatusPreferenceController(context)); + controllers.add(new EncryptionStatusPreferenceController(context, + PREF_KEY_ENCRYPTION_SECURITY_PAGE)); + controllers.add(new TrustAgentListPreferenceController(context, host, lifecycle)); + controllers.add(new LockScreenPreferenceController(context, lifecycle)); + controllers.add(new ChangeScreenLockPreferenceController(context, host)); + + final List profileSecurityControllers = new ArrayList<>(); + profileSecurityControllers.add(new ChangeProfileScreenLockPreferenceController( + context, host)); + profileSecurityControllers.add(new LockUnificationPreferenceController(context, host)); + profileSecurityControllers.add(new VisiblePatternProfilePreferenceController( + context, lifecycle)); + profileSecurityControllers.add(new FingerprintProfileStatusPreferenceController(context)); + controllers.add(new PreferenceCategoryController(context, "security_category_profile", + profileSecurityControllers)); + controllers.addAll(profileSecurityControllers); + + return controllers; + } + /** * For Search. Please keep it in sync when updating "createPreferenceHierarchy()" */ public static final SearchIndexProvider SEARCH_INDEX_DATA_PROVIDER = - new SecuritySearchIndexProvider(); + new BaseSearchIndexProvider() { - private static class SecuritySearchIndexProvider extends BaseSearchIndexProvider { - - // TODO (b/68001777) Refactor indexing to include all XML and block other settings. - - @Override - public List getXmlResourcesToIndex( - Context context, boolean enabled) { - final List index = new ArrayList<>(); - - final LockPatternUtils lockPatternUtils = new LockPatternUtils(context); - final ManagedLockPasswordProvider managedPasswordProvider = - ManagedLockPasswordProvider.get(context, MY_USER_ID); - final DevicePolicyManager dpm = (DevicePolicyManager) - context.getSystemService(Context.DEVICE_POLICY_SERVICE); - final UserManager um = UserManager.get(context); - final int profileUserId = Utils.getManagedProfileId(um, MY_USER_ID); - - // To add option for unlock screen, user's password must not be managed and - // must not be unified with managed profile, whose password is managed. - if (!isPasswordManaged(MY_USER_ID, context, dpm) - && (profileUserId == UserHandle.USER_NULL - || lockPatternUtils.isSeparateProfileChallengeAllowed(profileUserId) - || !isPasswordManaged(profileUserId, context, dpm))) { - // Add options for lock/unlock screen - final int resId = getResIdForLockUnlockScreen(lockPatternUtils, - managedPasswordProvider, MY_USER_ID); - index.add(getSearchResource(context, resId)); - } - - if (profileUserId != UserHandle.USER_NULL - && lockPatternUtils.isSeparateProfileChallengeAllowed(profileUserId) - && !isPasswordManaged(profileUserId, context, dpm)) { - index.add(getSearchResource(context, getResIdForLockUnlockScreen( - lockPatternUtils, managedPasswordProvider, profileUserId))); - } - - // Append the rest of the settings - index.add(getSearchResource(context, R.xml.security_settings_misc)); - - return index; - } - - private SearchIndexableResource getSearchResource(Context context, int xmlResId) { - final SearchIndexableResource sir = new SearchIndexableResource(context); - sir.xmlResId = xmlResId; - return sir; - } - - private boolean isPasswordManaged(int userId, Context context, DevicePolicyManager dpm) { - final EnforcedAdmin admin = RestrictedLockUtils.checkIfPasswordQualityIsSet( - context, userId); - return admin != null && dpm.getPasswordQuality(admin.component, userId) == - DevicePolicyManager.PASSWORD_QUALITY_MANAGED; - } - - @Override - public List getRawDataToIndex(Context context, boolean enabled) { - final List result = new ArrayList(); - final Resources res = context.getResources(); - - final String screenTitle = res.getString(R.string.security_settings_title); - - SearchIndexableRaw data = new SearchIndexableRaw(context); - data.title = screenTitle; - data.key = "security_settings_screen"; - data.screenTitle = screenTitle; - result.add(data); - - final UserManager um = UserManager.get(context); - - // Fingerprint - final FingerprintManager fpm = Utils.getFingerprintManagerOrNull(context); - if (fpm != null && fpm.isHardwareDetected()) { - // This catches the title which can be overloaded in an overlay - data = new SearchIndexableRaw(context); - data.title = res.getString(R.string.security_settings_fingerprint_preference_title); - data.key = "security_fingerprint"; - data.screenTitle = screenTitle; - result.add(data); - // Fallback for when the above doesn't contain "fingerprint" - data = new SearchIndexableRaw(context); - data.title = res.getString(R.string.fingerprint_manage_category_title); - data.key = "security_managed_fingerprint"; - data.screenTitle = screenTitle; - result.add(data); - } - - final LockPatternUtils lockPatternUtils = new LockPatternUtils(context); - final int profileUserId = Utils.getManagedProfileId(um, MY_USER_ID); - if (profileUserId != UserHandle.USER_NULL - && lockPatternUtils.isSeparateProfileChallengeAllowed(profileUserId)) { - if (lockPatternUtils.getKeyguardStoredPasswordQuality(profileUserId) - >= DevicePolicyManager.PASSWORD_QUALITY_SOMETHING - && lockPatternUtils.isSeparateProfileChallengeAllowedToUnify( - profileUserId)) { - data = new SearchIndexableRaw(context); - data.title = res.getString(R.string.lock_settings_profile_unification_title); - data.key = "security_use_one_lock"; - data.screenTitle = screenTitle; - result.add(data); + @Override + public List getXmlResourcesToIndex( + Context context, boolean enabled) { + final List index = new ArrayList<>(); + // Append the rest of the settings + final SearchIndexableResource sir = new SearchIndexableResource(context); + sir.xmlResId = R.xml.security_dashboard_settings; + index.add(sir); + return index; } - } - return result; - } - @Override - public List getNonIndexableKeys(Context context) { - final List keys = super.getNonIndexableKeys(context); - - LockPatternUtils lockPatternUtils = new LockPatternUtils(context); - - // Do not display SIM lock for devices without an Icc card - final UserManager um = UserManager.get(context); - final TelephonyManager tm = TelephonyManager.from(context); - if (!um.isAdminUser() || !tm.hasIccCard()) { - keys.add(KEY_SIM_LOCK); - } - - // TrustAgent settings disappear when the user has no primary security. - if (!lockPatternUtils.isSecure(MY_USER_ID)) { - keys.add(KEY_TRUST_AGENT); - keys.add(KEY_MANAGE_TRUST_AGENTS); - } - - if (!(new EnterprisePrivacyPreferenceController(context)) - .isAvailable()) { - keys.add(KEY_ENTERPRISE_PRIVACY); - } - - // Duplicate in special app access - keys.add(KEY_MANAGE_DEVICE_ADMIN); - // Duplicates between parent-child - keys.add(KEY_LOCATION); - keys.add(KEY_ENCRYPTION_AND_CREDENTIALS); - keys.add(KEY_SCREEN_PINNING); - keys.add(KEY_LOCATION_SCANNING); - - return keys; - } - } - - public static class UnificationConfirmationDialog extends InstrumentedDialogFragment { - private static final String EXTRA_COMPLIANT = "compliant"; - - public static UnificationConfirmationDialog newIntance(boolean compliant) { - UnificationConfirmationDialog dialog = new UnificationConfirmationDialog(); - Bundle args = new Bundle(); - args.putBoolean(EXTRA_COMPLIANT, compliant); - dialog.setArguments(args); - return dialog; - } - - @Override - public void show(FragmentManager manager, String tag) { - if (manager.findFragmentByTag(tag) == null) { - // Prevent opening multiple dialogs if tapped on button quickly - super.show(manager, tag); - } - } - - @Override - public Dialog onCreateDialog(Bundle savedInstanceState) { - final SecuritySettings parentFragment = ((SecuritySettings) getParentFragment()); - final boolean compliant = getArguments().getBoolean(EXTRA_COMPLIANT); - return new AlertDialog.Builder(getActivity()) - .setTitle(R.string.lock_settings_profile_unification_dialog_title) - .setMessage(compliant ? R.string.lock_settings_profile_unification_dialog_body - : R.string.lock_settings_profile_unification_dialog_uncompliant_body) - .setPositiveButton( - compliant ? R.string.lock_settings_profile_unification_dialog_confirm - : R.string.lock_settings_profile_unification_dialog_uncompliant_confirm, - (dialog, whichButton) -> { - if (compliant) { - parentFragment.launchConfirmDeviceLockForUnification(); - } else { - parentFragment.unifyUncompliantLocks(); - } - } - ) - .setNegativeButton(R.string.cancel, null) - .create(); - } - - @Override - public void onDismiss(DialogInterface dialog) { - super.onDismiss(dialog); - ((SecuritySettings) getParentFragment()).updateUnificationPreference(); - } - - @Override - public int getMetricsCategory() { - return MetricsEvent.DIALOG_UNIFICATION_CONFIRMATION; - } - } + @Override + public List getPreferenceControllers(Context + context) { + return buildPreferenceControllers(context, null /* lifecycle */, + null /* host*/); + } + }; static class SummaryProvider implements SummaryLoader.SummaryProvider { @@ -973,13 +180,13 @@ public class SecuritySettings extends SettingsPreferenceFragment public void setListening(boolean listening) { if (listening) { final FingerprintManager fpm = - Utils.getFingerprintManagerOrNull(mContext); + Utils.getFingerprintManagerOrNull(mContext); if (fpm != null && fpm.isHardwareDetected()) { mSummaryLoader.setSummary(this, - mContext.getString(R.string.security_dashboard_summary)); + mContext.getString(R.string.security_dashboard_summary)); } else { mSummaryLoader.setSummary(this, mContext.getString( - R.string.security_dashboard_summary_no_fingerprint)); + R.string.security_dashboard_summary_no_fingerprint)); } } } @@ -987,11 +194,10 @@ public class SecuritySettings extends SettingsPreferenceFragment public static final SummaryLoader.SummaryProviderFactory SUMMARY_PROVIDER_FACTORY = new SummaryLoader.SummaryProviderFactory() { - @Override - public SummaryLoader.SummaryProvider createSummaryProvider(Activity activity, - SummaryLoader summaryLoader) { - return new SummaryProvider(activity, summaryLoader); - } - }; - + @Override + public SummaryLoader.SummaryProvider createSummaryProvider(Activity activity, + SummaryLoader summaryLoader) { + return new SummaryProvider(activity, summaryLoader); + } + }; } diff --git a/src/com/android/settings/security/SecuritySettingsV2.java b/src/com/android/settings/security/SecuritySettingsV2.java deleted file mode 100644 index 323c0f4c87e..00000000000 --- a/src/com/android/settings/security/SecuritySettingsV2.java +++ /dev/null @@ -1,188 +0,0 @@ -package com.android.settings.security; - -import static com.android.settings.security.EncryptionStatusPreferenceController - .PREF_KEY_ENCRYPTION_SECURITY_PAGE; - -import android.app.Activity; -import android.content.Context; -import android.content.Intent; -import android.hardware.fingerprint.FingerprintManager; -import android.provider.SearchIndexableResource; - -import com.android.internal.logging.nano.MetricsProto; -import com.android.settings.R; -import com.android.settings.Utils; -import com.android.settings.dashboard.DashboardFragment; -import com.android.settings.dashboard.SummaryLoader; -import com.android.settings.enterprise.EnterprisePrivacyPreferenceController; -import com.android.settings.enterprise.ManageDeviceAdminPreferenceController; -import com.android.settings.fingerprint.FingerprintProfileStatusPreferenceController; -import com.android.settings.fingerprint.FingerprintStatusPreferenceController; -import com.android.settings.location.LocationPreferenceController; -import com.android.settings.search.BaseSearchIndexProvider; -import com.android.settings.security.screenlock.LockScreenPreferenceController; -import com.android.settings.security.trustagent.ManageTrustAgentsPreferenceController; -import com.android.settings.security.trustagent.TrustAgentListPreferenceController; -import com.android.settings.widget.PreferenceCategoryController; -import com.android.settingslib.core.AbstractPreferenceController; -import com.android.settingslib.core.lifecycle.Lifecycle; - -import java.util.ArrayList; -import java.util.List; - -public class SecuritySettingsV2 extends DashboardFragment { - - private static final String TAG = "SecuritySettingsV2"; - - public static final int SET_OR_CHANGE_LOCK_METHOD_REQUEST = 123; - public static final int CHANGE_TRUST_AGENT_SETTINGS = 126; - public static final int SET_OR_CHANGE_LOCK_METHOD_REQUEST_PROFILE = 127; - public static final int UNIFY_LOCK_CONFIRM_DEVICE_REQUEST = 128; - public static final int UNIFY_LOCK_CONFIRM_PROFILE_REQUEST = 129; - public static final int UNUNIFY_LOCK_CONFIRM_DEVICE_REQUEST = 130; - - @Override - public int getMetricsCategory() { - return MetricsProto.MetricsEvent.SECURITY; - } - - @Override - protected int getPreferenceScreenResId() { - return R.xml.security_settings_v2; - } - - @Override - protected String getLogTag() { - return TAG; - } - - @Override - public int getHelpResource() { - return R.string.help_url_security; - } - - @Override - protected List getPreferenceControllers(Context context) { - return buildPreferenceControllers(context, getLifecycle(), this /* host*/); - } - - /** - * see confirmPatternThenDisableAndClear - */ - @Override - public void onActivityResult(int requestCode, int resultCode, Intent data) { - if (getPreferenceController(TrustAgentListPreferenceController.class) - .handleActivityResult(requestCode, resultCode)) { - return; - } - if (getPreferenceController(LockUnificationPreferenceController.class) - .handleActivityResult(requestCode, resultCode, data)) { - return; - } - super.onActivityResult(requestCode, resultCode, data); - } - - void launchConfirmDeviceLockForUnification() { - getPreferenceController(LockUnificationPreferenceController.class) - .launchConfirmDeviceLockForUnification(); - } - - void unifyUncompliantLocks() { - getPreferenceController(LockUnificationPreferenceController.class).unifyUncompliantLocks(); - } - - void updateUnificationPreference() { - getPreferenceController(LockUnificationPreferenceController.class).updateState(null); - } - - private static List buildPreferenceControllers(Context context, - Lifecycle lifecycle, SecuritySettingsV2 host) { - final List controllers = new ArrayList<>(); - controllers.add(new LocationPreferenceController(context, lifecycle)); - controllers.add(new ManageDeviceAdminPreferenceController(context)); - controllers.add(new EnterprisePrivacyPreferenceController(context)); - controllers.add(new ManageTrustAgentsPreferenceController(context)); - controllers.add(new ScreenPinningPreferenceController(context)); - controllers.add(new SimLockPreferenceController(context)); - controllers.add(new ShowPasswordPreferenceController(context)); - controllers.add(new FingerprintStatusPreferenceController(context)); - controllers.add(new EncryptionStatusPreferenceController(context, - PREF_KEY_ENCRYPTION_SECURITY_PAGE)); - controllers.add(new TrustAgentListPreferenceController(context, host, lifecycle)); - controllers.add(new LockScreenPreferenceController(context, lifecycle)); - controllers.add(new ChangeScreenLockPreferenceController(context, host)); - - final List profileSecurityControllers = new ArrayList<>(); - profileSecurityControllers.add(new ChangeProfileScreenLockPreferenceController( - context, host)); - profileSecurityControllers.add(new LockUnificationPreferenceController(context, host)); - profileSecurityControllers.add(new VisiblePatternProfilePreferenceController( - context, lifecycle)); - profileSecurityControllers.add(new FingerprintProfileStatusPreferenceController(context)); - controllers.add(new PreferenceCategoryController(context, "security_category_profile", - profileSecurityControllers)); - controllers.addAll(profileSecurityControllers); - - return controllers; - } - - /** - * For Search. Please keep it in sync when updating "createPreferenceHierarchy()" - */ - public static final SearchIndexProvider SEARCH_INDEX_DATA_PROVIDER = - new BaseSearchIndexProvider() { - - @Override - public List getXmlResourcesToIndex( - Context context, boolean enabled) { - final List index = new ArrayList<>(); - // Append the rest of the settings - final SearchIndexableResource sir = new SearchIndexableResource(context); - sir.xmlResId = R.xml.security_settings_v2; - index.add(sir); - return index; - } - - @Override - public List getPreferenceControllers(Context - context) { - return buildPreferenceControllers(context, null /* lifecycle */, - null /* host*/); - } - }; - - static class SummaryProvider implements SummaryLoader.SummaryProvider { - - private final Context mContext; - private final SummaryLoader mSummaryLoader; - - public SummaryProvider(Context context, SummaryLoader summaryLoader) { - mContext = context; - mSummaryLoader = summaryLoader; - } - - @Override - public void setListening(boolean listening) { - if (listening) { - final FingerprintManager fpm = - Utils.getFingerprintManagerOrNull(mContext); - if (fpm != null && fpm.isHardwareDetected()) { - mSummaryLoader.setSummary(this, - mContext.getString(R.string.security_dashboard_summary)); - } else { - mSummaryLoader.setSummary(this, mContext.getString( - R.string.security_dashboard_summary_no_fingerprint)); - } - } - } - } - - public static final SummaryLoader.SummaryProviderFactory SUMMARY_PROVIDER_FACTORY = - new SummaryLoader.SummaryProviderFactory() { - @Override - public SummaryLoader.SummaryProvider createSummaryProvider(Activity activity, - SummaryLoader summaryLoader) { - return new SummaryProvider(activity, summaryLoader); - } - }; -} diff --git a/src/com/android/settings/security/UnificationConfirmationDialog.java b/src/com/android/settings/security/UnificationConfirmationDialog.java index 482e26880ee..029e64f3fe3 100644 --- a/src/com/android/settings/security/UnificationConfirmationDialog.java +++ b/src/com/android/settings/security/UnificationConfirmationDialog.java @@ -40,7 +40,7 @@ public class UnificationConfirmationDialog extends InstrumentedDialogFragment { return dialog; } - public void show(SecuritySettingsV2 host) { + public void show(SecuritySettings host) { final FragmentManager manager = host.getChildFragmentManager(); if (manager.findFragmentByTag(TAG_UNIFICATION_DIALOG) == null) { // Prevent opening multiple dialogs if tapped on button quickly @@ -50,7 +50,7 @@ public class UnificationConfirmationDialog extends InstrumentedDialogFragment { @Override public Dialog onCreateDialog(Bundle savedInstanceState) { - final SecuritySettingsV2 parentFragment = ((SecuritySettingsV2) getParentFragment()); + final SecuritySettings parentFragment = ((SecuritySettings) getParentFragment()); final boolean compliant = getArguments().getBoolean(EXTRA_COMPLIANT); return new AlertDialog.Builder(getActivity()) .setTitle(R.string.lock_settings_profile_unification_dialog_title) @@ -75,7 +75,7 @@ public class UnificationConfirmationDialog extends InstrumentedDialogFragment { @Override public void onDismiss(DialogInterface dialog) { super.onDismiss(dialog); - ((SecuritySettingsV2) getParentFragment()).updateUnificationPreference(); + ((SecuritySettings) getParentFragment()).updateUnificationPreference(); } @Override diff --git a/src/com/android/settings/security/trustagent/TrustAgentListPreferenceController.java b/src/com/android/settings/security/trustagent/TrustAgentListPreferenceController.java index 0c591ede39d..ec81aad75ff 100644 --- a/src/com/android/settings/security/trustagent/TrustAgentListPreferenceController.java +++ b/src/com/android/settings/security/trustagent/TrustAgentListPreferenceController.java @@ -16,7 +16,7 @@ package com.android.settings.security.trustagent; -import static com.android.settings.security.SecuritySettingsV2.CHANGE_TRUST_AGENT_SETTINGS; +import static com.android.settings.security.SecuritySettings.CHANGE_TRUST_AGENT_SETTINGS; import android.app.Activity; import android.content.Context; @@ -35,7 +35,7 @@ import com.android.settings.core.PreferenceControllerMixin; import com.android.settings.overlay.FeatureFactory; import com.android.settings.password.ChooseLockSettingsHelper; import com.android.settings.security.SecurityFeatureProvider; -import com.android.settings.security.SecuritySettingsV2; +import com.android.settings.security.SecuritySettings; import com.android.settingslib.RestrictedPreference; import com.android.settingslib.core.AbstractPreferenceController; import com.android.settingslib.core.lifecycle.Lifecycle; @@ -59,12 +59,12 @@ public class TrustAgentListPreferenceController extends AbstractPreferenceContro private final LockPatternUtils mLockPatternUtils; private final TrustAgentManager mTrustAgentManager; - private final SecuritySettingsV2 mHost; + private final SecuritySettings mHost; private Intent mTrustAgentClickIntent; private PreferenceCategory mSecurityCategory; - public TrustAgentListPreferenceController(Context context, SecuritySettingsV2 host, + public TrustAgentListPreferenceController(Context context, SecuritySettings host, Lifecycle lifecycle) { super(context); final SecurityFeatureProvider provider = FeatureFactory.getFactory(context) diff --git a/tests/robotests/assets/grandfather_not_in_search_index_provider_registry b/tests/robotests/assets/grandfather_not_in_search_index_provider_registry index 6a831b0a234..666b224558a 100644 --- a/tests/robotests/assets/grandfather_not_in_search_index_provider_registry +++ b/tests/robotests/assets/grandfather_not_in_search_index_provider_registry @@ -1,3 +1,2 @@ com.android.settings.display.ScreenZoomPreferenceFragmentForSetupWizard -com.android.settings.search.indexing.FakeSettingsFragment -com.android.settings.security.SecuritySettings \ No newline at end of file +com.android.settings.search.indexing.FakeSettingsFragment \ No newline at end of file diff --git a/tests/robotests/src/com/android/settings/core/XmlControllerAttributeTest.java b/tests/robotests/src/com/android/settings/core/XmlControllerAttributeTest.java index e6ca59b26c2..e69b97ef0c0 100644 --- a/tests/robotests/src/com/android/settings/core/XmlControllerAttributeTest.java +++ b/tests/robotests/src/com/android/settings/core/XmlControllerAttributeTest.java @@ -19,7 +19,6 @@ import com.android.settings.search.SearchFeatureProvider; import com.android.settings.search.SearchFeatureProviderImpl; import com.android.settings.search.XmlParserUtils; import com.android.settings.security.SecuritySettings; -import com.android.settings.security.SecuritySettingsV2; import com.android.settings.testutils.FakeFeatureFactory; import com.android.settings.testutils.SettingsRobolectricTestRunner; @@ -32,7 +31,6 @@ import org.robolectric.annotation.Config; import org.xmlpull.v1.XmlPullParser; import java.lang.reflect.Constructor; -import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; @@ -47,25 +45,13 @@ public class XmlControllerAttributeTest { // List of classes that are too hard to mock in order to retrieve xml information. private final List illegalClasses = new ArrayList<>( Arrays.asList( - SecuritySettings.class, - SecuritySettingsV2.class + SecuritySettings.class )); // List of XML that could be retrieved from the illegalClasses list. private final List whitelistXml = new ArrayList<>( Arrays.asList( - R.xml.security_settings_misc, - R.xml.security_settings_lockscreen_profile, - R.xml.security_settings_lockscreen, - R.xml.security_settings_chooser, - R.xml.security_settings_pattern_profile, - R.xml.security_settings_pin_profile, - R.xml.security_settings_password_profile, - R.xml.security_settings_pattern, - R.xml.security_settings_pin, - R.xml.security_settings_password, - R.xml.security_settings, - R.xml.security_settings_status + R.xml.security_dashboard_settings )); private static final String NO_VALID_CONSTRUCTOR_ERROR = diff --git a/tests/robotests/src/com/android/settings/security/LockUnificationPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/security/LockUnificationPreferenceControllerTest.java index 7a5a9fa6b50..2b612e1ae9a 100644 --- a/tests/robotests/src/com/android/settings/security/LockUnificationPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/security/LockUnificationPreferenceControllerTest.java @@ -55,7 +55,7 @@ public class LockUnificationPreferenceControllerTest { @Mock private PreferenceScreen mScreen; @Mock - private SecuritySettingsV2 mHost; + private SecuritySettings mHost; private FakeFeatureFactory mFeatureFactory; private Context mContext; diff --git a/tests/robotests/src/com/android/settings/security/SecurityFeatureProviderImplTest.java b/tests/robotests/src/com/android/settings/security/SecurityFeatureProviderImplTest.java index 627ecf507dc..86ba40fd431 100644 --- a/tests/robotests/src/com/android/settings/security/SecurityFeatureProviderImplTest.java +++ b/tests/robotests/src/com/android/settings/security/SecurityFeatureProviderImplTest.java @@ -16,192 +16,51 @@ package com.android.settings.security; -import static org.mockito.Matchers.any; -import static org.mockito.Matchers.anyInt; -import static org.mockito.Matchers.anyString; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.spy; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.verifyNoMoreInteractions; -import static org.mockito.Mockito.when; +import static com.google.common.truth.Truth.assertThat; import android.content.Context; -import android.content.Intent; import android.content.pm.PackageManager; -import android.content.res.Resources; -import android.graphics.drawable.Drawable; -import android.os.Bundle; -import android.support.v7.preference.Preference; -import android.support.v7.preference.PreferenceScreen; -import com.android.settings.R; +import com.android.internal.widget.LockPatternUtils; import com.android.settings.TestConfig; +import com.android.settings.security.trustagent.TrustAgentManager; import com.android.settings.testutils.SettingsRobolectricTestRunner; -import com.android.settings.testutils.shadow.ShadowTileUtils; -import com.android.settingslib.drawer.DashboardCategory; -import com.android.settingslib.drawer.Tile; -import com.android.settingslib.drawer.TileUtils; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.robolectric.RuntimeEnvironment; import org.robolectric.annotation.Config; -import org.robolectric.shadows.ShadowLooper; @RunWith(SettingsRobolectricTestRunner.class) @Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION) public class SecurityFeatureProviderImplTest { - private static final String MOCK_KEY = "key"; - private static final String MOCK_SUMMARY = "summary"; - private static final String URI_GET_SUMMARY = "content://package/text/summary"; - private static final String URI_GET_ICON = "content://package/icon/my_icon"; - - @Mock - private Drawable mMockDrawable; - @Mock private Context mContext; - @Mock - private PackageManager mPackageManager; - @Mock - private Resources mResources; - private SecurityFeatureProviderImpl mImpl; @Before public void setUp() throws PackageManager.NameNotFoundException { MockitoAnnotations.initMocks(this); - mContext = spy(RuntimeEnvironment.application); + mContext = RuntimeEnvironment.application; mImpl = new SecurityFeatureProviderImpl(); - when(mContext.getPackageManager()).thenReturn(mPackageManager); - when(mPackageManager.getResourcesForApplication(anyString())).thenReturn(mResources); - when(mResources.getDrawable(anyInt(), any())).thenReturn(mMockDrawable); } @Test - public void updateTilesData_shouldNotProcessEmptyScreenOrTiles() { - mImpl.updatePreferencesToRunOnWorkerThread(mContext, null, null); - ShadowLooper.runUiThreadTasks(); - mImpl.updatePreferencesToRunOnWorkerThread( - mContext, new PreferenceScreen(mContext, null), null); - ShadowLooper.runUiThreadTasks(); - verifyNoMoreInteractions(mPackageManager); + public void getTrustAgentManager_shouldReturnCache() { + final TrustAgentManager m1 = mImpl.getTrustAgentManager(); + final TrustAgentManager m2 = mImpl.getTrustAgentManager(); + + assertThat(m1).isSameAs(m2); } @Test - public void updateTilesData_shouldNotProcessNonMatchingPreference() { - DashboardCategory dashboardCategory = new DashboardCategory(); - dashboardCategory.addTile(new Tile()); - mImpl.updatePreferencesToRunOnWorkerThread( - mContext, getPreferenceScreen(), dashboardCategory); - ShadowLooper.runUiThreadTasks(); - verifyNoMoreInteractions(mPackageManager); + public void getLockPatternUtils_shouldReturnCache() { + final LockPatternUtils l1 = mImpl.getLockPatternUtils(mContext); + final LockPatternUtils l2 = mImpl.getLockPatternUtils(mContext); + + assertThat(l1).isSameAs(l2); } - @Test - public void updateTilesData_shouldNotProcessMatchingPreferenceWithNoData() { - mImpl.updatePreferencesToRunOnWorkerThread( - mContext, getPreferenceScreen(), getDashboardCategory()); - ShadowLooper.runUiThreadTasks(); - verifyNoMoreInteractions(mPackageManager); - } - - @Test - @Config(shadows = { - ShadowTileUtils.class, - }) - public void updateTilesData_shouldUpdateMatchingPreference() { - Bundle bundle = new Bundle(); - bundle.putString(TileUtils.META_DATA_PREFERENCE_ICON_URI, URI_GET_ICON); - bundle.putString(TileUtils.META_DATA_PREFERENCE_SUMMARY_URI, URI_GET_SUMMARY); - - PreferenceScreen screen = getPreferenceScreen(); - DashboardCategory dashboardCategory = getDashboardCategory(); - dashboardCategory.getTile(0).intent = new Intent().setPackage("package"); - dashboardCategory.getTile(0).metaData = bundle; - - mImpl.updatePreferencesToRunOnWorkerThread(mContext, screen, dashboardCategory); - ShadowLooper.runUiThreadTasks(); - verify(screen.findPreference(MOCK_KEY)).setIcon(mMockDrawable); - verify(screen.findPreference(MOCK_KEY)).setSummary(MOCK_SUMMARY); - } - - @Test - @Config(shadows = { - ShadowTileUtils.class, - }) - public void updateTilesData_shouldNotUpdateAlreadyUpdatedPreference() { - Bundle bundle = new Bundle(); - bundle.putString(TileUtils.META_DATA_PREFERENCE_ICON_URI, URI_GET_ICON); - bundle.putString(TileUtils.META_DATA_PREFERENCE_SUMMARY_URI, URI_GET_SUMMARY); - - PreferenceScreen screen = getPreferenceScreen(); - when(screen.findPreference(MOCK_KEY).getSummary()).thenReturn(MOCK_SUMMARY); - when(screen.findPreference(MOCK_KEY).getIcon()).thenReturn(mMockDrawable); - - DashboardCategory dashboardCategory = getDashboardCategory(); - dashboardCategory.getTile(0).intent = new Intent().setPackage("package"); - dashboardCategory.getTile(0).metaData = bundle; - - mImpl.updatePreferencesToRunOnWorkerThread(mContext, screen, dashboardCategory); - ShadowLooper.runUiThreadTasks(); - verify(screen.findPreference(MOCK_KEY), never()).setSummary(anyString()); - } - - @Test - public void initPreferences_shouldLoadDefaults() { - PreferenceScreen screen = getPreferenceScreen(); - DashboardCategory dashboardCategory = getDashboardCategory(); - dashboardCategory.getTile(0).metaData = new Bundle(); - - mImpl.initPreferences(mContext, screen, dashboardCategory); - verify(screen.findPreference(MOCK_KEY)).setIcon(SecurityFeatureProviderImpl.DEFAULT_ICON); - verify(screen.findPreference(MOCK_KEY)) - .setSummary(mContext.getString(R.string.summary_placeholder)); - } - - @Test - @Config(shadows = { - ShadowTileUtils.class, - }) - public void initPreferences_shouldLoadCached() { - Bundle bundle = new Bundle(); - bundle.putString(TileUtils.META_DATA_PREFERENCE_ICON_URI, URI_GET_ICON); - bundle.putString(TileUtils.META_DATA_PREFERENCE_SUMMARY_URI, URI_GET_SUMMARY); - - PreferenceScreen screen = getPreferenceScreen(); - DashboardCategory dashboardCategory = getDashboardCategory(); - dashboardCategory.getTile(0).metaData = bundle; - - SecurityFeatureProviderImpl.sIconCache.put( - URI_GET_ICON, - ShadowTileUtils.getIconFromUri(null, null, null, null)); - SecurityFeatureProviderImpl.sSummaryCache.put( - URI_GET_SUMMARY, - MOCK_SUMMARY); - - mImpl.initPreferences(mContext, screen, dashboardCategory); - verify(screen.findPreference(MOCK_KEY)).setIcon(mMockDrawable); - verify(screen.findPreference(MOCK_KEY)).setSummary(MOCK_SUMMARY); - } - - private PreferenceScreen getPreferenceScreen() { - final PreferenceScreen screen = mock(PreferenceScreen.class); - final Preference pref = mock(Preference.class); - when(screen.findPreference(MOCK_KEY)).thenReturn(pref); - when(pref.getKey()).thenReturn(MOCK_KEY); - return screen; - } - - private static DashboardCategory getDashboardCategory() { - DashboardCategory dashboardCategory = new DashboardCategory(); - Tile tile = new Tile(); - tile.key = MOCK_KEY; - dashboardCategory.addTile(tile); - return dashboardCategory; - } } diff --git a/tests/robotests/src/com/android/settings/security/SecuritySettingsTest.java b/tests/robotests/src/com/android/settings/security/SecuritySettingsTest.java index 3171c3d0dd2..421efe888ec 100644 --- a/tests/robotests/src/com/android/settings/security/SecuritySettingsTest.java +++ b/tests/robotests/src/com/android/settings/security/SecuritySettingsTest.java @@ -16,34 +16,18 @@ package com.android.settings.security; -import static com.google.common.truth.Truth.assertThat; -import static org.mockito.Matchers.anyInt; -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.reset; -import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoMoreInteractions; import static org.mockito.Mockito.when; -import android.app.Activity; import android.content.Context; -import android.os.UserHandle; -import android.os.UserManager; -import android.os.UserManager.EnforcingUser; -import android.support.v7.preference.Preference; -import android.support.v7.preference.PreferenceScreen; +import android.content.pm.PackageManager; +import android.hardware.fingerprint.FingerprintManager; -import com.android.internal.widget.LockPatternUtils; import com.android.settings.R; import com.android.settings.TestConfig; import com.android.settings.dashboard.SummaryLoader; -import com.android.settings.testutils.FakeFeatureFactory; import com.android.settings.testutils.SettingsRobolectricTestRunner; -import com.android.settings.testutils.XmlTestUtils; -import com.android.settings.testutils.shadow.ShadowLockPatternUtils; -import com.android.settings.testutils.shadow.ShadowUserManager; -import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin; -import com.android.settingslib.RestrictedSwitchPreference; import org.junit.Before; import org.junit.Test; @@ -51,123 +35,65 @@ import org.junit.runner.RunWith; import org.mockito.Answers; import org.mockito.Mock; import org.mockito.MockitoAnnotations; -import org.robolectric.RuntimeEnvironment; import org.robolectric.annotation.Config; -import org.robolectric.shadows.ShadowApplication; -import org.robolectric.util.ReflectionHelpers; - -import java.util.Arrays; -import java.util.Collections; -import java.util.List; @RunWith(SettingsRobolectricTestRunner.class) -@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION, - shadows = { - ShadowLockPatternUtils.class, - ShadowUserManager.class, - }) +@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION) public class SecuritySettingsTest { - @Mock(answer = Answers.RETURNS_DEEP_STUBS) private Context mContext; @Mock private SummaryLoader mSummaryLoader; - + @Mock + private FingerprintManager mFingerprintManager; private SecuritySettings.SummaryProvider mSummaryProvider; @Before public void setUp() { MockitoAnnotations.initMocks(this); - FakeFeatureFactory.setupForTest(); + when(mContext.getSystemService(Context.FINGERPRINT_SERVICE)) + .thenReturn(mFingerprintManager); + mSummaryProvider = new SecuritySettings.SummaryProvider(mContext, mSummaryLoader); } @Test - public void testInitTrustAgentPreference_secure_shouldSetSummaryToNumberOfTrustAgent() { - final Preference preference = mock(Preference.class); - final PreferenceScreen screen = mock(PreferenceScreen.class); - when(screen.findPreference(SecuritySettings.KEY_MANAGE_TRUST_AGENTS)) - .thenReturn(preference); - final LockPatternUtils utils = mock(LockPatternUtils.class); - when(utils.isSecure(anyInt())).thenReturn(true); - final Context context = ShadowApplication.getInstance().getApplicationContext(); - final Activity activity = mock(Activity.class); - when(activity.getResources()).thenReturn(context.getResources()); - final SecuritySettings securitySettings = spy(new SecuritySettings()); - when(securitySettings.getActivity()).thenReturn(activity); + public void testSummaryProvider_notListening() { + mSummaryProvider.setListening(false); - ReflectionHelpers.setField(securitySettings, "mLockPatternUtils", utils); - - securitySettings.initTrustAgentPreference(screen, 0); - verify(preference).setSummary(R.string.manage_trust_agents_summary); - - securitySettings.initTrustAgentPreference(screen, 2); - verify(preference).setSummary(context.getResources().getQuantityString( - R.plurals.manage_trust_agents_summary_on, 2, 2)); + verifyNoMoreInteractions(mSummaryLoader); } @Test - public void testNonIndexableKeys_existInXmlLayout() { - final Context context = spy(RuntimeEnvironment.application); - UserManager manager = mock(UserManager.class); - when(manager.isAdminUser()).thenReturn(false); - doReturn(manager).when(context).getSystemService(Context.USER_SERVICE); - final List niks = SecuritySettings.SEARCH_INDEX_DATA_PROVIDER - .getNonIndexableKeys(context); + public void testSummaryProvider_hasFingerPrint_hasStaticSummary() { + when(mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_FINGERPRINT)) + .thenReturn(true); + when(mFingerprintManager.isHardwareDetected()).thenReturn(true); - final List keys = XmlTestUtils.getKeysFromPreferenceXml(context, - R.xml.security_settings_misc); - keys.addAll(XmlTestUtils.getKeysFromPreferenceXml(context, - R.xml.location_settings)); - keys.addAll(XmlTestUtils.getKeysFromPreferenceXml(context, - R.xml.encryption_and_credential)); + mSummaryProvider.setListening(true); - assertThat(keys).containsAllIn(niks); + verify(mContext).getString(R.string.security_dashboard_summary); } @Test - public void testUnifyLockRestriction() { - // Set up instance under test. - final Context context = spy(RuntimeEnvironment.application); - final SecuritySettings securitySettings = spy(new SecuritySettings()); - when(securitySettings.getContext()).thenReturn(context); + public void testSummaryProvider_noFpFeature_shouldSetSummaryWithNoFingerprint() { + when(mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_FINGERPRINT)) + .thenReturn(false); - final int userId = 123; - ReflectionHelpers.setField(securitySettings, "mProfileChallengeUserId", userId); + mSummaryProvider.setListening(true); - final LockPatternUtils utils = mock(LockPatternUtils.class); - when(utils.isSeparateProfileChallengeEnabled(userId)).thenReturn(true); - ReflectionHelpers.setField(securitySettings, "mLockPatternUtils", utils); + verify(mContext).getString(R.string.security_dashboard_summary_no_fingerprint); + } - final RestrictedSwitchPreference unifyProfile = mock(RestrictedSwitchPreference.class); - ReflectionHelpers.setField(securitySettings, "mUnifyProfile", unifyProfile); + @Test + public void testSummaryProvider_noFpHardware_shouldSetSummaryWithNoFingerprint() { + when(mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_FINGERPRINT)) + .thenReturn(true); + when(mFingerprintManager.isHardwareDetected()).thenReturn(false); - // Pretend that no admins enforce the restriction. - ShadowUserManager.getShadow().setUserRestrictionSources( - UserManager.DISALLOW_UNIFIED_PASSWORD, - UserHandle.of(userId), - Collections.emptyList()); + mSummaryProvider.setListening(true); - securitySettings.updateUnificationPreference(); - - verify(unifyProfile).setDisabledByAdmin(null); - - reset(unifyProfile); - - // Pretend that the restriction is enforced by several admins. Having just one would - // require more mocking of implementation details. - final EnforcingUser enforcer1 = new EnforcingUser( - userId, UserManager.RESTRICTION_SOURCE_PROFILE_OWNER); - final EnforcingUser enforcer2 = new EnforcingUser( - UserHandle.USER_SYSTEM, UserManager.RESTRICTION_SOURCE_DEVICE_OWNER); - ShadowUserManager.getShadow().setUserRestrictionSources( - UserManager.DISALLOW_UNIFIED_PASSWORD, - UserHandle.of(userId), - Arrays.asList(enforcer1, enforcer2)); - - securitySettings.updateUnificationPreference(); - - verify(unifyProfile).setDisabledByAdmin(EnforcedAdmin.MULTIPLE_ENFORCED_ADMIN); + verify(mContext).getString(R.string.security_dashboard_summary_no_fingerprint); } } diff --git a/tests/robotests/src/com/android/settings/security/SecuritySettingsV2Test.java b/tests/robotests/src/com/android/settings/security/SecuritySettingsV2Test.java deleted file mode 100644 index f77903b211d..00000000000 --- a/tests/robotests/src/com/android/settings/security/SecuritySettingsV2Test.java +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Copyright (C) 2018 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.security; - -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.verifyNoMoreInteractions; -import static org.mockito.Mockito.when; - -import android.content.Context; -import android.content.pm.PackageManager; -import android.hardware.fingerprint.FingerprintManager; - -import com.android.settings.R; -import com.android.settings.TestConfig; -import com.android.settings.dashboard.SummaryLoader; -import com.android.settings.testutils.SettingsRobolectricTestRunner; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Answers; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; -import org.robolectric.annotation.Config; - -@RunWith(SettingsRobolectricTestRunner.class) -@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION) -public class SecuritySettingsV2Test { - - @Mock(answer = Answers.RETURNS_DEEP_STUBS) - private Context mContext; - @Mock - private SummaryLoader mSummaryLoader; - @Mock - private FingerprintManager mFingerprintManager; - private SecuritySettings.SummaryProvider mSummaryProvider; - - @Before - public void setUp() { - MockitoAnnotations.initMocks(this); - when(mContext.getSystemService(Context.FINGERPRINT_SERVICE)) - .thenReturn(mFingerprintManager); - - mSummaryProvider = new SecuritySettings.SummaryProvider(mContext, mSummaryLoader); - } - - @Test - public void testSummaryProvider_notListening() { - mSummaryProvider.setListening(false); - - verifyNoMoreInteractions(mSummaryLoader); - } - - @Test - public void testSummaryProvider_hasFingerPrint_hasStaticSummary() { - when(mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_FINGERPRINT)) - .thenReturn(true); - when(mFingerprintManager.isHardwareDetected()).thenReturn(true); - - mSummaryProvider.setListening(true); - - verify(mContext).getString(R.string.security_dashboard_summary); - } - - @Test - public void testSummaryProvider_noFpFeature_shouldSetSummaryWithNoFingerprint() { - when(mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_FINGERPRINT)) - .thenReturn(false); - - mSummaryProvider.setListening(true); - - verify(mContext).getString(R.string.security_dashboard_summary_no_fingerprint); - } - - @Test - public void testSummaryProvider_noFpHardware_shouldSetSummaryWithNoFingerprint() { - when(mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_FINGERPRINT)) - .thenReturn(true); - when(mFingerprintManager.isHardwareDetected()).thenReturn(false); - - mSummaryProvider.setListening(true); - - verify(mContext).getString(R.string.security_dashboard_summary_no_fingerprint); - } -} diff --git a/tests/robotests/src/com/android/settings/security/trustagent/TrustAgentListPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/security/trustagent/TrustAgentListPreferenceControllerTest.java index 7dd04c641e9..258833e310a 100644 --- a/tests/robotests/src/com/android/settings/security/trustagent/TrustAgentListPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/security/trustagent/TrustAgentListPreferenceControllerTest.java @@ -40,7 +40,7 @@ import android.support.v7.preference.PreferenceScreen; import com.android.internal.widget.LockPatternUtils; import com.android.settings.TestConfig; import com.android.settings.core.PreferenceControllerMixin; -import com.android.settings.security.SecuritySettingsV2; +import com.android.settings.security.SecuritySettings; import com.android.settings.testutils.FakeFeatureFactory; import com.android.settings.testutils.SettingsRobolectricTestRunner; import com.android.settingslib.core.lifecycle.Lifecycle; @@ -69,7 +69,7 @@ public class TrustAgentListPreferenceControllerTest { @Mock private PreferenceCategory mCategory; @Mock - private SecuritySettingsV2 mFragment; + private SecuritySettings mFragment; private Lifecycle mLifecycle; private LifecycleOwner mLifecycleOwner; diff --git a/tests/uitests/src/com/android/settings/ui/SecuritySettingsLaunchTest.java b/tests/uitests/src/com/android/settings/ui/SecuritySettingsLaunchTest.java index b730690d22c..6803c7e7868 100644 --- a/tests/uitests/src/com/android/settings/ui/SecuritySettingsLaunchTest.java +++ b/tests/uitests/src/com/android/settings/ui/SecuritySettingsLaunchTest.java @@ -66,7 +66,7 @@ public class SecuritySettingsLaunchTest { public void launchSecuritySettings() throws Exception { // Launch Settings SettingsHelper.launchSettingsPage( - InstrumentationRegistry.getContext(), Settings.ACTION_SECURITY_SETTINGS); + InstrumentationRegistry.getTargetContext(), Settings.ACTION_SECURITY_SETTINGS); mHelper.scrollVert(false); for (String category : CATEGORIES) { SettingsTestUtils.assertTitleMatch(mDevice, category); From 0e3225211195c95b17d626f61aa014fc1d40c9ed Mon Sep 17 00:00:00 2001 From: Doris Ling Date: Tue, 23 Jan 2018 12:08:50 -0800 Subject: [PATCH 08/11] Dismiss suggestion when close button is clicked. - add handling to the suggestion card to dismiss the suggestion when the close button is clicked. Bug: 70573674 Test: make RunSettingsRoboTests Change-Id: I8155efc326242abde753a633009e2579a9b3aa9b --- .../settings/dashboard/DashboardAdapterV2.java | 7 ++----- .../dashboard/suggestions/SuggestionAdapterV2.java | 14 ++++++++------ .../suggestions/SuggestionAdapterV2Test.java | 5 ++++- 3 files changed, 14 insertions(+), 12 deletions(-) diff --git a/src/com/android/settings/dashboard/DashboardAdapterV2.java b/src/com/android/settings/dashboard/DashboardAdapterV2.java index 7cd4f38e442..f98b440eff8 100644 --- a/src/com/android/settings/dashboard/DashboardAdapterV2.java +++ b/src/com/android/settings/dashboard/DashboardAdapterV2.java @@ -151,13 +151,10 @@ public class DashboardAdapterV2 extends RecyclerView.Adapter mSuggestionsShownLogged; + private final SuggestionFeatureProvider mSuggestionFeatureProvider; private final SuggestionControllerMixin mSuggestionControllerMixin; private final Callback mCallback; private final CardConfig mConfig; @@ -75,6 +76,7 @@ public class SuggestionAdapterV2 extends RecyclerView.Adapter { + closeButton.setOnClickListener(v -> { + mSuggestionFeatureProvider.dismissSuggestion( + mContext, mSuggestionControllerMixin, suggestion); + if (mCallback != null) { mCallback.onSuggestionClosed(suggestion); - }); - } else { - closeButton.setOnClickListener(null); - } + } + }); } View clickHandler = holder.itemView; diff --git a/tests/robotests/src/com/android/settings/dashboard/suggestions/SuggestionAdapterV2Test.java b/tests/robotests/src/com/android/settings/dashboard/suggestions/SuggestionAdapterV2Test.java index 1e76e2db6a4..dd9d0e499d5 100644 --- a/tests/robotests/src/com/android/settings/dashboard/suggestions/SuggestionAdapterV2Test.java +++ b/tests/robotests/src/com/android/settings/dashboard/suggestions/SuggestionAdapterV2Test.java @@ -200,7 +200,10 @@ public class SuggestionAdapterV2Test { mSuggestionAdapter.onBindViewHolder(mSuggestionHolder, 0); mSuggestionHolder.itemView.findViewById(R.id.close_button).performClick(); - verify(callback).onSuggestionClosed(suggestions.get(0)); + final Suggestion suggestion = suggestions.get(0); + verify(mFeatureFactory.suggestionsFeatureProvider).dismissSuggestion( + mActivity, mSuggestionControllerMixin, suggestion); + verify(callback).onSuggestionClosed(suggestion); } private void setupSuggestions(Context context, List suggestions) { From 26ba7cef8f209f21131bb8a3c2d069156cc36a61 Mon Sep 17 00:00:00 2001 From: Fan Zhang Date: Mon, 29 Jan 2018 13:22:21 -0800 Subject: [PATCH 09/11] Add search keyword for ambient display Change-Id: I725e734e656bf01d4d9a354d01d10717b724d848 Fixes: 71892510 Test: rebuild --- res/values/strings.xml | 3 +++ res/xml/ambient_display_settings.xml | 2 ++ 2 files changed, 5 insertions(+) diff --git a/res/values/strings.xml b/res/values/strings.xml index 711d720fdc1..057422213b5 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -2579,6 +2579,7 @@ Ambient display + Always on / Increased battery usage @@ -6714,6 +6715,8 @@ network, mobile network state, service state, signal strength, mobile network type, roaming, iccid serial number, hardware version android security patch level, baseband version, kernel version + + Ambient display, Lock screen display diff --git a/res/xml/ambient_display_settings.xml b/res/xml/ambient_display_settings.xml index a8ded0d9e77..8bd9bd6e6f0 100644 --- a/res/xml/ambient_display_settings.xml +++ b/res/xml/ambient_display_settings.xml @@ -17,7 +17,9 @@ Date: Fri, 19 Jan 2018 14:43:34 -0800 Subject: [PATCH 10/11] Move force stop button into option menu. - only show 1 button in the app info page - move all handling for the force stop button from AppActionButtonPreferenceController to a new option menu controller Bug: 71778950 Test: make RunSettingsRoboTests Change-Id: Iaa2c9784162a5f1acaaf9e11e3ce988945b40538 --- .../AppActionButtonPreferenceController.java | 55 +---- .../appinfo/AppInfoDashboardFragment.java | 70 ++---- .../ForceStopOptionsMenuController.java | 198 ++++++++++++++++ ...pActionButtonPreferenceControllerTest.java | 82 +------ ...AppHeaderViewPreferenceControllerTest.java | 6 +- .../ForceStopOptionsMenuControllerTest.java | 215 ++++++++++++++++++ 6 files changed, 442 insertions(+), 184 deletions(-) create mode 100644 src/com/android/settings/applications/appinfo/ForceStopOptionsMenuController.java create mode 100644 tests/robotests/src/com/android/settings/applications/appinfo/ForceStopOptionsMenuControllerTest.java diff --git a/src/com/android/settings/applications/appinfo/AppActionButtonPreferenceController.java b/src/com/android/settings/applications/appinfo/AppActionButtonPreferenceController.java index 130138c376f..1a5a285da1e 100644 --- a/src/com/android/settings/applications/appinfo/AppActionButtonPreferenceController.java +++ b/src/com/android/settings/applications/appinfo/AppActionButtonPreferenceController.java @@ -16,18 +16,14 @@ package com.android.settings.applications.appinfo; -import android.app.Activity; import android.app.ActivityManager; import android.app.admin.DevicePolicyManager; -import android.content.BroadcastReceiver; import android.content.ComponentName; import android.content.Context; -import android.content.Intent; import android.content.pm.ApplicationInfo; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; -import android.net.Uri; import android.os.Bundle; import android.os.RemoteException; import android.os.ServiceManager; @@ -35,7 +31,6 @@ import android.os.UserHandle; import android.os.UserManager; import android.support.annotation.VisibleForTesting; import android.support.v7.preference.PreferenceScreen; -import android.util.Log; import android.webkit.IWebViewUpdateService; import com.android.settings.R; @@ -71,16 +66,6 @@ public class AppActionButtonPreferenceController extends BasePreferenceControlle private UserManager mUserManager; private PackageManager mPm; - private final BroadcastReceiver mCheckKillProcessesReceiver = new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - final boolean enabled = getResultCode() != Activity.RESULT_CANCELED; - Log.d(TAG, "Got broadcast response: Restart status for " - + mParent.getAppEntry().info.packageName + " " + enabled); - updateForceStopButton(enabled); - } - }; - public AppActionButtonPreferenceController(Context context, AppInfoDashboardFragment parent, String packageName) { super(context, KEY_ACTION_BUTTONS); @@ -101,9 +86,7 @@ public class AppActionButtonPreferenceController extends BasePreferenceControlle public void displayPreference(PreferenceScreen screen) { super.displayPreference(screen); mActionButtons = ((ActionButtonPreference) screen.findPreference(KEY_ACTION_BUTTONS)) - .setButton2Text(R.string.force_stop) - .setButton2Positive(false) - .setButton2Enabled(false); + .setButton2Visible(false); } @Override @@ -140,7 +123,6 @@ public class AppActionButtonPreferenceController extends BasePreferenceControlle } } - checkForceStop(appEntry, packageInfo); initUninstallButtons(appEntry, packageInfo); } @@ -269,41 +251,6 @@ public class AppActionButtonPreferenceController extends BasePreferenceControlle return disableable; } - private void updateForceStopButton(boolean enabled) { - final boolean disallowedBySystem = RestrictedLockUtils.hasBaseUserRestriction( - mContext, UserManager.DISALLOW_APPS_CONTROL, mUserId); - mActionButtons - .setButton2Enabled(disallowedBySystem ? false : enabled) - .setButton2OnClickListener( - disallowedBySystem ? null : v -> mParent.handleForceStopButtonClick()); - } - - void checkForceStop(AppEntry appEntry, PackageInfo packageInfo) { - if (mDpm.packageHasActiveAdmins(packageInfo.packageName)) { - // User can't force stop device admin. - Log.w(TAG, "User can't force stop device admin"); - updateForceStopButton(false); - } else if (AppUtils.isInstant(packageInfo.applicationInfo)) { - updateForceStopButton(false); - mActionButtons.setButton2Visible(false); - } else if ((appEntry.info.flags & ApplicationInfo.FLAG_STOPPED) == 0) { - // If the app isn't explicitly stopped, then always show the - // force stop button. - Log.w(TAG, "App is not explicitly stopped"); - updateForceStopButton(true); - } else { - final Intent intent = new Intent(Intent.ACTION_QUERY_PACKAGE_RESTART, - Uri.fromParts("package", appEntry.info.packageName, null)); - intent.putExtra(Intent.EXTRA_PACKAGES, new String[] { appEntry.info.packageName }); - intent.putExtra(Intent.EXTRA_UID, appEntry.info.uid); - intent.putExtra(Intent.EXTRA_USER_HANDLE, UserHandle.getUserId(appEntry.info.uid)); - Log.d(TAG, "Sending broadcast to query restart status for " - + appEntry.info.packageName); - mContext.sendOrderedBroadcastAsUser(intent, UserHandle.CURRENT, null, - mCheckKillProcessesReceiver, null, Activity.RESULT_CANCELED, null, null); - } - } - private boolean signaturesMatch(String pkg1, String pkg2) { if (pkg1 != null && pkg2 != null) { try { diff --git a/src/com/android/settings/applications/appinfo/AppInfoDashboardFragment.java b/src/com/android/settings/applications/appinfo/AppInfoDashboardFragment.java index 41c1f7ce05b..a99ba6592c2 100755 --- a/src/com/android/settings/applications/appinfo/AppInfoDashboardFragment.java +++ b/src/com/android/settings/applications/appinfo/AppInfoDashboardFragment.java @@ -19,7 +19,6 @@ package com.android.settings.applications.appinfo; import static com.android.settingslib.RestrictedLockUtils.EnforcedAdmin; import android.app.Activity; -import android.app.ActivityManager; import android.app.AlertDialog; import android.app.Dialog; import android.app.DialogFragment; @@ -45,19 +44,15 @@ import android.util.Log; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; -import android.view.View; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.settings.DeviceAdminAdd; import com.android.settings.R; import com.android.settings.SettingsActivity; import com.android.settings.SettingsPreferenceFragment; -import com.android.settings.Utils; -import com.android.settings.applications.LayoutPreference; import com.android.settings.applications.manageapplications.ManageApplications; import com.android.settings.core.instrumentation.InstrumentedDialogFragment; import com.android.settings.dashboard.DashboardFragment; -import com.android.settings.widget.EntityHeaderController; import com.android.settings.widget.PreferenceCategoryController; import com.android.settings.wrapper.DevicePolicyManagerWrapper; import com.android.settingslib.RestrictedLockUtils; @@ -89,6 +84,7 @@ public class AppInfoDashboardFragment extends DashboardFragment // Menu identifiers private static final int UNINSTALL_ALL_USERS_MENU = 1; private static final int UNINSTALL_UPDATES = 2; + static final int FORCE_STOP_MENU = 3; // Result code identifiers @VisibleForTesting @@ -103,7 +99,7 @@ public class AppInfoDashboardFragment extends DashboardFragment // Dialog identifiers used in showDialog private static final int DLG_BASE = 0; - private static final int DLG_FORCE_STOP = DLG_BASE + 1; + static final int DLG_FORCE_STOP = DLG_BASE + 1; private static final int DLG_DISABLE = DLG_BASE + 2; private static final int DLG_SPECIAL_DISABLE = DLG_BASE + 3; @@ -141,6 +137,7 @@ public class AppInfoDashboardFragment extends DashboardFragment private InstantAppButtonsPreferenceController mInstantAppButtonPreferenceController; private AppActionButtonPreferenceController mAppActionButtonPreferenceController; + private ForceStopOptionsMenuController mForceStopOptionsMenuController; /** * Callback to invoke when app info has been changed. @@ -172,6 +169,9 @@ public class AppInfoDashboardFragment extends DashboardFragment return; } + mForceStopOptionsMenuController = + new ForceStopOptionsMenuController(activity, this /* parent */, mDpm, + mMetricsFeatureProvider, getLifecycle()); setHasOptionsMenu(true); } @@ -268,6 +268,10 @@ public class AppInfoDashboardFragment extends DashboardFragment return mAppEntry; } + void setAppEntry(ApplicationsState.AppEntry appEntry) { + mAppEntry = appEntry; + } + PackageInfo getPackageInfo() { if (mAppEntry == null) { retrieveAppEntry(); @@ -275,6 +279,10 @@ public class AppInfoDashboardFragment extends DashboardFragment return mPackageInfo; } + ApplicationsState getAppState() { + return mState; + } + @Override public void onPackageSizeChanged(String packageName) { if (!TextUtils.equals(packageName, mPackageName)) { @@ -315,6 +323,7 @@ public class AppInfoDashboardFragment extends DashboardFragment if (mFinishing) { return; } + super.onPrepareOptionsMenu(menu); menu.findItem(UNINSTALL_ALL_USERS_MENU).setVisible(shouldShowUninstallForAll(mAppEntry)); mUpdatedSysApp = (mAppEntry.info.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0; final MenuItem uninstallUpdatesItem = menu.findItem(UNINSTALL_UPDATES); @@ -335,7 +344,7 @@ public class AppInfoDashboardFragment extends DashboardFragment uninstallPkg(mAppEntry.info.packageName, false, false); return true; } - return false; + return super.onOptionsItemSelected(item); } @Override @@ -465,18 +474,10 @@ public class AppInfoDashboardFragment extends DashboardFragment }) .setNegativeButton(R.string.dlg_cancel, null) .create(); - case DLG_FORCE_STOP: - return new AlertDialog.Builder(getActivity()) - .setTitle(getActivity().getText(R.string.force_stop_dlg_title)) - .setMessage(getActivity().getText(R.string.force_stop_dlg_text)) - .setPositiveButton(R.string.dlg_ok, new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int which) { - // Force stop - forceStopPackage(mAppEntry.info.packageName); - } - }) - .setNegativeButton(R.string.dlg_cancel, null) - .create(); + } + final AlertDialog dialog = mForceStopOptionsMenuController.createDialog(id); + if (dialog != null) { + return dialog; } return mInstantAppButtonPreferenceController.createDialog(id); } @@ -493,21 +494,6 @@ public class AppInfoDashboardFragment extends DashboardFragment mDisableAfterUninstall = andDisable; } - private void forceStopPackage(String pkgName) { - mMetricsFeatureProvider.action(getContext(), MetricsEvent.ACTION_APP_FORCE_STOP, pkgName); - final ActivityManager am = (ActivityManager) getActivity().getSystemService( - Context.ACTIVITY_SERVICE); - Log.d(TAG, "Stopping package " + pkgName); - am.forceStopPackage(pkgName); - final int userId = UserHandle.getUserId(mAppEntry.info.uid); - mState.invalidatePackage(pkgName, userId); - final AppEntry newEnt = mState.getEntry(pkgName, userId); - if (newEnt != null) { - mAppEntry = newEnt; - } - mAppActionButtonPreferenceController.checkForceStop(mAppEntry, mPackageInfo); - } - public static void startAppInfoFragment(Class fragment, int title, SettingsPreferenceFragment caller, AppEntry appEntry) { // start new fragment to display extended information @@ -568,20 +554,6 @@ public class AppInfoDashboardFragment extends DashboardFragment } } - void handleForceStopButtonClick() { - if (mAppEntry == null) { - setIntentAndFinish(true, true); - return; - } - if (mAppsControlDisallowedAdmin != null && !mAppsControlDisallowedBySystem) { - RestrictedLockUtils.sendShowAdminSupportDetailsIntent( - getActivity(), mAppsControlDisallowedAdmin); - } else { - showDialogInner(DLG_FORCE_STOP, 0); - //forceStopPackage(mAppInfo.packageName); - } - } - /** Returns whether there is only one user on this device, not including the system-only user */ private boolean isSingleUser() { final int userCount = mUserManager.getUserCount(); @@ -679,7 +651,7 @@ public class AppInfoDashboardFragment extends DashboardFragment } } - private void setIntentAndFinish(boolean finish, boolean appChanged) { + void setIntentAndFinish(boolean finish, boolean appChanged) { if (localLOGV) Log.i(TAG, "appChanged="+appChanged); final Intent intent = new Intent(); intent.putExtra(ManageApplications.APP_CHG, appChanged); diff --git a/src/com/android/settings/applications/appinfo/ForceStopOptionsMenuController.java b/src/com/android/settings/applications/appinfo/ForceStopOptionsMenuController.java new file mode 100644 index 00000000000..cf8714795a2 --- /dev/null +++ b/src/com/android/settings/applications/appinfo/ForceStopOptionsMenuController.java @@ -0,0 +1,198 @@ +/* + * Copyright (C) 2018 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.applications.appinfo; + +import static com.android.settings.applications.appinfo.AppInfoDashboardFragment.FORCE_STOP_MENU; +import static com.android.settingslib.RestrictedLockUtils.EnforcedAdmin; + +import android.app.Activity; +import android.app.ActivityManager; +import android.app.AlertDialog; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.DialogInterface; +import android.content.Intent; +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageInfo; +import android.net.Uri; +import android.os.UserHandle; +import android.os.UserManager; +import android.support.annotation.VisibleForTesting; +import android.util.Log; +import android.view.Menu; +import android.view.MenuInflater; +import android.view.MenuItem; + +import com.android.internal.logging.nano.MetricsProto.MetricsEvent; +import com.android.settings.R; +import com.android.settings.wrapper.DevicePolicyManagerWrapper; +import com.android.settingslib.RestrictedLockUtils; +import com.android.settingslib.applications.AppUtils; +import com.android.settingslib.applications.ApplicationsState; +import com.android.settingslib.applications.ApplicationsState.AppEntry; +import com.android.settingslib.core.instrumentation.MetricsFeatureProvider; +import com.android.settingslib.core.lifecycle.Lifecycle; +import com.android.settingslib.core.lifecycle.LifecycleObserver; +import com.android.settingslib.core.lifecycle.events.OnCreateOptionsMenu; +import com.android.settingslib.core.lifecycle.events.OnOptionsItemSelected; +import com.android.settingslib.core.lifecycle.events.OnPrepareOptionsMenu; + +public class ForceStopOptionsMenuController implements LifecycleObserver, OnCreateOptionsMenu, + OnPrepareOptionsMenu, OnOptionsItemSelected { + + private static final String TAG = "ForceStopMenuController"; + + private final Context mContext; + private final AppInfoDashboardFragment mParent; + private final DevicePolicyManagerWrapper mDpm; + private final MetricsFeatureProvider mMetricsFeatureProvider; + + private int mUserId; + private MenuItem mForceStopMenu; + + private final BroadcastReceiver mCheckKillProcessesReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + final boolean enabled = getResultCode() != Activity.RESULT_CANCELED; + Log.d(TAG, "Got broadcast response: Restart status for " + + mParent.getAppEntry().info.packageName + " " + enabled); + enableForceStopMenu(enabled); + } + }; + + public ForceStopOptionsMenuController(Context context, AppInfoDashboardFragment parent, + DevicePolicyManagerWrapper devicePolicyManager, + MetricsFeatureProvider metricsFeatureProvider, Lifecycle lifecycle) { + mContext = context; + mParent = parent; + mDpm = devicePolicyManager; + mMetricsFeatureProvider = metricsFeatureProvider; + mUserId = UserHandle.myUserId(); + if (lifecycle != null) { + lifecycle.addObserver(this); + } + } + + @Override + public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { + menu.add(0, FORCE_STOP_MENU, 2, R.string.force_stop) + .setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER); + } + + @Override + public boolean onOptionsItemSelected(MenuItem menuItem) { + if (menuItem.getItemId() == FORCE_STOP_MENU) { + handleForceStopMenuClick(); + return true; + } + return false; + } + + @Override + public void onPrepareOptionsMenu(Menu menu) { + mForceStopMenu = menu.findItem(FORCE_STOP_MENU); + updateForceStopMenu(mParent.getAppEntry(), mParent.getPackageInfo()); + } + + @VisibleForTesting + void updateForceStopMenu(AppEntry appEntry, PackageInfo packageInfo) { + boolean enabled = false; + if (mDpm.packageHasActiveAdmins(packageInfo.packageName)) { + // User can't force stop device admin. + Log.w(TAG, "User can't force stop device admin"); + } else if (AppUtils.isInstant(packageInfo.applicationInfo)) { + // No force stop for instant app + if (mForceStopMenu != null) { + mForceStopMenu.setVisible(false); + } + } else if ((appEntry.info.flags & ApplicationInfo.FLAG_STOPPED) == 0) { + // If the app isn't explicitly stopped, then always show the + // force stop button. + Log.w(TAG, "App is not explicitly stopped"); + enabled = true; + } else { + final Intent intent = new Intent(Intent.ACTION_QUERY_PACKAGE_RESTART, + Uri.fromParts("package", appEntry.info.packageName, null)); + intent.putExtra(Intent.EXTRA_PACKAGES, new String[] { appEntry.info.packageName }); + intent.putExtra(Intent.EXTRA_UID, appEntry.info.uid); + intent.putExtra(Intent.EXTRA_USER_HANDLE, UserHandle.getUserId(appEntry.info.uid)); + Log.d(TAG, "Sending broadcast to query restart status for " + + appEntry.info.packageName); + mContext.sendOrderedBroadcastAsUser(intent, UserHandle.CURRENT, null, + mCheckKillProcessesReceiver, null, Activity.RESULT_CANCELED, null, null); + } + enableForceStopMenu(enabled); + } + + private void enableForceStopMenu(boolean enabled) { + if (mForceStopMenu != null) { + final boolean disallowedBySystem = RestrictedLockUtils.hasBaseUserRestriction( + mContext, UserManager.DISALLOW_APPS_CONTROL, mUserId); + mForceStopMenu.setEnabled(disallowedBySystem ? false : enabled); + } + } + + @VisibleForTesting + void handleForceStopMenuClick() { + if (mParent.getAppEntry() == null) { + mParent.setIntentAndFinish(true, true); + return; + } + final EnforcedAdmin admin = RestrictedLockUtils.checkIfRestrictionEnforced( + mContext, UserManager.DISALLOW_APPS_CONTROL, mUserId); + final boolean disallowedBySystem = RestrictedLockUtils.hasBaseUserRestriction( + mContext, UserManager.DISALLOW_APPS_CONTROL, mUserId); + if (admin != null && !disallowedBySystem) { + RestrictedLockUtils.sendShowAdminSupportDetailsIntent(mContext, admin); + } else { + mParent.showDialogInner(mParent.DLG_FORCE_STOP, 0); + } + } + + private void forceStopPackage(String pkgName) { + mMetricsFeatureProvider.action(mContext, MetricsEvent.ACTION_APP_FORCE_STOP, pkgName); + final ActivityManager am = (ActivityManager) mContext.getSystemService( + Context.ACTIVITY_SERVICE); + Log.d(TAG, "Stopping package " + pkgName); + am.forceStopPackage(pkgName); + final int userId = UserHandle.getUserId(mParent.getAppEntry().info.uid); + final ApplicationsState appState = mParent.getAppState(); + appState.invalidatePackage(pkgName, userId); + final AppEntry newEnt = appState.getEntry(pkgName, userId); + if (newEnt != null) { + mParent.setAppEntry(newEnt); + } + } + + public AlertDialog createDialog(int id) { + if (id != mParent.DLG_FORCE_STOP) { + return null; + } + return new AlertDialog.Builder(mContext) + .setTitle(mContext.getText(R.string.force_stop_dlg_title)) + .setMessage(mContext.getText(R.string.force_stop_dlg_text)) + .setPositiveButton(R.string.dlg_ok, new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int which) { + // Force stop + forceStopPackage(mParent.getAppEntry().info.packageName); + } + }) + .setNegativeButton(R.string.dlg_cancel, null) + .create(); + } + +} diff --git a/tests/robotests/src/com/android/settings/applications/appinfo/AppActionButtonPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/applications/appinfo/AppActionButtonPreferenceControllerTest.java index 7d5eb318026..70b9cc972d8 100644 --- a/tests/robotests/src/com/android/settings/applications/appinfo/AppActionButtonPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/applications/appinfo/AppActionButtonPreferenceControllerTest.java @@ -18,27 +18,18 @@ package com.android.settings.applications.appinfo; import static com.google.common.truth.Truth.assertThat; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyInt; -import static org.mockito.ArgumentMatchers.argThat; -import static org.mockito.ArgumentMatchers.nullable; import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; -import android.content.BroadcastReceiver; import android.content.Context; -import android.content.Intent; import android.content.pm.ApplicationInfo; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.UserInfo; import android.content.res.Resources; -import android.os.Bundle; -import android.os.Handler; -import android.os.UserHandle; import android.os.UserManager; import android.support.v7.preference.PreferenceScreen; @@ -120,16 +111,14 @@ public class AppActionButtonPreferenceControllerTest { } @Test - public void displayPreference_shouldInitializeForceStopButton() { + public void displayPreference_shouldSetButton2Invisible() { final PreferenceScreen screen = mock(PreferenceScreen.class); final ActionButtonPreference preference = spy(new ActionButtonPreference(mContext)); when(screen.findPreference(mController.getPreferenceKey())).thenReturn(preference); mController.displayPreference(screen); - verify(preference).setButton2Positive(false); - verify(preference).setButton2Text(R.string.force_stop); - verify(preference).setButton2Enabled(false); + verify(preference).setButton2Visible(false); } @Test @@ -138,14 +127,12 @@ public class AppActionButtonPreferenceControllerTest { final ApplicationsState.AppEntry appEntry = mock(ApplicationsState.AppEntry.class); final ApplicationInfo info = new ApplicationInfo(); appEntry.info = info; - doNothing().when(mController).checkForceStop(appEntry, packageInfo); doNothing().when(mController).initUninstallButtons(appEntry, packageInfo); when(mFragment.getAppEntry()).thenReturn(appEntry); when(mFragment.getPackageInfo()).thenReturn(packageInfo); mController.refreshUi(); - verify(mController).checkForceStop(appEntry, packageInfo); verify(mController).initUninstallButtons(appEntry, packageInfo); } @@ -198,71 +185,6 @@ public class AppActionButtonPreferenceControllerTest { assertThat(mController.initUninstallButtonForUserApp()).isFalse(); } - // Tests that we don't show the force stop button for instant apps (they aren't allowed to run - // when they aren't in the foreground). - @Test - public void checkForceStop_instantApps_shouldNotShowForceStop() { - // Make this app appear to be instant. - ReflectionHelpers.setStaticField(AppUtils.class, "sInstantAppDataProvider", - (InstantAppDataProvider) (i -> true)); - final PackageInfo packageInfo = mock(PackageInfo.class); - final ApplicationsState.AppEntry appEntry = mock(ApplicationsState.AppEntry.class); - final ApplicationInfo info = new ApplicationInfo(); - appEntry.info = info; - - mController.checkForceStop(appEntry, packageInfo); - - verify(mController.mActionButtons).setButton2Visible(false); - } - - @Test - public void checkForceStop_hasActiveAdmin_shouldDisableForceStop() { - ReflectionHelpers.setStaticField(AppUtils.class, "sInstantAppDataProvider", - (InstantAppDataProvider) (i -> false)); - final String packageName = "Package1"; - final PackageInfo packageInfo = new PackageInfo(); - packageInfo.packageName = packageName; - final ApplicationsState.AppEntry appEntry = mock(ApplicationsState.AppEntry.class); - when(mDevicePolicyManager.packageHasActiveAdmins(packageName)).thenReturn(true); - - mController.checkForceStop(appEntry, packageInfo); - - verify(mController.mActionButtons).setButton2Enabled(false); - } - - @Test - public void checkForceStop_appRunning_shouldEnableForceStop() { - ReflectionHelpers.setStaticField(AppUtils.class, "sInstantAppDataProvider", - (InstantAppDataProvider) (i -> false)); - final PackageInfo packageInfo = mock(PackageInfo.class); - final ApplicationsState.AppEntry appEntry = mock(ApplicationsState.AppEntry.class); - final ApplicationInfo info = new ApplicationInfo(); - appEntry.info = info; - - mController.checkForceStop(appEntry, packageInfo); - - verify(mController.mActionButtons).setButton2Enabled(true); - } - - @Test - public void checkForceStop_appStopped_shouldQueryPackageRestart() { - ReflectionHelpers.setStaticField(AppUtils.class, "sInstantAppDataProvider", - (InstantAppDataProvider) (i -> false)); - final PackageInfo packageInfo = mock(PackageInfo.class); - final ApplicationsState.AppEntry appEntry = mock(ApplicationsState.AppEntry.class); - final ApplicationInfo info = new ApplicationInfo(); - appEntry.info = info; - info.flags = ApplicationInfo.FLAG_STOPPED; - info.packageName = "com.android.setting"; - - mController.checkForceStop(appEntry, packageInfo); - - verify(mContext).sendOrderedBroadcastAsUser(argThat(intent-> intent != null - && intent.getAction().equals(Intent.ACTION_QUERY_PACKAGE_RESTART)), - any(UserHandle.class), nullable(String.class), any(BroadcastReceiver.class), - nullable(Handler.class), anyInt(), nullable(String.class), nullable(Bundle.class)); - } - @Test public void handleDisableable_appIsHomeApp_buttonShouldNotWork() { final ApplicationInfo info = new ApplicationInfo(); diff --git a/tests/robotests/src/com/android/settings/applications/appinfo/AppHeaderViewPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/applications/appinfo/AppHeaderViewPreferenceControllerTest.java index ee870b748bd..7108ef0820b 100644 --- a/tests/robotests/src/com/android/settings/applications/appinfo/AppHeaderViewPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/applications/appinfo/AppHeaderViewPreferenceControllerTest.java @@ -42,7 +42,9 @@ import com.android.settings.R; import com.android.settings.TestConfig; import com.android.settings.applications.LayoutPreference; import com.android.settings.testutils.SettingsRobolectricTestRunner; +import com.android.settingslib.applications.AppUtils; import com.android.settingslib.applications.ApplicationsState; +import com.android.settingslib.applications.instantapps.InstantAppDataProvider; import com.android.settingslib.core.lifecycle.Lifecycle; import org.junit.Before; @@ -53,6 +55,7 @@ import org.mockito.MockitoAnnotations; import org.robolectric.Robolectric; import org.robolectric.RuntimeEnvironment; import org.robolectric.annotation.Config; +import org.robolectric.util.ReflectionHelpers; @RunWith(SettingsRobolectricTestRunner.class) @Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION) @@ -103,7 +106,8 @@ public class AppHeaderViewPreferenceControllerTest { appEntry.info = info; when(mFragment.getAppEntry()).thenReturn(appEntry); when(mFragment.getPackageInfo()).thenReturn(packageInfo); - + ReflectionHelpers.setStaticField(AppUtils.class, "sInstantAppDataProvider", + (InstantAppDataProvider) (i -> false)); final TextView title = mHeader.findViewById(R.id.entity_header_title); final TextView summary = mHeader.findViewById(R.id.entity_header_summary); diff --git a/tests/robotests/src/com/android/settings/applications/appinfo/ForceStopOptionsMenuControllerTest.java b/tests/robotests/src/com/android/settings/applications/appinfo/ForceStopOptionsMenuControllerTest.java new file mode 100644 index 00000000000..47190086a51 --- /dev/null +++ b/tests/robotests/src/com/android/settings/applications/appinfo/ForceStopOptionsMenuControllerTest.java @@ -0,0 +1,215 @@ +/* + * Copyright (C) 2018 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.applications.appinfo; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.argThat; +import static org.mockito.ArgumentMatchers.nullable; +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager; +import android.os.Bundle; +import android.os.Handler; +import android.os.UserHandle; +import android.os.UserManager; +import android.view.Menu; +import android.view.MenuItem; + +import com.android.settings.R; +import com.android.settings.SettingsActivity; +import com.android.settings.TestConfig; +import com.android.settings.testutils.SettingsRobolectricTestRunner; +import com.android.settings.wrapper.DevicePolicyManagerWrapper; +import com.android.settingslib.applications.AppUtils; +import com.android.settingslib.applications.ApplicationsState.AppEntry; +import com.android.settingslib.applications.instantapps.InstantAppDataProvider; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Answers; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.robolectric.RuntimeEnvironment; +import org.robolectric.annotation.Config; +import org.robolectric.util.ReflectionHelpers; + +@RunWith(SettingsRobolectricTestRunner.class) +@Config( + manifest = TestConfig.MANIFEST_PATH, + sdk = TestConfig.SDK_VERSION +) +public final class ForceStopOptionsMenuControllerTest { + + private static final String PACKAGE_NAME = "test_package_name"; + + @Mock(answer = Answers.RETURNS_DEEP_STUBS) + private UserManager mUserManager; + @Mock + private SettingsActivity mActivity; + @Mock + private DevicePolicyManagerWrapper mDevicePolicyManager; + @Mock + private PackageManager mPackageManager; + + private AppInfoDashboardFragment mFragment; + private ForceStopOptionsMenuController mController; + private Context mShadowContext; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + mShadowContext = spy(RuntimeEnvironment.application); + mFragment = spy(new AppInfoDashboardFragment()); + ReflectionHelpers.setField(mFragment, "mDpm", mDevicePolicyManager); + ReflectionHelpers.setField(mFragment, "mUserManager", mUserManager); + doReturn(mActivity).when(mFragment).getActivity(); + doReturn(mShadowContext).when(mFragment).getContext(); + doReturn(mPackageManager).when(mActivity).getPackageManager(); + when(mShadowContext.getSystemService(Context.USER_SERVICE)).thenReturn(mUserManager); + mController = spy(new ForceStopOptionsMenuController( + mShadowContext, mFragment, mDevicePolicyManager, + null /* metricsFeatureProvider */, null /* lifecycle */)); + + // Default to not considering any apps to be instant (individual tests can override this). + ReflectionHelpers.setStaticField(AppUtils.class, "sInstantAppDataProvider", + (InstantAppDataProvider) (i -> false)); + } + + @Test + public void onCreateOptionsMenu_shouldAddForceStop() { + final Menu menu = mock(Menu.class); + when(menu.add(anyInt(), anyInt(), anyInt(), anyInt())).thenReturn(mock(MenuItem.class)); + + mController.onCreateOptionsMenu(menu, null /* inflater */); + + verify(menu).add(anyInt(), eq(AppInfoDashboardFragment.FORCE_STOP_MENU), anyInt(), + eq(R.string.force_stop)); + } + + @Test + public void onPrepareOptionsMenu_shouldUpdateForceStopMenu() { + final Menu menu = mock(Menu.class); + doNothing().when(mController).updateForceStopMenu(any(), any()); + doReturn(mock(AppEntry.class)).when(mFragment).getAppEntry(); + doReturn(mock(PackageInfo.class)).when(mFragment).getPackageInfo(); + + mController.onPrepareOptionsMenu(menu); + + verify(mController).updateForceStopMenu(any(), any()); + } + + @Test + public void onOptionsItemSelected_shouldHandleForceStopMenuClick() { + doReturn(mock(AppEntry.class)).when(mFragment).getAppEntry(); + doNothing().when(mController).handleForceStopMenuClick(); + final MenuItem menu = mock(MenuItem.class); + when(menu.getItemId()).thenReturn(AppInfoDashboardFragment.FORCE_STOP_MENU); + + mController.onOptionsItemSelected(menu); + + verify(mController).handleForceStopMenuClick(); + } + + // Tests that we don't show the force stop button for instant apps (they aren't allowed to run + // when they aren't in the foreground). + @Test + public void updateForceStopMenu_instantApps_shouldNotShowForceStop() { + when(mDevicePolicyManager.packageHasActiveAdmins(nullable(String.class))).thenReturn(false); + final MenuItem forceStopMenu = mock(MenuItem.class); + ReflectionHelpers.setField(mController, "mForceStopMenu", forceStopMenu); + // Make this app appear to be instant. + ReflectionHelpers.setStaticField(AppUtils.class, "sInstantAppDataProvider", + (InstantAppDataProvider) (i -> true)); + final PackageInfo packageInfo = mock(PackageInfo.class); + final AppEntry appEntry = mock(AppEntry.class); + final ApplicationInfo info = new ApplicationInfo(); + appEntry.info = info; + + mController.updateForceStopMenu(appEntry, packageInfo); + + verify(forceStopMenu).setVisible(false); + } + + @Test + public void updateForceStopMenu_hasActiveAdmin_shouldDisableForceStop() { + when(mDevicePolicyManager.packageHasActiveAdmins(nullable(String.class))).thenReturn(false); + final MenuItem forceStopMenu = mock(MenuItem.class); + ReflectionHelpers.setField(mController, "mForceStopMenu", forceStopMenu); + ReflectionHelpers.setStaticField(AppUtils.class, "sInstantAppDataProvider", + (InstantAppDataProvider) (i -> false)); + final String packageName = "Package1"; + final PackageInfo packageInfo = new PackageInfo(); + packageInfo.packageName = packageName; + final AppEntry appEntry = mock(AppEntry.class); + when(mDevicePolicyManager.packageHasActiveAdmins(packageName)).thenReturn(true); + + mController.updateForceStopMenu(appEntry, packageInfo); + + verify(forceStopMenu).setEnabled(false); + } + + @Test + public void updateForceStopMenu_appRunning_shouldEnableForceStop() { + when(mDevicePolicyManager.packageHasActiveAdmins(nullable(String.class))).thenReturn(false); + final MenuItem forceStopMenu = mock(MenuItem.class); + ReflectionHelpers.setField(mController, "mForceStopMenu", forceStopMenu); + ReflectionHelpers.setStaticField(AppUtils.class, "sInstantAppDataProvider", + (InstantAppDataProvider) (i -> false)); + final PackageInfo packageInfo = mock(PackageInfo.class); + final AppEntry appEntry = mock(AppEntry.class); + final ApplicationInfo info = new ApplicationInfo(); + appEntry.info = info; + + mController.updateForceStopMenu(appEntry, packageInfo); + + verify(forceStopMenu).setEnabled(true); + } + + @Test + public void updateForceStopMenu_appStopped_shouldQueryPackageRestart() { + when(mDevicePolicyManager.packageHasActiveAdmins(nullable(String.class))).thenReturn(false); + ReflectionHelpers.setStaticField(AppUtils.class, "sInstantAppDataProvider", + (InstantAppDataProvider) (i -> false)); + final PackageInfo packageInfo = mock(PackageInfo.class); + final AppEntry appEntry = mock(AppEntry.class); + final ApplicationInfo info = new ApplicationInfo(); + appEntry.info = info; + info.flags = ApplicationInfo.FLAG_STOPPED; + info.packageName = "com.android.setting"; + + mController.updateForceStopMenu(appEntry, packageInfo); + + verify(mShadowContext).sendOrderedBroadcastAsUser(argThat(intent-> intent != null + && intent.getAction().equals(Intent.ACTION_QUERY_PACKAGE_RESTART)), + any(UserHandle.class), nullable(String.class), any(BroadcastReceiver.class), + nullable(Handler.class), anyInt(), nullable(String.class), nullable(Bundle.class)); + } + +} From c04163a76eaad53d4660a16adb5826f539c14649 Mon Sep 17 00:00:00 2001 From: Doris Ling Date: Mon, 29 Jan 2018 13:11:57 -0800 Subject: [PATCH 11/11] Update suggestion card UI. - adjust suggestion card width and padding - tint icon if it is from settings package. Bug: 72330968 Test: visual Change-Id: I4b82d51b3013ad0656d297305e0000958b71e94d --- res/layout/suggestion_container.xml | 2 +- res/layout/suggestion_tile_v2.xml | 4 +- res/layout/suggestion_tile_with_button_v2.xml | 16 +++-- res/values-sw400dp/dimens.xml | 6 +- res/values/dimens.xml | 6 +- .../suggestions/SuggestionAdapterV2.java | 10 ++- .../suggestions/SuggestionAdapterV2Test.java | 69 +++++++++++++++++++ 7 files changed, 96 insertions(+), 17 deletions(-) diff --git a/res/layout/suggestion_container.xml b/res/layout/suggestion_container.xml index 9110c580563..640a91f29d4 100644 --- a/res/layout/suggestion_container.xml +++ b/res/layout/suggestion_container.xml @@ -55,7 +55,7 @@ android:id="@+id/suggestion_list" android:layout_width="match_parent" android:layout_height="wrap_content" - android:paddingTop="18dp" + android:paddingTop="14dp" android:paddingBottom="16dp" android:scrollbars="none"/> diff --git a/res/layout/suggestion_tile_v2.xml b/res/layout/suggestion_tile_v2.xml index e04febb9ed0..a7717b74cb3 100644 --- a/res/layout/suggestion_tile_v2.xml +++ b/res/layout/suggestion_tile_v2.xml @@ -18,7 +18,7 @@ xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:id="@+id/suggestion_card" - android:layout_width="328dp" + android:layout_width="wrap_content" android:layout_height="wrap_content" app:cardPreventCornerOverlap="false" app:cardUseCompatPadding="true" @@ -65,7 +65,7 @@ android:layout_marginEnd="12dp" android:singleLine="true" android:textAppearance="@style/TextAppearance.SuggestionTitleV2" - android:ellipsize="marquee" + android:ellipsize="end" android:fadingEdge="horizontal" /> @@ -37,16 +38,17 @@ 56dp - 380dp - 184dp - 176dp + 384dp + 188dp + 180dp 22dp diff --git a/res/values/dimens.xml b/res/values/dimens.xml index 332deea247f..f9ab8215220 100755 --- a/res/values/dimens.xml +++ b/res/values/dimens.xml @@ -304,9 +304,9 @@ 24dp - 328dp - 158dp - 152dp + 332dp + 162dp + 156dp 16dp 12dp 16dp diff --git a/src/com/android/settings/dashboard/suggestions/SuggestionAdapterV2.java b/src/com/android/settings/dashboard/suggestions/SuggestionAdapterV2.java index 483af924f72..c027f85caeb 100644 --- a/src/com/android/settings/dashboard/suggestions/SuggestionAdapterV2.java +++ b/src/com/android/settings/dashboard/suggestions/SuggestionAdapterV2.java @@ -18,6 +18,8 @@ package com.android.settings.dashboard.suggestions; import android.app.PendingIntent; import android.content.Context; import android.content.res.Resources; +import android.graphics.drawable.Drawable; +import android.graphics.drawable.Icon; import android.os.Bundle; import android.service.settings.suggestions.Suggestion; import android.support.v7.widget.RecyclerView; @@ -34,6 +36,7 @@ import com.android.settings.R; import com.android.settings.dashboard.DashboardAdapterV2.DashboardItemHolder; import com.android.settings.dashboard.DashboardAdapterV2.IconCache; import com.android.settings.overlay.FeatureFactory; +import com.android.settingslib.Utils; import com.android.settingslib.core.instrumentation.MetricsFeatureProvider; import com.android.settingslib.core.lifecycle.Lifecycle; import com.android.settingslib.core.lifecycle.LifecycleObserver; @@ -109,7 +112,12 @@ public class SuggestionAdapterV2 extends RecyclerView.Adapter suggestions = new ArrayList<>(); + suggestions.add(suggestion); + mSuggestionAdapter = new SuggestionAdapterV2(mActivity, mSuggestionControllerMixin, + null /* savedInstanceState */, null /* callback */, null /* lifecycle */); + mSuggestionAdapter.setSuggestions(suggestions); + mSuggestionHolder = mSuggestionAdapter.onCreateViewHolder( + new FrameLayout(RuntimeEnvironment.application), + mSuggestionAdapter.getItemViewType(0)); + DashboardAdapterV2.IconCache cache = mock(DashboardAdapterV2.IconCache.class); + final Drawable drawable = mock(Drawable.class); + when(cache.getIcon(icon)).thenReturn(drawable); + ReflectionHelpers.setField(mSuggestionAdapter, "mCache", cache); + + mSuggestionAdapter.onBindViewHolder(mSuggestionHolder, 0); + + verify(drawable, never()).setTint(anyInt()); + } + + @Test + public void onBindViewHolder_samePackage_shouldTintIcon() + throws PendingIntent.CanceledException { + final Icon icon = mock(Icon.class); + final String packageName = "pkg1"; + when(icon.getResPackage()).thenReturn(packageName); + when(mActivity.getPackageName()).thenReturn(packageName); + final Suggestion suggestion = new Suggestion.Builder(packageName) + .setPendingIntent(mock(PendingIntent.class)) + .setIcon(icon) + .build(); + final List suggestions = new ArrayList<>(); + suggestions.add(suggestion); + mSuggestionAdapter = new SuggestionAdapterV2(mActivity, mSuggestionControllerMixin, + null /* savedInstanceState */, null /* callback */, null /* lifecycle */); + mSuggestionAdapter.setSuggestions(suggestions); + mSuggestionHolder = mSuggestionAdapter.onCreateViewHolder( + new FrameLayout(RuntimeEnvironment.application), + mSuggestionAdapter.getItemViewType(0)); + DashboardAdapterV2.IconCache cache = mock(DashboardAdapterV2.IconCache.class); + final Drawable drawable = mock(Drawable.class); + when(cache.getIcon(icon)).thenReturn(drawable); + ReflectionHelpers.setField(mSuggestionAdapter, "mCache", cache); + TypedArray typedArray = mock(TypedArray.class); + final int colorAccent = 1234; + when(mActivity.obtainStyledAttributes(any())).thenReturn(typedArray); + when(typedArray.getColor(anyInt(), anyInt())).thenReturn(colorAccent); + + mSuggestionAdapter.onBindViewHolder(mSuggestionHolder, 0); + + verify(drawable).setTint(colorAccent); + } + private void setupSuggestions(Context context, List suggestions) { mSuggestionAdapter = new SuggestionAdapterV2(context, mSuggestionControllerMixin, null /* savedInstanceState */, null /* callback */, null /* lifecycle */);