Merge changes from topic "au-initial-commit-master"
* changes:
Update text when Active Unlock is enabled.
Update tile summary from ContentProvider.
Add Active Unlock tile under face & fingerprint
Add ActiveUnlock check when picking preference
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index b5818c2b..17b9414 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -1875,6 +1875,20 @@
android:value="@string/menu_key_security"/>
</activity>
+ <activity
+ android:name="Settings$MoreSecurityPrivacySettingsActivity"
+ android:label="@string/more_security_privacy_settings"
+ android:exported="true">
+ <intent-filter android:priority="1">
+ <action android:name="com.android.settings.MORE_SECURITY_PRIVACY_SETTINGS" />
+ <category android:name="android.intent.category.DEFAULT" />
+ </intent-filter>
+ <meta-data android:name="com.android.settings.FRAGMENT_CLASS"
+ android:value="com.android.settings.safetycenter.MoreSecurityPrivacyFragment" />
+ <meta-data android:name="com.android.settings.HIGHLIGHT_MENU_KEY"
+ android:value="@string/menu_key_safety_center"/>
+ </activity>
+
<activity android:name="MonitoringCertInfoActivity"
android:label=""
android:theme="@style/Transparent"
@@ -3622,7 +3636,7 @@
android:label="@string/notification_channel_title"
android:theme="@style/Theme.Panel"
android:excludeFromRecents="true"
- android:configChanges="orientation|keyboardHidden|screenSize"
+ android:configChanges="keyboardHidden|screenSize"
android:exported="true">
<intent-filter android:priority="1">
<action android:name="android.settings.CHANNEL_NOTIFICATION_SETTINGS" />
diff --git a/OWNERS b/OWNERS
index 93e04a7..881e2c7 100644
--- a/OWNERS
+++ b/OWNERS
@@ -17,6 +17,8 @@
# Emergency only
lijun@google.com
+wangqi@google.com
+yanglu@google.com
# Exempt resource files (because they are in a flat directory and too hard to manage via OWNERS)
-per-file *.xml=*
+per-file res/**=*
diff --git a/res-product/values/strings.xml b/res-product/values/strings.xml
index d549d66..a94efb5 100644
--- a/res-product/values/strings.xml
+++ b/res-product/values/strings.xml
@@ -245,6 +245,12 @@
<string name="security_settings_fingerprint_enroll_finish_v2_message" product="device">Now you can use your fingerprint to unlock your device or verify it\u2019s you, like when you sign in to apps or approve a purchase</string>
<!-- Message shown in fingerprint enrollment dialog once enrollment is completed (default) [CHAR LIMIT=NONE] -->
<string name="security_settings_fingerprint_enroll_finish_v2_message" product="default">Now you can use your fingerprint to unlock your phone or verify it\u2019s you, like when you sign in to apps or approve a purchase</string>
+ <!-- Message shown in fingerprint enrollment dialog once enrollment is completed (tablet) [CHAR LIMIT=NONE] -->
+ <string name="security_settings_fingerprint_enroll_finish_v2_add_fingerprint_message" product="tablet">Now you can use your fingerprint to unlock your tablet or verify it\u2019s you, like when you sign in to apps or approve a purchase. \n\nAdd another fingerprint so it\u2019s easier to unlock when you hold your tablet in different ways.</string>
+ <!-- Message shown in fingerprint enrollment dialog once enrollment is completed (device) [CHAR LIMIT=NONE] -->
+ <string name="security_settings_fingerprint_enroll_finish_v2_add_fingerprint_message" product="device">Now you can use your fingerprint to unlock your device or verify it\u2019s you, like when you sign in to apps or approve a purchase.\n\nAdd another fingerprint so it\u2019s easier to unlock when you hold your device in different ways.</string>
+ <!-- Message shown in fingerprint enrollment dialog once enrollment is completed (default) [CHAR LIMIT=NONE] -->
+ <string name="security_settings_fingerprint_enroll_finish_v2_add_fingerprint_message" product="default">Now you can use your fingerprint to unlock your phone or verify it\u2019s you, like when you sign in to apps or approve a purchase.\n\nAdd another fingerprint so it\u2019s easier to unlock when you hold your phone in different ways.</string>
<!-- Dialog text shown when the user tries to skip setting up a screen lock, warning that they can't continue to set up fingerprint. (tablet) [CHAR LIMIT=NONE] -->
<string name="lock_screen_pin_skip_message" product="tablet">A PIN protects the tablet if it\u2019s lost or stolen</string>
<!-- Dialog text shown when the user tries to skip setting up a screen lock, warning that they can't continue to set up fingerprint. (tablet) [CHAR LIMIT=NONE] -->
diff --git a/res/drawable/checkbox_circle_shape.xml b/res/drawable/checkbox_circle_shape.xml
new file mode 100644
index 0000000..68c5a2e
--- /dev/null
+++ b/res/drawable/checkbox_circle_shape.xml
@@ -0,0 +1,24 @@
+<!--
+ ~ Copyright (C) 2023 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item
+ android:state_checked="true"
+ android:drawable="@drawable/ic_check_circle_filled_24dp" />
+ <item
+ android:state_checked="false"
+ android:drawable="@drawable/ic_circle_outline_24dp" />
+</selector>
\ No newline at end of file
diff --git a/res/drawable/ic_check_circle_filled_24dp.xml b/res/drawable/ic_check_circle_filled_24dp.xml
new file mode 100644
index 0000000..8e1f1e7
--- /dev/null
+++ b/res/drawable/ic_check_circle_filled_24dp.xml
@@ -0,0 +1,27 @@
+<!--
+ ~ Copyright (C) 2023 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?androidprv:attr/colorAccentPrimaryVariant">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10c5.52,0 10,-4.48 10,-10S17.52,2 12,2zM10.59,16.6l-4.24,-4.24l1.41,-1.41l2.83,2.83l5.66,-5.66l1.41,1.41L10.59,16.6z"/>
+</vector>
diff --git a/res/drawable/ic_circle_outline_24dp.xml b/res/drawable/ic_circle_outline_24dp.xml
new file mode 100644
index 0000000..b9ffca5
--- /dev/null
+++ b/res/drawable/ic_circle_outline_24dp.xml
@@ -0,0 +1,26 @@
+<!--
+ ~ Copyright (C) 2023 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM12,20c-4.42,0 -8,-3.58 -8,-8s3.58,-8 8,-8 8,3.58 8,8 -3.58,8 -8,8z"/>
+</vector>
\ No newline at end of file
diff --git a/res/drawable/ic_pan_tool_18dp.xml b/res/drawable/ic_pan_tool_18dp.xml
index 36b133b..e3b21fa 100644
--- a/res/drawable/ic_pan_tool_18dp.xml
+++ b/res/drawable/ic_pan_tool_18dp.xml
@@ -19,12 +19,13 @@
android:width="18dp"
android:height="18dp"
android:viewportWidth="48"
- android:viewportHeight="48">
+ android:viewportHeight="48"
+ android:tint="?android:attr/colorControlNormal">
<group>
<clip-path
android:pathData="M0,0h48v48H0z M 0,0"/>
<path
android:pathData="M46,11v29c0,4.4 -3.6,8 -8,8H23.4c-2.16,0 -4.2,-0.86 -5.7,-2.38L2,29.66s2.52,-2.46 2.6,-2.5c0.44,-0.38 0.98,-0.58 1.58,-0.58 0.44,0 0.84,0.12 1.2,0.32 0.08,0.02 8.62,4.92 8.62,4.92V8c0,-1.66 1.34,-3 3,-3s3,1.34 3,3v14h2V3c0,-1.66 1.34,-3 3,-3s3,1.34 3,3v19h2V5c0,-1.66 1.34,-3 3,-3s3,1.34 3,3v17h2V11c0,-1.66 1.34,-3 3,-3s3,1.34 3,3z"
- android:fillColor="#757575"/>
+ android:fillColor="#FFFFFF"/>
</group>
</vector>
diff --git a/res/drawable/ic_visibility_18dp.xml b/res/drawable/ic_visibility_18dp.xml
index 9dc269f..81df477 100644
--- a/res/drawable/ic_visibility_18dp.xml
+++ b/res/drawable/ic_visibility_18dp.xml
@@ -19,8 +19,9 @@
android:width="18dp"
android:height="18dp"
android:viewportWidth="48"
- android:viewportHeight="48">
+ android:viewportHeight="48"
+ android:tint="?android:attr/colorControlNormal">
<path
android:pathData="M24,9C14,9 5.46,15.22 2,24c3.46,8.78 12,15 22,15 10.01,0 18.54,-6.22 22,-15 -3.46,-8.78 -11.99,-15 -22,-15zM24,34c-5.52,0 -10,-4.48 -10,-10s4.48,-10 10,-10 10,4.48 10,10 -4.48,10 -10,10zM24,18c-3.31,0 -6,2.69 -6,6s2.69,6 6,6 6,-2.69 6,-6 -2.69,-6 -6,-6z"
- android:fillColor="#757575"/>
+ android:fillColor="#FFFFFF"/>
</vector>
diff --git a/res/layout/choose_lock_password.xml b/res/layout/choose_lock_password.xml
index 70919a6..b748f94 100644
--- a/res/layout/choose_lock_password.xml
+++ b/res/layout/choose_lock_password.xml
@@ -67,8 +67,31 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
+ <CheckBox
+ android:id="@+id/auto_pin_confirm_enabler"
+ android:layout_marginTop="8dp"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_horizontal"
+ android:gravity="center"
+ android:paddingLeft="14dp"
+ android:text="@string/auto_pin_confirm_user_message"
+ android:textSize="16sp"
+ android:button="@drawable/checkbox_circle_shape"
+ android:visibility="gone" />
+
</LinearLayout>
+ <TextView
+ android:id="@+id/auto_pin_confirm_security_message"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="24dp"
+ android:gravity="center"
+ android:text="@string/auto_pin_confirm_opt_in_security_message"
+ android:textSize="16sp"
+ android:visibility="gone" />
+
<Button
android:id="@+id/screen_lock_options"
style="@style/SudGlifButton.Tertiary"
diff --git a/res/layout/notification_channel_panel.xml b/res/layout/notification_channel_panel.xml
index e59bb5d..06635a0 100644
--- a/res/layout/notification_channel_panel.xml
+++ b/res/layout/notification_channel_panel.xml
@@ -17,6 +17,7 @@
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/main_content"
android:layout_height="@dimen/output_switcher_slice_max_height"
+ android:maxHeight="@dimen/output_switcher_slice_max_height"
android:background="@drawable/settings_panel_background"
android:orientation="vertical"
android:layout_width="match_parent">
diff --git a/res/values-land/dimens.xml b/res/values-land/dimens.xml
index 644486d..4295dd4 100644
--- a/res/values-land/dimens.xml
+++ b/res/values-land/dimens.xml
@@ -19,4 +19,5 @@
<dimen name="biometric_auth_pattern_view_size">248dp</dimen>
<dimen name="biometric_auth_pattern_view_max_size">348dp</dimen>
+ <dimen name="output_switcher_slice_max_height">300dp</dimen>
</resources>
diff --git a/res/values/config.xml b/res/values/config.xml
index 0c610e3..aa345ca 100755
--- a/res/values/config.xml
+++ b/res/values/config.xml
@@ -101,6 +101,14 @@
-->
</string-array>
+ <!-- List containing the component names of pre-installed speech services. -->
+ <string-array name="config_preinstalled_speech_services" translatable="false">
+ <!--
+ <item>com.example.package.first/com.example.class.FirstService</item>
+ <item>com.example.package.second/com.example.class.SecondService</item>
+ -->
+ </string-array>
+
<!-- List containing the component names of pre-installed interaction control services. -->
<string-array name="config_preinstalled_interaction_control_services" translatable="false">
<!--
@@ -109,8 +117,9 @@
-->
</string-array>
- <!-- List containing the order of services in screen reader category by componentname.
- All componentnames in a category need to be specified to guarantee correct behavior.-->
+ <!-- List containing the order of services in screen reader category by {@link ComponentName}.
+ All {@link ComponentName} in a category need to be specified to guarantee correct
+ behavior.-->
<string-array name="config_order_screen_reader_services" translatable="false">
<!--
<item>com.example.package.first/com.example.class.FirstService</item>
@@ -119,8 +128,8 @@
</string-array>
<!-- List containing the order of services in captions category by preference key or
- componentname. All preference keys in a category need to be specified to guarantee correct
- behavior.-->
+ {@link ComponentName}. All preference keys in a category need to be specified to guarantee
+ correct behavior.-->
<string-array name="config_order_captions_services" translatable="false">
<!--
<item>com.example.package.first/com.example.class.FirstService</item>
@@ -131,8 +140,8 @@
-->
</string-array>
- <!-- List containing the order of services in audio and caption category by preference key
- or componentname. All preference keys in a category need to be specified to guarantee
+ <!-- List containing the order of services in audio and caption category by preference key or
+ {@link ComponentName}. All preference keys in a category need to be specified to guarantee
correct behavior.-->
<string-array name="config_order_audio_services" translatable="false">
<!--
@@ -144,8 +153,8 @@
-->
</string-array>
- <!-- List containing the order of services in display category by preference key
- or componentname. All preference keys in a category need to be specified to guarantee
+ <!-- List containing the order of services in display category by preference key or
+ {@link ComponentName}. All preference keys in a category need to be specified to guarantee
correct behavior.-->
<string-array name="config_order_display_services" translatable="false">
<!--
@@ -157,8 +166,21 @@
-->
</string-array>
- <!-- List containing the order of services in interaction control category by preference key
- or componentname. All preference keys in a category need to be specified to guarantee
+ <!-- List containing the order of services in speech category by preference key or
+ {@link ComponentName}. All preference keys in a category need to be specified to guarantee
+ correct behavior.-->
+ <string-array name="config_order_speech_services" translatable="false">
+ <!--
+ <item>com.example.package.first/com.example.class.FirstService</item>
+ <item>com.example.package.second/com.example.class.SecondService</item>
+ <item>font_size_preference_screen</item>
+ <item>dark_ui_mode_accessibility</item>
+ <item>...</item>
+ -->
+ </string-array>
+
+ <!-- List containing the order of services in interaction control category by preference key or
+ {@link ComponentName}. All preference keys in a category need to be specified to guarantee
correct behavior.-->
<string-array name="config_order_interaction_control_services" translatable="false">
<!--
diff --git a/res/values/strings.xml b/res/values/strings.xml
index cd1b909..29a56e1 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -827,6 +827,8 @@
<!-- Biometric settings --><skip />
<!-- Title shown for menu item that launches biometric settings. [CHAR LIMIT=66] -->
<string name="security_settings_biometric_preference_title">Face & Fingerprint Unlock</string>
+ <!-- Title shown for work menu item that launches biometric settings. [CHAR LIMIT=66] -->
+ <string name="security_settings_work_biometric_preference_title">Face & Fingerprint Unlock for work</string>
<!-- Message shown in summary field of biometric settings. [CHAR LIMIT=66] -->
<string name="security_settings_biometric_preference_summary_none_enrolled">Tap to set up</string>
<!-- Message shown in summary field of biometric settings when face is enrolled, and multiple fingerprints are enrolled. [CHAR LIMIT=66]-->
@@ -1010,6 +1012,15 @@
<!-- Title for the section that has additional privacy settings. [CHAR LIMIT=60] -->
<string name="privacy_advanced_settings">More privacy settings</string>
+ <!-- Title for the subpage in the "Security & privacy". This page consists of the more security and privacy settings. Can be navigated by Settings -> Security & privacy -> More Settings [CHAR LIMIT=NONE] -->
+ <string name="more_security_privacy_settings">More settings</string>
+ <!-- Title for the section that has security entries in the More Settings page. [CHAR LIMIT=60] -->
+ <string name="security_header">Security</string>
+ <!-- Title for the section that has privacy entries in the More Settings page. [CHAR LIMIT=60] -->
+ <string name="privacy_header">Privacy</string>
+ <!-- Title for the section that has work profile entries in the More Settings page. [CHAR LIMIT=60] -->
+ <string name="work_profile_category_header">Work profile</string>
+
<!-- Text shown when "Add fingerprint" button is disabled -->
<string name="fingerprint_add_max">You can add up to <xliff:g id="count" example="5">%d</xliff:g> fingerprints</string>
<!-- Text shown when users has enrolled a maximum number of fingerprints [CHAR LIMIT=NONE] -->
@@ -1079,6 +1090,15 @@
<!-- Title for dialog in screen lock settings, allowing users to choose other types of screen locks. [CHAR LIMIT=40] -->
<string name="setup_lock_settings_options_dialog_title">Screen lock options</string>
+ <!-- Title of the lock screen auto pin confirm setting. [CHAR LIMIT=NONE] -->
+ <string name="lock_screen_auto_pin_confirm_title">Auto-confirm unlock</string>
+ <!-- Summary of the lock screen auto pin confirm setting. [CHAR LIMIT=NONE] -->
+ <string name="lock_screen_auto_pin_confirm_summary">Unlock automatically if you input a correct PIN of 6 digits or more. This is slightly less secure than tapping Enter to confirm.</string>
+ <!-- Message shown to check auto pin confirmation feature when the user is updating the PIN. [CHAR LIMIT=NONE] -->
+ <string name="auto_pin_confirm_user_message">Auto-confirm correct PIN</string>
+ <!-- Message shown to explain the security concern if a user opts-in to the auto-pin feature. [CHAR LIMIT=NONE] -->
+ <string name="auto_pin_confirm_opt_in_security_message">Confirming your PIN by tapping Enter is more secure than using auto-confirm</string>
+
<!-- Main Security lock settings --><skip />
<!-- Title for PreferenceScreen to launch picker for security method when there is none [CHAR LIMIT=22] -->
<string name="unlock_set_unlock_launch_picker_title">Screen lock</string>
@@ -1239,6 +1259,12 @@
other {PIN must be at least # digits}
}</string>
+ <!-- Hint shown in dialog screen when PIN is too short with Additional text indicating minAutoConfirmLen(eg: 6) digits PIN offer additional security -->
+ <string name="lockpassword_pin_too_short_autoConfirm_extra_message">{count, plural,
+ =1 {PIN must contain at least # digit, but a {minAutoConfirmLen}-digit PIN is recommended for added security}
+ other {PIN must be at least # digits, but a {minAutoConfirmLen}-digit PIN is recommended for added security}
+ }</string>
+
<!-- Error shown in popup when password is too long -->
<string name="lockpassword_password_too_long">{count, plural,
=1 {Must be fewer than # character}
diff --git a/res/xml/accessibility_settings.xml b/res/xml/accessibility_settings.xml
index caba415..f8f32cb 100644
--- a/res/xml/accessibility_settings.xml
+++ b/res/xml/accessibility_settings.xml
@@ -170,6 +170,11 @@
</PreferenceCategory>
<PreferenceCategory
+ android:key="speech_category"
+ android:persistent="false"
+ android:title="@string/speech_category_title"/>
+
+ <PreferenceCategory
android:persistent="false"
android:title="@string/general_category_title">
diff --git a/res/xml/development_settings.xml b/res/xml/development_settings.xml
index ea2b938..82d7e43 100644
--- a/res/xml/development_settings.xml
+++ b/res/xml/development_settings.xml
@@ -48,14 +48,6 @@
android:key="reboot_with_mte"
android:title="@string/reboot_with_mte_title" />
- <com.android.settingslib.RestrictedPreference
- android:id="@+id/memtag_page"
- android:key="memtag_page"
- android:title="@string/memtag_title"
- settings:keywords="@string/keywords_memtag"
- android:fragment="com.android.settings.security.MemtagPage"
- settings:controller="com.android.settings.security.MemtagPagePreferenceController" />
-
<Preference
android:key="local_backup_password"
android:title="@string/local_backup_password_title"
diff --git a/res/xml/more_security_privacy_settings.xml b/res/xml/more_security_privacy_settings.xml
new file mode 100644
index 0000000..00957f7
--- /dev/null
+++ b/res/xml/more_security_privacy_settings.xml
@@ -0,0 +1,227 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2023 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<PreferenceScreen
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:settings="http://schemas.android.com/apk/res-auto"
+ android:key="more_security_privacy_settings"
+ android:title="@string/more_security_privacy_settings">
+
+ <!-- work profile security section. See also: security_advanced_settings.xml and
+ privacy_advanced_settings.xml. That page also has some duplicate entries -->
+ <PreferenceCategory
+ android:order="10"
+ android:key="work_profile_category"
+ android:title="@string/work_profile_category_header">
+
+ <!-- security_settings_unification -->
+ <com.android.settingslib.RestrictedSwitchPreference
+ android:key="unification"
+ android:title="@string/lock_settings_profile_unification_title"
+ android:summary="@string/lock_settings_profile_unification_summary"
+ settings:keywords="@string/keywords_unification" />
+
+ <com.android.settingslib.RestrictedPreference
+ android:key="unlock_set_or_change_profile"
+ android:title="@string/unlock_set_unlock_launch_picker_title_profile"
+ android:summary="@string/unlock_set_unlock_mode_pattern"
+ settings:keywords="@string/keywords_lockscreen" />
+
+ <SwitchPreference
+ android:key="visiblepattern_profile"
+ android:title="@string/lockpattern_settings_enable_visible_pattern_title_profile" />
+
+ <com.android.settingslib.RestrictedPreference
+ android:key="fingerprint_settings_profile"
+ android:title="@string/security_settings_work_fingerprint_preference_title"
+ android:summary="@string/summary_placeholder" />
+
+ <com.android.settingslib.RestrictedPreference
+ android:key="face_settings_profile"
+ android:title="@string/security_settings_face_profile_preference_title"
+ android:summary="@string/summary_placeholder" />
+
+ <com.android.settingslib.RestrictedPreference
+ android:key="biometric_settings_profile"
+ android:title="@string/security_settings_work_biometric_preference_title"
+ android:summary="@string/summary_placeholder" />
+
+ </PreferenceCategory>
+
+ <PreferenceCategory
+ android:key="privacy_work_profile_notifications_category"
+ android:title="@string/profile_section_header_for_advanced_privacy"
+ android:layout="@layout/preference_category_no_label"
+ android:order="20">
+
+ <com.android.settings.RestrictedListPreference
+ android:key="privacy_lock_screen_work_profile_notifications"
+ android:title="@string/locked_work_profile_notification_title"
+ android:summary="@string/summary_placeholder"
+ android:order="21"
+ settings:searchable="false"/>
+ </PreferenceCategory>
+
+ <!-- Connected work and personal apps -->
+ <Preference
+ android:key="interact_across_profiles_privacy"
+ android:title="@string/interact_across_profiles_title"
+ android:order="25"
+ android:fragment="com.android.settings.applications.specialaccess.interactacrossprofiles.InteractAcrossProfilesSettings"
+ settings:searchable="false"
+ settings:controller="com.android.settings.applications.specialaccess.interactacrossprofiles.InteractAcrossProfilesController" />
+
+ <!-- Main security section - for trust agents added in code. -->
+ <PreferenceCategory
+ android:order="30"
+ android:key="security_category"
+ android:title="@string/security_header" />
+
+ <PreferenceCategory
+ android:order="40"
+ android:key="security_settings_device_admin_category"
+ android:layout="@layout/preference_category_no_label">
+
+ <Preference
+ android:key="manage_device_admin"
+ android:title="@string/manage_device_admin"
+ android:summary="@string/summary_placeholder"
+ android:fragment=
+ "com.android.settings.applications.specialaccess.deviceadmin.DeviceAdminSettings"
+ settings:controller=
+ "com.android.settings.enterprise.ManageDeviceAdminPreferenceController" />
+
+ <Preference
+ android:key="enterprise_privacy"
+ android:title="@string/enterprise_privacy_settings"
+ android:summary="@string/summary_placeholder"
+ android:fragment="com.android.settings.enterprise.EnterprisePrivacySettings"
+ settings:controller="com.android.settings.enterprise.EnterprisePrivacyPreferenceController"/>
+
+ <Preference
+ android:key="financed_privacy"
+ android:title="@string/financed_privacy_settings"
+ android:summary="@string/summary_placeholder"
+ android:fragment="com.android.settings.enterprise.EnterprisePrivacySettings"
+ settings:controller="com.android.settings.enterprise.FinancedPrivacyPreferenceController"/>
+
+ </PreferenceCategory>
+
+ <Preference
+ android:order="50"
+ android:key="sim_lock_settings"
+ android:title="@string/sim_lock_settings_category"
+ settings:isPreferenceVisible="@bool/config_show_sim_info"
+ settings:controller="com.android.settings.security.SimLockPreferenceController">
+
+ <intent
+ android:action="android.intent.action.MAIN"
+ android:targetPackage="com.android.settings"
+ android:targetClass="com.android.settings.Settings$IccLockSettingsActivity" />
+
+ </Preference>
+
+ <Preference
+ android:order="60"
+ android:key="encryption_and_credential"
+ android:title="@string/encryption_and_credential_settings_title"
+ android:summary="@string/encryption_and_credential_settings_summary"
+ android:fragment="com.android.settings.security.EncryptionAndCredential"
+ settings:controller="com.android.settings.security.EncryptionStatusPreferenceController" />
+
+ <Preference
+ android:order="70"
+ android:key="manage_trust_agents"
+ android:title="@string/manage_trust_agents"
+ android:summary="@string/summary_placeholder"
+ android:fragment="com.android.settings.security.trustagent.TrustAgentSettings"
+ settings:controller="com.android.settings.security.trustagent.ManageTrustAgentsPreferenceController" />
+
+ <Preference
+ android:order="80"
+ android:key="screen_pinning_settings"
+ android:title="@string/screen_pinning_title"
+ android:summary="@string/summary_placeholder"
+ android:fragment="com.android.settings.security.ScreenPinningSettings"
+ settings:keywords="@string/keywords_app_pinning"
+ settings:controller="com.android.settings.security.ScreenPinningPreferenceController" />
+
+ <SwitchPreference
+ android:order="90"
+ android:key="confirm_sim_deletion"
+ android:title="@string/confirm_sim_deletion_title"
+ android:summary="@string/confirm_sim_deletion_description"
+ settings:isPreferenceVisible="@bool/config_show_sim_info"
+ settings:controller="com.android.settings.security.ConfirmSimDeletionPreferenceController" />
+
+ <Preference
+ android:order="100"
+ android:id="@+id/memtag_page"
+ android:key="memtag_page"
+ android:title="@string/memtag_title"
+ android:fragment="com.android.settings.security.MemtagPage"
+ settings:controller="com.android.settings.security.MemtagPagePreferenceController" />
+
+
+ <!-- Privacy section -->
+ <PreferenceCategory
+ android:order="200"
+ android:key="privacy_category"
+ android:title="@string/privacy_header">
+ <!-- Accessibility usage -->
+ <Preference
+ android:key="privacy_accessibility_usage"
+ android:title="@string/accessibility_usage_title"
+ settings:controller="com.android.settings.privacy.AccessibilityUsagePreferenceController">
+ <intent android:action="android.intent.action.REVIEW_ACCESSIBILITY_SERVICES"/>
+ </Preference>
+
+ <!-- On lock screen notifications -->
+ <com.android.settings.RestrictedListPreference
+ android:key="privacy_lock_screen_notifications"
+ android:title="@string/lock_screen_notifs_title"
+ android:summary="@string/summary_placeholder"
+ settings:searchable="false"/>
+
+ <!-- Show media on lock screen -->
+ <SwitchPreference
+ android:key="privacy_media_controls_lockscreen"
+ android:title="@string/media_controls_lockscreen_title"
+ android:summary="@string/media_controls_lockscreen_description"
+ settings:controller=
+ "com.android.settings.sound.MediaControlsLockScreenPreferenceController" />
+
+ <!-- Content Capture -->
+ <!-- NOTE: content capture has a different preference, depending whether or not the
+ ContentCaptureService implementations defines a custom settings activitiy on its manifest.
+ Hence, we show both here, but the controller itself will decide if it's available or not.
+ -->
+ <SwitchPreference
+ android:key="content_capture"
+ android:title="@string/content_capture"
+ android:summary="@string/content_capture_summary"
+ settings:controller="com.android.settings.privacy.EnableContentCapturePreferenceController"/>
+
+ <com.android.settingslib.PrimarySwitchPreference
+ android:key="content_capture_custom_settings"
+ android:title="@string/content_capture"
+ android:summary="@string/content_capture_summary"
+ settings:controller="com.android.settings.privacy.EnableContentCaptureWithServiceSettingsPreferenceController"/>
+
+ </PreferenceCategory>
+
+</PreferenceScreen>
\ No newline at end of file
diff --git a/res/xml/screen_lock_settings.xml b/res/xml/screen_lock_settings.xml
index dd4ac34..8174b0f 100644
--- a/res/xml/screen_lock_settings.xml
+++ b/res/xml/screen_lock_settings.xml
@@ -27,6 +27,12 @@
android:key="visiblepattern"
android:title="@string/lockpattern_settings_enable_visible_pattern_title" />
+ <!-- available in pin -->
+ <SwitchPreference
+ android:key="auto_pin_confirm"
+ android:title="@string/lock_screen_auto_pin_confirm_title"
+ android:summary="@string/lock_screen_auto_pin_confirm_summary" />
+
<!-- available in pin/pattern/password -->
<com.android.settings.display.TimeoutListPreference
android:key="lock_after_timeout"
diff --git a/res/xml/security_advanced_settings.xml b/res/xml/security_advanced_settings.xml
index f57ab9a..153b81f 100644
--- a/res/xml/security_advanced_settings.xml
+++ b/res/xml/security_advanced_settings.xml
@@ -107,10 +107,19 @@
settings:isPreferenceVisible="@bool/config_show_sim_info"
settings:controller="com.android.settings.security.ConfirmSimDeletionPreferenceController" />
+ <com.android.settingslib.RestrictedPreference
+ android:order="100"
+ android:id="@+id/memtag_page"
+ android:key="memtag_page"
+ android:title="@string/memtag_title"
+ settings:keywords="@string/keywords_memtag"
+ android:fragment="com.android.settings.security.MemtagPage"
+ settings:controller="com.android.settings.security.MemtagPagePreferenceController" />
+
<!-- work profile security section -->
<PreferenceCategory
android:order="110"
- android:key="security_category_profile"
+ android:key="work_profile_category"
android:title="@string/lock_settings_profile_title">
<!-- security_settings_unification -->
@@ -137,12 +146,12 @@
<com.android.settingslib.RestrictedPreference
android:key="face_settings_profile"
- android:title="@string/security_settings_face_preference_title"
+ android:title="@string/security_settings_face_profile_preference_title"
android:summary="@string/summary_placeholder" />
<com.android.settingslib.RestrictedPreference
android:key="biometric_settings_profile"
- android:title="@string/security_settings_biometric_preference_title"
+ android:title="@string/security_settings_work_biometric_preference_title"
android:summary="@string/summary_placeholder" />
</PreferenceCategory>
diff --git a/res/xml/security_settings_combined_biometric_profile.xml b/res/xml/security_settings_combined_biometric_profile.xml
index 1ba48ef..22d19ac 100644
--- a/res/xml/security_settings_combined_biometric_profile.xml
+++ b/res/xml/security_settings_combined_biometric_profile.xml
@@ -17,7 +17,7 @@
<PreferenceScreen
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:settings="http://schemas.android.com/apk/res-auto"
- android:title="@string/security_settings_biometric_preference_title">
+ android:title="@string/security_settings_work_biometric_preference_title">
<com.android.settingslib.widget.TopIntroPreference
android:title="@string/biometric_settings_intro" />
@@ -28,14 +28,14 @@
<com.android.settingslib.RestrictedPreference
android:key="biometric_fingerprint_settings_profile"
- android:title="@string/security_settings_fingerprint_preference_title"
+ android:title="@string/security_settings_work_fingerprint_preference_title"
android:summary="@string/summary_placeholder"
settings:keywords="@string/keywords_fingerprint_settings"
settings:controller="com.android.settings.biometrics.combination.BiometricFingerprintProfileStatusPreferenceController" />
<com.android.settingslib.RestrictedPreference
android:key="biometric_face_settings_profile"
- android:title="@string/security_settings_face_preference_title"
+ android:title="@string/security_settings_face_profile_preference_title"
android:summary="@string/summary_placeholder"
settings:keywords="@string/keywords_face_settings"
settings:controller="com.android.settings.biometrics.combination.BiometricFaceProfileStatusPreferenceController" />
diff --git a/src/com/android/settings/Settings.java b/src/com/android/settings/Settings.java
index 0c58fff..f9671b0 100644
--- a/src/com/android/settings/Settings.java
+++ b/src/com/android/settings/Settings.java
@@ -209,6 +209,8 @@
}
/** Activity for the Advanced security settings. */
public static class SecurityAdvancedSettings extends SettingsActivity { /* empty */ }
+ /** Activity for the More settings page. */
+ public static class MoreSecurityPrivacySettingsActivity extends SettingsActivity { /* empty */ }
public static class UsageAccessSettingsActivity extends SettingsActivity { /* empty */ }
public static class AppUsageAccessSettingsActivity extends SettingsActivity { /* empty */ }
public static class LocationSettingsActivity extends SettingsActivity { /* empty */ }
diff --git a/src/com/android/settings/accessibility/AccessibilitySettings.java b/src/com/android/settings/accessibility/AccessibilitySettings.java
index 10cdc4d..21f6425 100644
--- a/src/com/android/settings/accessibility/AccessibilitySettings.java
+++ b/src/com/android/settings/accessibility/AccessibilitySettings.java
@@ -63,13 +63,15 @@
private static final String CATEGORY_SCREEN_READER = "screen_reader_category";
private static final String CATEGORY_CAPTIONS = "captions_category";
private static final String CATEGORY_AUDIO = "audio_category";
+ private static final String CATEGORY_SPEECH = "speech_category";
private static final String CATEGORY_DISPLAY = "display_category";
- private static final String CATEGORY_INTERACTION_CONTROL = "interaction_control_category";
private static final String CATEGORY_DOWNLOADED_SERVICES = "user_installed_services_category";
+ @VisibleForTesting
+ static final String CATEGORY_INTERACTION_CONTROL = "interaction_control_category";
private static final String[] CATEGORIES = new String[]{
CATEGORY_SCREEN_READER, CATEGORY_CAPTIONS, CATEGORY_AUDIO, CATEGORY_DISPLAY,
- CATEGORY_INTERACTION_CONTROL, CATEGORY_DOWNLOADED_SERVICES
+ CATEGORY_SPEECH, CATEGORY_INTERACTION_CONTROL, CATEGORY_DOWNLOADED_SERVICES
};
// Extras passed to sub-fragments.
@@ -144,7 +146,8 @@
private final Map<String, PreferenceCategory> mCategoryToPrefCategoryMap =
new ArrayMap<>();
- private final Map<Preference, PreferenceCategory> mServicePreferenceToPreferenceCategoryMap =
+ @VisibleForTesting
+ final Map<Preference, PreferenceCategory> mServicePreferenceToPreferenceCategoryMap =
new ArrayMap<>();
private final Map<ComponentName, PreferenceCategory> mPreBundledServiceComponentToCategoryMap =
new ArrayMap<>();
@@ -349,9 +352,17 @@
R.array.config_preinstalled_audio_services);
initializePreBundledServicesMapFromArray(CATEGORY_DISPLAY,
R.array.config_preinstalled_display_services);
+ initializePreBundledServicesMapFromArray(CATEGORY_SPEECH,
+ R.array.config_preinstalled_speech_services);
initializePreBundledServicesMapFromArray(CATEGORY_INTERACTION_CONTROL,
R.array.config_preinstalled_interaction_control_services);
+ // ACCESSIBILITY_MENU_IN_SYSTEM is a default pre-bundled interaction control service.
+ // If the device opts out of including this service then this is a no-op.
+ mPreBundledServiceComponentToCategoryMap.put(
+ AccessibilityManager.ACCESSIBILITY_MENU_IN_SYSTEM,
+ mCategoryToPrefCategoryMap.get(CATEGORY_INTERACTION_CONTROL));
+
final List<RestrictedPreference> preferenceList = getInstalledAccessibilityList(
getPrefContext());
@@ -382,6 +393,8 @@
R.array.config_order_interaction_control_services);
updateCategoryOrderFromArray(CATEGORY_DISPLAY,
R.array.config_order_display_services);
+ updateCategoryOrderFromArray(CATEGORY_SPEECH,
+ R.array.config_order_speech_services);
// Need to check each time when updateServicePreferences() called.
if (downloadedServicesCategory.getPreferenceCount() == 0) {
@@ -390,8 +403,9 @@
getPreferenceScreen().addPreference(downloadedServicesCategory);
}
- // Hide screen reader category if it is empty.
+ // Hide category if it is empty.
updatePreferenceCategoryVisibility(CATEGORY_SCREEN_READER);
+ updatePreferenceCategoryVisibility(CATEGORY_SPEECH);
}
private List<RestrictedPreference> getInstalledAccessibilityList(Context context) {
diff --git a/src/com/android/settings/applications/appinfo/AppInfoDashboardFragment.java b/src/com/android/settings/applications/appinfo/AppInfoDashboardFragment.java
index 06b25d6..3f335bc 100644
--- a/src/com/android/settings/applications/appinfo/AppInfoDashboardFragment.java
+++ b/src/com/android/settings/applications/appinfo/AppInfoDashboardFragment.java
@@ -650,6 +650,7 @@
new SubSettingLauncher(context)
.setDestination(destination.getName())
.setArguments(args)
+ .setUserHandle(UserHandle.getUserHandleForUid(app.uid))
.setSourceMetricsCategory(sourceMetricsCategory)
.launch();
}
diff --git a/src/com/android/settings/applications/specialaccess/notificationaccess/BridgedAppsPreferenceController.java b/src/com/android/settings/applications/specialaccess/notificationaccess/BridgedAppsPreferenceController.java
index 8e2d3d4..4fb2f6e 100644
--- a/src/com/android/settings/applications/specialaccess/notificationaccess/BridgedAppsPreferenceController.java
+++ b/src/com/android/settings/applications/specialaccess/notificationaccess/BridgedAppsPreferenceController.java
@@ -25,6 +25,7 @@
import com.android.settings.applications.AppStateBaseBridge;
import com.android.settings.core.BasePreferenceController;
import com.android.settings.notification.NotificationBackend;
+import com.android.settings.widget.AppCheckBoxPreference;
import com.android.settingslib.applications.AppUtils;
import com.android.settingslib.applications.ApplicationsState;
import com.android.settingslib.applications.ApplicationsState.AppEntry;
@@ -126,9 +127,9 @@
final AppEntry entry = apps.get(i);
final String prefKey = entry.info.packageName + "|" + entry.info.uid;
appsKeySet.add(prefKey);
- CheckBoxPreference preference = mScreen.findPreference(prefKey);
+ AppCheckBoxPreference preference = mScreen.findPreference(prefKey);
if (preference == null) {
- preference = new CheckBoxPreference(mScreen.getContext());
+ preference = new AppCheckBoxPreference(mScreen.getContext());
preference.setIcon(AppUtils.getIcon(mContext, entry));
preference.setTitle(entry.label);
preference.setKey(prefKey);
diff --git a/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollFinish.java b/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollFinish.java
index 2125d52..bbaa3c7 100644
--- a/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollFinish.java
+++ b/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollFinish.java
@@ -70,6 +70,9 @@
}
setHeaderText(R.string.security_settings_fingerprint_enroll_finish_title);
setDescriptionText(R.string.security_settings_fingerprint_enroll_finish_v2_message);
+ if (mCanAssumeSfps) {
+ setDescriptionForSfps();
+ }
mFooterBarMixin = getLayout().getMixin(FooterBarMixin.class);
mFooterBarMixin.setSecondaryButton(
@@ -90,6 +93,20 @@
);
}
+ private void setDescriptionForSfps() {
+ final FingerprintManager fpm = Utils.getFingerprintManagerOrNull(this);
+ if (fpm != null) {
+ final List<FingerprintSensorPropertiesInternal> props =
+ fpm.getSensorPropertiesInternal();
+ final int maxEnrollments = props.get(0).maxEnrollmentsPerUser;
+ final int enrolled = fpm.getEnrolledFingerprints(mUserId).size();
+ if (enrolled < maxEnrollments) {
+ setDescriptionText(R.string
+ .security_settings_fingerprint_enroll_finish_v2_add_fingerprint_message);
+ }
+ }
+ }
+
@Override
public void onBackPressed() {
updateFingerprintSuggestionEnableState();
diff --git a/src/com/android/settings/biometrics2/factory/BiometricsViewModelFactory.java b/src/com/android/settings/biometrics2/factory/BiometricsViewModelFactory.java
index 0c43375..0b84f4c 100644
--- a/src/com/android/settings/biometrics2/factory/BiometricsViewModelFactory.java
+++ b/src/com/android/settings/biometrics2/factory/BiometricsViewModelFactory.java
@@ -49,10 +49,11 @@
private static final String TAG = "BiometricsViewModelFact";
public static final CreationExtras.Key<ChallengeGenerator> CHALLENGE_GENERATOR_KEY =
- new CreationExtras.Key<>() {};
+ new CreationExtras.Key<ChallengeGenerator>() {};
public static final CreationExtras.Key<EnrollmentRequest> ENROLLMENT_REQUEST_KEY =
- new CreationExtras.Key<>() {};
- public static final CreationExtras.Key<Integer> USER_ID_KEY = new CreationExtras.Key<>() {};
+ new CreationExtras.Key<EnrollmentRequest>() {};
+ public static final CreationExtras.Key<Integer> USER_ID_KEY =
+ new CreationExtras.Key<Integer>() {};
@NonNull
@Override
diff --git a/src/com/android/settings/core/gateway/SettingsGateway.java b/src/com/android/settings/core/gateway/SettingsGateway.java
index 5d80193..708f317 100644
--- a/src/com/android/settings/core/gateway/SettingsGateway.java
+++ b/src/com/android/settings/core/gateway/SettingsGateway.java
@@ -165,6 +165,7 @@
import com.android.settings.privacy.PrivacyControlsFragment;
import com.android.settings.privacy.PrivacyDashboardFragment;
import com.android.settings.regionalpreferences.RegionalPreferencesEntriesFragment;
+import com.android.settings.safetycenter.MoreSecurityPrivacyFragment;
import com.android.settings.security.LockscreenDashboardFragment;
import com.android.settings.security.MemtagPage;
import com.android.settings.security.SecurityAdvancedSettings;
@@ -240,6 +241,7 @@
LocationServices.class.getName(),
SecuritySettings.class.getName(),
SecurityAdvancedSettings.class.getName(),
+ MoreSecurityPrivacyFragment.class.getName(),
UsageAccessDetails.class.getName(),
PrivacySettings.class.getName(),
DeviceAdminSettings.class.getName(),
diff --git a/src/com/android/settings/development/qstile/DevelopmentTiles.java b/src/com/android/settings/development/qstile/DevelopmentTiles.java
index bb5216c..3b6c646 100644
--- a/src/com/android/settings/development/qstile/DevelopmentTiles.java
+++ b/src/com/android/settings/development/qstile/DevelopmentTiles.java
@@ -212,6 +212,7 @@
static final int SURFACE_FLINGER_LAYER_TRACE_CONTROL_CODE = 1025;
@VisibleForTesting
static final int SURFACE_FLINGER_LAYER_TRACE_STATUS_CODE = 1026;
+ private static final String VIEW_CAPTURE_ENABLED = "view_capture_enabled";
private IBinder mSurfaceFlinger;
private IWindowManager mWindowManager;
private ImeTracing mImeTracing;
@@ -279,10 +280,19 @@
return mImeTracing.isEnabled();
}
+ private boolean isViewCaptureEnabled() {
+ // Add null checking to avoid test case failure.
+ if (getApplicationContext() != null) {
+ return Settings.Global.getInt(getApplicationContext().getContentResolver(),
+ VIEW_CAPTURE_ENABLED, 0) != 0;
+ }
+ return false;
+ }
+
@Override
protected boolean isEnabled() {
return isWindowTraceEnabled() || isLayerTraceEnabled() || isSystemUiTracingEnabled()
- || isImeTraceEnabled();
+ || isImeTraceEnabled() || isViewCaptureEnabled();
}
private void setWindowTraceEnabled(boolean isEnabled) {
@@ -340,12 +350,21 @@
}
}
+ private void setViewCaptureEnabled(boolean isEnabled) {
+ // Add null checking to avoid test case failure.
+ if (getApplicationContext() != null) {
+ Settings.Global.putInt(getApplicationContext()
+ .getContentResolver(), VIEW_CAPTURE_ENABLED, isEnabled ? 1 : 0);
+ }
+ }
+
@Override
protected void setIsEnabled(boolean isEnabled) {
setWindowTraceEnabled(isEnabled);
setLayerTraceEnabled(isEnabled);
setSystemUiTracing(isEnabled);
setImeTraceEnabled(isEnabled);
+ setViewCaptureEnabled(isEnabled);
if (!isEnabled) {
mToast.show();
}
diff --git a/src/com/android/settings/password/ChooseLockPassword.java b/src/com/android/settings/password/ChooseLockPassword.java
index 0c05039..55e01b0 100644
--- a/src/com/android/settings/password/ChooseLockPassword.java
+++ b/src/com/android/settings/password/ChooseLockPassword.java
@@ -71,6 +71,7 @@
import android.view.ViewGroup;
import android.view.WindowManager;
import android.view.inputmethod.EditorInfo;
+import android.widget.CheckBox;
import android.widget.ImeAwareEditText;
import android.widget.TextView;
import android.widget.TextView.OnEditorActionListener;
@@ -101,7 +102,9 @@
import java.util.ArrayList;
import java.util.Collections;
+import java.util.HashMap;
import java.util.List;
+import java.util.Map;
public class ChooseLockPassword extends SettingsActivity {
private static final String TAG = "ChooseLockPassword";
@@ -223,6 +226,8 @@
private static final String KEY_CURRENT_CREDENTIAL = "current_credential";
private static final String FRAGMENT_TAG_SAVE_AND_FINISH = "save_and_finish_worker";
+ private static final int MIN_AUTO_PIN_REQUIREMENT_LENGTH = 6;
+
private LockscreenCredential mCurrentCredential;
private LockscreenCredential mChosenPassword;
private boolean mRequestGatekeeperPassword;
@@ -255,6 +260,9 @@
protected FooterButton mSkipOrClearButton;
private FooterButton mNextButton;
private TextView mMessage;
+ protected CheckBox mAutoPinConfirmOption;
+ protected TextView mAutoConfirmSecurityMessage;
+ protected boolean mIsAutoPinConfirmOptionSetManually;
private TextChangedHandler mTextChangedHandler;
@@ -515,6 +523,16 @@
mPasswordEntry.requestFocus();
mPasswordEntryInputDisabler = new TextViewInputDisabler(mPasswordEntry);
+ // Fetch the AutoPinConfirmOption
+ mAutoPinConfirmOption = view.findViewById(R.id.auto_pin_confirm_enabler);
+ mAutoConfirmSecurityMessage = view.findViewById(R.id.auto_pin_confirm_security_message);
+ mIsAutoPinConfirmOptionSetManually = false;
+ setOnAutoConfirmOptionClickListener();
+ if (mAutoPinConfirmOption != null) {
+ mAutoPinConfirmOption.setVisibility(View.GONE);
+ mAutoPinConfirmOption.setChecked(false);
+ }
+
final Activity activity = getActivity();
int currentType = mPasswordEntry.getInputType();
@@ -808,10 +826,22 @@
R.string.lockpassword_password_requires_nonnumerical));
break;
case TOO_SHORT:
- messages.add(StringUtil.getIcuPluralsString(getContext(), error.requirement,
+ String message = StringUtil.getIcuPluralsString(getContext(),
+ error.requirement,
mIsAlphaMode
? R.string.lockpassword_password_too_short
- : R.string.lockpassword_pin_too_short));
+ : R.string.lockpassword_pin_too_short);
+ if (mLockPatternUtils.isAutoPinConfirmFeatureAvailable()
+ && !mIsAlphaMode
+ && error.requirement < MIN_AUTO_PIN_REQUIREMENT_LENGTH) {
+ Map<String, Object> arguments = new HashMap<>();
+ arguments.put("count", error.requirement);
+ arguments.put("minAutoConfirmLen", MIN_AUTO_PIN_REQUIREMENT_LENGTH);
+ message = StringUtil.getIcuPluralsString(getContext(),
+ arguments,
+ R.string.lockpassword_pin_too_short_autoConfirm_extra_message);
+ }
+ messages.add(message);
break;
case TOO_SHORT_WHEN_ALL_NUMERIC:
messages.add(
@@ -864,6 +894,8 @@
String[] messages = convertErrorCodeToMessages();
// Update the fulfillment of requirements.
mPasswordRequirementAdapter.setRequirements(messages);
+ // set the visibility of pin_auto_confirm option accordingly
+ setAutoPinConfirmOption(passwordCompliant, length);
// Enable/Disable the next button accordingly.
setNextEnabled(passwordCompliant);
} else {
@@ -896,6 +928,36 @@
return visibleOrGone ? View.VISIBLE : View.GONE;
}
+ private void setAutoPinConfirmOption(boolean enabled, int length) {
+ if (!mLockPatternUtils.isAutoPinConfirmFeatureAvailable()
+ || mAutoPinConfirmOption == null) {
+ return;
+ }
+ if (enabled && !mIsAlphaMode && isAutoPinConfirmPossible(length)) {
+ mAutoPinConfirmOption.setVisibility(View.VISIBLE);
+ mAutoConfirmSecurityMessage.setVisibility(View.VISIBLE);
+ if (!mIsAutoPinConfirmOptionSetManually) {
+ mAutoPinConfirmOption.setChecked(length == MIN_AUTO_PIN_REQUIREMENT_LENGTH);
+ }
+ } else {
+ mAutoPinConfirmOption.setVisibility(View.GONE);
+ mAutoConfirmSecurityMessage.setVisibility(View.GONE);
+ mAutoPinConfirmOption.setChecked(false);
+ }
+ }
+
+ private boolean isAutoPinConfirmPossible(int currentPinLength) {
+ return currentPinLength >= MIN_AUTO_PIN_REQUIREMENT_LENGTH;
+ }
+
+ private void setOnAutoConfirmOptionClickListener() {
+ if (mAutoPinConfirmOption != null) {
+ mAutoPinConfirmOption.setOnClickListener((v) -> {
+ mIsAutoPinConfirmOptionSetManually = true;
+ });
+ }
+ }
+
private void setHeaderText(String text) {
// Only set the text if it is different than the existing one to avoid announcing again.
if (!TextUtils.isEmpty(mLayout.getHeaderText())
@@ -951,6 +1013,10 @@
}
mSaveAndFinishWorker.start(mLockPatternUtils, mRequestGatekeeperPassword,
mChosenPassword, mCurrentCredential, mUserId);
+ // update the pin_auto_confirm setting accordingly.
+ mLockPatternUtils.setAutoPinConfirm(
+ (mAutoPinConfirmOption != null && mAutoPinConfirmOption.isChecked()),
+ mUserId);
}
@Override
diff --git a/src/com/android/settings/password/SetupChooseLockPassword.java b/src/com/android/settings/password/SetupChooseLockPassword.java
index 5306719..74cb271 100644
--- a/src/com/android/settings/password/SetupChooseLockPassword.java
+++ b/src/com/android/settings/password/SetupChooseLockPassword.java
@@ -170,6 +170,12 @@
mOptionsButton.setVisibility(
mUiStage == Stage.Introduction ? View.VISIBLE : View.GONE);
}
+
+ // Visibility of auto pin confirm opt-in/out option should always be invisible.
+ if (mAutoPinConfirmOption != null) {
+ mAutoPinConfirmOption.setVisibility(View.GONE);
+ mAutoConfirmSecurityMessage.setVisibility(View.GONE);
+ }
}
}
}
diff --git a/src/com/android/settings/privacy/PrivacyDashboardFragment.java b/src/com/android/settings/privacy/PrivacyDashboardFragment.java
index 46a05b0..045405b 100644
--- a/src/com/android/settings/privacy/PrivacyDashboardFragment.java
+++ b/src/com/android/settings/privacy/PrivacyDashboardFragment.java
@@ -16,12 +16,6 @@
package com.android.settings.privacy;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.CONNECTED_WORK_AND_PERSONAL_APPS_TITLE;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.WORK_PROFILE_LOCKED_NOTIFICATION_TITLE;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.WORK_PROFILE_NOTIFICATIONS_SECTION_HEADER;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.WORK_PROFILE_PRIVACY_POLICY_INFO;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.WORK_PROFILE_PRIVACY_POLICY_INFO_SUMMARY;
-
import android.app.settings.SettingsEnums;
import android.content.Context;
import android.os.Bundle;
@@ -32,23 +26,20 @@
import com.android.settings.R;
import com.android.settings.Utils;
import com.android.settings.dashboard.DashboardFragment;
-import com.android.settings.notification.LockScreenNotificationPreferenceController;
import com.android.settings.safetycenter.SafetyCenterManagerWrapper;
+import com.android.settings.safetycenter.SafetyCenterUtils;
+import com.android.settings.safetycenter.SafetyCenterUtils.EnterpriseOverrideString;
import com.android.settings.search.BaseSearchIndexProvider;
import com.android.settingslib.core.AbstractPreferenceController;
import com.android.settingslib.core.lifecycle.Lifecycle;
import com.android.settingslib.search.SearchIndexable;
-import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@SearchIndexable
public class PrivacyDashboardFragment extends DashboardFragment {
private static final String TAG = "PrivacyDashboardFrag";
- private static final String KEY_LOCK_SCREEN_NOTIFICATIONS = "privacy_lock_screen_notifications";
- private static final String KEY_WORK_PROFILE_CATEGORY =
- "privacy_work_profile_notifications_category";
private static final String KEY_NOTIFICATION_WORK_PROFILE_NOTIFICATIONS =
"privacy_lock_screen_work_profile_notifications";
@@ -65,18 +56,13 @@
@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
- replaceEnterpriseStringTitle("privacy_lock_screen_work_profile_notifications",
- WORK_PROFILE_LOCKED_NOTIFICATION_TITLE,
- R.string.locked_work_profile_notification_title);
- replaceEnterpriseStringTitle("interact_across_profiles_privacy",
- CONNECTED_WORK_AND_PERSONAL_APPS_TITLE, R.string.interact_across_profiles_title);
- replaceEnterpriseStringTitle("privacy_work_profile_notifications_category",
- WORK_PROFILE_NOTIFICATIONS_SECTION_HEADER, R.string.profile_section_header);
- replaceEnterpriseStringTitle("work_policy_info",
- WORK_PROFILE_PRIVACY_POLICY_INFO, R.string.work_policy_privacy_settings);
- replaceEnterpriseStringSummary("work_policy_info",
- WORK_PROFILE_PRIVACY_POLICY_INFO_SUMMARY,
- R.string.work_policy_privacy_settings_summary);
+ List<EnterpriseOverrideString> privacyOverrideStrings =
+ SafetyCenterUtils.getEnterpriseOverrideStringForPrivacyEntries();
+ for (int i = 0; i < privacyOverrideStrings.size(); i++) {
+ EnterpriseOverrideString overrideString = privacyOverrideStrings.get(i);
+ replaceEnterpriseStringTitle(overrideString.getPreferenceKey(),
+ overrideString.getOverrideKey(), overrideString.getResource());
+ }
}
@Override
@@ -104,26 +90,21 @@
private static List<AbstractPreferenceController> buildPreferenceControllers(
Context context, Lifecycle lifecycle) {
- final List<AbstractPreferenceController> controllers = new ArrayList<>();
- final LockScreenNotificationPreferenceController notificationController =
- new LockScreenNotificationPreferenceController(context,
- KEY_LOCK_SCREEN_NOTIFICATIONS,
- KEY_WORK_PROFILE_CATEGORY,
- KEY_NOTIFICATION_WORK_PROFILE_NOTIFICATIONS);
- if (lifecycle != null) {
- lifecycle.addObserver(notificationController);
- }
- controllers.add(notificationController);
-
- return controllers;
-
+ return SafetyCenterUtils.getControllersForAdvancedPrivacy(context, lifecycle);
}
public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
new BaseSearchIndexProvider() {
+ /**
+ * If SafetyCenter is enabled, all of these entries will be in the More Settings
+ * page, and we don't want to index these entries.
+ */
@Override
public List<SearchIndexableResource> getXmlResourcesToIndex(
Context context, boolean enabled) {
+ if (SafetyCenterManagerWrapper.get().isEnabled(context)) {
+ return null;
+ }
final SearchIndexableResource sir = new SearchIndexableResource(context);
sir.xmlResId = getPreferenceScreenResId(context);
return Arrays.asList(sir);
diff --git a/src/com/android/settings/safetycenter/MoreSecurityPrivacyFragment.java b/src/com/android/settings/safetycenter/MoreSecurityPrivacyFragment.java
new file mode 100644
index 0000000..95732f4
--- /dev/null
+++ b/src/com/android/settings/safetycenter/MoreSecurityPrivacyFragment.java
@@ -0,0 +1,155 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.safetycenter;
+
+import android.app.settings.SettingsEnums;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.provider.SearchIndexableResource;
+
+import com.android.settings.R;
+import com.android.settings.Utils;
+import com.android.settings.dashboard.DashboardFragment;
+import com.android.settings.safetycenter.SafetyCenterUtils.EnterpriseOverrideString;
+import com.android.settings.search.BaseSearchIndexProvider;
+import com.android.settings.security.LockUnificationPreferenceController;
+import com.android.settings.security.trustagent.TrustAgentListPreferenceController;
+import com.android.settingslib.core.AbstractPreferenceController;
+import com.android.settingslib.core.lifecycle.Lifecycle;
+import com.android.settingslib.search.SearchIndexable;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * An overflow menu for {@code SecuritySettings} containing advanced security and privacy settings.
+ *
+ * <p>This also includes all work-profile related settings.
+ */
+@SearchIndexable
+public class MoreSecurityPrivacyFragment extends DashboardFragment {
+ private static final String TAG = "MoreSecurityPrivacyFragment";
+ private static final String KEY_NOTIFICATION_WORK_PROFILE_NOTIFICATIONS =
+ "privacy_lock_screen_work_profile_notifications";
+
+ @Override
+ public int getMetricsCategory() {
+ return SettingsEnums.MORE_SECURITY_PRIVACY_SETTINGS;
+ }
+
+ @Override
+ protected int getPreferenceScreenResId() {
+ return R.xml.more_security_privacy_settings;
+ }
+
+ @Override
+ protected String getLogTag() {
+ return TAG;
+ }
+
+ @Override
+ public void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+ List<EnterpriseOverrideString> privacyOverrideStrings =
+ SafetyCenterUtils.getEnterpriseOverrideStringForPrivacyEntries();
+ for (int i = 0; i < privacyOverrideStrings.size(); i++) {
+ EnterpriseOverrideString overrideString = privacyOverrideStrings.get(i);
+ replaceEnterpriseStringTitle(overrideString.getPreferenceKey(),
+ overrideString.getOverrideKey(), overrideString.getResource());
+ }
+ List<EnterpriseOverrideString> securityOverrideStrings =
+ SafetyCenterUtils.getEnterpriseOverrideStringForSecurityEntries();
+ for (int i = 0; i < securityOverrideStrings.size(); i++) {
+ EnterpriseOverrideString overrideString = securityOverrideStrings.get(i);
+ replaceEnterpriseStringTitle(overrideString.getPreferenceKey(),
+ overrideString.getOverrideKey(), overrideString.getResource());
+ }
+ }
+
+ /**
+ * see confirmPatternThenDisableAndClear
+ */
+ @Override
+ public void onActivityResult(int requestCode, int resultCode, Intent data) {
+ if (use(TrustAgentListPreferenceController.class)
+ .handleActivityResult(requestCode, resultCode)) {
+ return;
+ }
+ if (use(LockUnificationPreferenceController.class)
+ .handleActivityResult(requestCode, resultCode, data)) {
+ return;
+ }
+ super.onActivityResult(requestCode, resultCode, data);
+ }
+
+ @Override
+ protected List<AbstractPreferenceController> createPreferenceControllers(Context context) {
+ return buildPreferenceControllers(context, getSettingsLifecycle(), this /* host*/);
+ }
+
+ private static List<AbstractPreferenceController> buildPreferenceControllers(
+ Context context, Lifecycle lifecycle, DashboardFragment host) {
+ final List<AbstractPreferenceController> controllers = new ArrayList<>();
+ controllers.addAll(SafetyCenterUtils.getControllersForAdvancedPrivacy(context, lifecycle));
+ controllers.addAll(
+ SafetyCenterUtils.getControllersForAdvancedSecurity(context, lifecycle, host));
+ return controllers;
+
+ }
+
+
+ public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
+ new BaseSearchIndexProvider(R.xml.more_security_privacy_settings) {
+ /**
+ * If SafetyCenter is disabled, all of these entries will be in the More Security
+ * Settings and the Privacy page, and we don't want to index these entries.
+ */
+ @Override
+ public List<SearchIndexableResource> getXmlResourcesToIndex(
+ Context context, boolean enabled) {
+ if (!SafetyCenterManagerWrapper.get().isEnabled(context)) {
+ return null;
+ }
+ return super.getXmlResourcesToIndex(context, enabled);
+ }
+
+ @Override
+ public List<AbstractPreferenceController> createPreferenceControllers(
+ Context context) {
+ return buildPreferenceControllers(context, null, null);
+ }
+
+ @Override
+ public List<String> getNonIndexableKeys(Context context) {
+ final List<String> keys = super.getNonIndexableKeys(context);
+ final int profileUserId =
+ Utils.getManagedProfileId(
+ UserManager.get(context), UserHandle.myUserId());
+ // If work profile is supported, we should keep the search result.
+ if (profileUserId != UserHandle.USER_NULL) {
+ return keys;
+ }
+
+ // Otherwise, we should hide the search result.
+ keys.add(KEY_NOTIFICATION_WORK_PROFILE_NOTIFICATIONS);
+ return keys;
+ }
+ };
+}
diff --git a/src/com/android/settings/safetycenter/SafetyCenterUtils.java b/src/com/android/settings/safetycenter/SafetyCenterUtils.java
new file mode 100644
index 0000000..6c7967d
--- /dev/null
+++ b/src/com/android/settings/safetycenter/SafetyCenterUtils.java
@@ -0,0 +1,191 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.safetycenter;
+
+import static android.app.admin.DevicePolicyResources.Strings.Settings.CONNECTED_WORK_AND_PERSONAL_APPS_TITLE;
+import static android.app.admin.DevicePolicyResources.Strings.Settings.FINGERPRINT_FOR_WORK;
+import static android.app.admin.DevicePolicyResources.Strings.Settings.MANAGED_DEVICE_INFO;
+import static android.app.admin.DevicePolicyResources.Strings.Settings.MANAGE_DEVICE_ADMIN_APPS;
+import static android.app.admin.DevicePolicyResources.Strings.Settings.WORK_PROFILE_LOCKED_NOTIFICATION_TITLE;
+import static android.app.admin.DevicePolicyResources.Strings.Settings.WORK_PROFILE_NOTIFICATIONS_SECTION_HEADER;
+import static android.app.admin.DevicePolicyResources.Strings.Settings.WORK_PROFILE_PRIVACY_POLICY_INFO;
+import static android.app.admin.DevicePolicyResources.Strings.Settings.WORK_PROFILE_PRIVACY_POLICY_INFO_SUMMARY;
+import static android.app.admin.DevicePolicyResources.Strings.Settings.WORK_PROFILE_SECURITY_TITLE;
+import static android.app.admin.DevicePolicyResources.Strings.Settings.WORK_PROFILE_SET_UNLOCK_LAUNCH_PICKER_TITLE;
+import static android.app.admin.DevicePolicyResources.Strings.Settings.WORK_PROFILE_UNIFY_LOCKS_SUMMARY;
+
+import android.annotation.StringRes;
+import android.content.Context;
+
+import com.android.settings.R;
+import com.android.settings.biometrics.combination.CombinedBiometricProfileStatusPreferenceController;
+import com.android.settings.biometrics.face.FaceProfileStatusPreferenceController;
+import com.android.settings.biometrics.fingerprint.FingerprintProfileStatusPreferenceController;
+import com.android.settings.dashboard.DashboardFragment;
+import com.android.settings.notification.LockScreenNotificationPreferenceController;
+import com.android.settings.privacy.PrivacyDashboardFragment;
+import com.android.settings.security.ChangeProfileScreenLockPreferenceController;
+import com.android.settings.security.LockUnificationPreferenceController;
+import com.android.settings.security.VisiblePatternProfilePreferenceController;
+import com.android.settings.security.trustagent.TrustAgentListPreferenceController;
+import com.android.settings.widget.PreferenceCategoryController;
+import com.android.settingslib.core.AbstractPreferenceController;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * A class with helper method used in logic involving safety center.
+ */
+public final class SafetyCenterUtils {
+
+ /**
+ * Returns preference controllers related to advanced security entries.
+ * This is used in {@link MoreSecurityPrivacyFragment} and
+ * {@link com.android.settings.security.SecurityAdvancedSettings}.
+ */
+ public static List<AbstractPreferenceController> getControllersForAdvancedSecurity(
+ Context context,
+ com.android.settingslib.core.lifecycle.Lifecycle lifecycle, DashboardFragment host) {
+ final String WORK_PROFILE_SECURITY_CATEGORY = "work_profile_category";
+ final List<AbstractPreferenceController> controllers = new ArrayList<>();
+ controllers.add(new TrustAgentListPreferenceController(context, host, lifecycle));
+
+ final List<AbstractPreferenceController> profileSecurityControllers = new ArrayList<>();
+ profileSecurityControllers.add(new ChangeProfileScreenLockPreferenceController(
+ context, host));
+ profileSecurityControllers.add(new LockUnificationPreferenceController(context, host));
+ profileSecurityControllers.add(new VisiblePatternProfilePreferenceController(
+ context, lifecycle));
+ profileSecurityControllers.add(new FaceProfileStatusPreferenceController(
+ context, lifecycle));
+ profileSecurityControllers.add(new FingerprintProfileStatusPreferenceController(
+ context, lifecycle));
+ profileSecurityControllers
+ .add(new CombinedBiometricProfileStatusPreferenceController(context, lifecycle));
+ controllers.add(new PreferenceCategoryController(context, WORK_PROFILE_SECURITY_CATEGORY)
+ .setChildren(profileSecurityControllers));
+ controllers.addAll(profileSecurityControllers);
+ return controllers;
+ }
+
+ /**
+ * Returns preference controllers for advanced privacy entries.
+ * This is used in {@link MoreSecurityPrivacyFragment} and {@link PrivacyDashboardFragment}.
+ */
+ public static List<AbstractPreferenceController> getControllersForAdvancedPrivacy(
+ Context context, com.android.settingslib.core.lifecycle.Lifecycle lifecycle) {
+ final String KEY_LOCK_SCREEN_NOTIFICATIONS = "privacy_lock_screen_notifications";
+ final String KEY_WORK_PROFILE_CATEGORY =
+ "privacy_work_profile_notifications_category";
+ final String KEY_NOTIFICATION_WORK_PROFILE_NOTIFICATIONS =
+ "privacy_lock_screen_work_profile_notifications";
+ final List<AbstractPreferenceController> controllers = new ArrayList<>();
+ final LockScreenNotificationPreferenceController notificationController =
+ new LockScreenNotificationPreferenceController(context,
+ KEY_LOCK_SCREEN_NOTIFICATIONS,
+ KEY_WORK_PROFILE_CATEGORY,
+ KEY_NOTIFICATION_WORK_PROFILE_NOTIFICATIONS);
+ if (lifecycle != null) {
+ lifecycle.addObserver(notificationController);
+ }
+ controllers.add(notificationController);
+ return controllers;
+ }
+
+ /**
+ * A class that stores the resource that will be overridden using preferenceKey and overrideKey.
+ */
+ public static final class EnterpriseOverrideString {
+ private final String mPreferenceKey;
+ private final String mOverrideKey;
+ @StringRes private final int mResource;
+
+ public EnterpriseOverrideString(
+ String preferenceKey,
+ String overrideKey,
+ @StringRes int resource) {
+ this.mPreferenceKey = preferenceKey;
+ this.mOverrideKey = overrideKey;
+ this.mResource = resource;
+ }
+
+ @StringRes
+ public int getResource() {
+ return mResource;
+ }
+
+ public String getPreferenceKey() {
+ return mPreferenceKey;
+ }
+
+ public String getOverrideKey() {
+ return mOverrideKey;
+ }
+ }
+
+ /**
+ * Returns a list of @{EnterpriseOverrideString} for the privacy entries.
+ */
+ public static List<EnterpriseOverrideString> getEnterpriseOverrideStringForPrivacyEntries() {
+ List<EnterpriseOverrideString> enterpriseOverrideStrings = new ArrayList<>();
+ enterpriseOverrideStrings.add(
+ new EnterpriseOverrideString("privacy_lock_screen_work_profile_notifications",
+ WORK_PROFILE_LOCKED_NOTIFICATION_TITLE,
+ R.string.locked_work_profile_notification_title));
+ enterpriseOverrideStrings.add(
+ new EnterpriseOverrideString("interact_across_profiles_privacy",
+ CONNECTED_WORK_AND_PERSONAL_APPS_TITLE,
+ R.string.interact_across_profiles_title));
+ enterpriseOverrideStrings.add(
+ new EnterpriseOverrideString("privacy_work_profile_notifications_category",
+ WORK_PROFILE_NOTIFICATIONS_SECTION_HEADER,
+ R.string.profile_section_header));
+ enterpriseOverrideStrings.add(new EnterpriseOverrideString("work_policy_info",
+ WORK_PROFILE_PRIVACY_POLICY_INFO, R.string.work_policy_privacy_settings));
+ enterpriseOverrideStrings.add(new EnterpriseOverrideString("work_policy_info",
+ WORK_PROFILE_PRIVACY_POLICY_INFO_SUMMARY,
+ R.string.work_policy_privacy_settings_summary));
+ return enterpriseOverrideStrings;
+ }
+
+ /**
+ * Returns a list of @{EnterpriseOverrideString} for the security entries.
+ */
+ public static List<EnterpriseOverrideString> getEnterpriseOverrideStringForSecurityEntries() {
+ List<EnterpriseOverrideString> enterpriseOverrideStrings = new ArrayList<>();
+ enterpriseOverrideStrings.add(new EnterpriseOverrideString("unlock_set_or_change_profile",
+ WORK_PROFILE_SET_UNLOCK_LAUNCH_PICKER_TITLE,
+ R.string.unlock_set_unlock_launch_picker_title_profile));
+ enterpriseOverrideStrings.add(new EnterpriseOverrideString("unification",
+ WORK_PROFILE_UNIFY_LOCKS_SUMMARY,
+ R.string.lock_settings_profile_unification_summary));
+ enterpriseOverrideStrings.add(new EnterpriseOverrideString("fingerprint_settings_profile",
+ FINGERPRINT_FOR_WORK,
+ R.string.security_settings_work_fingerprint_preference_title));
+ enterpriseOverrideStrings.add(new EnterpriseOverrideString("manage_device_admin",
+ MANAGE_DEVICE_ADMIN_APPS, R.string.manage_device_admin));
+ enterpriseOverrideStrings.add(new EnterpriseOverrideString("security_category_profile",
+ WORK_PROFILE_SECURITY_TITLE, R.string.lock_settings_profile_title));
+ enterpriseOverrideStrings.add(
+ new EnterpriseOverrideString("enterprise_privacy", MANAGED_DEVICE_INFO,
+ R.string.enterprise_privacy_settings));
+ return enterpriseOverrideStrings;
+ }
+
+ private SafetyCenterUtils() {}
+}
diff --git a/src/com/android/settings/security/SecurityAdvancedSettings.java b/src/com/android/settings/security/SecurityAdvancedSettings.java
index f716064..b2b2782 100644
--- a/src/com/android/settings/security/SecurityAdvancedSettings.java
+++ b/src/com/android/settings/security/SecurityAdvancedSettings.java
@@ -16,34 +16,25 @@
package com.android.settings.security;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.FINGERPRINT_FOR_WORK;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.MANAGED_DEVICE_INFO;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.MANAGE_DEVICE_ADMIN_APPS;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.WORK_PROFILE_SECURITY_TITLE;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.WORK_PROFILE_SET_UNLOCK_LAUNCH_PICKER_TITLE;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.WORK_PROFILE_UNIFY_LOCKS_SUMMARY;
-
import android.app.settings.SettingsEnums;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
+import android.provider.SearchIndexableResource;
import com.android.settings.R;
-import com.android.settings.biometrics.combination.CombinedBiometricProfileStatusPreferenceController;
-import com.android.settings.biometrics.face.FaceProfileStatusPreferenceController;
-import com.android.settings.biometrics.fingerprint.FingerprintProfileStatusPreferenceController;
import com.android.settings.dashboard.DashboardFragment;
import com.android.settings.overlay.FeatureFactory;
import com.android.settings.safetycenter.SafetyCenterManagerWrapper;
+import com.android.settings.safetycenter.SafetyCenterUtils;
+import com.android.settings.safetycenter.SafetyCenterUtils.EnterpriseOverrideString;
import com.android.settings.search.BaseSearchIndexProvider;
import com.android.settings.security.trustagent.TrustAgentListPreferenceController;
-import com.android.settings.widget.PreferenceCategoryController;
import com.android.settingslib.core.AbstractPreferenceController;
import com.android.settingslib.core.lifecycle.Lifecycle;
import com.android.settingslib.drawer.CategoryKey;
import com.android.settingslib.search.SearchIndexable;
-import java.util.ArrayList;
import java.util.List;
/**
@@ -55,7 +46,6 @@
public class SecurityAdvancedSettings extends DashboardFragment {
private static final String TAG = "SecurityAdvancedSettings";
- private static final String WORK_PROFILE_SECURITY_CATEGORY = "security_category_profile";
/** Used in case of old Security settings when SafetyCenter is disabled */
private static final String CATEGORY_SECURITY_LEGACY_ADVANCED_SETTINGS =
@@ -64,22 +54,13 @@
@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
- replaceEnterpriseStringTitle("unlock_set_or_change_profile",
- WORK_PROFILE_SET_UNLOCK_LAUNCH_PICKER_TITLE,
- R.string.unlock_set_unlock_launch_picker_title_profile);
- replaceEnterpriseStringSummary("unification",
- WORK_PROFILE_UNIFY_LOCKS_SUMMARY,
- R.string.lock_settings_profile_unification_summary);
- replaceEnterpriseStringTitle("fingerprint_settings_profile",
- FINGERPRINT_FOR_WORK,
- R.string.security_settings_work_fingerprint_preference_title);
- replaceEnterpriseStringTitle("manage_device_admin",
- MANAGE_DEVICE_ADMIN_APPS, R.string.manage_device_admin);
- replaceEnterpriseStringTitle("security_category_profile",
- WORK_PROFILE_SECURITY_TITLE, R.string.lock_settings_profile_title);
- replaceEnterpriseStringTitle("enterprise_privacy", MANAGED_DEVICE_INFO,
- R.string.enterprise_privacy_settings);
-
+ List<EnterpriseOverrideString> securityOverrideStrings =
+ SafetyCenterUtils.getEnterpriseOverrideStringForSecurityEntries();
+ for (int i = 0; i < securityOverrideStrings.size(); i++) {
+ EnterpriseOverrideString overrideString = securityOverrideStrings.get(i);
+ replaceEnterpriseStringTitle(overrideString.getPreferenceKey(),
+ overrideString.getOverrideKey(), overrideString.getResource());
+ }
}
@Override
@@ -140,26 +121,7 @@
private static List<AbstractPreferenceController> buildPreferenceControllers(Context context,
Lifecycle lifecycle, DashboardFragment host) {
- final List<AbstractPreferenceController> controllers = new ArrayList<>();
- controllers.add(new TrustAgentListPreferenceController(context, host, lifecycle));
-
- final List<AbstractPreferenceController> profileSecurityControllers = new ArrayList<>();
- profileSecurityControllers.add(new ChangeProfileScreenLockPreferenceController(
- context, host));
- profileSecurityControllers.add(new LockUnificationPreferenceController(context, host));
- profileSecurityControllers.add(new VisiblePatternProfilePreferenceController(
- context, lifecycle));
- profileSecurityControllers.add(new FaceProfileStatusPreferenceController(
- context, lifecycle));
- profileSecurityControllers.add(new FingerprintProfileStatusPreferenceController(
- context, lifecycle));
- profileSecurityControllers
- .add(new CombinedBiometricProfileStatusPreferenceController(context, lifecycle));
- controllers.add(new PreferenceCategoryController(context, WORK_PROFILE_SECURITY_CATEGORY)
- .setChildren(profileSecurityControllers));
- controllers.addAll(profileSecurityControllers);
-
- return controllers;
+ return SafetyCenterUtils.getControllersForAdvancedSecurity(context, lifecycle, host);
}
/**
@@ -167,6 +129,18 @@
*/
public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
new BaseSearchIndexProvider(R.xml.security_advanced_settings) {
+ /**
+ * If SafetyCenter is enabled, all of these entries will be in the More Settings
+ * page, and we don't want to index these entries.
+ */
+ @Override
+ public List<SearchIndexableResource> getXmlResourcesToIndex(Context context,
+ boolean enabled) {
+ if (SafetyCenterManagerWrapper.get().isEnabled(context)) {
+ return null;
+ }
+ return super.getXmlResourcesToIndex(context, enabled);
+ }
@Override
public List<AbstractPreferenceController> createPreferenceControllers(Context
diff --git a/src/com/android/settings/security/screenlock/AutoPinConfirmPreferenceController.java b/src/com/android/settings/security/screenlock/AutoPinConfirmPreferenceController.java
new file mode 100644
index 0000000..75af1fa
--- /dev/null
+++ b/src/com/android/settings/security/screenlock/AutoPinConfirmPreferenceController.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.security.screenlock;
+
+import android.content.Context;
+
+import androidx.preference.Preference;
+import androidx.preference.TwoStatePreference;
+
+import com.android.internal.widget.LockPatternUtils;
+import com.android.settings.core.PreferenceControllerMixin;
+import com.android.settingslib.core.AbstractPreferenceController;
+
+/**
+ * Preference controller for the pin_auto_confirm setting.
+ */
+public class AutoPinConfirmPreferenceController extends AbstractPreferenceController implements
+ PreferenceControllerMixin, Preference.OnPreferenceChangeListener {
+
+ private static final String PREF_KEY_PIN_AUTO_CONFIRM = "auto_pin_confirm";
+ private static final long MIN_AUTO_PIN_REQUIREMENT_LENGTH = 6L;
+
+ private final int mUserId;
+ private final LockPatternUtils mLockPatternUtils;
+
+ public AutoPinConfirmPreferenceController(Context context, int userId,
+ LockPatternUtils lockPatternUtils) {
+ super(context);
+ mUserId = userId;
+ mLockPatternUtils = lockPatternUtils;
+ }
+
+ @Override
+ public boolean onPreferenceChange(Preference preference, Object newValue) {
+ setPinAutoConfirmSettingState((boolean) newValue);
+ return true;
+ }
+
+ @Override
+ public void updateState(Preference preference) {
+ ((TwoStatePreference) preference).setChecked(getPinAutoConfirmSettingState());
+ }
+
+ @Override
+ public boolean isAvailable() {
+ return mLockPatternUtils.isAutoPinConfirmFeatureAvailable() && isPinLock()
+ && isPinLengthEligibleForAutoConfirmation();
+ }
+
+ @Override
+ public String getPreferenceKey() {
+ return PREF_KEY_PIN_AUTO_CONFIRM;
+ }
+
+ private boolean isPinLock() {
+ return mLockPatternUtils.getCredentialTypeForUser(mUserId)
+ == LockPatternUtils.CREDENTIAL_TYPE_PIN;
+ }
+
+ private boolean isPinLengthEligibleForAutoConfirmation() {
+ return mLockPatternUtils.getPinLength(mUserId) >= MIN_AUTO_PIN_REQUIREMENT_LENGTH;
+ }
+
+ private boolean getPinAutoConfirmSettingState() {
+ return mLockPatternUtils.isAutoPinConfirmEnabled(mUserId);
+ }
+
+ private void setPinAutoConfirmSettingState(boolean state) {
+ mLockPatternUtils.setAutoPinConfirm(state, mUserId);
+ }
+}
diff --git a/src/com/android/settings/security/screenlock/ScreenLockSettings.java b/src/com/android/settings/security/screenlock/ScreenLockSettings.java
index 082e333..af3cb65 100644
--- a/src/com/android/settings/security/screenlock/ScreenLockSettings.java
+++ b/src/com/android/settings/security/screenlock/ScreenLockSettings.java
@@ -75,6 +75,8 @@
context, MY_USER_ID, lockPatternUtils));
controllers.add(new LockAfterTimeoutPreferenceController(
context, MY_USER_ID, lockPatternUtils));
+ controllers.add(new AutoPinConfirmPreferenceController(
+ context, MY_USER_ID, lockPatternUtils));
controllers.add(new OwnerInfoPreferenceController(context, parent));
return controllers;
}
diff --git a/src/com/android/settings/spa/app/appinfo/AppBatteryPreference.kt b/src/com/android/settings/spa/app/appinfo/AppBatteryPreference.kt
index 720422f..edb2a1e 100644
--- a/src/com/android/settings/spa/app/appinfo/AppBatteryPreference.kt
+++ b/src/com/android/settings/spa/app/appinfo/AppBatteryPreference.kt
@@ -40,7 +40,9 @@
import com.android.settings.fuelgauge.batteryusage.BatteryDiffEntry
import com.android.settingslib.spa.widget.preference.Preference
import com.android.settingslib.spa.widget.preference.PreferenceModel
+import com.android.settingslib.spaprivileged.framework.common.asUser
import com.android.settingslib.spaprivileged.model.app.installed
+import com.android.settingslib.spaprivileged.model.app.userHandle
import com.android.settingslib.spaprivileged.model.app.userId
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
@@ -63,6 +65,7 @@
}
private class AppBatteryPresenter(private val context: Context, private val app: ApplicationInfo) {
+ private val userContext = context.asUser(app.userHandle)
private var batteryDiffEntryState: LoadingState<BatteryDiffEntry?>
by mutableStateOf(LoadingState.Loading)
@@ -84,7 +87,7 @@
private suspend fun getBatteryDiffEntry(): BatteryDiffEntry? = withContext(Dispatchers.IO) {
BatteryChartPreferenceController.getAppBatteryUsageData(
- context, app.packageName, app.userId
+ userContext, app.packageName, app.userId
).also {
Log.d(TAG, "loadBatteryDiffEntries():\n$it")
}
@@ -141,6 +144,7 @@
.setDestination(AdvancedPowerUsageDetail::class.java.name)
.setTitleRes(R.string.battery_details_title)
.setArguments(args)
+ .setUserHandle(app.userHandle)
.setSourceMetricsCategory(AppInfoSettingsProvider.METRICS_CATEGORY)
.launch()
}
diff --git a/tests/robotests/src/com/android/settings/accessibility/AccessibilitySettingsTest.java b/tests/robotests/src/com/android/settings/accessibility/AccessibilitySettingsTest.java
index 30aa00a..bf3951e 100644
--- a/tests/robotests/src/com/android/settings/accessibility/AccessibilitySettingsTest.java
+++ b/tests/robotests/src/com/android/settings/accessibility/AccessibilitySettingsTest.java
@@ -328,13 +328,43 @@
}
+ @Test
+ @Config(shadows = {ShadowFragment.class, ShadowUserManager.class})
+ public void testAccessibilityMenuInSystem_IncludedInInteractionControl() {
+ mShadowAccessibilityManager.setInstalledAccessibilityServiceList(
+ List.of(getMockAccessibilityServiceInfo(
+ AccessibilityManager.ACCESSIBILITY_MENU_IN_SYSTEM)));
+ setupFragment();
+
+ final RestrictedPreference pref = mFragment.getPreferenceScreen().findPreference(
+ AccessibilityManager.ACCESSIBILITY_MENU_IN_SYSTEM.flattenToString());
+ final String prefCategory = mFragment.mServicePreferenceToPreferenceCategoryMap.get(
+ pref).getKey();
+ assertThat(prefCategory).isEqualTo(AccessibilitySettings.CATEGORY_INTERACTION_CONTROL);
+ }
+
+ @Test
+ @Config(shadows = {ShadowFragment.class, ShadowUserManager.class})
+ public void testAccessibilityMenuInSystem_NoPrefWhenNotInstalled() {
+ mShadowAccessibilityManager.setInstalledAccessibilityServiceList(List.of());
+ setupFragment();
+
+ final RestrictedPreference pref = mFragment.getPreferenceScreen().findPreference(
+ AccessibilityManager.ACCESSIBILITY_MENU_IN_SYSTEM.flattenToString());
+ assertThat(pref).isNull();
+ }
+
private AccessibilityServiceInfo getMockAccessibilityServiceInfo(String packageName,
String className) {
+ return getMockAccessibilityServiceInfo(new ComponentName(packageName, className));
+ }
+
+ private AccessibilityServiceInfo getMockAccessibilityServiceInfo(ComponentName componentName) {
final ApplicationInfo applicationInfo = new ApplicationInfo();
final ServiceInfo serviceInfo = new ServiceInfo();
- applicationInfo.packageName = packageName;
- serviceInfo.packageName = packageName;
- serviceInfo.name = className;
+ applicationInfo.packageName = componentName.getPackageName();
+ serviceInfo.packageName = componentName.getPackageName();
+ serviceInfo.name = componentName.getClassName();
serviceInfo.applicationInfo = applicationInfo;
final ResolveInfo resolveInfo = new ResolveInfo();
@@ -342,7 +372,7 @@
try {
final AccessibilityServiceInfo info = new AccessibilityServiceInfo(resolveInfo,
mContext);
- info.setComponentName(new ComponentName(packageName, className));
+ info.setComponentName(componentName);
return info;
} catch (XmlPullParserException | IOException e) {
// Do nothing
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/ScreenOnTimeControllerTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/ScreenOnTimeControllerTest.java
index 0e15dcd..acf4a2e 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/ScreenOnTimeControllerTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/ScreenOnTimeControllerTest.java
@@ -98,7 +98,7 @@
ArgumentCaptor<CharSequence> argumentCaptor = ArgumentCaptor.forClass(CharSequence.class);
verify(mScreenOnTimeTextPreference).setText(argumentCaptor.capture());
- assertThat(argumentCaptor.getValue().toString()).isEqualTo("18 days, 12 hr, 27 min");
+ assertThat(argumentCaptor.getValue().toString()).isEqualTo("18 days 12 hr 27 min");
verify(mScreenOnTimeTextPreference).setVisible(true);
}
}
diff --git a/tests/robotests/src/com/android/settings/password/ChooseLockPasswordTest.java b/tests/robotests/src/com/android/settings/password/ChooseLockPasswordTest.java
index 43a49a1..d26278c 100644
--- a/tests/robotests/src/com/android/settings/password/ChooseLockPasswordTest.java
+++ b/tests/robotests/src/com/android/settings/password/ChooseLockPasswordTest.java
@@ -27,8 +27,10 @@
import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX;
import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_SOMETHING;
import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
+import static android.provider.DeviceConfig.NAMESPACE_AUTO_PIN_CONFIRMATION;
import static android.view.WindowManager.LayoutParams.FLAG_SECURE;
+import static com.android.internal.widget.LockPatternUtils.FLAG_ENABLE_AUTO_PIN_CONFIRMATION;
import static com.android.internal.widget.LockPatternUtils.PASSWORD_TYPE_KEY;
import static com.android.settings.password.ChooseLockGeneric.CONFIRM_CREDENTIALS;
@@ -43,15 +45,21 @@
import android.app.admin.PasswordPolicy;
import android.content.Intent;
import android.os.UserHandle;
+import android.provider.DeviceConfig;
+import android.view.View;
+import android.widget.CheckBox;
+import android.widget.TextView;
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;
import com.android.settings.testutils.shadow.SettingsShadowResources;
+import com.android.settings.testutils.shadow.ShadowDeviceConfig;
import com.android.settings.testutils.shadow.ShadowDevicePolicyManager;
import com.android.settings.testutils.shadow.ShadowLockPatternUtils;
import com.android.settings.testutils.shadow.ShadowUtils;
+import com.android.settings.widget.ScrollToParentEditText;
import com.google.android.setupdesign.GlifLayout;
@@ -71,9 +79,9 @@
ShadowLockPatternUtils.class,
ShadowUtils.class,
ShadowDevicePolicyManager.class,
+ ShadowDeviceConfig.class,
})
public class ChooseLockPasswordTest {
-
@Before
public void setUp() {
SettingsShadowResources.overrideResource(
@@ -387,7 +395,9 @@
}
@Test
- public void processAndValidatePasswordRequirements_defaultPinMinimumLength() {
+ public void processAndValidatePasswordRequirements_autoPinDisabled_defaultPinMinimumLength() {
+ DeviceConfig.setProperty(NAMESPACE_AUTO_PIN_CONFIRMATION, FLAG_ENABLE_AUTO_PIN_CONFIRMATION,
+ /* value= */ "false", /* makeDefault= */ false);
PasswordPolicy policy = new PasswordPolicy();
policy.quality = PASSWORD_QUALITY_UNSPECIFIED;
@@ -400,6 +410,22 @@
}
@Test
+ public void processAndValidatePasswordRequirements_autoPinEnabled_defaultPinMinimumLength() {
+ DeviceConfig.setProperty(NAMESPACE_AUTO_PIN_CONFIRMATION, FLAG_ENABLE_AUTO_PIN_CONFIRMATION,
+ /* value= */ "true", /* makeDefault= */ false);
+ PasswordPolicy policy = new PasswordPolicy();
+ policy.quality = PASSWORD_QUALITY_UNSPECIFIED;
+
+ assertPasswordValidationResult(
+ /* minMetrics */ policy.getMinMetrics(),
+ /* minComplexity= */ PASSWORD_COMPLEXITY_NONE,
+ /* passwordType= */ PASSWORD_QUALITY_NUMERIC,
+ /* userEnteredPassword= */ LockscreenCredential.createPassword("11"),
+ "PIN must be at least 4 digits"
+ + ", but a 6-digit PIN is recommended for added security");
+ }
+
+ @Test
public void processAndValidatePasswordRequirements_maximumLength() {
PasswordPolicy policy = new PasswordPolicy();
policy.quality = PASSWORD_QUALITY_UNSPECIFIED;
@@ -424,6 +450,123 @@
"PIN must be at least 8 digits");
}
+ @Test
+ public void autoPinConfirmOption_featureEnabledAndUntouchedByUser_changeStateAsPerRules() {
+ DeviceConfig.setProperty(NAMESPACE_AUTO_PIN_CONFIRMATION, FLAG_ENABLE_AUTO_PIN_CONFIRMATION,
+ /* value= */ "true", /* makeDefault= */ false);
+ ChooseLockPassword passwordActivity = setupActivityWithPinTypeAndDefaultPolicy();
+
+ ChooseLockPasswordFragment fragment = getChooseLockPasswordFragment(passwordActivity);
+ ScrollToParentEditText passwordEntry = passwordActivity.findViewById(R.id.password_entry);
+ CheckBox pinAutoConfirmOption = passwordActivity
+ .findViewById(R.id.auto_pin_confirm_enabler);
+ TextView securityMessage =
+ passwordActivity.findViewById(R.id.auto_pin_confirm_security_message);
+
+ passwordEntry.setText("1234");
+ fragment.updateUi();
+ assertThat(pinAutoConfirmOption.getVisibility()).isEqualTo(View.GONE);
+ assertThat(securityMessage.getVisibility()).isEqualTo(View.GONE);
+ assertThat(pinAutoConfirmOption.isChecked()).isFalse();
+
+ passwordEntry.setText("123456");
+ fragment.updateUi();
+ assertThat(pinAutoConfirmOption.getVisibility()).isEqualTo(View.VISIBLE);
+ assertThat(securityMessage.getVisibility()).isEqualTo(View.VISIBLE);
+ assertThat(pinAutoConfirmOption.isChecked()).isTrue();
+
+ passwordEntry.setText("12345678");
+ fragment.updateUi();
+ assertThat(pinAutoConfirmOption.getVisibility()).isEqualTo(View.VISIBLE);
+ assertThat(securityMessage.getVisibility()).isEqualTo(View.VISIBLE);
+ assertThat(pinAutoConfirmOption.isChecked()).isFalse();
+
+ passwordEntry.setText("123456");
+ fragment.updateUi();
+ assertThat(pinAutoConfirmOption.getVisibility()).isEqualTo(View.VISIBLE);
+ assertThat(securityMessage.getVisibility()).isEqualTo(View.VISIBLE);
+ assertThat(pinAutoConfirmOption.isChecked()).isTrue();
+ }
+
+ @Test
+ public void autoPinConfirmOption_featureEnabledAndModifiedByUser_shouldChangeStateAsPerRules() {
+ DeviceConfig.setProperty(NAMESPACE_AUTO_PIN_CONFIRMATION, FLAG_ENABLE_AUTO_PIN_CONFIRMATION,
+ /* value= */ "true", /* makeDefault= */ false);
+ ChooseLockPassword passwordActivity = setupActivityWithPinTypeAndDefaultPolicy();
+
+ ChooseLockPasswordFragment fragment = getChooseLockPasswordFragment(passwordActivity);
+ ScrollToParentEditText passwordEntry = passwordActivity.findViewById(R.id.password_entry);
+ CheckBox pinAutoConfirmOption = passwordActivity
+ .findViewById(R.id.auto_pin_confirm_enabler);
+ TextView securityMessage =
+ passwordActivity.findViewById(R.id.auto_pin_confirm_security_message);
+
+ passwordEntry.setText("123456");
+ fragment.updateUi();
+ assertThat(pinAutoConfirmOption.getVisibility()).isEqualTo(View.VISIBLE);
+ assertThat(securityMessage.getVisibility()).isEqualTo(View.VISIBLE);
+ assertThat(pinAutoConfirmOption.isChecked()).isTrue();
+
+ pinAutoConfirmOption.performClick();
+ assertThat(pinAutoConfirmOption.isChecked()).isFalse();
+
+ passwordEntry.setText("12345678");
+ fragment.updateUi();
+ assertThat(pinAutoConfirmOption.getVisibility()).isEqualTo(View.VISIBLE);
+ assertThat(securityMessage.getVisibility()).isEqualTo(View.VISIBLE);
+ assertThat(pinAutoConfirmOption.isChecked()).isFalse();
+
+ passwordEntry.setText("123456");
+ fragment.updateUi();
+ assertThat(pinAutoConfirmOption.getVisibility()).isEqualTo(View.VISIBLE);
+ assertThat(securityMessage.getVisibility()).isEqualTo(View.VISIBLE);
+ assertThat(pinAutoConfirmOption.isChecked()).isFalse();
+ }
+
+ @Test
+ public void autoPinConfirmOption_featureDisabled_shouldRemainInvisibleAndUnchecked() {
+ DeviceConfig.setProperty(NAMESPACE_AUTO_PIN_CONFIRMATION, FLAG_ENABLE_AUTO_PIN_CONFIRMATION,
+ /* value= */ "false", /* makeDefault= */ false);
+ ChooseLockPassword passwordActivity = setupActivityWithPinTypeAndDefaultPolicy();
+
+ ChooseLockPasswordFragment fragment = getChooseLockPasswordFragment(passwordActivity);
+ ScrollToParentEditText passwordEntry = passwordActivity.findViewById(R.id.password_entry);
+ CheckBox pinAutoConfirmOption = passwordActivity
+ .findViewById(R.id.auto_pin_confirm_enabler);
+ TextView securityMessage =
+ passwordActivity.findViewById(R.id.auto_pin_confirm_security_message);
+
+ passwordEntry.setText("1234");
+ fragment.updateUi();
+ assertThat(pinAutoConfirmOption.getVisibility()).isEqualTo(View.GONE);
+ assertThat(securityMessage.getVisibility()).isEqualTo(View.GONE);
+ assertThat(pinAutoConfirmOption.isChecked()).isFalse();
+
+ passwordEntry.setText("123456");
+ fragment.updateUi();
+ assertThat(pinAutoConfirmOption.getVisibility()).isEqualTo(View.GONE);
+ assertThat(securityMessage.getVisibility()).isEqualTo(View.GONE);
+ assertThat(pinAutoConfirmOption.isChecked()).isFalse();
+
+ passwordEntry.setText("12345678");
+ fragment.updateUi();
+ assertThat(pinAutoConfirmOption.getVisibility()).isEqualTo(View.GONE);
+ assertThat(securityMessage.getVisibility()).isEqualTo(View.GONE);
+ assertThat(pinAutoConfirmOption.isChecked()).isFalse();
+ }
+
+ private ChooseLockPassword setupActivityWithPinTypeAndDefaultPolicy() {
+ PasswordPolicy policy = new PasswordPolicy();
+ policy.quality = PASSWORD_QUALITY_UNSPECIFIED;
+
+ return buildChooseLockPasswordActivity(
+ new IntentBuilder(application)
+ .setUserId(UserHandle.myUserId())
+ .setPasswordType(PASSWORD_QUALITY_NUMERIC)
+ .setPasswordRequirement(PASSWORD_COMPLEXITY_NONE, policy.getMinMetrics())
+ .build());
+ }
+
private ChooseLockPassword buildChooseLockPasswordActivity(Intent intent) {
return Robolectric.buildActivity(ChooseLockPassword.class, intent).setup().get();
}
diff --git a/tests/robotests/src/com/android/settings/security/screenlock/AutoPinConfirmPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/security/screenlock/AutoPinConfirmPreferenceControllerTest.java
new file mode 100644
index 0000000..370b214
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/security/screenlock/AutoPinConfirmPreferenceControllerTest.java
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.security.screenlock;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+
+import androidx.preference.SwitchPreference;
+import androidx.test.core.app.ApplicationProvider;
+
+import com.android.internal.widget.LockPatternUtils;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RobolectricTestRunner;
+
+@RunWith(RobolectricTestRunner.class)
+public class AutoPinConfirmPreferenceControllerTest {
+ private static final Integer TEST_USER_ID = 1;
+ @Mock
+ private LockPatternUtils mLockPatternUtils;
+ private AutoPinConfirmPreferenceController mController;
+ private SwitchPreference mPreference;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ Context context = ApplicationProvider.getApplicationContext();
+ mController =
+ new AutoPinConfirmPreferenceController(context, TEST_USER_ID, mLockPatternUtils);
+ mPreference = new SwitchPreference(context);
+ }
+
+ @Test
+ public void isAvailable_featureEnabledAndLockSetToNone_shouldReturnFalse() {
+ when(mLockPatternUtils.isSecure(TEST_USER_ID)).thenReturn(true);
+ when(mLockPatternUtils.isAutoPinConfirmFeatureAvailable()).thenReturn(true);
+
+ assertThat(mController.isAvailable()).isFalse();
+ }
+
+ @Test
+ public void isAvailable_featureEnabledAndLockSetToPassword_shouldReturnFalse() {
+ when(mLockPatternUtils.isSecure(TEST_USER_ID)).thenReturn(true);
+ when(mLockPatternUtils.isAutoPinConfirmFeatureAvailable()).thenReturn(true);
+ when(mLockPatternUtils.getCredentialTypeForUser(TEST_USER_ID))
+ .thenReturn(LockPatternUtils.CREDENTIAL_TYPE_PASSWORD);
+
+ assertThat(mController.isAvailable()).isFalse();
+ }
+
+ @Test
+ public void isAvailable_featureEnabledAndLockSetToPIN_lengthLessThanSix_shouldReturnFalse() {
+ when(mLockPatternUtils.isAutoPinConfirmFeatureAvailable()).thenReturn(true);
+ when(mLockPatternUtils.getCredentialTypeForUser(TEST_USER_ID))
+ .thenReturn(LockPatternUtils.CREDENTIAL_TYPE_PIN);
+ when(mLockPatternUtils.getPinLength(TEST_USER_ID)).thenReturn(5L);
+
+ assertThat(mController.isAvailable()).isFalse();
+ }
+
+ @Test
+ public void isAvailable_featureEnabledAndLockSetToPIN_lengthMoreThanEqSix_shouldReturnTrue() {
+ when(mLockPatternUtils.isSecure(TEST_USER_ID)).thenReturn(true);
+ when(mLockPatternUtils.isAutoPinConfirmFeatureAvailable()).thenReturn(true);
+ when(mLockPatternUtils.getCredentialTypeForUser(TEST_USER_ID))
+ .thenReturn(LockPatternUtils.CREDENTIAL_TYPE_PIN);
+ when(mLockPatternUtils.getPinLength(TEST_USER_ID)).thenReturn(6L);
+
+ assertThat(mController.isAvailable()).isTrue();
+ }
+
+ @Test
+ public void isAvailable_featureDisabledAndLockSetToPIN_shouldReturnFalse() {
+ when(mLockPatternUtils.isAutoPinConfirmFeatureAvailable()).thenReturn(false);
+ when(mLockPatternUtils.isSecure(TEST_USER_ID)).thenReturn(true);
+ when(mLockPatternUtils.getCredentialTypeForUser(TEST_USER_ID))
+ .thenReturn(LockPatternUtils.CREDENTIAL_TYPE_PIN);
+
+ assertThat(mController.isAvailable()).isFalse();
+ }
+
+ @Test
+ public void updateState_ChangingSettingState_shouldSetPreferenceToAppropriateCheckedState() {
+ when(mLockPatternUtils.isAutoPinConfirmFeatureAvailable()).thenReturn(true);
+ // When auto_pin_confirm setting is disabled, switchPreference is unchecked
+ when(mLockPatternUtils.isAutoPinConfirmEnabled(TEST_USER_ID)).thenReturn(false);
+ mController.updateState(mPreference);
+ assertThat(mPreference.isChecked()).isFalse();
+
+ // When auto_pin_confirm setting is enabled, switchPreference is checked
+ when(mLockPatternUtils.isAutoPinConfirmEnabled(TEST_USER_ID)).thenReturn(true);
+ mController.updateState(mPreference);
+ assertThat(mPreference.isChecked()).isTrue();
+ }
+
+ @Test
+ public void onPreferenceChange_shouldUpdatePinAutoConfirmSetting() {
+ when(mLockPatternUtils.isAutoPinConfirmFeatureAvailable()).thenReturn(true);
+ mController.onPreferenceChange(mPreference, /* newValue= */ true);
+ verify(mLockPatternUtils).setAutoPinConfirm(true, TEST_USER_ID);
+ }
+}
diff --git a/tests/spa_unit/src/com/android/settings/spa/app/appinfo/AppBatteryPreferenceTest.kt b/tests/spa_unit/src/com/android/settings/spa/app/appinfo/AppBatteryPreferenceTest.kt
index fd286ca..276b711 100644
--- a/tests/spa_unit/src/com/android/settings/spa/app/appinfo/AppBatteryPreferenceTest.kt
+++ b/tests/spa_unit/src/com/android/settings/spa/app/appinfo/AppBatteryPreferenceTest.kt
@@ -36,6 +36,9 @@
import com.android.settings.fuelgauge.AdvancedPowerUsageDetail
import com.android.settings.fuelgauge.batteryusage.BatteryChartPreferenceController
import com.android.settings.fuelgauge.batteryusage.BatteryDiffEntry
+import com.android.settings.testutils.mockAsUser
+import com.android.settingslib.spaprivileged.framework.common.asUser
+import com.android.settingslib.spaprivileged.model.app.userHandle
import com.android.settingslib.spaprivileged.model.app.userId
import org.junit.After
import org.junit.Before
@@ -69,6 +72,7 @@
.mockStatic(AdvancedPowerUsageDetail::class.java)
.strictness(Strictness.LENIENT)
.startMocking()
+ context.mockAsUser()
whenever(context.resources).thenReturn(resources)
whenever(resources.getBoolean(R.bool.config_show_app_info_settings_battery))
.thenReturn(true)
diff --git a/tests/unit/src/com/android/settings/TestUtils.java b/tests/unit/src/com/android/settings/TestUtils.java
index d7b1ea4..151b7c1 100644
--- a/tests/unit/src/com/android/settings/TestUtils.java
+++ b/tests/unit/src/com/android/settings/TestUtils.java
@@ -15,6 +15,21 @@
*/
package com.android.settings;
+import static com.android.settings.core.PreferenceXmlParserUtils.METADATA_KEY;
+import static com.android.settings.core.PreferenceXmlParserUtils.MetadataFlag.FLAG_INCLUDE_PREF_SCREEN;
+import static com.android.settings.core.PreferenceXmlParserUtils.MetadataFlag.FLAG_NEED_KEY;
+
+import android.annotation.XmlRes;
+import android.content.Context;
+import android.os.Bundle;
+import android.provider.SearchIndexableResource;
+
+import com.android.settings.core.PreferenceXmlParserUtils;
+import com.android.settings.search.BaseSearchIndexProvider;
+
+import java.util.ArrayList;
+import java.util.List;
+
/**
* Convenience methods and constants for testing.
*/
@@ -22,4 +37,30 @@
public static final long KILOBYTE = 1024L; // TODO: Change to 1000 in O Robolectric.
public static final long MEGABYTE = KILOBYTE * KILOBYTE;
public static final long GIGABYTE = KILOBYTE * MEGABYTE;
+
+ public static List<String> getAllXmlKeys(
+ Context context, BaseSearchIndexProvider indexProvider)
+ throws Exception {
+ final List<SearchIndexableResource> resources = indexProvider.getXmlResourcesToIndex(
+ context, true /* not used*/);
+ if (resources == null || resources.isEmpty()) {
+ return new ArrayList<>();
+ }
+ final List<String> keys = new ArrayList<>();
+ for (SearchIndexableResource res : resources) {
+ keys.addAll(getKeysFromXml(res.xmlResId, context));
+ }
+ return keys;
+ }
+
+ private static List<String> getKeysFromXml(@XmlRes int xmlResId, Context context)
+ throws Exception {
+ final List<String> keys = new ArrayList<>();
+ final List<Bundle> metadata = PreferenceXmlParserUtils.extractMetadata(context, xmlResId,
+ FLAG_NEED_KEY | FLAG_INCLUDE_PREF_SCREEN);
+ for (Bundle bundle : metadata) {
+ keys.add(bundle.getString(METADATA_KEY));
+ }
+ return keys;
+ }
}
diff --git a/tests/unit/src/com/android/settings/applications/specialaccess/notificationaccess/BridgedAppsPreferenceControllerTest.java b/tests/unit/src/com/android/settings/applications/specialaccess/notificationaccess/BridgedAppsPreferenceControllerTest.java
index 38c605c..8371eaf 100644
--- a/tests/unit/src/com/android/settings/applications/specialaccess/notificationaccess/BridgedAppsPreferenceControllerTest.java
+++ b/tests/unit/src/com/android/settings/applications/specialaccess/notificationaccess/BridgedAppsPreferenceControllerTest.java
@@ -34,7 +34,6 @@
import android.service.notification.NotificationListenerFilter;
import android.util.ArraySet;
-import androidx.preference.CheckBoxPreference;
import androidx.preference.Preference;
import androidx.preference.PreferenceManager;
import androidx.preference.PreferenceScreen;
@@ -42,6 +41,7 @@
import androidx.test.ext.junit.runners.AndroidJUnit4;
import com.android.settings.notification.NotificationBackend;
+import com.android.settings.widget.AppCheckBoxPreference;
import com.android.settingslib.applications.ApplicationsState;
import org.junit.Before;
@@ -120,7 +120,7 @@
when(mNm.isNotificationListenerAccessGranted(mCn)).thenReturn(true);
when(mNm.getListenerFilter(mCn, 0)).thenReturn(new NotificationListenerFilter());
- CheckBoxPreference p = mock(CheckBoxPreference.class);
+ AppCheckBoxPreference p = mock(AppCheckBoxPreference.class);
when(p.getKey()).thenReturn("pkg|12300");
mScreen.addPreference(p);
@@ -161,7 +161,7 @@
mController.onRebuildComplete(entries);
- CheckBoxPreference actual = mScreen.findPreference("pkg|12300");
+ AppCheckBoxPreference actual = mScreen.findPreference("pkg|12300");
assertThat(actual.isChecked()).isTrue();
assertThat(actual.getTitle()).isEqualTo("hi");
@@ -178,7 +178,7 @@
when(mNm.isNotificationListenerAccessGranted(mCn)).thenReturn(true);
when(mNm.getListenerFilter(mCn, 0)).thenReturn(nlf);
- CheckBoxPreference pref = new CheckBoxPreference(mContext);
+ AppCheckBoxPreference pref = new AppCheckBoxPreference(mContext);
pref.setKey("pkg|567");
mController.onPreferenceChange(pref, false);
@@ -204,7 +204,7 @@
when(mNm.isNotificationListenerAccessGranted(mCn)).thenReturn(true);
when(mNm.getListenerFilter(mCn, 0)).thenReturn(nlf);
- CheckBoxPreference pref = new CheckBoxPreference(mContext);
+ AppCheckBoxPreference pref = new AppCheckBoxPreference(mContext);
pref.setKey("pkg|567");
mController.onPreferenceChange(pref, true);
diff --git a/tests/unit/src/com/android/settings/privacy/PrivacyDashboardFragmentTest.java b/tests/unit/src/com/android/settings/privacy/PrivacyDashboardFragmentTest.java
new file mode 100644
index 0000000..c49bb25
--- /dev/null
+++ b/tests/unit/src/com/android/settings/privacy/PrivacyDashboardFragmentTest.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.privacy;
+
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.os.Looper;
+
+import androidx.test.annotation.UiThreadTest;
+import androidx.test.core.app.ApplicationProvider;
+
+import com.android.settings.TestUtils;
+import com.android.settings.safetycenter.SafetyCenterManagerWrapper;
+import com.android.settings.search.BaseSearchIndexProvider;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.util.List;
+
+public class PrivacyDashboardFragmentTest {
+
+ private Context mContext;
+ private PrivacyDashboardFragment mPrivacyDashboardFragment;
+
+ @Mock
+ private SafetyCenterManagerWrapper mSafetyCenterManagerWrapper;
+
+ @Before
+ @UiThreadTest
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ MockitoAnnotations.initMocks(this);
+ if (Looper.myLooper() == null) {
+ Looper.prepare();
+ }
+
+ mContext = ApplicationProvider.getApplicationContext();
+ SafetyCenterManagerWrapper.sInstance = mSafetyCenterManagerWrapper;
+ mPrivacyDashboardFragment = spy(new PrivacyDashboardFragment());
+ when(mPrivacyDashboardFragment.getContext()).thenReturn(mContext);
+ }
+
+ @Test
+ public void whenSafetyCenterIsEnabled_pageIndexExcluded() throws Exception {
+ when(mSafetyCenterManagerWrapper.isEnabled(any())).thenReturn(true);
+ BaseSearchIndexProvider indexProvider = PrivacyDashboardFragment.SEARCH_INDEX_DATA_PROVIDER;
+
+ List<String> allXmlKeys = TestUtils.getAllXmlKeys(mContext, indexProvider);
+ List<String> nonIndexableKeys = indexProvider.getNonIndexableKeys(mContext);
+ allXmlKeys.removeAll(nonIndexableKeys);
+
+ assertThat(allXmlKeys).isEmpty();
+ }
+}
diff --git a/tests/unit/src/com/android/settings/safetycenter/MoreSecurityPrivacyFragmentSettingsTest.java b/tests/unit/src/com/android/settings/safetycenter/MoreSecurityPrivacyFragmentSettingsTest.java
new file mode 100644
index 0000000..7ed0a02
--- /dev/null
+++ b/tests/unit/src/com/android/settings/safetycenter/MoreSecurityPrivacyFragmentSettingsTest.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.safetycenter;
+
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.os.Looper;
+
+import androidx.test.annotation.UiThreadTest;
+import androidx.test.core.app.ApplicationProvider;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import com.android.settings.TestUtils;
+import com.android.settings.search.BaseSearchIndexProvider;
+import com.android.settings.testutils.ResourcesUtils;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.util.List;
+
+@RunWith(AndroidJUnit4.class)
+public class MoreSecurityPrivacyFragmentSettingsTest {
+ private static final String SCREEN_XML_RESOURCE_NAME = "more_security_privacy_settings";
+ private MoreSecurityPrivacyFragment mMoreSecurityPrivacyFragment;
+ private Context mContext;
+ @Mock
+ private SafetyCenterManagerWrapper mSafetyCenterManagerWrapper;
+ @Before
+ @UiThreadTest
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ MockitoAnnotations.initMocks(this);
+ if (Looper.myLooper() == null) {
+ Looper.prepare();
+ }
+
+ mContext = ApplicationProvider.getApplicationContext();
+ SafetyCenterManagerWrapper.sInstance = mSafetyCenterManagerWrapper;
+ mMoreSecurityPrivacyFragment = spy(new MoreSecurityPrivacyFragment());
+ when(mMoreSecurityPrivacyFragment.getContext()).thenReturn(mContext);
+ }
+
+ @Test
+ public void getPreferenceXml_returnsMoreSecurityPrivacy() {
+ assertThat(mMoreSecurityPrivacyFragment.getPreferenceScreenResId())
+ .isEqualTo(getXmlResId(SCREEN_XML_RESOURCE_NAME));
+ }
+
+ @Test
+ public void whenSafetyCenterIsEnabled_pageIndexIncluded() throws Exception {
+ when(mSafetyCenterManagerWrapper.isEnabled(any())).thenReturn(true);
+ BaseSearchIndexProvider indexProvider =
+ MoreSecurityPrivacyFragment.SEARCH_INDEX_DATA_PROVIDER;
+
+ List<String> allXmlKeys = TestUtils.getAllXmlKeys(mContext, indexProvider);
+ List<String> nonIndexableKeys = indexProvider.getNonIndexableKeys(mContext);
+ allXmlKeys.removeAll(nonIndexableKeys);
+
+ assertThat(allXmlKeys).isNotEmpty();
+ }
+
+ @Test
+ public void whenSafetyCenterIsDisabled_pageIndexExcluded() throws Exception {
+ when(mSafetyCenterManagerWrapper.isEnabled(any())).thenReturn(false);
+ BaseSearchIndexProvider indexProvider =
+ MoreSecurityPrivacyFragment.SEARCH_INDEX_DATA_PROVIDER;
+
+ List<String> allXmlKeys = TestUtils.getAllXmlKeys(mContext, indexProvider);
+ List<String> nonIndexableKeys = indexProvider.getNonIndexableKeys(mContext);
+ allXmlKeys.removeAll(nonIndexableKeys);
+
+ assertThat(allXmlKeys).isEmpty();
+ }
+
+ private int getXmlResId(String resName) {
+ return ResourcesUtils.getResourcesId(mContext, "xml", resName);
+ }
+}
diff --git a/tests/unit/src/com/android/settings/security/SecurityAdvancedSettingsTest.java b/tests/unit/src/com/android/settings/security/SecurityAdvancedSettingsTest.java
index 2efb357..9851a1a 100644
--- a/tests/unit/src/com/android/settings/security/SecurityAdvancedSettingsTest.java
+++ b/tests/unit/src/com/android/settings/security/SecurityAdvancedSettingsTest.java
@@ -16,6 +16,7 @@
package com.android.settings.security;
+
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
@@ -29,7 +30,9 @@
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
+import com.android.settings.TestUtils;
import com.android.settings.safetycenter.SafetyCenterManagerWrapper;
+import com.android.settings.search.BaseSearchIndexProvider;
import com.android.settings.testutils.FakeFeatureFactory;
import com.android.settings.testutils.ResourcesUtils;
import com.android.settingslib.drawer.CategoryKey;
@@ -40,6 +43,8 @@
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import java.util.List;
+
@RunWith(AndroidJUnit4.class)
public class SecurityAdvancedSettingsTest {
private static final String SCREEN_XML_RESOURCE_NAME = "security_advanced_settings";
@@ -100,6 +105,18 @@
.isEqualTo(LEGACY_CATEGORY_KEY);
}
+ @Test
+ public void whenSafetyCenterIsEnabled_pageIndexExcluded() throws Exception {
+ when(mSafetyCenterManagerWrapper.isEnabled(any())).thenReturn(false);
+ BaseSearchIndexProvider indexProvider = SecurityAdvancedSettings.SEARCH_INDEX_DATA_PROVIDER;
+
+ List<String> allXmlKeys = TestUtils.getAllXmlKeys(mContext, indexProvider);
+ List<String> nonIndexableKeys = indexProvider.getNonIndexableKeys(mContext);
+ allXmlKeys.removeAll(nonIndexableKeys);
+
+ assertThat(allXmlKeys).isEmpty();
+ }
+
private int getXmlResId(String resName) {
return ResourcesUtils.getResourcesId(mContext, "xml", resName);
}
diff --git a/tests/unit/src/com/android/settings/security/SecuritySettingsTest.java b/tests/unit/src/com/android/settings/security/SecuritySettingsTest.java
index c517884..dee90b4 100644
--- a/tests/unit/src/com/android/settings/security/SecuritySettingsTest.java
+++ b/tests/unit/src/com/android/settings/security/SecuritySettingsTest.java
@@ -21,24 +21,18 @@
import static android.content.pm.PackageManager.FEATURE_FACE;
import static android.content.pm.PackageManager.FEATURE_FINGERPRINT;
-import static com.android.settings.core.PreferenceXmlParserUtils.METADATA_KEY;
-import static com.android.settings.core.PreferenceXmlParserUtils.MetadataFlag.FLAG_INCLUDE_PREF_SCREEN;
-import static com.android.settings.core.PreferenceXmlParserUtils.MetadataFlag.FLAG_NEED_KEY;
-
import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;
-import android.annotation.XmlRes;
import android.content.Context;
import android.content.pm.PackageManager;
import android.hardware.face.FaceManager;
import android.hardware.fingerprint.FingerprintManager;
-import android.os.Bundle;
import android.os.Looper;
-import android.provider.SearchIndexableResource;
import androidx.lifecycle.Lifecycle;
import androidx.preference.Preference;
@@ -48,10 +42,11 @@
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
+import com.android.settings.TestUtils;
import com.android.settings.biometrics.combination.CombinedBiometricStatusPreferenceController;
import com.android.settings.biometrics.face.FaceStatusPreferenceController;
import com.android.settings.biometrics.fingerprint.FingerprintStatusPreferenceController;
-import com.android.settings.core.PreferenceXmlParserUtils;
+import com.android.settings.safetycenter.SafetyCenterManagerWrapper;
import com.android.settings.search.BaseSearchIndexProvider;
import com.android.settings.security.trustagent.TrustAgentManager;
import com.android.settings.testutils.FakeFeatureFactory;
@@ -64,7 +59,6 @@
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
-import java.util.ArrayList;
import java.util.List;
@RunWith(AndroidJUnit4.class)
@@ -85,6 +79,8 @@
private FingerprintManager mFingerprintManager;
@Mock
private PackageManager mPackageManager;
+ @Mock
+ private SafetyCenterManagerWrapper mSafetyCenterManagerWrapper;
private PreferenceScreen mScreen;
@@ -96,6 +92,7 @@
}
MockitoAnnotations.initMocks(this);
+ SafetyCenterManagerWrapper.sInstance = mSafetyCenterManagerWrapper;
mContext = spy(ApplicationProvider.getApplicationContext());
when(mContext.getPackageManager()).thenReturn(mPackageManager);
when(mPackageManager.hasSystemFeature(FEATURE_FACE)).thenReturn(true);
@@ -132,12 +129,14 @@
}
@Test
- public void noAlternativeFragmentAvailable_pageIndexIncluded() throws Exception {
+ public void noAlternativeFragmentAvailableAndSafetyCenterIsDisabled_pageIndexIncluded()
+ throws Exception {
when(mSecuritySettingsFeatureProvider.hasAlternativeSecuritySettingsFragment()).thenReturn(
false);
+ when(mSafetyCenterManagerWrapper.isEnabled(any())).thenReturn(false);
BaseSearchIndexProvider indexProvider = SecuritySettings.SEARCH_INDEX_DATA_PROVIDER;
- List<String> allXmlKeys = getAllXmlKeys(indexProvider);
+ List<String> allXmlKeys = TestUtils.getAllXmlKeys(mContext, indexProvider);
List<String> nonIndexableKeys = indexProvider.getNonIndexableKeys(mContext);
allXmlKeys.removeAll(nonIndexableKeys);
@@ -150,7 +149,7 @@
true);
BaseSearchIndexProvider indexProvider = SecuritySettings.SEARCH_INDEX_DATA_PROVIDER;
- List<String> allXmlKeys = getAllXmlKeys(indexProvider);
+ List<String> allXmlKeys = TestUtils.getAllXmlKeys(mContext, indexProvider);
List<String> nonIndexableKeys = indexProvider.getNonIndexableKeys(mContext);
allXmlKeys.removeAll(nonIndexableKeys);
@@ -340,29 +339,6 @@
assertThat(mPreferenceCombined.isVisible()).isFalse();
}
- private List<String> getAllXmlKeys(BaseSearchIndexProvider indexProvider) throws Exception {
- final List<SearchIndexableResource> resources = indexProvider.getXmlResourcesToIndex(
- mContext, true /* not used*/);
- if (resources == null || resources.isEmpty()) {
- return new ArrayList<>();
- }
- final List<String> keys = new ArrayList<>();
- for (SearchIndexableResource res : resources) {
- keys.addAll(getKeysFromXml(res.xmlResId));
- }
- return keys;
- }
-
- private List<String> getKeysFromXml(@XmlRes int xmlResId) throws Exception {
- final List<String> keys = new ArrayList<>();
- final List<Bundle> metadata = PreferenceXmlParserUtils.extractMetadata(mContext, xmlResId,
- FLAG_NEED_KEY | FLAG_INCLUDE_PREF_SCREEN);
- for (Bundle bundle : metadata) {
- keys.add(bundle.getString(METADATA_KEY));
- }
- return keys;
- }
-
boolean isFacePrefAvailable(List<AbstractPreferenceController> controllers) {
return controllers.stream().filter(
controller -> controller instanceof FaceStatusPreferenceController