Merge "Update the logic of querying crashed a11y services"
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index c48d51b..62803af 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -2981,6 +2981,8 @@
<intent-filter>
<action android:name="android.service.quicksettings.action.QS_TILE" />
</intent-filter>
+ <meta-data android:name="android.service.quicksettings.BOOLEAN_TILE"
+ android:value="true"/>
</service>
<service
android:name=".development.qstile.DevelopmentTiles$GPUProfiling"
@@ -2991,6 +2993,8 @@
<intent-filter>
<action android:name="android.service.quicksettings.action.QS_TILE" />
</intent-filter>
+ <meta-data android:name="android.service.quicksettings.BOOLEAN_TILE"
+ android:value="true"/>
</service>
<service
android:name=".development.qstile.DevelopmentTiles$ForceRTL"
@@ -3001,6 +3005,8 @@
<intent-filter>
<action android:name="android.service.quicksettings.action.QS_TILE" />
</intent-filter>
+ <meta-data android:name="android.service.quicksettings.BOOLEAN_TILE"
+ android:value="true"/>
</service>
<service
android:name=".development.qstile.DevelopmentTiles$AnimationSpeed"
@@ -3011,6 +3017,8 @@
<intent-filter>
<action android:name="android.service.quicksettings.action.QS_TILE" />
</intent-filter>
+ <meta-data android:name="android.service.quicksettings.BOOLEAN_TILE"
+ android:value="true"/>
</service>
<service
@@ -3022,6 +3030,8 @@
<intent-filter>
<action android:name="android.service.quicksettings.action.QS_TILE" />
</intent-filter>
+ <meta-data android:name="android.service.quicksettings.BOOLEAN_TILE"
+ android:value="true"/>
</service>
<service
@@ -3033,6 +3043,8 @@
<intent-filter>
<action android:name="android.service.quicksettings.action.QS_TILE" />
</intent-filter>
+ <meta-data android:name="android.service.quicksettings.BOOLEAN_TILE"
+ android:value="true"/>
</service>
<activity
@@ -3088,6 +3100,8 @@
</intent-filter>
<meta-data android:name="com.android.settings.FRAGMENT_CLASS"
android:value="com.android.settings.bluetooth.BluetoothDeviceDetailsFragment" />
+ <meta-data android:name="com.android.settings.PRIMARY_PROFILE_CONTROLLED"
+ android:value="true" />
</activity>
<activity android:name=".panel.SettingsPanelActivity"
diff --git a/PREUPLOAD.cfg b/PREUPLOAD.cfg
index 8e1ab2b..883e968 100644
--- a/PREUPLOAD.cfg
+++ b/PREUPLOAD.cfg
@@ -3,3 +3,4 @@
strings_lint_hook = ${REPO_ROOT}/frameworks/base/tools/stringslint/stringslint_sha.sh ${PREUPLOAD_COMMIT}
+checkstyle_hook = ${REPO_ROOT}/prebuilts/checkstyle/checkstyle.py --sha ${PREUPLOAD_COMMIT}
diff --git a/res/drawable/ic_suggestion_close_button.xml b/res/drawable/ic_suggestion_close_button.xml
index 615b215..8b1f0f8 100644
--- a/res/drawable/ic_suggestion_close_button.xml
+++ b/res/drawable/ic_suggestion_close_button.xml
@@ -18,8 +18,10 @@
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
- android:viewportHeight="24.0">
+ android:viewportHeight="24.0"
+ android:tint="?android:attr/colorControlNormal">
+
<path
- android:fillColor="#FF000000"
+ android:fillColor="@android:color/white"
android:pathData="M18.3,5.71a0.996,0.996 0,0 0,-1.41 0L12,10.59 7.11,5.7A0.996,0.996 0,1 0,5.7 7.11L10.59,12 5.7,16.89a0.996,0.996 0,1 0,1.41 1.41L12,13.41l4.89,4.89a0.996,0.996 0,1 0,1.41 -1.41L13.41,12l4.89,-4.89c0.38,-0.38 0.38,-1.02 0,-1.4z"/>
</vector>
diff --git a/res/layout/profile_select_tablayout.xml b/res/layout/profile_select_tablayout.xml
new file mode 100644
index 0000000..afacaae
--- /dev/null
+++ b/res/layout/profile_select_tablayout.xml
@@ -0,0 +1,42 @@
+<!--
+ Copyright (C) 2019 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.
+ -->
+
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ android:theme="@style/Theme.MaterialComponents.DayNight"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical">
+
+ <androidx.viewpager.widget.ViewPager
+ android:id="@+id/view_pager"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <com.google.android.material.tabs.TabLayout
+ android:background="@android:color/transparent"
+ android:id="@+id/tabs"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ app:tabMaxWidth="0dp"
+ app:tabGravity="fill"
+ app:tabMode="fixed"
+ app:tabIndicatorColor="@*android:color/accent_device_default"
+ app:tabSelectedTextColor="@*android:color/accent_device_default"
+ app:tabTextColor="?android:attr/textColorSecondary" />
+ </androidx.viewpager.widget.ViewPager>
+</LinearLayout>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 1f2add0..ed5865a 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -329,11 +329,11 @@
<string name="bluetooth_disable_a2dp_hw_offload_dialog_cancel">Cancel</string>
<!-- Title for Bluetooth device group with media capability group [CHAR LIMIT=none]-->
- <string name="connected_device_available_media_title">Available media devices</string>
+ <string name="connected_device_media_device_title">Media devices</string>
<!-- Title for Bluetooth device group with media capability group [CHAR LIMIT=none]-->
- <string name="connected_device_available_call_title">Available call devices</string>
+ <string name="connected_device_call_device_title">Call devices</string>
<!-- Title for connected device group [CHAR LIMIT=none]-->
- <string name="connected_device_connected_title">Currently connected</string>
+ <string name="connected_device_other_device_title">Other devices</string>
<!-- Title for connected device group [CHAR LIMIT=none]-->
<string name="connected_device_saved_title">Saved devices</string>
<!-- Summary for preference to add a device [CHAR LIMIT=none]-->
@@ -1410,9 +1410,6 @@
<item quantity="other">Must be fewer than <xliff:g id="number" example="17">%d</xliff:g> digits</item>
</plurals>
- <!-- Error shown when in PIN mode and user enters a non-digit -->
- <string name="lockpassword_pin_contains_non_digits">Must contain only digits 0-9</string>
-
<!-- Error shown when in PIN mode and PIN has been used recently. Please keep this string short! -->
<string name="lockpassword_pin_recently_used">Device admin doesn\'t allow using a recent PIN</string>
@@ -1467,6 +1464,11 @@
<item quantity="other">Must contain at least <xliff:g id="count" example="3">%d</xliff:g> non-letter characters</item>
</plurals>
+ <plurals name="lockpassword_password_requires_nonnumerical">
+ <item quantity="one">Must contain at least 1 non-numerical character</item>
+ <item quantity="other">Must contain at least <xliff:g id="count" example="3">%d</xliff:g> non-numerical characters</item>
+ </plurals>
+
<!-- Error shown when in PASSWORD mode and password has been used recently. Please keep this string short! -->
<string name="lockpassword_password_recently_used">Device admin doesn\'t allow using a recent
password</string>
@@ -4685,7 +4687,7 @@
<!-- Title for the accessibility preference category of interaction control services and settings. [CHAR LIMIT=50] -->
<string name="interaction_control_category_title">Interaction controls</string>
<!-- Title for the accessibility preference category of services downloaded by the user. [CHAR LIMIT=50] -->
- <string name="user_installed_services_category_title">Downloaded services</string>
+ <string name="user_installed_services_category_title">Downloaded apps</string>
<!-- Title for the accessibility preference category of settings considered to be experimental, meaning they might be changed or removed in the future. [CHAR LIMIT=50] -->
<string name="experimental_category_title">Experimental</string>
<!-- Title for feature flags dashboard where developers can turn on experimental features [CHAR LIMIT=50] -->
@@ -4809,7 +4811,7 @@
<!-- Title for accessibility preference for configuring touch feedback vibrations. -->
<string name="accessibility_touch_vibration_title">Touch feedback</string>
<!-- Used in the acessibilty service settings to control turning on/off the service entirely -->
- <string name="accessibility_service_master_switch_title">Use service</string>
+ <string name="accessibility_service_master_switch_title">Use <xliff:g id="accessibility_app_name" example="TalkBack">%1$s</xliff:g></string>
<!-- Used in the Color correction settings screen to control turning on/off the feature entirely -->
<string name="accessibility_daltonizer_master_switch_title">Use color correction</string>
<!-- Used in the Captions settings screen to control turning on/off the feature entirely -->
diff --git a/res/xml/accounts_personal_dashboard_settings.xml b/res/xml/accounts_personal_dashboard_settings.xml
new file mode 100644
index 0000000..db57e3d
--- /dev/null
+++ b/res/xml/accounts_personal_dashboard_settings.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2019 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.
+ -->
+
+<PreferenceScreen
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:settings="http://schemas.android.com/apk/res-auto"
+ android:key="user_and_account_settings_screen"
+ android:title="@string/account_dashboard_title"
+ settings:keywords="@string/keywords_accounts">
+
+ <PreferenceCategory
+ android:key="dashboard_tile_placeholder"
+ android:order="30"/>
+
+ <SwitchPreference
+ android:key="auto_sync_account_data"
+ android:title="@string/auto_sync_account_title"
+ android:summary="@string/auto_sync_account_summary"
+ android:order="100"
+ settings:allowDividerAbove="true"/>
+
+ <SwitchPreference
+ android:key="auto_sync_personal_account_data"
+ android:title="@string/account_settings_menu_auto_sync_personal"
+ android:summary="@string/auto_sync_account_summary"
+ android:order="110"/>
+
+</PreferenceScreen>
diff --git a/res/xml/accounts_work_dashboard_settings.xml b/res/xml/accounts_work_dashboard_settings.xml
new file mode 100644
index 0000000..b27357d
--- /dev/null
+++ b/res/xml/accounts_work_dashboard_settings.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2019 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.
+ -->
+
+<PreferenceScreen
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:settings="http://schemas.android.com/apk/res-auto"
+ android:key="user_and_account_settings_screen"
+ android:title="@string/account_dashboard_title"
+ settings:keywords="@string/keywords_accounts">
+
+ <PreferenceCategory
+ android:key="dashboard_tile_placeholder"
+ android:order="30"/>
+
+ <SwitchPreference
+ android:key="auto_sync_account_data"
+ android:title="@string/auto_sync_account_title"
+ android:summary="@string/auto_sync_account_summary"
+ android:order="100"
+ settings:allowDividerAbove="true"/>
+
+ <SwitchPreference
+ android:key="auto_sync_work_account_data"
+ android:title="@string/account_settings_menu_auto_sync_work"
+ android:summary="@string/auto_sync_account_summary"
+ android:order="110"/>
+
+</PreferenceScreen>
diff --git a/res/xml/connected_devices.xml b/res/xml/connected_devices.xml
index a210ea5..0e5afc3 100644
--- a/res/xml/connected_devices.xml
+++ b/res/xml/connected_devices.xml
@@ -28,12 +28,12 @@
<PreferenceCategory
android:key="available_device_list"
- android:title="@string/connected_device_available_media_title"
+ android:title="@string/connected_device_media_device_title"
settings:controller="com.android.settings.connecteddevice.AvailableMediaDeviceGroupController"/>
<PreferenceCategory
android:key="connected_device_list"
- android:title="@string/connected_device_connected_title"
+ android:title="@string/connected_device_other_device_title"
settings:controller="com.android.settings.connecteddevice.ConnectedDeviceGroupController"/>
<com.android.settingslib.RestrictedPreference
diff --git a/res/xml/tether_prefs.xml b/res/xml/tether_prefs.xml
index 3f9b8c8..54c49e8 100644
--- a/res/xml/tether_prefs.xml
+++ b/res/xml/tether_prefs.xml
@@ -23,7 +23,7 @@
<com.android.settings.widget.FixedLineSummaryPreference
android:key="wifi_tether"
android:title="@string/wifi_hotspot_checkbox_text"
- android:summary="@string/summary_two_lines_placeholder"
+ android:summary="@string/summary_placeholder"
android:fragment="com.android.settings.wifi.tether.WifiTetherSettings"
settings:summaryLineCount="2" />
diff --git a/src/com/android/settings/CryptKeeper.java b/src/com/android/settings/CryptKeeper.java
index 05054b4..604333f 100644
--- a/src/com/android/settings/CryptKeeper.java
+++ b/src/com/android/settings/CryptKeeper.java
@@ -727,7 +727,7 @@
public void onPatternDetected(List<LockPatternView.Cell> pattern) {
mLockPatternView.setEnabled(false);
if (pattern.size() >= MIN_LENGTH_BEFORE_REPORT) {
- new DecryptTask().execute(LockPatternUtils.patternToString(pattern));
+ new DecryptTask().execute(new String(LockPatternUtils.patternToByteArray(pattern)));
} else {
// Allow user to make as many of these as they want.
fakeUnlockAttempt(mLockPatternView);
diff --git a/src/com/android/settings/RegulatoryInfoDisplayActivity.java b/src/com/android/settings/RegulatoryInfoDisplayActivity.java
index 4c7515d..20aafc2 100644
--- a/src/com/android/settings/RegulatoryInfoDisplayActivity.java
+++ b/src/com/android/settings/RegulatoryInfoDisplayActivity.java
@@ -60,12 +60,6 @@
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- Resources resources = getResources();
-
- if (!resources.getBoolean(R.bool.config_show_regulatory_info)) {
- finish(); // no regulatory info to display for this device
- }
-
AlertDialog.Builder builder = new AlertDialog.Builder(this)
.setTitle(R.string.regulatory_labels)
.setOnDismissListener(this);
@@ -95,7 +89,8 @@
}
}
- CharSequence regulatoryText = resources.getText(R.string.regulatory_info_text);
+ CharSequence regulatoryText = getResources()
+ .getText(R.string.regulatory_info_text);
if (regulatoryInfoDrawableExists) {
View view = getLayoutInflater().inflate(R.layout.regulatory_info, null);
diff --git a/src/com/android/settings/SettingsActivity.java b/src/com/android/settings/SettingsActivity.java
index 9270a5a..4d813d5 100644
--- a/src/com/android/settings/SettingsActivity.java
+++ b/src/com/android/settings/SettingsActivity.java
@@ -35,6 +35,7 @@
import android.os.UserHandle;
import android.os.UserManager;
import android.text.TextUtils;
+import android.util.FeatureFlagUtils;
import android.util.Log;
import android.view.View;
import android.widget.Button;
@@ -52,11 +53,13 @@
import com.android.internal.util.ArrayUtils;
import com.android.settings.Settings.WifiSettingsActivity;
import com.android.settings.applications.manageapplications.ManageApplications;
+import com.android.settings.core.FeatureFlags;
import com.android.settings.core.OnActivityResultListener;
import com.android.settings.core.SettingsBaseActivity;
import com.android.settings.core.SubSettingLauncher;
import com.android.settings.core.gateway.SettingsGateway;
import com.android.settings.dashboard.DashboardFeatureProvider;
+import com.android.settings.dashboard.profileselector.ProfileFragmentBridge;
import com.android.settings.homepage.TopLevelSettings;
import com.android.settings.overlay.FeatureFactory;
import com.android.settings.wfd.WifiDisplaySettings;
@@ -565,7 +568,15 @@
throw new IllegalArgumentException("Invalid fragment for this activity: "
+ fragmentName);
}
- Fragment f = Fragment.instantiate(this, fragmentName, args);
+ Fragment f = null;
+ if (FeatureFlagUtils.isEnabled(this, FeatureFlags.PERSONAL_WORK_PROFILE)
+ && UserManager.get(this).getUserProfiles().size() > 1
+ && ProfileFragmentBridge.FRAGMENT_MAP.get(fragmentName) != null) {
+ f = Fragment.instantiate(this, ProfileFragmentBridge.FRAGMENT_MAP.get(fragmentName),
+ args);
+ } else {
+ f = Fragment.instantiate(this, fragmentName, args);
+ }
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
transaction.replace(R.id.main_content, f);
if (titleResId > 0) {
diff --git a/src/com/android/settings/accessibility/AccessibilityShortcutPreferenceFragment.java b/src/com/android/settings/accessibility/AccessibilityShortcutPreferenceFragment.java
index 95a2b76..ab855bc 100644
--- a/src/com/android/settings/accessibility/AccessibilityShortcutPreferenceFragment.java
+++ b/src/com/android/settings/accessibility/AccessibilityShortcutPreferenceFragment.java
@@ -34,6 +34,7 @@
import com.android.internal.accessibility.AccessibilityShortcutController;
import com.android.settings.R;
+import com.android.settings.widget.SwitchBar;
import com.android.settings.search.BaseSearchIndexProvider;
import com.android.settingslib.search.Indexable;
import com.android.settingslib.accessibility.AccessibilityUtils;
@@ -126,6 +127,13 @@
updatePreferences();
}
+ @Override
+ protected void updateSwitchBarText(SwitchBar switchBar) {
+ final String switchBarText = getString(R.string.accessibility_service_master_switch_title,
+ getString(R.string.accessibility_global_gesture_preference_title));
+ switchBar.setSwitchBarText(switchBarText, switchBarText);
+ }
+
private void updatePreferences() {
ContentResolver cr = getContentResolver();
Context context = getContext();
diff --git a/src/com/android/settings/accessibility/ToggleAccessibilityServicePreferenceFragment.java b/src/com/android/settings/accessibility/ToggleAccessibilityServicePreferenceFragment.java
index 1556bec..f30af54 100644
--- a/src/com/android/settings/accessibility/ToggleAccessibilityServicePreferenceFragment.java
+++ b/src/com/android/settings/accessibility/ToggleAccessibilityServicePreferenceFragment.java
@@ -44,6 +44,7 @@
import com.android.internal.widget.LockPatternUtils;
import com.android.settings.R;
import com.android.settings.password.ConfirmDeviceCredentialActivity;
+import com.android.settings.widget.SwitchBar;
import com.android.settings.widget.ToggleSwitch;
import com.android.settings.widget.ToggleSwitch.OnBeforeCheckedChangeListener;
import com.android.settingslib.accessibility.AccessibilityUtils;
@@ -211,6 +212,15 @@
}
}
+ @Override
+ protected void updateSwitchBarText(SwitchBar switchBar) {
+ final AccessibilityServiceInfo info = getAccessibilityServiceInfo();
+ final String switchBarText = (info == null) ? "" :
+ getString(R.string.accessibility_service_master_switch_title,
+ info.getResolveInfo().loadLabel(getPackageManager()));
+ switchBar.setSwitchBarText(switchBarText, switchBarText);
+ }
+
private void updateSwitchBarToggleSwitch() {
final boolean checked = AccessibilityUtils.getEnabledServicesFromSettings(getActivity())
.contains(mComponentName);
diff --git a/src/com/android/settings/accessibility/ToggleAutoclickPreferenceFragment.java b/src/com/android/settings/accessibility/ToggleAutoclickPreferenceFragment.java
index df72cff..45dd39e 100644
--- a/src/com/android/settings/accessibility/ToggleAutoclickPreferenceFragment.java
+++ b/src/com/android/settings/accessibility/ToggleAutoclickPreferenceFragment.java
@@ -172,6 +172,13 @@
return false;
}
+ @Override
+ protected void updateSwitchBarText(SwitchBar switchBar) {
+ final String switchBarText = getString(R.string.accessibility_service_master_switch_title,
+ getString(R.string.accessibility_autoclick_preference_title));
+ switchBar.setSwitchBarText(switchBarText, switchBarText);
+ }
+
/**
* Converts seek bar preference progress value to autoclick delay associated with it.
*/
diff --git a/src/com/android/settings/accessibility/ToggleDaltonizerPreferenceFragment.java b/src/com/android/settings/accessibility/ToggleDaltonizerPreferenceFragment.java
index c5376eb..e02a74a 100644
--- a/src/com/android/settings/accessibility/ToggleDaltonizerPreferenceFragment.java
+++ b/src/com/android/settings/accessibility/ToggleDaltonizerPreferenceFragment.java
@@ -105,8 +105,9 @@
@Override
protected void updateSwitchBarText(SwitchBar switchBar) {
- switchBar.setSwitchBarText(R.string.accessibility_daltonizer_master_switch_title,
- R.string.accessibility_daltonizer_master_switch_title);
+ final String switchBarText = getString(R.string.accessibility_service_master_switch_title,
+ getString(R.string.accessibility_display_daltonizer_preference_title));
+ switchBar.setSwitchBarText(switchBarText, switchBarText);
}
private void initPreferences() {
diff --git a/src/com/android/settings/accessibility/ToggleFeaturePreferenceFragment.java b/src/com/android/settings/accessibility/ToggleFeaturePreferenceFragment.java
index 314a577..a4b1878 100644
--- a/src/com/android/settings/accessibility/ToggleFeaturePreferenceFragment.java
+++ b/src/com/android/settings/accessibility/ToggleFeaturePreferenceFragment.java
@@ -58,10 +58,10 @@
SettingsActivity activity = (SettingsActivity) getActivity();
mSwitchBar = activity.getSwitchBar();
- updateSwitchBarText(mSwitchBar);
mToggleSwitch = mSwitchBar.getSwitch();
onProcessArguments(getArguments());
+ updateSwitchBarText(mSwitchBar);
// Show the "Settings" menu as if it were a preference screen
if (mSettingsTitle != null && mSettingsIntent != null) {
diff --git a/src/com/android/settings/accessibility/ToggleScreenMagnificationPreferenceFragment.java b/src/com/android/settings/accessibility/ToggleScreenMagnificationPreferenceFragment.java
index ec3ebcc..842ec5c 100644
--- a/src/com/android/settings/accessibility/ToggleScreenMagnificationPreferenceFragment.java
+++ b/src/com/android/settings/accessibility/ToggleScreenMagnificationPreferenceFragment.java
@@ -50,6 +50,7 @@
ToggleFeaturePreferenceFragment implements SwitchBar.OnSwitchChangeListener {
private static final int DIALOG_ID_GESTURE_NAVIGATION_TUTORIAL = 1;
+ private static final int DIALOG_ID_ACCESSIBILITY_BUTTON_TUTORIAL = 2;
private Dialog mDialog;
@@ -172,14 +173,17 @@
@Override
public Dialog onCreateDialog(int dialogId) {
- if (dialogId == DIALOG_ID_GESTURE_NAVIGATION_TUTORIAL) {
- if (isGestureNavigateEnabled()) {
+ switch (dialogId) {
+ case DIALOG_ID_GESTURE_NAVIGATION_TUTORIAL:
mDialog = AccessibilityGestureNavigationTutorial
.showGestureNavigationTutorialDialog(getActivity());
- } else {
+ break;
+ case DIALOG_ID_ACCESSIBILITY_BUTTON_TUTORIAL:
mDialog = AccessibilityGestureNavigationTutorial
.showAccessibilityButtonTutorialDialog(getActivity());
- }
+ break;
+ default:
+ throw new IllegalArgumentException();
}
return mDialog;
@@ -193,7 +197,14 @@
@Override
public int getDialogMetricsCategory(int dialogId) {
- return SettingsEnums.ACCESSIBILITY_TOGGLE_SCREEN_MAGNIFICATION;
+ switch (dialogId) {
+ case DIALOG_ID_GESTURE_NAVIGATION_TUTORIAL:
+ return SettingsEnums.DIALOG_TOGGLE_SCREEN_MAGNIFICATION_GESTURE_NAVIGATION;
+ case DIALOG_ID_ACCESSIBILITY_BUTTON_TUTORIAL:
+ return SettingsEnums.DIALOG_TOGGLE_SCREEN_MAGNIFICATION_ACCESSIBILITY_BUTTON;
+ default:
+ return 0;
+ }
}
@Override
@@ -206,7 +217,8 @@
if (enabled && TextUtils.equals(
Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_NAVBAR_ENABLED,
preferenceKey)) {
- showDialog(DIALOG_ID_GESTURE_NAVIGATION_TUTORIAL);
+ showDialog(isGestureNavigateEnabled() ? DIALOG_ID_GESTURE_NAVIGATION_TUTORIAL
+ : DIALOG_ID_ACCESSIBILITY_BUTTON_TUTORIAL);
}
MagnificationPreferenceFragment.setChecked(getContentResolver(), preferenceKey, enabled);
updateConfigurationWarningIfNeeded();
@@ -228,6 +240,13 @@
}
@Override
+ protected void updateSwitchBarText(SwitchBar switchBar) {
+ final String switchBarText = getString(R.string.accessibility_service_master_switch_title,
+ getString(R.string.accessibility_screen_magnification_title));
+ switchBar.setSwitchBarText(switchBarText, switchBarText);
+ }
+
+ @Override
protected void onProcessArguments(Bundle arguments) {
super.onProcessArguments(arguments);
if (arguments == null) {
diff --git a/src/com/android/settings/accounts/AccountDashboardFragment.java b/src/com/android/settings/accounts/AccountDashboardFragment.java
index 83f071a..46c08ab 100644
--- a/src/com/android/settings/accounts/AccountDashboardFragment.java
+++ b/src/com/android/settings/accounts/AccountDashboardFragment.java
@@ -23,6 +23,7 @@
import com.android.settings.R;
import com.android.settings.SettingsPreferenceFragment;
import com.android.settings.dashboard.DashboardFragment;
+import com.android.settings.dashboard.profileselector.ProfileSelectFragment;
import com.android.settings.search.BaseSearchIndexProvider;
import com.android.settings.users.AutoSyncDataPreferenceController;
import com.android.settings.users.AutoSyncPersonalDataPreferenceController;
@@ -70,7 +71,8 @@
final List<AbstractPreferenceController> controllers = new ArrayList<>();
final AccountPreferenceController accountPrefController =
- new AccountPreferenceController(context, parent, authorities);
+ new AccountPreferenceController(context, parent, authorities,
+ ProfileSelectFragment.ALL);
if (parent != null) {
parent.getSettingsLifecycle().addObserver(accountPrefController);
}
diff --git a/src/com/android/settings/accounts/AccountPersonalDashboardFragment.java b/src/com/android/settings/accounts/AccountPersonalDashboardFragment.java
new file mode 100644
index 0000000..e0db7f5
--- /dev/null
+++ b/src/com/android/settings/accounts/AccountPersonalDashboardFragment.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2019 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.accounts;
+
+import static android.provider.Settings.EXTRA_AUTHORITIES;
+
+import android.app.settings.SettingsEnums;
+import android.content.Context;
+
+import com.android.settings.R;
+import com.android.settings.SettingsPreferenceFragment;
+import com.android.settings.dashboard.DashboardFragment;
+import com.android.settings.dashboard.profileselector.ProfileSelectFragment;
+import com.android.settings.users.AutoSyncDataPreferenceController;
+import com.android.settings.users.AutoSyncPersonalDataPreferenceController;
+import com.android.settingslib.core.AbstractPreferenceController;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Account Setting page for personal profile.
+ */
+public class AccountPersonalDashboardFragment extends DashboardFragment {
+
+ private static final String TAG = "AccountPersonalFrag";
+
+ @Override
+ public int getMetricsCategory() {
+ return SettingsEnums.ACCOUNT;
+ }
+
+ @Override
+ protected String getLogTag() {
+ return TAG;
+ }
+
+ @Override
+ protected int getPreferenceScreenResId() {
+ return R.xml.accounts_personal_dashboard_settings;
+ }
+
+ @Override
+ public int getHelpResource() {
+ return R.string.help_url_user_and_account_dashboard;
+ }
+
+ @Override
+ protected List<AbstractPreferenceController> createPreferenceControllers(Context context) {
+ final String[] authorities = getIntent().getStringArrayExtra(EXTRA_AUTHORITIES);
+ return buildPreferenceControllers(context, this /* parent */, authorities);
+ }
+
+ private static List<AbstractPreferenceController> buildPreferenceControllers(Context context,
+ SettingsPreferenceFragment parent, String[] authorities) {
+ final List<AbstractPreferenceController> controllers = new ArrayList<>();
+
+ final AccountPreferenceController accountPrefController =
+ new AccountPreferenceController(context, parent, authorities,
+ ProfileSelectFragment.PERSONAL);
+ if (parent != null) {
+ parent.getSettingsLifecycle().addObserver(accountPrefController);
+ }
+ controllers.add(accountPrefController);
+ controllers.add(new AutoSyncDataPreferenceController(context, parent));
+ controllers.add(new AutoSyncPersonalDataPreferenceController(context, parent));
+ return controllers;
+ }
+
+ // TODO: b/141601408. After featureFlag settings_work_profile is launched, unmark this
+// public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
+// new BaseSearchIndexProvider(R.xml.accounts_personal_dashboard_settings) {
+//
+// @Override
+// public List<AbstractPreferenceController> createPreferenceControllers(
+// Context context) {
+// return buildPreferenceControllers(
+// context, null /* parent */, null /* authorities*/);
+// }
+// };
+}
diff --git a/src/com/android/settings/accounts/AccountPreferenceController.java b/src/com/android/settings/accounts/AccountPreferenceController.java
index 5c930e2..8e3e702 100644
--- a/src/com/android/settings/accounts/AccountPreferenceController.java
+++ b/src/com/android/settings/accounts/AccountPreferenceController.java
@@ -53,8 +53,8 @@
import com.android.settings.Utils;
import com.android.settings.core.PreferenceControllerMixin;
import com.android.settings.core.SubSettingLauncher;
+import com.android.settings.dashboard.profileselector.ProfileSelectFragment;
import com.android.settings.overlay.FeatureFactory;
-import com.android.settingslib.search.SearchIndexableRaw;
import com.android.settingslib.RestrictedPreference;
import com.android.settingslib.accounts.AuthenticatorHelper;
import com.android.settingslib.core.AbstractPreferenceController;
@@ -62,6 +62,7 @@
import com.android.settingslib.core.lifecycle.LifecycleObserver;
import com.android.settingslib.core.lifecycle.events.OnPause;
import com.android.settingslib.core.lifecycle.events.OnResume;
+import com.android.settingslib.search.SearchIndexableRaw;
import java.util.ArrayList;
import java.util.Collections;
@@ -81,8 +82,8 @@
private UserManager mUm;
private SparseArray<ProfileData> mProfiles = new SparseArray<ProfileData>();
- private ManagedProfileBroadcastReceiver mManagedProfileBroadcastReceiver
- = new ManagedProfileBroadcastReceiver();
+ private ManagedProfileBroadcastReceiver mManagedProfileBroadcastReceiver =
+ new ManagedProfileBroadcastReceiver();
private Preference mProfileNotAvailablePreference;
private String[] mAuthorities;
private int mAuthoritiesCount = 0;
@@ -90,6 +91,7 @@
private int mAccountProfileOrder = ORDER_ACCOUNT_PROFILES;
private AccountRestrictionHelper mHelper;
private MetricsFeatureProvider mMetricsFeatureProvider;
+ private @ProfileSelectFragment.ProfileType int mType;
/**
* Holds data related to the accounts belonging to one profile.
@@ -130,13 +132,14 @@
}
public AccountPreferenceController(Context context, SettingsPreferenceFragment parent,
- String[] authorities) {
- this(context, parent, authorities, new AccountRestrictionHelper(context));
+ String[] authorities, @ProfileSelectFragment.ProfileType int type) {
+ this(context, parent, authorities, new AccountRestrictionHelper(context), type);
}
@VisibleForTesting
AccountPreferenceController(Context context, SettingsPreferenceFragment parent,
- String[] authorities, AccountRestrictionHelper helper) {
+ String[] authorities, AccountRestrictionHelper helper,
+ @ProfileSelectFragment.ProfileType int type) {
super(context);
mUm = (UserManager) context.getSystemService(Context.USER_SERVICE);
mAuthorities = authorities;
@@ -147,6 +150,7 @@
final FeatureFactory featureFactory = FeatureFactory.getFactory(mContext);
mMetricsFeatureProvider = featureFactory.getMetricsFeatureProvider();
mHelper = helper;
+ mType = type;
}
@Override
@@ -186,7 +190,7 @@
}
if (userInfo.isManagedProfile()) {
if (!mHelper.hasBaseUserRestriction(DISALLOW_REMOVE_MANAGED_PROFILE,
- UserHandle.myUserId())) {
+ UserHandle.myUserId())) {
SearchIndexableRaw data = new SearchIndexableRaw(mContext);
data.title = res.getString(R.string.remove_managed_profile_label);
data.screenTitle = screenTitle;
@@ -277,7 +281,13 @@
List<UserInfo> profiles = mUm.getProfiles(UserHandle.myUserId());
final int profilesCount = profiles.size();
for (int i = 0; i < profilesCount; i++) {
- updateProfileUi(profiles.get(i));
+ if (profiles.get(i).isManagedProfile()
+ && (mType & ProfileSelectFragment.WORK) != 0) {
+ updateProfileUi(profiles.get(i));
+ } else if (!profiles.get(i).isManagedProfile()
+ && (mType & ProfileSelectFragment.PERSONAL) != 0) {
+ updateProfileUi(profiles.get(i));
+ }
}
}
cleanUpPreferences();
@@ -302,7 +312,7 @@
if (userInfo.isEnabled()) {
// recreate the authentication helper to refresh the list of enabled accounts
data.authenticatorHelper =
- new AuthenticatorHelper(mContext, userInfo.getUserHandle(), this);
+ new AuthenticatorHelper(mContext, userInfo.getUserHandle(), this);
}
return;
}
@@ -310,27 +320,28 @@
final ProfileData profileData = new ProfileData();
profileData.userInfo = userInfo;
AccessiblePreferenceCategory preferenceGroup =
- mHelper.createAccessiblePreferenceCategory(mParent.getPreferenceManager().getContext());
+ mHelper.createAccessiblePreferenceCategory(
+ mParent.getPreferenceManager().getContext());
preferenceGroup.setOrder(mAccountProfileOrder++);
if (isSingleProfile()) {
preferenceGroup.setTitle(context.getString(R.string.account_for_section_header,
BidiFormatter.getInstance().unicodeWrap(userInfo.name)));
preferenceGroup.setContentDescription(
- mContext.getString(R.string.account_settings));
+ mContext.getString(R.string.account_settings));
} else if (userInfo.isManagedProfile()) {
preferenceGroup.setTitle(R.string.category_work);
String workGroupSummary = getWorkGroupSummary(context, userInfo);
preferenceGroup.setSummary(workGroupSummary);
preferenceGroup.setContentDescription(
- mContext.getString(R.string.accessibility_category_work, workGroupSummary));
+ mContext.getString(R.string.accessibility_category_work, workGroupSummary));
profileData.removeWorkProfilePreference = newRemoveWorkProfilePreference();
mHelper.enforceRestrictionOnPreference(profileData.removeWorkProfilePreference,
- DISALLOW_REMOVE_MANAGED_PROFILE, UserHandle.myUserId());
+ DISALLOW_REMOVE_MANAGED_PROFILE, UserHandle.myUserId());
profileData.managedProfilePreference = newManagedProfileSettings();
} else {
preferenceGroup.setTitle(R.string.category_personal);
preferenceGroup.setContentDescription(
- mContext.getString(R.string.accessibility_category_personal));
+ mContext.getString(R.string.accessibility_category_personal));
}
final PreferenceScreen screen = mParent.getPreferenceScreen();
if (screen != null) {
@@ -342,14 +353,14 @@
userInfo.getUserHandle(), this);
profileData.addAccountPreference = newAddAccountPreference();
mHelper.enforceRestrictionOnPreference(profileData.addAccountPreference,
- DISALLOW_MODIFY_ACCOUNTS, userInfo.id);
+ DISALLOW_MODIFY_ACCOUNTS, userInfo.id);
}
mProfiles.put(userInfo.id, profileData);
}
private RestrictedPreference newAddAccountPreference() {
RestrictedPreference preference =
- new RestrictedPreference(mParent.getPreferenceManager().getContext());
+ new RestrictedPreference(mParent.getPreferenceManager().getContext());
preference.setTitle(R.string.add_account_label);
preference.setIcon(R.drawable.ic_add_24dp);
preference.setOnPreferenceClickListener(this);
@@ -359,7 +370,7 @@
private RestrictedPreference newRemoveWorkProfilePreference() {
RestrictedPreference preference = new RestrictedPreference(
- mParent.getPreferenceManager().getContext());
+ mParent.getPreferenceManager().getContext());
preference.setTitle(R.string.remove_managed_profile_label);
preference.setIcon(R.drawable.ic_delete);
preference.setOnPreferenceClickListener(this);
@@ -393,7 +404,7 @@
return;
}
final int count = mProfiles.size();
- for (int i = count-1; i >= 0; i--) {
+ for (int i = count - 1; i >= 0; i--) {
final ProfileData data = mProfiles.valueAt(i);
if (data.pendingRemoval) {
screen.removePreference(data.preferenceGroup);
@@ -449,7 +460,7 @@
}
for (String key : preferenceToRemove.keySet()) {
profileData.preferenceGroup.removePreference(
- profileData.accountPreferences.get(key));
+ profileData.accountPreferences.get(key));
profileData.accountPreferences.remove(key);
}
} else {
@@ -457,7 +468,7 @@
// Put a label instead of the accounts list
if (mProfileNotAvailablePreference == null) {
mProfileNotAvailablePreference =
- new Preference(mParent.getPreferenceManager().getContext());
+ new Preference(mParent.getPreferenceManager().getContext());
}
mProfileNotAvailablePreference.setEnabled(false);
mProfileNotAvailablePreference.setIcon(R.drawable.empty_icon);
@@ -507,26 +518,26 @@
continue;
}
final ArrayList<String> auths =
- helper.getAuthoritiesForAccountType(account.type);
+ helper.getAuthoritiesForAccountType(account.type);
if (!AccountRestrictionHelper.showAccount(mAuthorities, auths)) {
continue;
}
final Bundle fragmentArguments = new Bundle();
fragmentArguments.putParcelable(AccountDetailDashboardFragment.KEY_ACCOUNT,
- account);
+ account);
fragmentArguments.putParcelable(AccountDetailDashboardFragment.KEY_USER_HANDLE,
- userHandle);
+ userHandle);
fragmentArguments.putString(AccountDetailDashboardFragment.KEY_ACCOUNT_TYPE,
- accountType);
+ accountType);
fragmentArguments.putString(AccountDetailDashboardFragment.KEY_ACCOUNT_LABEL,
- label.toString());
+ label.toString());
fragmentArguments.putInt(AccountDetailDashboardFragment.KEY_ACCOUNT_TITLE_RES,
- titleResId);
+ titleResId);
fragmentArguments.putParcelable(EXTRA_USER, userHandle);
accountTypePreferences.add(new AccountTypePreference(
- prefContext, mMetricsFeatureProvider.getMetricsCategory(mParent),
- account, titleResPackageName, titleResId, label,
- AccountDetailDashboardFragment.class.getName(), fragmentArguments, icon));
+ prefContext, mMetricsFeatureProvider.getMetricsCategory(mParent),
+ account, titleResPackageName, titleResId, label,
+ AccountDetailDashboardFragment.class.getName(), fragmentArguments, icon));
}
helper.preloadDrawableForType(mContext, accountType);
}
@@ -536,7 +547,7 @@
public int compare(AccountTypePreference t1, AccountTypePreference t2) {
int result = t1.getSummary().toString().compareTo(t2.getSummary().toString());
return result != 0
- ? result : t1.getTitle().toString().compareTo(t2.getTitle().toString());
+ ? result : t1.getTitle().toString().compareTo(t2.getTitle().toString());
}
});
return accountTypePreferences;
diff --git a/src/com/android/settings/accounts/AccountProfileSelectFragment.java b/src/com/android/settings/accounts/AccountProfileSelectFragment.java
new file mode 100644
index 0000000..128596d
--- /dev/null
+++ b/src/com/android/settings/accounts/AccountProfileSelectFragment.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2019 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.accounts;
+import androidx.fragment.app.Fragment;
+
+import com.android.settings.dashboard.profileselector.ProfileSelectFragment;
+
+/**
+ * Account Setting page for personal/managed profile.
+ */
+public class AccountProfileSelectFragment extends ProfileSelectFragment {
+
+ @Override
+ public Fragment[] getFragments() {
+ return new Fragment[] {
+ new AccountPersonalDashboardFragment(),
+ new AccountWorkProfileDashboardFragment()
+ };
+ }
+}
diff --git a/src/com/android/settings/accounts/AccountWorkProfileDashboardFragment.java b/src/com/android/settings/accounts/AccountWorkProfileDashboardFragment.java
new file mode 100644
index 0000000..a31340a
--- /dev/null
+++ b/src/com/android/settings/accounts/AccountWorkProfileDashboardFragment.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2019 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.accounts;
+
+import static android.provider.Settings.EXTRA_AUTHORITIES;
+
+import android.app.settings.SettingsEnums;
+import android.content.Context;
+
+import com.android.settings.R;
+import com.android.settings.SettingsPreferenceFragment;
+import com.android.settings.dashboard.DashboardFragment;
+import com.android.settings.dashboard.profileselector.ProfileSelectFragment;
+import com.android.settings.users.AutoSyncDataPreferenceController;
+import com.android.settings.users.AutoSyncWorkDataPreferenceController;
+import com.android.settingslib.core.AbstractPreferenceController;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Account Setting page for work profile.
+ */
+public class AccountWorkProfileDashboardFragment extends DashboardFragment {
+
+ private static final String TAG = "AccountWorkProfileFrag";
+
+ @Override
+ public int getMetricsCategory() {
+ return SettingsEnums.ACCOUNT;
+ }
+
+ @Override
+ protected String getLogTag() {
+ return TAG;
+ }
+
+ @Override
+ protected int getPreferenceScreenResId() {
+ return R.xml.accounts_work_dashboard_settings;
+ }
+
+ @Override
+ public int getHelpResource() {
+ return R.string.help_url_user_and_account_dashboard;
+ }
+
+ @Override
+ protected List<AbstractPreferenceController> createPreferenceControllers(Context context) {
+ final String[] authorities = getIntent().getStringArrayExtra(EXTRA_AUTHORITIES);
+ return buildPreferenceControllers(context, this /* parent */, authorities);
+ }
+
+ private static List<AbstractPreferenceController> buildPreferenceControllers(Context context,
+ SettingsPreferenceFragment parent, String[] authorities) {
+ final List<AbstractPreferenceController> controllers = new ArrayList<>();
+
+ final AccountPreferenceController accountPrefController =
+ new AccountPreferenceController(context, parent, authorities,
+ ProfileSelectFragment.WORK);
+ if (parent != null) {
+ parent.getSettingsLifecycle().addObserver(accountPrefController);
+ }
+ controllers.add(accountPrefController);
+ controllers.add(new AutoSyncDataPreferenceController(context, parent));
+ controllers.add(new AutoSyncWorkDataPreferenceController(context, parent));
+ return controllers;
+ }
+
+ // TODO: b/141601408. After featureFlag settings_work_profile is launched, unmark this
+// public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
+// new BaseSearchIndexProvider(R.xml.accounts_work_dashboard_settings) {
+//
+// @Override
+// public List<AbstractPreferenceController> createPreferenceControllers(
+// Context context) {
+// return buildPreferenceControllers(
+// context, null /* parent */, null /* authorities*/);
+// }
+// };
+}
diff --git a/src/com/android/settings/bluetooth/BluetoothSliceBuilder.java b/src/com/android/settings/bluetooth/BluetoothSliceBuilder.java
index 18df872..5a4ee1f 100644
--- a/src/com/android/settings/bluetooth/BluetoothSliceBuilder.java
+++ b/src/com/android/settings/bluetooth/BluetoothSliceBuilder.java
@@ -136,6 +136,6 @@
final Intent intent = new Intent(ACTION_BLUETOOTH_SLICE_CHANGED)
.setClass(context, SliceBroadcastReceiver.class);
return PendingIntent.getBroadcast(context, 0 /* requestCode */, intent,
- PendingIntent.FLAG_CANCEL_CURRENT);
+ PendingIntent.FLAG_UPDATE_CURRENT);
}
}
diff --git a/src/com/android/settings/connecteddevice/AvailableMediaDeviceGroupController.java b/src/com/android/settings/connecteddevice/AvailableMediaDeviceGroupController.java
index cac46b0..d895154 100644
--- a/src/com/android/settings/connecteddevice/AvailableMediaDeviceGroupController.java
+++ b/src/com/android/settings/connecteddevice/AvailableMediaDeviceGroupController.java
@@ -141,11 +141,11 @@
if (isAudioModeOngoingCall(mContext)) {
// in phone call
mPreferenceGroup.
- setTitle(mContext.getString(R.string.connected_device_available_call_title));
+ setTitle(mContext.getString(R.string.connected_device_call_device_title));
} else {
// without phone call
mPreferenceGroup.
- setTitle(mContext.getString(R.string.connected_device_available_media_title));
+ setTitle(mContext.getString(R.string.connected_device_media_device_title));
}
}
}
diff --git a/src/com/android/settings/connecteddevice/usb/UsbDetailsFunctionsController.java b/src/com/android/settings/connecteddevice/usb/UsbDetailsFunctionsController.java
index 9c9400d..31bca12 100644
--- a/src/com/android/settings/connecteddevice/usb/UsbDetailsFunctionsController.java
+++ b/src/com/android/settings/connecteddevice/usb/UsbDetailsFunctionsController.java
@@ -114,16 +114,16 @@
if (function != previousFunction && !Utils.isMonkeyRunning()) {
mPreviousFunction = previousFunction;
- if (function == UsbManager.FUNCTION_RNDIS) {
- //Update the UI in advance to make it looks smooth
- final RadioButtonPreference prevPref =
- (RadioButtonPreference) mProfilesContainer.findPreference(
- UsbBackend.usbFunctionsToString(mPreviousFunction));
- if (prevPref != null) {
- prevPref.setChecked(false);
- preference.setChecked(true);
- }
+ //Update the UI in advance to make it looks smooth
+ final RadioButtonPreference prevPref =
+ (RadioButtonPreference) mProfilesContainer.findPreference(
+ UsbBackend.usbFunctionsToString(mPreviousFunction));
+ if (prevPref != null) {
+ prevPref.setChecked(false);
+ preference.setChecked(true);
+ }
+ if (function == UsbManager.FUNCTION_RNDIS) {
// We need to have entitlement check for usb tethering, so use API in
// ConnectivityManager.
mConnectivityManager.startTethering(TETHERING_USB, true /* showProvisioningUi */,
diff --git a/src/com/android/settings/core/FeatureFlags.java b/src/com/android/settings/core/FeatureFlags.java
index fee9c42..8203b35 100644
--- a/src/com/android/settings/core/FeatureFlags.java
+++ b/src/com/android/settings/core/FeatureFlags.java
@@ -27,4 +27,5 @@
public static final String NETWORK_INTERNET_V2 = "settings_network_and_internet_v2";
public static final String WIFI_DETAILS_DATAUSAGE_HEADER =
"settings_wifi_details_datausage_header";
+ public static final String PERSONAL_WORK_PROFILE = "settings_work_profile";
}
diff --git a/src/com/android/settings/dashboard/profileselector/ProfileFragmentBridge.java b/src/com/android/settings/dashboard/profileselector/ProfileFragmentBridge.java
new file mode 100644
index 0000000..797782a
--- /dev/null
+++ b/src/com/android/settings/dashboard/profileselector/ProfileFragmentBridge.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2019 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.dashboard.profileselector;
+
+import android.util.ArrayMap;
+
+import com.android.settings.accounts.AccountDashboardFragment;
+import com.android.settings.accounts.AccountProfileSelectFragment;
+
+import java.util.Map;
+
+/**
+ * A registry to keep track of which page and its own profile selection page.
+ */
+public class ProfileFragmentBridge {
+
+ /**
+ * Map from parent fragment to category key. The parent fragment hosts child with
+ * category_key.
+ */
+ public static final Map<String, String> FRAGMENT_MAP;
+
+ static {
+ FRAGMENT_MAP = new ArrayMap<>();
+ FRAGMENT_MAP.put(AccountDashboardFragment.class.getName(),
+ AccountProfileSelectFragment.class.getName());
+ }
+}
diff --git a/src/com/android/settings/dashboard/profileselector/ProfileSelectFragment.java b/src/com/android/settings/dashboard/profileselector/ProfileSelectFragment.java
new file mode 100644
index 0000000..96eace8
--- /dev/null
+++ b/src/com/android/settings/dashboard/profileselector/ProfileSelectFragment.java
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2019 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.dashboard.profileselector;
+
+import android.annotation.IntDef;
+import android.content.Context;
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+import androidx.fragment.app.Fragment;
+import androidx.fragment.app.FragmentStatePagerAdapter;
+import androidx.viewpager.widget.ViewPager;
+
+import com.android.settings.R;
+import com.android.settings.core.InstrumentedFragment;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Base fragment class for per profile settings.
+ */
+public abstract class ProfileSelectFragment extends InstrumentedFragment {
+
+ /**
+ * Denotes the profile type.
+ */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef({PERSONAL, WORK, ALL})
+ public @interface ProfileType {
+ }
+
+ /**
+ * It is personal work profile.
+ */
+ public static final int PERSONAL = 1;
+
+ /**
+ * It is work profile
+ */
+ public static final int WORK = 1 << 1;
+
+ /**
+ * It is personal and work profile
+ */
+ public static final int ALL = PERSONAL | WORK;
+
+ private View mContentView;
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ mContentView = inflater.inflate(R.layout.profile_select_tablayout, null /* root */);
+ final ViewPager viewPager = mContentView.findViewById(R.id.view_pager);
+ viewPager.setAdapter(new ViewPagerAdapter(this));
+ return mContentView;
+ }
+
+ @Override
+ public int getMetricsCategory() {
+ return METRICS_CATEGORY_UNKNOWN;
+ }
+
+ /**
+ * Returns an array of {@link Fragment} to display in the
+ * {@link com.google.android.material.tabs.TabLayout}
+ */
+ public abstract Fragment[] getFragments();
+
+ static class ViewPagerAdapter extends FragmentStatePagerAdapter {
+
+ private final Fragment[] mChildFragments;
+ private final Context mContext;
+
+ ViewPagerAdapter(ProfileSelectFragment fragment) {
+ super(fragment.getActivity().getSupportFragmentManager());
+ mContext = fragment.getContext();
+ mChildFragments = fragment.getFragments();
+ }
+
+ @Override
+ public Fragment getItem(int position) {
+ return mChildFragments[position];
+ }
+
+ @Override
+ public int getCount() {
+ return mChildFragments.length;
+ }
+
+ @Override
+ public CharSequence getPageTitle(int position) {
+ if (position == 0) {
+ return mContext.getString(R.string.category_personal);
+ } else {
+ return mContext.getString(R.string.category_work);
+ }
+ }
+ }
+}
diff --git a/src/com/android/settings/datausage/DataSaverBackend.java b/src/com/android/settings/datausage/DataSaverBackend.java
index db92659..92b2ef9 100644
--- a/src/com/android/settings/datausage/DataSaverBackend.java
+++ b/src/com/android/settings/datausage/DataSaverBackend.java
@@ -23,6 +23,7 @@
import android.net.INetworkPolicyListener;
import android.net.NetworkPolicyManager;
import android.os.RemoteException;
+import android.telephony.SubscriptionPlan;
import android.util.SparseIntArray;
import com.android.settings.overlay.FeatureFactory;
@@ -199,8 +200,11 @@
}
@Override
- public void onSubscriptionOverride(int subId, int overrideMask, int overrideValue,
- long networkTypeMask) {
+ public void onSubscriptionOverride(int subId, int overrideMask, int overrideValue) {
+ }
+
+ @Override
+ public void onSubscriptionPlansChanged(int subId, SubscriptionPlan[] plans) {
}
};
diff --git a/src/com/android/settings/password/ChooseLockGeneric.java b/src/com/android/settings/password/ChooseLockGeneric.java
index f86292b..a2885d6 100644
--- a/src/com/android/settings/password/ChooseLockGeneric.java
+++ b/src/com/android/settings/password/ChooseLockGeneric.java
@@ -61,6 +61,7 @@
import androidx.preference.PreferenceScreen;
import com.android.internal.widget.LockPatternUtils;
+import com.android.internal.widget.LockscreenCredential;
import com.android.settings.EncryptionInterstitial;
import com.android.settings.EventLogTags;
import com.android.settings.R;
@@ -151,7 +152,7 @@
private boolean mPasswordConfirmed = false;
private boolean mWaitingForConfirmation = false;
private boolean mForChangeCredRequiredForBoot = false;
- private byte[] mUserPassword;
+ private LockscreenCredential mUserPassword;
private LockPatternUtils mLockPatternUtils;
private FingerprintManager mFingerprintManager;
private FaceManager mFaceManager;
@@ -207,7 +208,7 @@
.getBooleanExtra(CONFIRM_CREDENTIALS, true);
if (getActivity() instanceof ChooseLockGeneric.InternalActivity) {
mPasswordConfirmed = !confirmCredentials;
- mUserPassword = getActivity().getIntent().getByteArrayExtra(
+ mUserPassword = getActivity().getIntent().getParcelableExtra(
ChooseLockSettingsHelper.EXTRA_KEY_PASSWORD);
}
@@ -233,7 +234,7 @@
mPasswordConfirmed = savedInstanceState.getBoolean(PASSWORD_CONFIRMED);
mWaitingForConfirmation = savedInstanceState.getBoolean(WAITING_FOR_CONFIRMATION);
if (mUserPassword == null) {
- mUserPassword = savedInstanceState.getByteArray(
+ mUserPassword = savedInstanceState.getParcelable(
ChooseLockSettingsHelper.EXTRA_KEY_PASSWORD);
}
}
@@ -392,11 +393,11 @@
if (requestCode == CONFIRM_EXISTING_REQUEST && resultCode == Activity.RESULT_OK) {
mPasswordConfirmed = true;
mUserPassword = data != null
- ? data.getByteArrayExtra(ChooseLockSettingsHelper.EXTRA_KEY_PASSWORD)
+ ? data.getParcelableExtra(ChooseLockSettingsHelper.EXTRA_KEY_PASSWORD)
: null;
updatePreferencesOrFinish(false /* isRecreatingActivity */);
if (mForChangeCredRequiredForBoot) {
- if (!(mUserPassword == null || mUserPassword.length == 0)) {
+ if (mUserPassword != null && !mUserPassword.isNone()) {
maybeEnableEncryption(
mLockPatternUtils.getKeyguardStoredPasswordQuality(mUserId), false);
} else {
@@ -459,7 +460,7 @@
outState.putBoolean(PASSWORD_CONFIRMED, mPasswordConfirmed);
outState.putBoolean(WAITING_FOR_CONFIRMATION, mWaitingForConfirmation);
if (mUserPassword != null) {
- outState.putByteArray(ChooseLockSettingsHelper.EXTRA_KEY_PASSWORD, mUserPassword);
+ outState.putParcelable(ChooseLockSettingsHelper.EXTRA_KEY_PASSWORD, mUserPassword);
}
}
@@ -682,7 +683,7 @@
setPreferenceSummary(ScreenLockType.MANAGED, R.string.secure_lock_encryption_warning);
}
- protected Intent getLockManagedPasswordIntent(byte[] password) {
+ protected Intent getLockManagedPasswordIntent(LockscreenCredential password) {
return mManagedPasswordProvider.createIntent(false, password);
}
@@ -759,7 +760,12 @@
if (quality == DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) {
// Clearing of user biometrics when screen lock is cleared is done at
// LockSettingsService.removeBiometricsForUser().
- mChooseLockSettingsHelper.utils().clearLock(mUserPassword, mUserId);
+ if (mUserPassword != null) {
+ // No need to call setLockCredential if the user currently doesn't
+ // have a password
+ mChooseLockSettingsHelper.utils().setLockCredential(
+ LockscreenCredential.createNone(), mUserPassword, mUserId);
+ }
mChooseLockSettingsHelper.utils().setLockScreenDisabled(disabled, mUserId);
getActivity().setResult(Activity.RESULT_OK);
finish();
diff --git a/src/com/android/settings/password/ChooseLockGenericController.java b/src/com/android/settings/password/ChooseLockGenericController.java
index 62a0063..1bfdac9 100644
--- a/src/com/android/settings/password/ChooseLockGenericController.java
+++ b/src/com/android/settings/password/ChooseLockGenericController.java
@@ -92,6 +92,7 @@
*/
public int upgradeQuality(int quality) {
// Compare specified quality and dpm quality
+ // TODO(b/142781408): convert from quality to credential type once PIN is supported.
int dpmUpgradedQuality = Math.max(quality, mDpm.getPasswordQuality(null, mUserId));
return Math.max(dpmUpgradedQuality,
PasswordMetrics.complexityLevelToMinQuality(mRequestedMinComplexity));
diff --git a/src/com/android/settings/password/ChooseLockPassword.java b/src/com/android/settings/password/ChooseLockPassword.java
index 820aecb..ff94d8b 100644
--- a/src/com/android/settings/password/ChooseLockPassword.java
+++ b/src/com/android/settings/password/ChooseLockPassword.java
@@ -17,12 +17,20 @@
package com.android.settings.password;
import static android.app.admin.DevicePolicyManager.PASSWORD_COMPLEXITY_NONE;
-import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC;
-import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC;
-import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_COMPLEX;
import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_NUMERIC;
-import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX;
+import static com.android.internal.widget.PasswordValidationError.CONTAINS_INVALID_CHARACTERS;
+import static com.android.internal.widget.PasswordValidationError.CONTAINS_SEQUENCE;
+import static com.android.internal.widget.PasswordValidationError.NOT_ENOUGH_DIGITS;
+import static com.android.internal.widget.PasswordValidationError.NOT_ENOUGH_LETTERS;
+import static com.android.internal.widget.PasswordValidationError.NOT_ENOUGH_LOWER_CASE;
+import static com.android.internal.widget.PasswordValidationError.NOT_ENOUGH_NON_DIGITS;
+import static com.android.internal.widget.PasswordValidationError.NOT_ENOUGH_NON_LETTER;
+import static com.android.internal.widget.PasswordValidationError.NOT_ENOUGH_SYMBOLS;
+import static com.android.internal.widget.PasswordValidationError.NOT_ENOUGH_UPPER_CASE;
+import static com.android.internal.widget.PasswordValidationError.RECENTLY_USED;
+import static com.android.internal.widget.PasswordValidationError.TOO_LONG;
+import static com.android.internal.widget.PasswordValidationError.TOO_SHORT;
import static com.android.settings.password.ChooseLockSettingsHelper.EXTRA_KEY_REQUESTED_MIN_COMPLEXITY;
import android.app.Activity;
@@ -51,7 +59,6 @@
import android.view.View;
import android.view.ViewGroup;
import android.view.inputmethod.EditorInfo;
-import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.TextView.OnEditorActionListener;
@@ -63,6 +70,8 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.widget.LockPatternUtils;
import com.android.internal.widget.LockPatternUtils.RequestThrottledException;
+import com.android.internal.widget.LockscreenCredential;
+import com.android.internal.widget.PasswordValidationError;
import com.android.internal.widget.TextViewInputDisabler;
import com.android.settings.EncryptionInterstitial;
import com.android.settings.R;
@@ -78,7 +87,7 @@
import com.google.android.setupdesign.GlifLayout;
import java.util.ArrayList;
-import java.util.Arrays;
+import java.util.Collections;
import java.util.List;
public class ChooseLockPassword extends SettingsActivity {
@@ -124,7 +133,7 @@
return this;
}
- public IntentBuilder setPassword(byte[] password) {
+ public IntentBuilder setPassword(LockscreenCredential password) {
mIntent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_PASSWORD, password);
return this;
}
@@ -180,28 +189,23 @@
public static class ChooseLockPasswordFragment extends InstrumentedFragment
implements OnEditorActionListener, TextWatcher, SaveAndFinishWorker.Listener {
- private static final String KEY_FIRST_PIN = "first_pin";
+ private static final String KEY_FIRST_PASSWORD = "first_password";
private static final String KEY_UI_STAGE = "ui_stage";
- private static final String KEY_CURRENT_PASSWORD = "current_password";
+ private static final String KEY_CURRENT_CREDENTIAL = "current_credential";
private static final String FRAGMENT_TAG_SAVE_AND_FINISH = "save_and_finish_worker";
- private byte[] mCurrentPassword;
- private byte[] mChosenPassword;
+ private LockscreenCredential mCurrentCredential;
+ private LockscreenCredential mChosenPassword;
private boolean mHasChallenge;
private long mChallenge;
private ImeAwareEditText mPasswordEntry;
private TextViewInputDisabler mPasswordEntryInputDisabler;
- private int mPasswordMinLength = LockPatternUtils.MIN_LOCK_PASSWORD_SIZE;
- private int mPasswordMaxLength = 16;
- private int mPasswordMinLetters = 0;
- private int mPasswordMinUpperCase = 0;
- private int mPasswordMinLowerCase = 0;
- private int mPasswordMinSymbols = 0;
- private int mPasswordMinNumeric = 0;
- private int mPasswordMinNonLetter = 0;
- private int mPasswordMinLengthToFulfillAllPolicies = 0;
- private boolean mPasswordNumSequenceAllowed = true;
- @PasswordComplexity private int mRequestedMinComplexity = PASSWORD_COMPLEXITY_NONE;
+
+ // Minimum password metrics enforced by admins.
+ private PasswordMetrics mMinMetrics;
+ private List<PasswordValidationError> mValidationErrors;
+
+ @PasswordComplexity private int mMinComplexity = PASSWORD_COMPLEXITY_NONE;
protected int mUserId;
private byte[] mPasswordHistoryHashFactor;
@@ -215,7 +219,7 @@
protected boolean mForFingerprint;
protected boolean mForFace;
- private byte[] mFirstPin;
+ private LockscreenCredential mFirstPassword;
private RecyclerView mPasswordRestrictionView;
protected boolean mIsAlphaMode;
protected FooterButton mSkipOrClearButton;
@@ -227,28 +231,6 @@
private static final int CONFIRM_EXISTING_REQUEST = 58;
static final int RESULT_FINISHED = RESULT_FIRST_USER;
- private static final int MIN_LETTER_IN_PASSWORD = 0;
- private static final int MIN_UPPER_LETTERS_IN_PASSWORD = 1;
- private static final int MIN_LOWER_LETTERS_IN_PASSWORD = 2;
- private static final int MIN_SYMBOLS_IN_PASSWORD = 3;
- private static final int MIN_NUMBER_IN_PASSWORD = 4;
- private static final int MIN_NON_LETTER_IN_PASSWORD = 5;
-
- // Error code returned from {@link #validatePassword(byte[])}.
- static final int NO_ERROR = 0;
- static final int CONTAIN_INVALID_CHARACTERS = 1 << 0;
- static final int TOO_SHORT = 1 << 1;
- static final int TOO_LONG = 1 << 2;
- static final int CONTAIN_NON_DIGITS = 1 << 3;
- static final int CONTAIN_SEQUENTIAL_DIGITS = 1 << 4;
- static final int RECENTLY_USED = 1 << 5;
- static final int NOT_ENOUGH_LETTER = 1 << 6;
- static final int NOT_ENOUGH_UPPER_CASE = 1 << 7;
- static final int NOT_ENOUGH_LOWER_CASE = 1 << 8;
- static final int NOT_ENOUGH_DIGITS = 1 << 9;
- static final int NOT_ENOUGH_SYMBOLS = 1 << 10;
- static final int NOT_ENOUGH_NON_LETTER = 1 << 11;
-
/**
* Keep track internally of where the user is in choosing a pattern.
*/
@@ -380,13 +362,13 @@
mForFingerprint = intent.getBooleanExtra(
ChooseLockSettingsHelper.EXTRA_KEY_FOR_FINGERPRINT, false);
mForFace = intent.getBooleanExtra(ChooseLockSettingsHelper.EXTRA_KEY_FOR_FACE, false);
- mRequestedMinComplexity = intent.getIntExtra(
+ mMinComplexity = intent.getIntExtra(
EXTRA_KEY_REQUESTED_MIN_COMPLEXITY, PASSWORD_COMPLEXITY_NONE);
- mRequestedQuality = Math.max(
- intent.getIntExtra(LockPatternUtils.PASSWORD_TYPE_KEY, mRequestedQuality),
- mLockPatternUtils.getRequestedPasswordQuality(mUserId));
- loadDpmPasswordRequirements();
+ mRequestedQuality = intent.getIntExtra(
+ LockPatternUtils.PASSWORD_TYPE_KEY, PASSWORD_QUALITY_NUMERIC);
+
+ mMinMetrics = mLockPatternUtils.getRequestedPasswordMetrics(mUserId);
mChooseLockSettingsHelper = new ChooseLockSettingsHelper(getActivity());
if (intent.getBooleanExtra(
@@ -394,13 +376,13 @@
SaveAndFinishWorker w = new SaveAndFinishWorker();
final boolean required = getActivity().getIntent().getBooleanExtra(
EncryptionInterstitial.EXTRA_REQUIRE_PASSWORD, true);
- byte[] currentBytes = intent.getByteArrayExtra(
+ LockscreenCredential currentCredential = intent.getParcelableExtra(
ChooseLockSettingsHelper.EXTRA_KEY_PASSWORD);
w.setBlocking(true);
w.setListener(this);
w.start(mChooseLockSettingsHelper.utils(), required, false, 0,
- currentBytes, currentBytes, mRequestedQuality, mUserId);
+ currentCredential, currentCredential, mUserId);
}
mTextChangedHandler = new TextChangedHandler();
}
@@ -482,7 +464,7 @@
Intent intent = getActivity().getIntent();
final boolean confirmCredentials = intent.getBooleanExtra(
ChooseLockGeneric.CONFIRM_CREDENTIALS, true);
- mCurrentPassword = intent.getByteArrayExtra(
+ mCurrentCredential = intent.getParcelableExtra(
ChooseLockSettingsHelper.EXTRA_KEY_PASSWORD);
mHasChallenge = intent.getBooleanExtra(
ChooseLockSettingsHelper.EXTRA_KEY_HAS_CHALLENGE, false);
@@ -497,15 +479,15 @@
} else {
// restore from previous state
- mFirstPin = savedInstanceState.getByteArray(KEY_FIRST_PIN);
+ mFirstPassword = savedInstanceState.getParcelable(KEY_FIRST_PASSWORD);
final String state = savedInstanceState.getString(KEY_UI_STAGE);
if (state != null) {
mUiStage = Stage.valueOf(state);
updateStage(mUiStage);
}
- if (mCurrentPassword == null) {
- mCurrentPassword = savedInstanceState.getByteArray(KEY_CURRENT_PASSWORD);
+ if (mCurrentCredential == null) {
+ mCurrentCredential = savedInstanceState.getParcelable(KEY_CURRENT_CREDENTIAL);
}
// Re-attach to the exiting worker if there is one.
@@ -563,8 +545,8 @@
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putString(KEY_UI_STAGE, mUiStage.name());
- outState.putByteArray(KEY_FIRST_PIN, mFirstPin);
- outState.putByteArray(KEY_CURRENT_PASSWORD, mCurrentPassword);
+ outState.putParcelable(KEY_FIRST_PASSWORD, mFirstPassword);
+ outState.putParcelable(KEY_CURRENT_CREDENTIAL, mCurrentCredential);
}
@Override
@@ -577,7 +559,7 @@
getActivity().setResult(RESULT_FINISHED);
getActivity().finish();
} else {
- mCurrentPassword = data.getByteArrayExtra(
+ mCurrentCredential = data.getParcelableExtra(
ChooseLockSettingsHelper.EXTRA_KEY_PASSWORD);
}
break;
@@ -601,208 +583,23 @@
}
/**
- * Read the requirements from {@link DevicePolicyManager} and intent and aggregate them.
- */
- private void loadDpmPasswordRequirements() {
- final int dpmPasswordQuality = mLockPatternUtils.getRequestedPasswordQuality(mUserId);
- if (dpmPasswordQuality == PASSWORD_QUALITY_NUMERIC_COMPLEX) {
- mPasswordNumSequenceAllowed = false;
- }
- mPasswordMinLength = Math.max(LockPatternUtils.MIN_LOCK_PASSWORD_SIZE,
- mLockPatternUtils.getRequestedMinimumPasswordLength(mUserId));
- mPasswordMaxLength = mLockPatternUtils.getMaximumPasswordLength(mRequestedQuality);
- mPasswordMinLetters = mLockPatternUtils.getRequestedPasswordMinimumLetters(mUserId);
- mPasswordMinUpperCase = mLockPatternUtils.getRequestedPasswordMinimumUpperCase(mUserId);
- mPasswordMinLowerCase = mLockPatternUtils.getRequestedPasswordMinimumLowerCase(mUserId);
- mPasswordMinNumeric = mLockPatternUtils.getRequestedPasswordMinimumNumeric(mUserId);
- mPasswordMinSymbols = mLockPatternUtils.getRequestedPasswordMinimumSymbols(mUserId);
- mPasswordMinNonLetter = mLockPatternUtils.getRequestedPasswordMinimumNonLetter(mUserId);
-
- // Modify the value based on dpm policy
- switch (dpmPasswordQuality) {
- case PASSWORD_QUALITY_ALPHABETIC:
- if (mPasswordMinLetters == 0) {
- mPasswordMinLetters = 1;
- }
- break;
- case PASSWORD_QUALITY_ALPHANUMERIC:
- if (mPasswordMinLetters == 0) {
- mPasswordMinLetters = 1;
- }
- if (mPasswordMinNumeric == 0) {
- mPasswordMinNumeric = 1;
- }
- break;
- case PASSWORD_QUALITY_COMPLEX:
- // Reserve all the requirements.
- break;
- default:
- mPasswordMinNumeric = 0;
- mPasswordMinLetters = 0;
- mPasswordMinUpperCase = 0;
- mPasswordMinLowerCase = 0;
- mPasswordMinSymbols = 0;
- mPasswordMinNonLetter = 0;
- }
-
- mPasswordMinLengthToFulfillAllPolicies = getMinLengthToFulfillAllPolicies();
- }
-
- /**
- * Merges the dpm requirements and the min complexity requirements.
+ * Validates PIN/Password and returns the validation result and updates mValidationErrors
+ * and mPasswordReused to reflect validation results.
*
- * <p>Since there are more than one set of metrics to meet the min complexity requirement,
- * and we are not hard-coding any one of them to be the requirements the user must fulfil,
- * we are taking what the user has already entered into account when compiling the list of
- * requirements from min complexity. Then we merge this list with the DPM requirements, and
- * present the merged set as validation results to the user on the UI.
- *
- * <p>For example, suppose min complexity requires either ALPHABETIC(8+), or
- * ALPHANUMERIC(6+). If the user has entered "a", the length requirement displayed on the UI
- * would be 8. Then the user appends "1" to make it "a1". We now know the user is entering
- * an alphanumeric password so we would update the min complexity required min length to 6.
- * This might result in a little confusion for the user but the UI does not support showing
- * multiple sets of requirements / validation results as options to users, this is the best
- * we can do now.
- */
- private void mergeMinComplexityAndDpmRequirements(int userEnteredPasswordQuality) {
- if (mRequestedMinComplexity == PASSWORD_COMPLEXITY_NONE) {
- // dpm requirements are dominant if min complexity is none
- return;
- }
-
- // reset dpm requirements
- loadDpmPasswordRequirements();
-
- PasswordMetrics minMetrics = PasswordMetrics.getMinimumMetrics(
- mRequestedMinComplexity, userEnteredPasswordQuality, mRequestedQuality,
- requiresNumeric(), requiresLettersOrSymbols());
- mPasswordNumSequenceAllowed = mPasswordNumSequenceAllowed
- && minMetrics.quality != PASSWORD_QUALITY_NUMERIC_COMPLEX;
- mPasswordMinLength = Math.max(mPasswordMinLength, minMetrics.length);
- mPasswordMinLetters = Math.max(mPasswordMinLetters, minMetrics.letters);
- mPasswordMinUpperCase = Math.max(mPasswordMinUpperCase, minMetrics.upperCase);
- mPasswordMinLowerCase = Math.max(mPasswordMinLowerCase, minMetrics.lowerCase);
- mPasswordMinNumeric = Math.max(mPasswordMinNumeric, minMetrics.numeric);
- mPasswordMinSymbols = Math.max(mPasswordMinSymbols, minMetrics.symbols);
- mPasswordMinNonLetter = Math.max(mPasswordMinNonLetter, minMetrics.nonLetter);
-
- if (minMetrics.quality == PASSWORD_QUALITY_ALPHABETIC) {
- if (!requiresLettersOrSymbols()) {
- mPasswordMinLetters = 1;
- }
- }
- if (minMetrics.quality == PASSWORD_QUALITY_ALPHANUMERIC) {
- if (!requiresLettersOrSymbols()) {
- mPasswordMinLetters = 1;
- }
- if (!requiresNumeric()) {
- mPasswordMinNumeric = 1;
- }
- }
-
- mPasswordMinLengthToFulfillAllPolicies = getMinLengthToFulfillAllPolicies();
- }
-
- private boolean requiresLettersOrSymbols() {
- // This is the condition for the password to be considered ALPHABETIC according to
- // PasswordMetrics.computeForPassword()
- return mPasswordMinLetters + mPasswordMinUpperCase
- + mPasswordMinLowerCase + mPasswordMinSymbols + mPasswordMinNonLetter > 0;
- }
-
- private boolean requiresNumeric() {
- return mPasswordMinNumeric > 0;
- }
-
- /**
- * Validates PIN/Password and returns the validation result.
- *
- * @param password the raw password the user typed in
- * @return the validation result.
+ * @param credential credential the user typed in.
+ * @return whether password satisfies all the requirements.
*/
@VisibleForTesting
- int validatePassword(byte[] password) {
- int errorCode = NO_ERROR;
- final PasswordMetrics metrics = PasswordMetrics.computeForPassword(password);
- mergeMinComplexityAndDpmRequirements(metrics.quality);
-
- if (password == null || password.length < mPasswordMinLength) {
- if (mPasswordMinLength > mPasswordMinLengthToFulfillAllPolicies) {
- errorCode |= TOO_SHORT;
- }
- } else if (password.length > mPasswordMaxLength) {
- errorCode |= TOO_LONG;
- } else {
- // The length requirements are fulfilled.
- if (!mPasswordNumSequenceAllowed
- && !requiresLettersOrSymbols()
- && metrics.numeric == password.length) {
- // Check for repeated characters or sequences (e.g. '1234', '0000', '2468')
- // if DevicePolicyManager or min password complexity requires a complex numeric
- // password. There can be two cases in the UI: 1. User chooses to enroll a
- // PIN, 2. User chooses to enroll a password but enters a numeric-only pin. We
- // should carry out the sequence check in both cases.
- //
- // Conditions for the !requiresLettersOrSymbols() to be necessary:
- // - DPM requires NUMERIC_COMPLEX
- // - min complexity not NONE, user picks PASSWORD type so ALPHABETIC or
- // ALPHANUMERIC is required
- // Imagine user has entered "12345678", if we don't skip the sequence check, the
- // validation result would show both "requires a letter" and "sequence not
- // allowed", while the only requirement the user needs to know is "requires a
- // letter" because once the user has fulfilled the alphabetic requirement, the
- // password would not be containing only digits so this check would not be
- // performed anyway.
- final int sequence = PasswordMetrics.maxLengthSequence(password);
- if (sequence > PasswordMetrics.MAX_ALLOWED_SEQUENCE) {
- errorCode |= CONTAIN_SEQUENTIAL_DIGITS;
- }
- }
- // Is the password recently used?
- if (mLockPatternUtils.checkPasswordHistory(password, getPasswordHistoryHashFactor(),
- mUserId)) {
- errorCode |= RECENTLY_USED;
- }
+ boolean validatePassword(LockscreenCredential credential) {
+ final byte[] password = credential.getCredential();
+ mValidationErrors = PasswordMetrics.validatePassword(
+ mMinMetrics, mMinComplexity, !mIsAlphaMode, password);
+ if (mValidationErrors.isEmpty() && mLockPatternUtils.checkPasswordHistory(
+ password, getPasswordHistoryHashFactor(), mUserId)) {
+ mValidationErrors =
+ Collections.singletonList(new PasswordValidationError(RECENTLY_USED));
}
-
- // Allow non-control Latin-1 characters only.
- for (int i = 0; i < password.length; i++) {
- char c = (char) password[i];
- if (c < 32 || c > 127) {
- errorCode |= CONTAIN_INVALID_CHARACTERS;
- break;
- }
- }
-
- // Ensure no non-digits if we are requesting numbers. This shouldn't be possible unless
- // user finds some way to bring up soft keyboard.
- if (mRequestedQuality == PASSWORD_QUALITY_NUMERIC
- || mRequestedQuality == PASSWORD_QUALITY_NUMERIC_COMPLEX) {
- if (metrics.letters > 0 || metrics.symbols > 0) {
- errorCode |= CONTAIN_NON_DIGITS;
- }
- }
-
- if (metrics.letters < mPasswordMinLetters) {
- errorCode |= NOT_ENOUGH_LETTER;
- }
- if (metrics.upperCase < mPasswordMinUpperCase) {
- errorCode |= NOT_ENOUGH_UPPER_CASE;
- }
- if (metrics.lowerCase < mPasswordMinLowerCase) {
- errorCode |= NOT_ENOUGH_LOWER_CASE;
- }
- if (metrics.symbols < mPasswordMinSymbols) {
- errorCode |= NOT_ENOUGH_SYMBOLS;
- }
- if (metrics.numeric < mPasswordMinNumeric) {
- errorCode |= NOT_ENOUGH_DIGITS;
- }
- if (metrics.nonLetter < mPasswordMinNonLetter) {
- errorCode |= NOT_ENOUGH_NON_LETTER;
- }
- return errorCode;
+ return mValidationErrors.isEmpty();
}
/**
@@ -812,7 +609,8 @@
private byte[] getPasswordHistoryHashFactor() {
if (mPasswordHistoryHashFactor == null) {
mPasswordHistoryHashFactor = mLockPatternUtils.getPasswordHistoryHashFactor(
- mCurrentPassword, mUserId);
+ mCurrentCredential != null ? mCurrentCredential
+ : LockscreenCredential.createNone(), mUserId);
}
return mPasswordHistoryHashFactor;
}
@@ -820,20 +618,22 @@
public void handleNext() {
if (mSaveAndFinishWorker != null) return;
// TODO(b/120484642): This is a point of entry for passwords from the UI
- mChosenPassword = LockPatternUtils.charSequenceToByteArray(mPasswordEntry.getText());
- if (mChosenPassword == null || mChosenPassword.length == 0) {
+ final Editable passwordText = mPasswordEntry.getText();
+ if (TextUtils.isEmpty(passwordText)) {
return;
}
+ mChosenPassword = mIsAlphaMode ? LockscreenCredential.createPassword(passwordText)
+ : LockscreenCredential.createPin(passwordText);
if (mUiStage == Stage.Introduction) {
- if (validatePassword(mChosenPassword) == NO_ERROR) {
- mFirstPin = mChosenPassword;
+ if (validatePassword(mChosenPassword)) {
+ mFirstPassword = mChosenPassword;
mPasswordEntry.setText("");
updateStage(Stage.NeedToConfirm);
} else {
- Arrays.fill(mChosenPassword, (byte) 0);
+ mChosenPassword.zeroize();
}
} else if (mUiStage == Stage.NeedToConfirm) {
- if (Arrays.equals(mFirstPin, mChosenPassword)) {
+ if (mChosenPassword.equals(mFirstPassword)) {
startSaveAndFinish();
} else {
CharSequence tmp = mPasswordEntry.getText();
@@ -841,7 +641,7 @@
Selection.setSelection((Spannable) tmp, 0, tmp.length());
}
updateStage(Stage.ConfirmWrong);
- Arrays.fill(mChosenPassword, (byte) 0);
+ mChosenPassword.zeroize();
}
}
}
@@ -874,79 +674,79 @@
}
/**
- * @param errorCode error code returned from {@link #validatePassword(String)}.
+ * @param errorCode error code returned from password validation.
* @return an array of messages describing the error, important messages come first.
*/
- String[] convertErrorCodeToMessages(int errorCode) {
+ String[] convertErrorCodeToMessages() {
List<String> messages = new ArrayList<>();
- if ((errorCode & CONTAIN_INVALID_CHARACTERS) > 0) {
- messages.add(getString(R.string.lockpassword_illegal_character));
+ for (PasswordValidationError error : mValidationErrors) {
+ switch (error.errorCode) {
+ case CONTAINS_INVALID_CHARACTERS:
+ messages.add(getString(R.string.lockpassword_illegal_character));
+ break;
+ case NOT_ENOUGH_UPPER_CASE:
+ messages.add(getResources().getQuantityString(
+ R.plurals.lockpassword_password_requires_uppercase,
+ error.requirement, error.requirement));
+ break;
+ case NOT_ENOUGH_LOWER_CASE:
+ messages.add(getResources().getQuantityString(
+ R.plurals.lockpassword_password_requires_lowercase,
+ error.requirement, error.requirement));
+ break;
+ case NOT_ENOUGH_LETTERS:
+ messages.add(getResources().getQuantityString(
+ R.plurals.lockpassword_password_requires_letters,
+ error.requirement, error.requirement));
+ break;
+ case NOT_ENOUGH_DIGITS:
+ messages.add(getResources().getQuantityString(
+ R.plurals.lockpassword_password_requires_numeric,
+ error.requirement, error.requirement));
+ break;
+ case NOT_ENOUGH_SYMBOLS:
+ messages.add(getResources().getQuantityString(
+ R.plurals.lockpassword_password_requires_symbols,
+ error.requirement, error.requirement));
+ break;
+ case NOT_ENOUGH_NON_LETTER:
+ messages.add(getResources().getQuantityString(
+ R.plurals.lockpassword_password_requires_nonletter,
+ error.requirement, error.requirement));
+ break;
+ case NOT_ENOUGH_NON_DIGITS:
+ messages.add(getResources().getQuantityString(
+ R.plurals.lockpassword_password_requires_nonnumerical,
+ error.requirement, error.requirement));
+ break;
+ case TOO_SHORT:
+ messages.add(getResources().getQuantityString(
+ mIsAlphaMode
+ ? R.plurals.lockpassword_password_too_short
+ : R.plurals.lockpassword_pin_too_short,
+ error.requirement, error.requirement));
+ break;
+ case TOO_LONG:
+ messages.add(getResources().getQuantityString(
+ mIsAlphaMode
+ ? R.plurals.lockpassword_password_too_long
+ : R.plurals.lockpassword_pin_too_long,
+ error.requirement + 1, error.requirement + 1));
+ break;
+ case CONTAINS_SEQUENCE:
+ messages.add(getString(R.string.lockpassword_pin_no_sequential_digits));
+ break;
+ case RECENTLY_USED:
+ messages.add(getString(mIsAlphaMode
+ ? R.string.lockpassword_password_recently_used
+ : R.string.lockpassword_pin_recently_used));
+ break;
+ default:
+ Log.wtf(TAG, "unknown error validating password: " + error);
+ }
}
- if ((errorCode & CONTAIN_NON_DIGITS) > 0) {
- messages.add(getString(R.string.lockpassword_pin_contains_non_digits));
- }
- if ((errorCode & NOT_ENOUGH_UPPER_CASE) > 0) {
- messages.add(getResources().getQuantityString(
- R.plurals.lockpassword_password_requires_uppercase, mPasswordMinUpperCase,
- mPasswordMinUpperCase));
- }
- if ((errorCode & NOT_ENOUGH_LOWER_CASE) > 0) {
- messages.add(getResources().getQuantityString(
- R.plurals.lockpassword_password_requires_lowercase, mPasswordMinLowerCase,
- mPasswordMinLowerCase));
- }
- if ((errorCode & NOT_ENOUGH_LETTER) > 0) {
- messages.add(getResources().getQuantityString(
- R.plurals.lockpassword_password_requires_letters, mPasswordMinLetters,
- mPasswordMinLetters));
- }
- if ((errorCode & NOT_ENOUGH_DIGITS) > 0) {
- messages.add(getResources().getQuantityString(
- R.plurals.lockpassword_password_requires_numeric, mPasswordMinNumeric,
- mPasswordMinNumeric));
- }
- if ((errorCode & NOT_ENOUGH_SYMBOLS) > 0) {
- messages.add(getResources().getQuantityString(
- R.plurals.lockpassword_password_requires_symbols, mPasswordMinSymbols,
- mPasswordMinSymbols));
- }
- if ((errorCode & NOT_ENOUGH_NON_LETTER) > 0) {
- messages.add(getResources().getQuantityString(
- R.plurals.lockpassword_password_requires_nonletter, mPasswordMinNonLetter,
- mPasswordMinNonLetter));
- }
- if ((errorCode & TOO_SHORT) > 0) {
- messages.add(getResources().getQuantityString(
- mIsAlphaMode
- ? R.plurals.lockpassword_password_too_short
- : R.plurals.lockpassword_pin_too_short,
- mPasswordMinLength,
- mPasswordMinLength));
- }
- if ((errorCode & TOO_LONG) > 0) {
- messages.add(getResources().getQuantityString(
- mIsAlphaMode
- ? R.plurals.lockpassword_password_too_long
- : R.plurals.lockpassword_pin_too_long,
- mPasswordMaxLength + 1,
- mPasswordMaxLength + 1));
- }
- if ((errorCode & CONTAIN_SEQUENTIAL_DIGITS) > 0) {
- messages.add(getString(R.string.lockpassword_pin_no_sequential_digits));
- }
- if ((errorCode & RECENTLY_USED) > 0) {
- messages.add(getString((mIsAlphaMode) ? R.string.lockpassword_password_recently_used
- : R.string.lockpassword_pin_recently_used));
- }
- return messages.toArray(new String[0]);
- }
- private int getMinLengthToFulfillAllPolicies() {
- final int minLengthForLetters = Math.max(mPasswordMinLetters,
- mPasswordMinUpperCase + mPasswordMinLowerCase);
- final int minLengthForNonLetters = Math.max(mPasswordMinNonLetter,
- mPasswordMinSymbols + mPasswordMinNumeric);
- return minLengthForLetters + minLengthForNonLetters;
+ return messages.toArray(new String[0]);
}
/**
@@ -954,21 +754,24 @@
*/
protected void updateUi() {
final boolean canInput = mSaveAndFinishWorker == null;
- byte[] password = LockPatternUtils.charSequenceToByteArray(mPasswordEntry.getText());
- final int length = password.length;
+
+ LockscreenCredential password = mIsAlphaMode
+ ? LockscreenCredential.createPasswordOrNone(mPasswordEntry.getText())
+ : LockscreenCredential.createPinOrNone(mPasswordEntry.getText());
+ final int length = password.size();
if (mUiStage == Stage.Introduction) {
mPasswordRestrictionView.setVisibility(View.VISIBLE);
- final int errorCode = validatePassword(password);
- String[] messages = convertErrorCodeToMessages(errorCode);
+ final boolean passwordCompliant = validatePassword(password);
+ String[] messages = convertErrorCodeToMessages();
// Update the fulfillment of requirements.
mPasswordRequirementAdapter.setRequirements(messages);
// Enable/Disable the next button accordingly.
- setNextEnabled(errorCode == NO_ERROR);
+ setNextEnabled(passwordCompliant);
} else {
// Hide password requirement view when we are just asking user to confirm the pw.
mPasswordRestrictionView.setVisibility(View.GONE);
setHeaderText(getString(mUiStage.getHint(mIsAlphaMode, getStageType())));
- setNextEnabled(canInput && length >= mPasswordMinLength);
+ setNextEnabled(canInput && length >= LockPatternUtils.MIN_LOCK_PASSWORD_SIZE);
mSkipOrClearButton.setVisibility(toVisibility(canInput && length > 0));
}
int message = mUiStage.getMessage(mIsAlphaMode, getStageType());
@@ -981,7 +784,7 @@
setNextText(mUiStage.buttonText);
mPasswordEntryInputDisabler.setInputEnabled(canInput);
- Arrays.fill(password, (byte) 0);
+ password.zeroize();
}
protected int toVisibility(boolean visibleOrGone) {
@@ -1033,7 +836,7 @@
final boolean required = getActivity().getIntent().getBooleanExtra(
EncryptionInterstitial.EXTRA_REQUIRE_PASSWORD, true);
mSaveAndFinishWorker.start(mLockPatternUtils, required, mHasChallenge, mChallenge,
- mChosenPassword, mCurrentPassword, mRequestedQuality, mUserId);
+ mChosenPassword, mCurrentCredential, mUserId);
}
@Override
@@ -1041,13 +844,13 @@
getActivity().setResult(RESULT_FINISHED, resultData);
if (mChosenPassword != null) {
- Arrays.fill(mChosenPassword, (byte) 0);
+ mChosenPassword.zeroize();
}
- if (mCurrentPassword != null) {
- Arrays.fill(mCurrentPassword, (byte) 0);
+ if (mCurrentCredential != null) {
+ mCurrentCredential.zeroize();
}
- if (mFirstPin != null) {
- Arrays.fill(mFirstPin, (byte) 0);
+ if (mFirstPassword != null) {
+ mFirstPassword.zeroize();
}
mPasswordEntry.setText("");
@@ -1088,18 +891,18 @@
public static class SaveAndFinishWorker extends SaveChosenLockWorkerBase {
- private byte[] mChosenPassword;
- private byte[] mCurrentPassword;
- private int mRequestedQuality;
+ private LockscreenCredential mChosenPassword;
+ private LockscreenCredential mCurrentCredential;
public void start(LockPatternUtils utils, boolean required,
boolean hasChallenge, long challenge,
- byte[] chosenPassword, byte[] currentPassword, int requestedQuality, int userId) {
+ LockscreenCredential chosenPassword, LockscreenCredential currentCredential,
+ int userId) {
prepare(utils, required, hasChallenge, challenge, userId);
mChosenPassword = chosenPassword;
- mCurrentPassword = currentPassword;
- mRequestedQuality = requestedQuality;
+ mCurrentCredential = currentCredential != null ? currentCredential
+ : LockscreenCredential.createNone();
mUserId = userId;
start();
@@ -1107,13 +910,13 @@
@Override
protected Pair<Boolean, Intent> saveAndVerifyInBackground() {
- final boolean success = mUtils.saveLockPassword(
- mChosenPassword, mCurrentPassword, mRequestedQuality, mUserId);
+ final boolean success = mUtils.setLockCredential(
+ mChosenPassword, mCurrentCredential, mUserId);
Intent result = null;
if (success && mHasChallenge) {
byte[] token;
try {
- token = mUtils.verifyPassword(mChosenPassword, mChallenge, mUserId);
+ token = mUtils.verifyCredential(mChosenPassword, mChallenge, mUserId);
} catch (RequestThrottledException e) {
token = null;
}
diff --git a/src/com/android/settings/password/ChooseLockPattern.java b/src/com/android/settings/password/ChooseLockPattern.java
index 5de4e3a..b81b0c4 100644
--- a/src/com/android/settings/password/ChooseLockPattern.java
+++ b/src/com/android/settings/password/ChooseLockPattern.java
@@ -36,12 +36,14 @@
import androidx.fragment.app.Fragment;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.widget.LinearLayoutWithDefaultTouchRecepient;
import com.android.internal.widget.LockPatternUtils;
import com.android.internal.widget.LockPatternUtils.RequestThrottledException;
import com.android.internal.widget.LockPatternView;
import com.android.internal.widget.LockPatternView.Cell;
import com.android.internal.widget.LockPatternView.DisplayMode;
+import com.android.internal.widget.LockscreenCredential;
import com.android.settings.EncryptionInterstitial;
import com.android.settings.R;
import com.android.settings.SettingsActivity;
@@ -116,7 +118,7 @@
return this;
}
- public IntentBuilder setPattern(byte[] pattern) {
+ public IntentBuilder setPattern(LockscreenCredential pattern) {
mIntent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_PASSWORD, pattern);
return this;
}
@@ -188,7 +190,7 @@
private static final String FRAGMENT_TAG_SAVE_AND_FINISH = "save_and_finish_worker";
- private byte[] mCurrentPattern;
+ private LockscreenCredential mCurrentCredential;
private boolean mHasChallenge;
private long mChallenge;
protected TextView mTitleText;
@@ -198,7 +200,7 @@
protected TextView mFooterText;
protected FooterButton mSkipOrClearButton;
private FooterButton mNextButton;
- protected List<LockPatternView.Cell> mChosenPattern = null;
+ @VisibleForTesting protected LockscreenCredential mChosenPattern;
private ColorStateList mDefaultHeaderColorList;
// ScrollView that contains title and header, only exist in land mode
@@ -225,7 +227,7 @@
getActivity().setResult(RESULT_FINISHED);
getActivity().finish();
} else {
- mCurrentPattern = data.getByteArrayExtra(
+ mCurrentCredential = data.getParcelableExtra(
ChooseLockSettingsHelper.EXTRA_KEY_PASSWORD);
}
@@ -262,16 +264,19 @@
if (mUiStage == Stage.NeedToConfirm || mUiStage == Stage.ConfirmWrong) {
if (mChosenPattern == null) throw new IllegalStateException(
"null chosen pattern in stage 'need to confirm");
- if (mChosenPattern.equals(pattern)) {
- updateStage(Stage.ChoiceConfirmed);
- } else {
- updateStage(Stage.ConfirmWrong);
+ try (LockscreenCredential confirmPattern =
+ LockscreenCredential.createPattern(pattern)) {
+ if (mChosenPattern.equals(confirmPattern)) {
+ updateStage(Stage.ChoiceConfirmed);
+ } else {
+ updateStage(Stage.ConfirmWrong);
+ }
}
} else if (mUiStage == Stage.Introduction || mUiStage == Stage.ChoiceTooShort){
if (pattern.size() < LockPatternUtils.MIN_LOCK_PATTERN_SIZE) {
updateStage(Stage.ChoiceTooShort);
} else {
- mChosenPattern = new ArrayList<LockPatternView.Cell>(pattern);
+ mChosenPattern = LockscreenCredential.createPattern(pattern);
updateStage(Stage.FirstChoiceValid);
}
} else {
@@ -458,12 +463,12 @@
SaveAndFinishWorker w = new SaveAndFinishWorker();
final boolean required = getActivity().getIntent().getBooleanExtra(
EncryptionInterstitial.EXTRA_REQUIRE_PASSWORD, true);
- byte[] current = intent.getByteArrayExtra(
+ LockscreenCredential current = intent.getParcelableExtra(
ChooseLockSettingsHelper.EXTRA_KEY_PASSWORD);
w.setBlocking(true);
w.setListener(this);
w.start(mChooseLockSettingsHelper.utils(), required,
- false, 0, LockPatternUtils.byteArrayToPattern(current), current, mUserId);
+ false, 0, current, current, mUserId);
}
mForFingerprint = intent.getBooleanExtra(
ChooseLockSettingsHelper.EXTRA_KEY_FOR_FINGERPRINT, false);
@@ -541,8 +546,8 @@
final boolean confirmCredentials = getActivity().getIntent()
.getBooleanExtra(ChooseLockGeneric.CONFIRM_CREDENTIALS, true);
Intent intent = getActivity().getIntent();
- mCurrentPattern =
- intent.getByteArrayExtra(ChooseLockSettingsHelper.EXTRA_KEY_PASSWORD);
+ mCurrentCredential =
+ intent.getParcelableExtra(ChooseLockSettingsHelper.EXTRA_KEY_PASSWORD);
mHasChallenge = intent.getBooleanExtra(
ChooseLockSettingsHelper.EXTRA_KEY_HAS_CHALLENGE, false);
mChallenge = intent.getLongExtra(ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE, 0);
@@ -565,13 +570,10 @@
}
} else {
// restore from previous state
- final byte[] pattern = savedInstanceState.getByteArray(KEY_PATTERN_CHOICE);
- if (pattern != null) {
- mChosenPattern = LockPatternUtils.byteArrayToPattern(pattern);
- }
+ mChosenPattern = savedInstanceState.getParcelable(KEY_PATTERN_CHOICE);
- if (mCurrentPattern == null) {
- mCurrentPattern = savedInstanceState.getByteArray(KEY_CURRENT_PATTERN);
+ if (mCurrentCredential == null) {
+ mCurrentCredential = savedInstanceState.getParcelable(KEY_CURRENT_PATTERN);
}
updateStage(Stage.values()[savedInstanceState.getInt(KEY_UI_STAGE)]);
@@ -606,6 +608,7 @@
public void handleLeftButton() {
if (mUiStage.leftMode == LeftButtonMode.Retry) {
+ mChosenPattern.zeroize();
mChosenPattern = null;
mLockPatternView.clearPattern();
updateStage(Stage.Introduction);
@@ -667,12 +670,11 @@
outState.putInt(KEY_UI_STAGE, mUiStage.ordinal());
if (mChosenPattern != null) {
- outState.putByteArray(KEY_PATTERN_CHOICE,
- LockPatternUtils.patternToByteArray(mChosenPattern));
+ outState.putParcelable(KEY_PATTERN_CHOICE, mChosenPattern);
}
- if (mCurrentPattern != null) {
- outState.putByteArray(KEY_CURRENT_PATTERN, mCurrentPattern);
+ if (mCurrentCredential != null) {
+ outState.putParcelable(KEY_CURRENT_PATTERN, mCurrentCredential);
}
}
@@ -812,15 +814,18 @@
final boolean required = getActivity().getIntent().getBooleanExtra(
EncryptionInterstitial.EXTRA_REQUIRE_PASSWORD, true);
mSaveAndFinishWorker.start(mChooseLockSettingsHelper.utils(), required,
- mHasChallenge, mChallenge, mChosenPattern, mCurrentPattern, mUserId);
+ mHasChallenge, mChallenge, mChosenPattern, mCurrentCredential, mUserId);
}
@Override
public void onChosenLockSaveFinished(boolean wasSecureBefore, Intent resultData) {
getActivity().setResult(RESULT_FINISHED, resultData);
- if (mCurrentPattern != null) {
- Arrays.fill(mCurrentPattern, (byte) 0);
+ if (mChosenPattern != null) {
+ mChosenPattern.zeroize();
+ }
+ if (mCurrentCredential != null) {
+ mCurrentCredential.zeroize();
}
if (!wasSecureBefore) {
@@ -835,16 +840,17 @@
public static class SaveAndFinishWorker extends SaveChosenLockWorkerBase {
- private List<LockPatternView.Cell> mChosenPattern;
- private byte[] mCurrentPattern;
+ private LockscreenCredential mChosenPattern;
+ private LockscreenCredential mCurrentCredential;
private boolean mLockVirgin;
- public void start(LockPatternUtils utils, boolean credentialRequired,
- boolean hasChallenge, long challenge,
- List<LockPatternView.Cell> chosenPattern, byte[] currentPattern, int userId) {
+ public void start(LockPatternUtils utils, boolean credentialRequired, boolean hasChallenge,
+ long challenge, LockscreenCredential chosenPattern,
+ LockscreenCredential currentCredential, int userId) {
prepare(utils, credentialRequired, hasChallenge, challenge, userId);
- mCurrentPattern = currentPattern;
+ mCurrentCredential = currentCredential != null ? currentCredential
+ : LockscreenCredential.createNone();
mChosenPattern = chosenPattern;
mUserId = userId;
@@ -856,12 +862,13 @@
@Override
protected Pair<Boolean, Intent> saveAndVerifyInBackground() {
final int userId = mUserId;
- final boolean success = mUtils.saveLockPattern(mChosenPattern, mCurrentPattern, userId);
+ final boolean success = mUtils.setLockCredential(mChosenPattern, mCurrentCredential,
+ userId);
Intent result = null;
if (success && mHasChallenge) {
byte[] token;
try {
- token = mUtils.verifyPattern(mChosenPattern, mChallenge, userId);
+ token = mUtils.verifyCredential(mChosenPattern, mChallenge, userId);
} catch (RequestThrottledException e) {
token = null;
}
diff --git a/src/com/android/settings/password/ConfirmDeviceCredentialActivity.java b/src/com/android/settings/password/ConfirmDeviceCredentialActivity.java
index 1da2a63..bf8c571 100644
--- a/src/com/android/settings/password/ConfirmDeviceCredentialActivity.java
+++ b/src/com/android/settings/password/ConfirmDeviceCredentialActivity.java
@@ -25,6 +25,7 @@
import android.app.trust.TrustManager;
import android.content.Context;
import android.content.Intent;
+import android.content.pm.PackageManager;
import android.hardware.biometrics.BiometricConstants;
import android.hardware.biometrics.BiometricManager;
import android.hardware.biometrics.BiometricPrompt;
@@ -52,6 +53,12 @@
public class ConfirmDeviceCredentialActivity extends FragmentActivity {
public static final String TAG = ConfirmDeviceCredentialActivity.class.getSimpleName();
+ /**
+ * If the intent is sent from {@link com.android.systemui.keyguard.WorkLockActivity} then
+ * check for device policy management flags.
+ */
+ public static final String EXTRA_FROM_WORK_LOCK_ACTIVITY = "from_work_lock_activity";
+
// The normal flow that apps go through
private static final int CREDENTIAL_NORMAL = 1;
// Unlocks the managed profile when the primary profile is unlocked
@@ -90,6 +97,8 @@
private TrustManager mTrustManager;
private ChooseLockSettingsHelper mChooseLockSettingsHelper;
private Handler mHandler = new Handler(Looper.getMainLooper());
+ private Context mContext;
+ private boolean mFromWorkLockActivity;
private String mTitle;
private String mDetails;
@@ -149,6 +158,8 @@
mLockPatternUtils = new LockPatternUtils(this);
Intent intent = getIntent();
+ mContext = this;
+ mFromWorkLockActivity = intent.getBooleanExtra(EXTRA_FROM_WORK_LOCK_ACTIVITY, false);
mTitle = intent.getStringExtra(KeyguardManager.EXTRA_TITLE);
mDetails = intent.getStringExtra(KeyguardManager.EXTRA_DESCRIPTION);
String alternateButton = intent.getStringExtra(
@@ -190,7 +201,7 @@
} else if (isManagedProfile && isInternalActivity()
&& !lockPatternUtils.isSeparateProfileChallengeEnabled(mUserId)) {
mCredentialMode = CREDENTIAL_MANAGED;
- if (isBiometricAllowed(effectiveUserId, mUserId)) {
+ if (mFromWorkLockActivity && isBiometricAllowed(effectiveUserId, mUserId)) {
showBiometricPrompt(bpBundle);
launchedBiometric = true;
} else {
@@ -256,10 +267,36 @@
|| !mUserManager.isUserUnlocked(mUserId);
}
+ /**
+ * TODO: Pass a list of disabled features to an internal BiometricPrompt API, so we can
+ * potentially show different modalities on multi-auth devices.
+ *
+ * @param effectiveUserId
+ * @return false if their exists one biometric on the device which is not disabled by the
+ * policy manager.
+ */
private boolean isBiometricDisabledByAdmin(int effectiveUserId) {
final int disabledFeatures =
- mDevicePolicyManager.getKeyguardDisabledFeatures(null, effectiveUserId);
- return (disabledFeatures & DevicePolicyManager.KEYGUARD_DISABLE_BIOMETRICS) != 0;
+ mDevicePolicyManager.getKeyguardDisabledFeatures(null, effectiveUserId);
+
+ final PackageManager pm = mContext.getPackageManager();
+ if (pm.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT)
+ && (disabledFeatures & DevicePolicyManager.KEYGUARD_DISABLE_FINGERPRINT) == 0) {
+ Log.d(TAG,"Fingerprint enabled & allowed by device policy manager");
+ return false;
+ }
+ if (pm.hasSystemFeature(PackageManager.FEATURE_IRIS)
+ && (disabledFeatures & DevicePolicyManager.KEYGUARD_DISABLE_IRIS) == 0) {
+ Log.d(TAG,"Iris enabled & allowed by device policy manager");
+ return false;
+ }
+ if (pm.hasSystemFeature(PackageManager.FEATURE_FACE)
+ && (disabledFeatures & DevicePolicyManager.KEYGUARD_DISABLE_FACE) == 0) {
+ Log.d(TAG,"Face enabled & allowed by device policy manager");
+ return false;
+ }
+
+ return true;
}
private boolean isBiometricAllowed(int effectiveUserId, int realUserId) {
diff --git a/src/com/android/settings/password/ConfirmLockPassword.java b/src/com/android/settings/password/ConfirmLockPassword.java
index 5c891cd..13d3749 100644
--- a/src/com/android/settings/password/ConfirmLockPassword.java
+++ b/src/com/android/settings/password/ConfirmLockPassword.java
@@ -27,6 +27,7 @@
import android.os.SystemClock;
import android.os.UserManager;
import android.os.storage.StorageManager;
+import android.text.Editable;
import android.text.InputType;
import android.text.TextUtils;
import android.view.KeyEvent;
@@ -44,6 +45,7 @@
import com.android.internal.widget.LockPatternChecker;
import com.android.internal.widget.LockPatternUtils;
+import com.android.internal.widget.LockscreenCredential;
import com.android.internal.widget.TextViewInputDisabler;
import com.android.settings.R;
import com.android.settings.widget.ImeAwareEditText;
@@ -332,10 +334,13 @@
}
// TODO(b/120484642): This is a point of entry for passwords from the UI
- final byte[] pin = LockPatternUtils.charSequenceToByteArray(mPasswordEntry.getText());
- if (pin == null || pin.length == 0) {
+ final Editable passwordText = mPasswordEntry.getText();
+ if (TextUtils.isEmpty(passwordText)) {
return;
}
+ final LockscreenCredential credential =
+ mIsAlpha ? LockscreenCredential.createPassword(passwordText)
+ : LockscreenCredential.createPin(passwordText);
mPasswordEntryInputDisabler.setInputEnabled(false);
final boolean verifyChallenge = getActivity().getIntent().getBooleanExtra(
@@ -344,11 +349,11 @@
Intent intent = new Intent();
if (verifyChallenge) {
if (isInternalActivity()) {
- startVerifyPassword(pin, intent);
+ startVerifyPassword(credential, intent);
return;
}
} else {
- startCheckPassword(pin, intent);
+ startCheckPassword(credential, intent);
return;
}
@@ -359,7 +364,7 @@
return getActivity() instanceof ConfirmLockPassword.InternalActivity;
}
- private void startVerifyPassword(final byte[] pin, final Intent intent) {
+ private void startVerifyPassword(LockscreenCredential credential, final Intent intent) {
long challenge = getActivity().getIntent().getLongExtra(
ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE, 0);
final int localEffectiveUserId = mEffectiveUserId;
@@ -383,29 +388,32 @@
}
};
mPendingLockCheck = (localEffectiveUserId == localUserId)
- ? LockPatternChecker.verifyPassword(
- mLockPatternUtils, pin, challenge, localUserId, onVerifyCallback)
+ ? LockPatternChecker.verifyCredential(
+ mLockPatternUtils, credential, challenge, localUserId, onVerifyCallback)
: LockPatternChecker.verifyTiedProfileChallenge(
- mLockPatternUtils, pin, false, challenge, localUserId,
+ mLockPatternUtils, credential, challenge, localUserId,
onVerifyCallback);
}
- private void startCheckPassword(final byte[] pin, final Intent intent) {
+ private void startCheckPassword(final LockscreenCredential credential,
+ final Intent intent) {
final int localEffectiveUserId = mEffectiveUserId;
- mPendingLockCheck = LockPatternChecker.checkPassword(
+ mPendingLockCheck = LockPatternChecker.checkCredential(
mLockPatternUtils,
- pin,
+ credential,
localEffectiveUserId,
new LockPatternChecker.OnCheckCallback() {
@Override
public void onChecked(boolean matched, int timeoutMs) {
mPendingLockCheck = null;
if (matched && isInternalActivity() && mReturnCredentials) {
+ // TODO: get rid of EXTRA_KEY_TYPE, since EXTRA_KEY_PASSWORD already
+ // distinguishes beteween PIN and password.
intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_TYPE,
mIsAlpha ? StorageManager.CRYPT_TYPE_PASSWORD
: StorageManager.CRYPT_TYPE_PIN);
intent.putExtra(
- ChooseLockSettingsHelper.EXTRA_KEY_PASSWORD, pin);
+ ChooseLockSettingsHelper.EXTRA_KEY_PASSWORD, credential);
}
mCredentialCheckResultTracker.setResult(matched, intent, timeoutMs,
localEffectiveUserId);
diff --git a/src/com/android/settings/password/ConfirmLockPattern.java b/src/com/android/settings/password/ConfirmLockPattern.java
index b1d8e60..2f7557e 100644
--- a/src/com/android/settings/password/ConfirmLockPattern.java
+++ b/src/com/android/settings/password/ConfirmLockPattern.java
@@ -37,6 +37,7 @@
import com.android.internal.widget.LockPatternUtils;
import com.android.internal.widget.LockPatternView;
import com.android.internal.widget.LockPatternView.Cell;
+import com.android.internal.widget.LockscreenCredential;
import com.android.settings.R;
import com.android.settingslib.animation.AppearAnimationCreator;
import com.android.settingslib.animation.AppearAnimationUtils;
@@ -401,14 +402,16 @@
final boolean verifyChallenge = getActivity().getIntent().getBooleanExtra(
ChooseLockSettingsHelper.EXTRA_KEY_HAS_CHALLENGE, false);
+ final LockscreenCredential credential = LockscreenCredential.createPattern(pattern);
+ //TODO: how to sanitize this?
Intent intent = new Intent();
if (verifyChallenge) {
if (isInternalActivity()) {
- startVerifyPattern(pattern, intent);
+ startVerifyPattern(credential, intent);
return;
}
} else {
- startCheckPattern(pattern, intent);
+ startCheckPattern(credential, intent);
return;
}
@@ -419,7 +422,7 @@
return getActivity() instanceof ConfirmLockPattern.InternalActivity;
}
- private void startVerifyPattern(final List<LockPatternView.Cell> pattern,
+ private void startVerifyPattern(final LockscreenCredential pattern,
final Intent intent) {
final int localEffectiveUserId = mEffectiveUserId;
final int localUserId = mUserId;
@@ -444,15 +447,15 @@
}
};
mPendingLockCheck = (localEffectiveUserId == localUserId)
- ? LockPatternChecker.verifyPattern(
+ ? LockPatternChecker.verifyCredential(
mLockPatternUtils, pattern, challenge, localUserId,
onVerifyCallback)
: LockPatternChecker.verifyTiedProfileChallenge(
- mLockPatternUtils, LockPatternUtils.patternToByteArray(pattern),
- true, challenge, localUserId, onVerifyCallback);
+ mLockPatternUtils, pattern,
+ challenge, localUserId, onVerifyCallback);
}
- private void startCheckPattern(final List<LockPatternView.Cell> pattern,
+ private void startCheckPattern(final LockscreenCredential pattern,
final Intent intent) {
if (pattern.size() < LockPatternUtils.MIN_PATTERN_REGISTER_FAIL) {
// Pattern size is less than the minimum, do not count it as an fail attempt.
@@ -461,7 +464,7 @@
}
final int localEffectiveUserId = mEffectiveUserId;
- mPendingLockCheck = LockPatternChecker.checkPattern(
+ mPendingLockCheck = LockPatternChecker.checkCredential(
mLockPatternUtils,
pattern,
localEffectiveUserId,
@@ -473,7 +476,7 @@
intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_TYPE,
StorageManager.CRYPT_TYPE_PATTERN);
intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_PASSWORD,
- LockPatternUtils.patternToByteArray(pattern));
+ pattern);
}
mCredentialCheckResultTracker.setResult(matched, intent, timeoutMs,
localEffectiveUserId);
diff --git a/src/com/android/settings/password/ManagedLockPasswordProvider.java b/src/com/android/settings/password/ManagedLockPasswordProvider.java
index 5006926..ac8a73a 100644
--- a/src/com/android/settings/password/ManagedLockPasswordProvider.java
+++ b/src/com/android/settings/password/ManagedLockPasswordProvider.java
@@ -19,6 +19,8 @@
import android.content.Context;
import android.content.Intent;
+import com.android.internal.widget.LockscreenCredential;
+
/**
* Helper for handling managed passwords in security settings UI.
* It provides resources that should be shown in settings UI when lock password quality is set to
@@ -59,7 +61,7 @@
* @param password Current lock password.
* @return Intent that should update lock password to a managed password.
*/
- Intent createIntent(boolean requirePasswordToDecrypt, byte[] password) {
+ Intent createIntent(boolean requirePasswordToDecrypt, LockscreenCredential password) {
return null;
}
}
diff --git a/src/com/android/settings/security/CryptKeeperSettings.java b/src/com/android/settings/security/CryptKeeperSettings.java
index 6555f56..aa47b2b 100644
--- a/src/com/android/settings/security/CryptKeeperSettings.java
+++ b/src/com/android/settings/security/CryptKeeperSettings.java
@@ -37,6 +37,7 @@
import androidx.appcompat.app.AlertDialog;
import androidx.preference.Preference;
+import com.android.internal.widget.LockscreenCredential;
import com.android.settings.CryptKeeperConfirm;
import com.android.settings.R;
import com.android.settings.SettingsActivity;
@@ -193,9 +194,10 @@
// confirmation prompt; otherwise, go back to the initial state.
if (resultCode == Activity.RESULT_OK && data != null) {
int type = data.getIntExtra(ChooseLockSettingsHelper.EXTRA_KEY_TYPE, -1);
- byte[] password = data.getByteArrayExtra(ChooseLockSettingsHelper.EXTRA_KEY_PASSWORD);
- if (!(password == null || password.length == 0)) {
- showFinalConfirmation(type, password);
+ LockscreenCredential password = data.getParcelableExtra(
+ ChooseLockSettingsHelper.EXTRA_KEY_PASSWORD);
+ if (password != null && !password.isNone()) {
+ showFinalConfirmation(type, password.getCredential());
}
}
}
diff --git a/src/com/android/settings/security/LockUnificationPreferenceController.java b/src/com/android/settings/security/LockUnificationPreferenceController.java
index bf374de..4bac601 100644
--- a/src/com/android/settings/security/LockUnificationPreferenceController.java
+++ b/src/com/android/settings/security/LockUnificationPreferenceController.java
@@ -32,6 +32,7 @@
import androidx.preference.PreferenceScreen;
import com.android.internal.widget.LockPatternUtils;
+import com.android.internal.widget.LockscreenCredential;
import com.android.settings.R;
import com.android.settings.Utils;
import com.android.settings.core.PreferenceControllerMixin;
@@ -70,8 +71,8 @@
private RestrictedSwitchPreference mUnifyProfile;
- private byte[] mCurrentDevicePassword;
- private byte[] mCurrentProfilePassword;
+ private LockscreenCredential mCurrentDevicePassword;
+ private LockscreenCredential mCurrentProfilePassword;
private boolean mKeepDeviceLock;
@Override
@@ -89,6 +90,8 @@
.getSecurityFeatureProvider()
.getLockPatternUtils(context);
mProfileUserId = Utils.getManagedProfileId(mUm, MY_USER_ID);
+ mCurrentDevicePassword = LockscreenCredential.createNone();
+ mCurrentProfilePassword = LockscreenCredential.createNone();
}
@Override
@@ -151,13 +154,13 @@
} else if (requestCode == UNIFY_LOCK_CONFIRM_DEVICE_REQUEST
&& resultCode == Activity.RESULT_OK) {
mCurrentDevicePassword =
- data.getByteArrayExtra(ChooseLockSettingsHelper.EXTRA_KEY_PASSWORD);
+ data.getParcelableExtra(ChooseLockSettingsHelper.EXTRA_KEY_PASSWORD);
launchConfirmProfileLock();
return true;
} else if (requestCode == UNIFY_LOCK_CONFIRM_PROFILE_REQUEST
&& resultCode == Activity.RESULT_OK) {
mCurrentProfilePassword =
- data.getByteArrayExtra(ChooseLockSettingsHelper.EXTRA_KEY_PASSWORD);
+ data.getParcelableExtra(ChooseLockSettingsHelper.EXTRA_KEY_PASSWORD);
unifyLocks();
return true;
}
@@ -221,17 +224,8 @@
}
private void unifyKeepingWorkLock() {
- final int profileQuality =
- mLockPatternUtils.getKeyguardStoredPasswordQuality(mProfileUserId);
- // PASSWORD_QUALITY_SOMETHING means pattern, everything above means PIN/password.
- if (profileQuality == DevicePolicyManager.PASSWORD_QUALITY_SOMETHING) {
- mLockPatternUtils.saveLockPattern(
- LockPatternUtils.byteArrayToPattern(mCurrentProfilePassword),
- mCurrentDevicePassword, MY_USER_ID);
- } else {
- mLockPatternUtils.saveLockPassword(
- mCurrentProfilePassword, mCurrentDevicePassword, profileQuality, MY_USER_ID);
- }
+ mLockPatternUtils.setLockCredential(
+ mCurrentProfilePassword, mCurrentDevicePassword, MY_USER_ID);
mLockPatternUtils.setSeparateProfileChallengeEnabled(mProfileUserId, false,
mCurrentProfilePassword);
final boolean profilePatternVisibility =
diff --git a/src/com/android/settings/slices/CustomSliceable.java b/src/com/android/settings/slices/CustomSliceable.java
index 9566be1..92c604e 100644
--- a/src/com/android/settings/slices/CustomSliceable.java
+++ b/src/com/android/settings/slices/CustomSliceable.java
@@ -95,7 +95,7 @@
.setData(getUri())
.setClass(context, SliceBroadcastReceiver.class);
return PendingIntent.getBroadcast(context, 0 /* requestCode */, intent,
- PendingIntent.FLAG_CANCEL_CURRENT);
+ PendingIntent.FLAG_UPDATE_CURRENT);
}
@Override
diff --git a/src/com/android/settings/slices/SlicePreference.java b/src/com/android/settings/slices/SlicePreference.java
index a2a7fe1..fe5ed60 100644
--- a/src/com/android/settings/slices/SlicePreference.java
+++ b/src/com/android/settings/slices/SlicePreference.java
@@ -46,6 +46,7 @@
mSliceView = findViewById(R.id.slice_view);
mSliceView.setShowTitleItems(true);
mSliceView.setScrollable(false);
+ mSliceView.setVisibility(View.GONE);
}
public void onSliceUpdated(Slice slice) {
diff --git a/src/com/android/settings/slices/SlicePreferenceController.java b/src/com/android/settings/slices/SlicePreferenceController.java
index 8f3d0fb..df28304 100644
--- a/src/com/android/settings/slices/SlicePreferenceController.java
+++ b/src/com/android/settings/slices/SlicePreferenceController.java
@@ -65,7 +65,6 @@
mUri = uri;
mLiveData = SliceLiveData.fromUri(mContext, mUri, (int type, Throwable source) -> {
Log.w(TAG, "Slice may be null. uri = " + uri + ", error = " + type);
- onChanged(null);
});
//TODO(b/120803703): figure out why we need to remove observer first
diff --git a/src/com/android/settings/widget/SwitchBar.java b/src/com/android/settings/widget/SwitchBar.java
index 0dd59e6..de0d98b 100644
--- a/src/com/android/settings/widget/SwitchBar.java
+++ b/src/com/android/settings/widget/SwitchBar.java
@@ -77,14 +77,12 @@
private TextView mTextView;
private String mLabel;
private String mSummary;
+ private String mOnText;
+ private String mOffText;
@ColorInt
private int mBackgroundColor;
@ColorInt
private int mBackgroundActivatedColor;
- @StringRes
- private int mOnTextId;
- @StringRes
- private int mOffTextId;
private boolean mLoggingIntialized;
private boolean mDisabledByAdmin;
@@ -178,14 +176,20 @@
}
public void setTextViewLabelAndBackground(boolean isChecked) {
- mLabel = getResources().getString(isChecked ? mOnTextId : mOffTextId);
+ mLabel = isChecked ? mOnText : mOffText;
setBackgroundColor(isChecked ? mBackgroundActivatedColor : mBackgroundColor);
updateText();
}
- public void setSwitchBarText(int onText, int offText) {
- mOnTextId = onText;
- mOffTextId = offText;
+ public void setSwitchBarText(int onTextId, int offTextId) {
+ mOnText = getResources().getString(onTextId);
+ mOffText = getResources().getString(offTextId);
+ setTextViewLabelAndBackground(isChecked());
+ }
+
+ public void setSwitchBarText(String onText, String offText) {
+ mOnText = onText;
+ mOffText = offText;
setTextViewLabelAndBackground(isChecked());
}
diff --git a/src/com/android/settings/wifi/savedaccesspoints/SavedAccessPointsPreferenceController.java b/src/com/android/settings/wifi/savedaccesspoints/SavedAccessPointsPreferenceController.java
index 81803dd..2315c9b 100644
--- a/src/com/android/settings/wifi/savedaccesspoints/SavedAccessPointsPreferenceController.java
+++ b/src/com/android/settings/wifi/savedaccesspoints/SavedAccessPointsPreferenceController.java
@@ -30,7 +30,6 @@
import com.android.settingslib.wifi.AccessPointPreference.UserBadgeCache;
import com.android.settingslib.wifi.WifiSavedConfigUtils;
-import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
@@ -40,17 +39,14 @@
public class SavedAccessPointsPreferenceController extends BasePreferenceController implements
Preference.OnPreferenceClickListener {
- private static final String TAG = "SavedApPrefCtrl";
-
- private final WifiManager mWifiManager;
+ protected final WifiManager mWifiManager;
private final UserBadgeCache mUserBadgeCache;
private PreferenceGroup mPreferenceGroup;
private SavedAccessPointsWifiSettings mHost;
@VisibleForTesting
List<AccessPoint> mAccessPoints;
- public SavedAccessPointsPreferenceController(Context context,
- String preferenceKey) {
+ public SavedAccessPointsPreferenceController(Context context, String preferenceKey) {
super(context, preferenceKey);
mUserBadgeCache = new AccessPointPreference.UserBadgeCache(context.getPackageManager());
mWifiManager = context.getSystemService(WifiManager.class);
@@ -84,7 +80,7 @@
return false;
}
- private void refreshSavedAccessPoints() {
+ protected void refreshSavedAccessPoints() {
mAccessPoints = WifiSavedConfigUtils.getAllConfigs(mContext, mWifiManager).stream()
.filter(accessPoint -> !accessPoint.isPasspointConfig())
.sorted(SavedNetworkComparator.INSTANCE)
diff --git a/src/com/android/settings/wifi/savedaccesspoints/SubscribedAccessPointsPreferenceController.java b/src/com/android/settings/wifi/savedaccesspoints/SubscribedAccessPointsPreferenceController.java
index 4d7dc60..b86113e 100644
--- a/src/com/android/settings/wifi/savedaccesspoints/SubscribedAccessPointsPreferenceController.java
+++ b/src/com/android/settings/wifi/savedaccesspoints/SubscribedAccessPointsPreferenceController.java
@@ -17,92 +17,26 @@
package com.android.settings.wifi.savedaccesspoints;
import android.content.Context;
-import android.net.wifi.WifiManager;
-import androidx.annotation.VisibleForTesting;
-import androidx.preference.Preference;
-import androidx.preference.PreferenceGroup;
-import androidx.preference.PreferenceScreen;
-
-import com.android.settings.core.BasePreferenceController;
-import com.android.settingslib.wifi.AccessPoint;
-import com.android.settingslib.wifi.AccessPointPreference;
-import com.android.settingslib.wifi.AccessPointPreference.UserBadgeCache;
import com.android.settingslib.wifi.WifiSavedConfigUtils;
-import java.util.Collections;
-import java.util.List;
import java.util.stream.Collectors;
/**
* Controller that manages a PreferenceGroup, which contains a list of subscribed access points.
*/
-public class SubscribedAccessPointsPreferenceController extends BasePreferenceController implements
- Preference.OnPreferenceClickListener {
+public class SubscribedAccessPointsPreferenceController extends
+ SavedAccessPointsPreferenceController {
- private static final String TAG = "SubscribedApPrefCtrl";
-
- private final WifiManager mWifiManager;
- private final UserBadgeCache mUserBadgeCache;
- private PreferenceGroup mPreferenceGroup;
- private SavedAccessPointsWifiSettings mHost;
- @VisibleForTesting
- List<AccessPoint> mAccessPoints;
-
- public SubscribedAccessPointsPreferenceController(Context context,
- String preferenceKey) {
+ public SubscribedAccessPointsPreferenceController(Context context, String preferenceKey) {
super(context, preferenceKey);
- mUserBadgeCache = new AccessPointPreference.UserBadgeCache(context.getPackageManager());
- mWifiManager = context.getSystemService(WifiManager.class);
- }
-
- public SubscribedAccessPointsPreferenceController setHost(SavedAccessPointsWifiSettings host) {
- mHost = host;
- return this;
}
@Override
- public int getAvailabilityStatus() {
- return mAccessPoints.size() > 0 ? AVAILABLE : CONDITIONALLY_UNAVAILABLE;
- }
-
- @Override
- public void displayPreference(PreferenceScreen screen) {
- mPreferenceGroup = screen.findPreference(getPreferenceKey());
- refreshSubscribedAccessPoints();
- updatePreference();
- super.displayPreference(screen);
- }
-
- @Override
- public boolean onPreferenceClick(Preference preference) {
- if (mHost != null) {
- final Preference preferenceInGroup =
- mPreferenceGroup.findPreference(preference.getKey());
- mHost.showWifiPage((AccessPointPreference) preferenceInGroup);
- }
- return false;
- }
-
- private void refreshSubscribedAccessPoints() {
+ protected void refreshSavedAccessPoints() {
mAccessPoints = WifiSavedConfigUtils.getAllConfigs(mContext, mWifiManager).stream()
.filter(accessPoint -> accessPoint.isPasspointConfig())
.sorted(SavedNetworkComparator.INSTANCE)
.collect(Collectors.toList());
}
-
- private void updatePreference() {
- mPreferenceGroup.removeAll();
- for (AccessPoint accessPoint : mAccessPoints) {
- final String key = accessPoint.getKey();
-
- final AccessPointPreference preference = new AccessPointPreference(accessPoint,
- mContext, mUserBadgeCache, true /* forSavedNetworks */);
- preference.setKey(key);
- preference.setIcon(null);
- preference.setOnPreferenceClickListener(this);
-
- mPreferenceGroup.addPreference(preference);
- }
- }
}
diff --git a/tests/robotests/src/com/android/settings/accounts/AccountPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/accounts/AccountPreferenceControllerTest.java
index 65f485e..bf64190 100644
--- a/tests/robotests/src/com/android/settings/accounts/AccountPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/accounts/AccountPreferenceControllerTest.java
@@ -46,6 +46,7 @@
import com.android.settings.AccessiblePreferenceCategory;
import com.android.settings.R;
import com.android.settings.SettingsPreferenceFragment;
+import com.android.settings.dashboard.profileselector.ProfileSelectFragment;
import com.android.settings.testutils.shadow.ShadowAccountManager;
import com.android.settings.testutils.shadow.ShadowContentResolver;
import com.android.settingslib.search.SearchIndexableRaw;
@@ -96,7 +97,8 @@
when(mAccountManager.getAuthenticatorTypesAsUser(anyInt()))
.thenReturn(new AuthenticatorDescription[0]);
when(mAccountManager.getAccountsAsUser(anyInt())).thenReturn(new Account[0]);
- mController = new AccountPreferenceController(mContext, mFragment, null, mAccountHelper);
+ mController = new AccountPreferenceController(mContext, mFragment, null, mAccountHelper,
+ ProfileSelectFragment.ALL);
}
@After
diff --git a/tests/robotests/src/com/android/settings/connecteddevice/AvailableMediaDeviceGroupControllerTest.java b/tests/robotests/src/com/android/settings/connecteddevice/AvailableMediaDeviceGroupControllerTest.java
index c4b5901..ad630ff 100644
--- a/tests/robotests/src/com/android/settings/connecteddevice/AvailableMediaDeviceGroupControllerTest.java
+++ b/tests/robotests/src/com/android/settings/connecteddevice/AvailableMediaDeviceGroupControllerTest.java
@@ -193,7 +193,7 @@
mAvailableMediaDeviceGroupController.onAudioModeChanged();
assertThat(mPreferenceGroup.getTitle()).isEqualTo(
- mContext.getText(R.string.connected_device_available_call_title));
+ mContext.getText(R.string.connected_device_call_device_title));
}
@Test
@@ -202,7 +202,7 @@
mAvailableMediaDeviceGroupController.onAudioModeChanged();
assertThat(mPreferenceGroup.getTitle()).isEqualTo(
- mContext.getText(R.string.connected_device_available_media_title));
+ mContext.getText(R.string.connected_device_media_device_title));
}
@Test
diff --git a/tests/robotests/src/com/android/settings/password/ChooseLockPasswordTest.java b/tests/robotests/src/com/android/settings/password/ChooseLockPasswordTest.java
index 73707a6..4bbf51d 100644
--- a/tests/robotests/src/com/android/settings/password/ChooseLockPasswordTest.java
+++ b/tests/robotests/src/com/android/settings/password/ChooseLockPasswordTest.java
@@ -41,6 +41,7 @@
import android.content.Intent;
import android.os.UserHandle;
+import com.android.internal.widget.LockscreenCredential;
import com.android.settings.R;
import com.android.settings.password.ChooseLockPassword.ChooseLockPasswordFragment;
import com.android.settings.password.ChooseLockPassword.IntentBuilder;
@@ -76,7 +77,6 @@
SettingsShadowResources.overrideResource(
com.android.internal.R.string.config_headlineFontFamily, "");
mShadowDpm = ShadowDevicePolicyManager.getShadow();
- mShadowDpm.setPasswordMaximumLength(16);
}
@After
@@ -87,7 +87,7 @@
@Test
public void intentBuilder_setPassword_shouldAddExtras() {
Intent intent = new IntentBuilder(application)
- .setPassword("password".getBytes())
+ .setPassword(LockscreenCredential.createPassword("password"))
.setPasswordQuality(DevicePolicyManager.PASSWORD_QUALITY_NUMERIC)
.setUserId(123)
.build();
@@ -95,9 +95,10 @@
assertThat(intent.getBooleanExtra(ChooseLockSettingsHelper.EXTRA_KEY_HAS_CHALLENGE, true))
.named("EXTRA_KEY_HAS_CHALLENGE")
.isFalse();
- assertThat(intent.getByteArrayExtra(ChooseLockSettingsHelper.EXTRA_KEY_PASSWORD))
+ assertThat((LockscreenCredential) intent.getParcelableExtra(
+ ChooseLockSettingsHelper.EXTRA_KEY_PASSWORD))
.named("EXTRA_KEY_PASSWORD")
- .isEqualTo("password".getBytes());
+ .isEqualTo(LockscreenCredential.createPassword("password"));
assertThat(intent.getIntExtra(PASSWORD_TYPE_KEY, 0))
.named("PASSWORD_TYPE_KEY")
.isEqualTo(DevicePolicyManager.PASSWORD_QUALITY_NUMERIC);
@@ -154,8 +155,8 @@
assertPasswordValidationResult(
/* minComplexity= */ PASSWORD_COMPLEXITY_NONE,
/* passwordType= */ PASSWORD_QUALITY_ALPHABETIC,
- /* userEnteredPassword= */ "",
- "Must contain at least 1 letter",
+ /* userEnteredPassword= */ LockscreenCredential.createNone(),
+ "Must contain at least 1 non-numerical character",
"Must be at least 10 characters");
}
@@ -166,7 +167,7 @@
assertPasswordValidationResult(
/* minComplexity= */ PASSWORD_COMPLEXITY_HIGH,
/* passwordType= */ PASSWORD_QUALITY_NUMERIC,
- /* userEnteredPassword= */ "",
+ /* userEnteredPassword= */ LockscreenCredential.createNone(),
"PIN must be at least 8 digits");
}
@@ -177,8 +178,8 @@
assertPasswordValidationResult(
/* minComplexity= */ PASSWORD_COMPLEXITY_MEDIUM,
/* passwordType= */ PASSWORD_QUALITY_ALPHABETIC,
- /* userEnteredPassword= */ "",
- "Must contain at least 1 letter",
+ /* userEnteredPassword= */ LockscreenCredential.createNone(),
+ "Must contain at least 1 non-numerical character",
"Must be at least 4 characters");
}
@@ -190,8 +191,8 @@
assertPasswordValidationResult(
/* minComplexity= */ PASSWORD_COMPLEXITY_LOW,
/* passwordType= */ PASSWORD_QUALITY_ALPHABETIC,
- /* userEnteredPassword= */ "",
- "Must contain at least 1 letter",
+ /* userEnteredPassword= */ LockscreenCredential.createNone(),
+ "Must contain at least 1 non-numerical character",
"Must contain at least 1 numerical digit",
"Must be at least 9 characters");
}
@@ -204,7 +205,7 @@
assertPasswordValidationResult(
/* minComplexity= */ PASSWORD_COMPLEXITY_MEDIUM,
/* passwordType= */ PASSWORD_QUALITY_NUMERIC,
- /* userEnteredPassword= */ "",
+ /* userEnteredPassword= */ LockscreenCredential.createNone(),
"PIN must be at least 11 digits");
}
@@ -216,9 +217,11 @@
assertPasswordValidationResult(
/* minComplexity= */ PASSWORD_COMPLEXITY_HIGH,
/* passwordType= */ PASSWORD_QUALITY_ALPHABETIC,
- /* userEnteredPassword= */ "",
+ /* userEnteredPassword= */ LockscreenCredential.createNone(),
"Must contain at least 2 special symbols",
- "Must be at least 6 characters");
+ "Must be at least 6 characters",
+ "Must contain at least 1 letter",
+ "Must contain at least 1 numerical digit");
}
@Test
@@ -229,7 +232,7 @@
assertPasswordValidationResult(
/* minComplexity= */ PASSWORD_COMPLEXITY_NONE,
/* passwordType= */ PASSWORD_QUALITY_NUMERIC,
- /* userEnteredPassword= */ "12345678",
+ /* userEnteredPassword= */ LockscreenCredential.createPassword("12345678"),
"Ascending, descending, or repeated sequence of digits isn't allowed");
}
@@ -241,7 +244,7 @@
assertPasswordValidationResult(
/* minComplexity= */ PASSWORD_COMPLEXITY_NONE,
/* passwordType= */ PASSWORD_QUALITY_ALPHABETIC,
- /* userEnteredPassword= */ "12345678",
+ /* userEnteredPassword= */ LockscreenCredential.createPassword("12345678"),
"Ascending, descending, or repeated sequence of digits isn't allowed");
}
@@ -253,7 +256,7 @@
assertPasswordValidationResult(
/* minComplexity= */ PASSWORD_COMPLEXITY_HIGH,
/* passwordType= */ PASSWORD_QUALITY_NUMERIC,
- /* userEnteredPassword= */ "12345678",
+ /* userEnteredPassword= */ LockscreenCredential.createPassword("12345678"),
"Ascending, descending, or repeated sequence of digits isn't allowed");
}
@@ -265,7 +268,7 @@
assertPasswordValidationResult(
/* minComplexity= */ PASSWORD_COMPLEXITY_HIGH,
/* passwordType= */ PASSWORD_QUALITY_NUMERIC,
- /* userEnteredPassword= */ "12345678",
+ /* userEnteredPassword= */ LockscreenCredential.createPassword("12345678"),
"Ascending, descending, or repeated sequence of digits isn't allowed");
}
@@ -277,8 +280,8 @@
assertPasswordValidationResult(
/* minComplexity= */ PASSWORD_COMPLEXITY_LOW,
/* passwordType= */ PASSWORD_QUALITY_ALPHABETIC,
- /* userEnteredPassword= */ "12345678",
- "Must contain at least 1 letter");
+ /* userEnteredPassword= */ LockscreenCredential.createPassword("12345678"),
+ "Ascending, descending, or repeated sequence of digits isn't allowed");
}
@Test
@@ -288,9 +291,9 @@
assertPasswordValidationResult(
/* minComplexity= */ PASSWORD_COMPLEXITY_HIGH,
/* passwordType= */ PASSWORD_QUALITY_ALPHABETIC,
- /* userEnteredPassword= */ "",
- "Must contain at least 1 letter",
- "Must be at least 6 characters");
+ /* userEnteredPassword= */ LockscreenCredential.createNone(),
+ "Must be at least 6 characters",
+ "Must contain at least 1 non-numerical character");
}
@Test
@@ -300,9 +303,9 @@
assertPasswordValidationResult(
/* minComplexity= */ PASSWORD_COMPLEXITY_HIGH,
/* passwordType= */ PASSWORD_QUALITY_ALPHABETIC,
- /* userEnteredPassword= */ "1",
- "Must contain at least 1 letter",
- "Must be at least 6 characters");
+ /* userEnteredPassword= */ LockscreenCredential.createPassword("1"),
+ "Must be at least 6 characters",
+ "Must contain at least 1 non-numerical character");
}
@Test
@@ -312,7 +315,7 @@
assertPasswordValidationResult(
/* minComplexity= */ PASSWORD_COMPLEXITY_HIGH,
/* passwordType= */ PASSWORD_QUALITY_ALPHABETIC,
- /* userEnteredPassword= */ "b",
+ /* userEnteredPassword= */ LockscreenCredential.createPassword("b"),
"Must be at least 6 characters");
}
@@ -323,11 +326,33 @@
assertPasswordValidationResult(
/* minComplexity= */ PASSWORD_COMPLEXITY_HIGH,
/* passwordType= */ PASSWORD_QUALITY_ALPHABETIC,
- /* userEnteredPassword= */ "b1",
+ /* userEnteredPassword= */ LockscreenCredential.createPassword("b1"),
"Must be at least 6 characters");
}
@Test
+ public void processAndValidatePasswordRequirements_defaultPinMinimumLength() {
+ mShadowDpm.setPasswordQuality(PASSWORD_QUALITY_UNSPECIFIED);
+
+ assertPasswordValidationResult(
+ /* minComplexity= */ PASSWORD_COMPLEXITY_NONE,
+ /* passwordType= */ PASSWORD_QUALITY_NUMERIC,
+ /* userEnteredPassword= */ LockscreenCredential.createPassword("11"),
+ "PIN must be at least 4 digits");
+ }
+
+ @Test
+ public void processAndValidatePasswordRequirements_maximumLength() {
+ mShadowDpm.setPasswordQuality(PASSWORD_QUALITY_UNSPECIFIED);
+
+ assertPasswordValidationResult(
+ /* minComplexity= */ PASSWORD_COMPLEXITY_NONE,
+ /* passwordType= */ PASSWORD_QUALITY_ALPHABETIC,
+ LockscreenCredential.createPassword("01234567890123456789"),
+ "Must be fewer than 17 characters");
+ }
+
+ @Test
public void assertThat_chooseLockIconChanged_WhenFingerprintExtraSet() {
ShadowDrawable drawable = setActivityAndGetIconDrawable(true);
assertThat(drawable.getCreatedFromResId()).isEqualTo(R.drawable.ic_fingerprint_header);
@@ -359,18 +384,16 @@
}
private void assertPasswordValidationResult(@PasswordComplexity int minComplexity,
- int passwordType, String userEnteredPassword, String... expectedValidationResult) {
+ int passwordType, LockscreenCredential userEnteredPassword,
+ String... expectedValidationResult) {
Intent intent = new Intent();
intent.putExtra(CONFIRM_CREDENTIALS, false);
intent.putExtra(PASSWORD_TYPE_KEY, passwordType);
intent.putExtra(EXTRA_KEY_REQUESTED_MIN_COMPLEXITY, minComplexity);
ChooseLockPassword activity = buildChooseLockPasswordActivity(intent);
ChooseLockPasswordFragment fragment = getChooseLockPasswordFragment(activity);
- byte[] userEnteredPasswordBytes = userEnteredPassword != null
- ? userEnteredPassword.getBytes() : null;
- int validateResult = fragment.validatePassword(userEnteredPasswordBytes);
- String[] messages = fragment.convertErrorCodeToMessages(validateResult);
-
+ fragment.validatePassword(userEnteredPassword);
+ String[] messages = fragment.convertErrorCodeToMessages();
assertThat(messages).asList().containsExactly((Object[]) expectedValidationResult);
}
}
diff --git a/tests/robotests/src/com/android/settings/password/ChooseLockPatternTest.java b/tests/robotests/src/com/android/settings/password/ChooseLockPatternTest.java
index 48ebbec..0100744 100644
--- a/tests/robotests/src/com/android/settings/password/ChooseLockPatternTest.java
+++ b/tests/robotests/src/com/android/settings/password/ChooseLockPatternTest.java
@@ -24,6 +24,8 @@
import android.os.UserHandle;
import android.view.View;
+import com.android.internal.widget.LockPatternUtils;
+import com.android.internal.widget.LockscreenCredential;
import com.android.settings.R;
import com.android.settings.password.ChooseLockPattern.ChooseLockPatternFragment;
import com.android.settings.password.ChooseLockPattern.IntentBuilder;
@@ -52,7 +54,7 @@
@Test
public void intentBuilder_setPattern_shouldAddExtras() {
Intent intent = new IntentBuilder(application)
- .setPattern("pattern".getBytes())
+ .setPattern(createPattern("1234"))
.setUserId(123)
.build();
@@ -60,10 +62,10 @@
.getBooleanExtra(ChooseLockSettingsHelper.EXTRA_KEY_HAS_CHALLENGE, true))
.named("EXTRA_KEY_HAS_CHALLENGE")
.isFalse();
- assertThat(intent
- .getByteArrayExtra(ChooseLockSettingsHelper.EXTRA_KEY_PASSWORD))
+ assertThat((LockscreenCredential) intent
+ .getParcelableExtra(ChooseLockSettingsHelper.EXTRA_KEY_PASSWORD))
.named("EXTRA_KEY_PASSWORD")
- .isEqualTo("pattern".getBytes());
+ .isEqualTo(createPattern("1234"));
assertThat(intent.getIntExtra(Intent.EXTRA_USER_ID, 0))
.named("EXTRA_USER_ID")
.isEqualTo(123);
@@ -120,4 +122,9 @@
.build())
.setup().get();
}
+
+ private LockscreenCredential createPattern(String patternString) {
+ return LockscreenCredential.createPattern(LockPatternUtils.byteArrayToPattern(
+ patternString.getBytes()));
+ }
}
diff --git a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowDevicePolicyManager.java b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowDevicePolicyManager.java
index ca75916..b8fdf89 100644
--- a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowDevicePolicyManager.java
+++ b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowDevicePolicyManager.java
@@ -6,6 +6,8 @@
import android.annotation.Nullable;
import android.annotation.UserIdInt;
import android.app.admin.DevicePolicyManager;
+import android.app.admin.PasswordMetrics;
+import android.app.admin.PasswordPolicy;
import android.content.ComponentName;
import org.robolectric.RuntimeEnvironment;
@@ -26,7 +28,6 @@
private ComponentName mDeviceOwnerComponentName;
private int mDeviceOwnerUserId = -1;
private int mPasswordMinQuality = PASSWORD_QUALITY_UNSPECIFIED;
- private int mPasswordMaxLength = 16;
private int mPasswordMinLength = 0;
private int mPasswordMinSymbols = 0;
@@ -77,41 +78,26 @@
}
@Implementation
- public int getPasswordQuality(ComponentName admin, int userHandle) {
- return mPasswordMinQuality;
+ public PasswordMetrics getPasswordMinimumMetrics(int userHandle) {
+ PasswordPolicy policy = new PasswordPolicy();
+ policy.quality = mPasswordMinQuality;
+ policy.length = mPasswordMinLength;
+ policy.symbols = mPasswordMinSymbols;
+ return policy.getMinMetrics();
}
public void setPasswordQuality(int quality) {
mPasswordMinQuality = quality;
}
- @Implementation
- public int getPasswordMinimumLength(ComponentName admin, int userHandle) {
- return mPasswordMinLength;
- }
-
public void setPasswordMinimumLength(int length) {
mPasswordMinLength = length;
}
- @Implementation
- public int getPasswordMinimumSymbols(ComponentName admin, int userHandle) {
- return mPasswordMinSymbols;
- }
-
public void setPasswordMinimumSymbols(int numOfSymbols) {
mPasswordMinSymbols = numOfSymbols;
}
- @Implementation
- public int getPasswordMaximumLength(int quality) {
- return mPasswordMaxLength;
- }
-
- public void setPasswordMaximumLength(int length) {
- mPasswordMaxLength = length;
- }
-
public static ShadowDevicePolicyManager getShadow() {
return (ShadowDevicePolicyManager) Shadow.extract(
RuntimeEnvironment.application.getSystemService(DevicePolicyManager.class));
diff --git a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowLockPatternUtils.java b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowLockPatternUtils.java
index e9be346..38756ac 100644
--- a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowLockPatternUtils.java
+++ b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowLockPatternUtils.java
@@ -20,6 +20,7 @@
import android.content.ComponentName;
import com.android.internal.widget.LockPatternUtils;
+import com.android.internal.widget.LockscreenCredential;
import org.robolectric.annotation.Implementation;
import org.robolectric.annotation.Implements;
@@ -66,7 +67,8 @@
}
@Implementation
- protected byte[] getPasswordHistoryHashFactor(byte[] currentPassword, int userId) {
+ protected byte[] getPasswordHistoryHashFactor(LockscreenCredential currentPassword,
+ int userId) {
return null;
}
diff --git a/tests/robotests/src/com/android/settings/widget/SwitchBarTest.java b/tests/robotests/src/com/android/settings/widget/SwitchBarTest.java
index f186222..31cb966 100644
--- a/tests/robotests/src/com/android/settings/widget/SwitchBarTest.java
+++ b/tests/robotests/src/com/android/settings/widget/SwitchBarTest.java
@@ -85,6 +85,24 @@
}
@Test
+ public void setCheck_customLabelWithStringType_shouldUpdateTextAndBackground() {
+ final String onText = mContext.getString(
+ R.string.accessibility_service_master_switch_title);
+ final String offText = mContext.getString(
+ R.string.accessibility_service_master_switch_title);
+ final TextView switchBarTextView = ((TextView) mBar.findViewById(R.id.switch_text));
+
+ mBar.setSwitchBarText(onText, offText);
+
+ assertThat(switchBarTextView.getText()).isEqualTo(offText);
+
+ mBar.setChecked(true);
+
+ assertThat(mBar.getBackground()).isInstanceOf(ColorDrawable.class);
+ assertThat(switchBarTextView.getText()).isEqualTo(onText);
+ }
+
+ @Test
public void disabledByAdmin_shouldDelegateToRestrictedIcon() {
mBar.setDisabledByAdmin(new EnforcedAdmin());
assertThat(mBar.getDelegatingView().getId()).isEqualTo(R.id.restricted_icon);
diff --git a/tests/robotests/src/com/android/settings/wifi/savedaccesspoints/SavedAccessPointsPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/wifi/savedaccesspoints/SavedAccessPointsPreferenceControllerTest.java
index 73e1297..e955224 100644
--- a/tests/robotests/src/com/android/settings/wifi/savedaccesspoints/SavedAccessPointsPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/wifi/savedaccesspoints/SavedAccessPointsPreferenceControllerTest.java
@@ -98,7 +98,7 @@
@Test
@Config(shadows = ShadowAccessPoint.class)
- public void refreshSavedAccessPoints_shouldListNonSubscribedAPs() {
+ public void displayPreference_oneAccessPoint_shouldListNonSubscribedAPs() {
final WifiConfiguration config = new WifiConfiguration();
config.SSID = "SSID";
config.BSSID = "BSSID";
@@ -117,7 +117,7 @@
@Test
@Config(shadows = ShadowAccessPoint.class)
- public void refreshSavedAccessPoints_shouldNotListSubscribedAPs() {
+ public void displayPreference_onePasspoint_shouldNotListSubscribedAPs() {
mWifiManager.addOrUpdatePasspointConfiguration(
SubscribedAccessPointsPreferenceControllerTest.createMockPasspointConfiguration());
diff --git a/tests/robotests/src/com/android/settings/wifi/savedaccesspoints/SubscribedAccessPointsPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/wifi/savedaccesspoints/SubscribedAccessPointsPreferenceControllerTest.java
index f9307db..b28498b 100644
--- a/tests/robotests/src/com/android/settings/wifi/savedaccesspoints/SubscribedAccessPointsPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/wifi/savedaccesspoints/SubscribedAccessPointsPreferenceControllerTest.java
@@ -16,9 +16,6 @@
package com.android.settings.wifi.savedaccesspoints;
-import static com.android.settings.core.BasePreferenceController.AVAILABLE;
-import static com.android.settings.core.BasePreferenceController.CONDITIONALLY_UNAVAILABLE;
-
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
@@ -32,7 +29,6 @@
import android.net.wifi.WifiManager;
import android.net.wifi.hotspot2.PasspointConfiguration;
import android.net.wifi.hotspot2.pps.HomeSp;
-import android.os.Bundle;
import androidx.preference.PreferenceCategory;
import androidx.preference.PreferenceScreen;
@@ -42,9 +38,6 @@
import com.android.settingslib.wifi.AccessPoint;
import com.android.settingslib.wifi.AccessPointPreference;
-import java.util.ArrayList;
-import java.util.Arrays;
-
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -84,23 +77,8 @@
}
@Test
- public void getAvailability_noSavedAccessPoint_shouldNotAvailable() {
- mController.mAccessPoints = new ArrayList<>();
-
- assertThat(mController.getAvailabilityStatus()).isEqualTo(CONDITIONALLY_UNAVAILABLE);
- }
-
- @Test
- public void getAvailability_oneSavedAccessPoint_shouldAvailable() {
- final AccessPoint accessPoint = new AccessPoint(mContext, new Bundle() /* savedState */);
- mController.mAccessPoints = new ArrayList<AccessPoint>(Arrays.asList(accessPoint));
-
- assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE);
- }
-
- @Test
@Config(shadows = ShadowAccessPoint.class)
- public void refreshSubscribedAccessPoints_shouldNotListNonSubscribedAPs() {
+ public void displayPreference_oneAccessPoint_shouldNotListNonSubscribedAPs() {
final WifiConfiguration config = new WifiConfiguration();
config.SSID = "SSID";
config.BSSID = "BSSID";
@@ -114,7 +92,7 @@
@Test
@Config(shadows = ShadowAccessPoint.class)
- public void refreshSubscribedAccessPoints_shouldListSubscribedAPs() {
+ public void displayPreference_onePasspoint_shouldListSubscribedAPs() {
mWifiManager.addOrUpdatePasspointConfiguration(createMockPasspointConfiguration());
mController.displayPreference(mPreferenceScreen);
diff --git a/tests/unit/src/com/android/settings/RegulatoryInfoDisplayActivityTest.java b/tests/unit/src/com/android/settings/RegulatoryInfoDisplayActivityTest.java
deleted file mode 100644
index 1701ddf..0000000
--- a/tests/unit/src/com/android/settings/RegulatoryInfoDisplayActivityTest.java
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.settings;
-
-import static junit.framework.Assert.fail;
-
-import android.app.Instrumentation;
-import android.app.UiAutomation;
-import android.content.Context;
-import android.content.Intent;
-import android.content.pm.ResolveInfo;
-
-import androidx.test.InstrumentationRegistry;
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public class RegulatoryInfoDisplayActivityTest {
- private static final String TAG = "RegulatoryInfoTest";
-
- private Instrumentation mInstrumentation;
- private Intent mRegulatoryInfoIntent;
- private UiAutomation mUiAutomation;
-
- @Before
- public void setUp() {
- mInstrumentation = InstrumentationRegistry.getInstrumentation();
- mUiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
- mRegulatoryInfoIntent = new Intent("android.settings.SHOW_REGULATORY_INFO")
- .addCategory(Intent.CATEGORY_DEFAULT)
- .setPackage(mInstrumentation.getTargetContext().getPackageName());
- }
-
- @Test
- public void resolveRegulatoryInfoIntent_intentShouldMatchConfig() {
- // Load intent from PackageManager and load config from Settings app
- final Context context = mInstrumentation.getTargetContext();
-
- final boolean hasRegulatoryInfo = context.getResources()
- .getBoolean(R.bool.config_show_regulatory_info);
- final ResolveInfo resolveInfo = mInstrumentation.getTargetContext().getPackageManager()
- .resolveActivity(mRegulatoryInfoIntent, 0 /* flags */);
-
- // Check config and intent both enable or both disabled.
- if (hasRegulatoryInfo && resolveInfo == null) {
- fail("Config enables regulatory info but there is no handling intent");
- return;
- }
- if (!hasRegulatoryInfo && resolveInfo != null) {
- fail("Config disables regulatory info but there is at least one handling intent");
- return;
- }
- }
-}
diff --git a/tests/unit/src/com/android/settings/password/ChooseLockGenericTest.java b/tests/unit/src/com/android/settings/password/ChooseLockGenericTest.java
index 582afd2..4b539cc 100644
--- a/tests/unit/src/com/android/settings/password/ChooseLockGenericTest.java
+++ b/tests/unit/src/com/android/settings/password/ChooseLockGenericTest.java
@@ -43,6 +43,7 @@
import androidx.test.runner.lifecycle.Stage;
import com.android.internal.widget.LockPatternUtils;
+import com.android.internal.widget.LockscreenCredential;
import org.junit.Before;
import org.junit.Rule;
@@ -150,7 +151,7 @@
.putExtra(LockPatternUtils.PASSWORD_TYPE_KEY,
DevicePolicyManager.PASSWORD_QUALITY_NUMERIC)
.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_PASSWORD,
- "12345")
+ LockscreenCredential.createPin("12345"))
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
getInstrumentation().getContext().startActivity(newPasswordIntent);
mDevice.waitForIdle();