Merge "Sort notification channel in NotificationChannelSlice"
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index a12c982..8362fd6 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -1249,12 +1249,11 @@
android:label="@string/local_backup_password_title"
android:exported="false" />
- <activity android:name="CredentialStorage"
+ <activity android:name=".security.CredentialStorage"
android:theme="@style/Transparent"
android:launchMode="singleTop"
android:configChanges="orientation|keyboardHidden|screenSize">
<intent-filter android:priority="1">
- <action android:name="com.android.credentials.UNLOCK" />
<action android:name="com.android.credentials.INSTALL" />
<action android:name="com.android.credentials.RESET" />
<category android:name="android.intent.category.DEFAULT" />
@@ -1826,7 +1825,7 @@
<activity
android:name="Settings$PrintSettingsActivity"
android:label="@string/print_settings"
- android:icon="@drawable/ic_settings_print"
+ android:icon="@*android:drawable/ic_settings_print"
android:parentActivityName="Settings">
<intent-filter android:priority="1">
<action android:name="android.settings.ACTION_PRINT_SETTINGS" />
@@ -2978,8 +2977,23 @@
<action android:name="android.settings.panel.action.VOLUME" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
+ <intent-filter>
+ <action android:name="android.settings.panel.action.NFC" />
+ <category android:name="android.intent.category.DEFAULT" />
+ </intent-filter>
</activity>
+ <activity-alias
+ android:name="MediaOutputSlice"
+ android:label="@string/media_output_panel_title"
+ android:permission="android.permission.BLUETOOTH_PRIVILEGED"
+ android:targetActivity=".panel.SettingsPanelActivity">
+ <intent-filter>
+ <action android:name="com.android.settings.panel.action.MEDIA_OUTPUT" />
+ <category android:name="android.intent.category.DEFAULT" />
+ </intent-filter>
+ </activity-alias>
+
<provider android:name=".slices.SettingsSliceProvider"
android:authorities="com.android.settings.slices;android.settings.slices"
android:exported="true"
@@ -3045,7 +3059,7 @@
<intent-filter>
<action android:name="android.settings.WIFI_DPP_CONFIGURATOR_QR_CODE_SCANNER"/>
<action android:name="android.settings.WIFI_DPP_CONFIGURATOR_QR_CODE_GENERATOR"/>
- <action android:name="android.settings.PROCESS_WIFI_DPP_QR_CODE"/>
+ <action android:name="android.settings.PROCESS_WIFI_EASY_CONNECT_QR_CODE"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</activity>
diff --git a/protos/contextual_card_list.proto b/protos/contextual_card_list.proto
index 3496c8c..5645c87 100644
--- a/protos/contextual_card_list.proto
+++ b/protos/contextual_card_list.proto
@@ -19,6 +19,7 @@
POSSIBLE = 2;
IMPORTANT = 3;
EXCLUSIVE = 4;
+ DEFERRED_SETUP = 5;
}
/** Slice uri of the contextual card */
diff --git a/res/drawable-nodpi/gesture_silence b/res/drawable-nodpi/gesture_silence
deleted file mode 100644
index e69de29..0000000
--- a/res/drawable-nodpi/gesture_silence
+++ /dev/null
diff --git a/res/drawable-nodpi/gesture_skip b/res/drawable-nodpi/gesture_skip
deleted file mode 100644
index e69de29..0000000
--- a/res/drawable-nodpi/gesture_skip
+++ /dev/null
diff --git a/res/drawable/ic_expand.xml b/res/drawable/ic_expand.xml
index 72da2b9..f5b3f66 100644
--- a/res/drawable/ic_expand.xml
+++ b/res/drawable/ic_expand.xml
@@ -19,6 +19,6 @@
<item android:state_checked="true" android:drawable="@drawable/ic_expand_less" />
- <item android:drawable="@drawable/ic_expand_more" />
+ <item android:drawable="@*android:drawable/ic_expand_more" />
</selector>
diff --git a/res/drawable/ic_expand_more.xml b/res/drawable/ic_expand_more.xml
deleted file mode 100644
index edffde3..0000000
--- a/res/drawable/ic_expand_more.xml
+++ /dev/null
@@ -1,30 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- Copyright (C) 2015 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="?android:attr/colorControlNormal">
-
- <path
- android:fillColor="#000000"
- android:pathData="M8.12 9.29L12 13.17l3.88-3.88a.996 .996 0 1 1 1.41 1.41l-4.59 4.59a.996 .996 0 0
-1-1.41 0L6.7 10.7a.996 .996 0 0 1 0-1.41c.39-.38 1.03-.39 1.42 0z" />
-
-</vector>
diff --git a/res/layout/advanced_bt_entity_header.xml b/res/layout/advanced_bt_entity_header.xml
new file mode 100644
index 0000000..4aadad1
--- /dev/null
+++ b/res/layout/advanced_bt_entity_header.xml
@@ -0,0 +1,68 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2019 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/entity_header"
+ style="@style/EntityHeader"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical">
+
+ <TextView
+ android:id="@+id/entity_header_title"
+ style="@style/TextAppearance.EntityHeaderTitle"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_horizontal"
+ android:singleLine="false"
+ android:ellipsize="marquee"
+ android:textDirection="locale"/>
+
+ <TextView
+ android:id="@+id/entity_header_summary"
+ style="@style/TextAppearance.EntityHeaderSummary"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_horizontal"
+ android:layout_marginTop="2dp"
+ android:singleLine="false"
+ android:ellipsize="marquee"
+ android:textDirection="locale"
+ android:text="test_summary"/>
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="16dp"
+ android:orientation="horizontal">
+
+ <include
+ android:id="@+id/layout_left"
+ layout="@layout/advanced_bt_entity_sub"/>
+
+ <include
+ android:id="@+id/layout_middle"
+ layout="@layout/advanced_bt_entity_sub"/>
+
+ <include
+ android:id="@+id/layout_right"
+ layout="@layout/advanced_bt_entity_sub"/>
+
+ </LinearLayout>
+
+</LinearLayout>
diff --git a/res/layout/advanced_bt_entity_sub.xml b/res/layout/advanced_bt_entity_sub.xml
new file mode 100644
index 0000000..07ea814
--- /dev/null
+++ b/res/layout/advanced_bt_entity_sub.xml
@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2019 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:orientation="vertical">
+
+ <ImageView
+ android:id="@+id/header_icon"
+ android:layout_width="72dp"
+ android:layout_height="72dp"
+ android:scaleType="fitCenter"
+ android:layout_gravity="center_horizontal"
+ android:antialias="true"/>
+
+ <TextView
+ android:id="@+id/header_title"
+ style="@style/TextAppearance.EntityHeaderTitle"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_horizontal"
+ android:singleLine="false"
+ android:ellipsize="marquee"
+ android:textDirection="locale"
+ android:layout_marginTop="24dp"/>
+
+ <LinearLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="2dp"
+ android:layout_gravity="center_horizontal"
+ android:orientation="horizontal">
+ <ImageView
+ android:id="@+id/bt_battery_icon"
+ android:layout_width="13dp"
+ android:layout_height="20dp"/>
+ <TextView
+ android:id="@+id/bt_battery_summary"
+ style="@style/TextAppearance.EntityHeaderSummary"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="4dp"
+ android:layout_gravity="center_horizontal"/>
+ </LinearLayout>
+
+</LinearLayout>
\ No newline at end of file
diff --git a/res/layout/crypt_keeper_switch_input_method.xml b/res/layout/crypt_keeper_switch_input_method.xml
index b55db22..3fae593 100644
--- a/res/layout/crypt_keeper_switch_input_method.xml
+++ b/res/layout/crypt_keeper_switch_input_method.xml
@@ -22,7 +22,7 @@
android:id="@+id/switch_ime_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:src="@drawable/ic_lockscreen_ime"
+ android:src="@*android:drawable/ic_lockscreen_ime"
android:clickable="true"
android:contentDescription="@string/crypt_keeper_switch_input_method"
android:padding="@dimen/crypt_keeper_edit_text_ime_padding"
diff --git a/res/layout/dialog_firmware_version.xml b/res/layout/dialog_firmware_version.xml
index 874d7af..1d5f531 100644
--- a/res/layout/dialog_firmware_version.xml
+++ b/res/layout/dialog_firmware_version.xml
@@ -53,6 +53,18 @@
<TextView
style="@style/device_info_dialog_label"
+ android:id="@+id/module_version_label"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/module_version"/>
+ <TextView
+ style="@style/device_info_dialog_value"
+ android:id="@+id/module_version_value"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"/>
+
+ <TextView
+ style="@style/device_info_dialog_label"
android:id="@+id/baseband_version_label"
android:layout_width="match_parent"
android:layout_height="wrap_content"
diff --git a/res/layout/face_enroll_introduction.xml b/res/layout/face_enroll_introduction.xml
index 69b00fe..4096925 100644
--- a/res/layout/face_enroll_introduction.xml
+++ b/res/layout/face_enroll_introduction.xml
@@ -85,12 +85,6 @@
android:layout_height="wrap_content"
FaceEnrollAccessibilitySwitch:messageText="@string/security_settings_face_enroll_introduction_accessibility_diversity"/>
- <com.android.settings.biometrics.face.FaceEnrollAccessibilityToggle
- android:id="@+id/toggle_vision"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- FaceEnrollAccessibilitySwitch:messageText="@string/security_settings_face_enroll_introduction_accessibility_vision"/>
-
</LinearLayout>
</FrameLayout>
diff --git a/res/layout/homepage_condition_header.xml b/res/layout/homepage_condition_header.xml
index 8f3a92c..a2796ec 100644
--- a/res/layout/homepage_condition_header.xml
+++ b/res/layout/homepage_condition_header.xml
@@ -45,8 +45,8 @@
android:paddingTop="@dimen/homepage_condition_header_indicator_padding_top"
android:paddingStart="@dimen/homepage_condition_header_indicator_padding_start"
android:paddingEnd="@dimen/homepage_condition_header_indicator_padding_end"
- android:src="@drawable/ic_expand_more"/>
+ android:src="@*android:drawable/ic_expand_more"/>
</LinearLayout>
-</com.google.android.material.card.MaterialCardView>
\ No newline at end of file
+</com.google.android.material.card.MaterialCardView>
diff --git a/res/layout/homepage_dismissal_view.xml b/res/layout/homepage_dismissal_view.xml
index 6d8f711..4295ff6 100644
--- a/res/layout/homepage_dismissal_view.xml
+++ b/res/layout/homepage_dismissal_view.xml
@@ -34,7 +34,6 @@
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:layout_marginBottom="@dimen/homepage_card_dismissal_margin_bottom"
android:gravity="bottom|end">
<Button
@@ -49,8 +48,8 @@
style="@style/ContextualCardDismissalButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_marginStart="@dimen/homepage_card_dismissal_button_side_margin"
- android:layout_marginEnd="@dimen/homepage_card_dismissal_button_side_margin"
+ android:layout_marginStart="@dimen/homepage_card_dismissal_button_margin_start"
+ android:layout_marginEnd="@dimen/homepage_card_dismissal_button_margin_end"
android:text="@string/contextual_card_dismiss_keep"/>
</LinearLayout>
diff --git a/res/layout/homepage_slice_deferred_setup_tile.xml b/res/layout/homepage_slice_deferred_setup_tile.xml
new file mode 100644
index 0000000..8c83c09
--- /dev/null
+++ b/res/layout/homepage_slice_deferred_setup_tile.xml
@@ -0,0 +1,79 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2019 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<com.google.android.material.card.MaterialCardView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ style="@style/ContextualCardStyle"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+
+ <ViewFlipper
+ android:id="@+id/view_flipper"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <LinearLayout
+ android:id="@+id/content"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:gravity="left"
+ android:orientation="vertical"
+ android:paddingBottom="@dimen/homepage_deferred_setup_card_padding_bottom"
+ android:paddingEnd="@dimen/homepage_card_padding_end"
+ android:paddingStart="@dimen/homepage_card_padding_start"
+ android:paddingTop="@dimen/homepage_deferred_setup_card_padding_top">
+
+ <ImageView
+ android:id="@android:id/icon"
+ android:layout_width="@dimen/homepage_card_icon_size"
+ android:layout_height="@dimen/homepage_card_icon_size"/>
+
+ <TextView
+ android:id="@android:id/title"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/homepage_deferred_setup_card_title_margin_top"
+ android:ellipsize="end"
+ android:maxLines="2"
+ android:minLines="1"
+ android:textAppearance="@style/TextAppearance.DeferredSetupCardTitle"/>
+
+ <TextView
+ android:id="@android:id/summary"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/homepage_deferred_setup_card_summary_margin_top"
+ android:ellipsize="end"
+ android:maxLines="2"
+ android:minLines="1"
+ android:textAppearance="@style/TextAppearance.DeferredSetupCardSummary"/>
+
+ <Button
+ android:id="@+id/finish_setup"
+ style="@style/DeferredSetupCardButton"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/homepage_deferred_setup_card_button_margin_top"
+ android:text="@string/suggestion_button_text"/>
+
+ </LinearLayout>
+
+ <!--dismissal view-->
+ <include layout="@layout/homepage_dismissal_view"/>
+
+ </ViewFlipper>
+</com.google.android.material.card.MaterialCardView>
\ No newline at end of file
diff --git a/res/layout/network_request_dialog_title.xml b/res/layout/network_request_dialog_title.xml
index 186768e..f643e0f 100644
--- a/res/layout/network_request_dialog_title.xml
+++ b/res/layout/network_request_dialog_title.xml
@@ -31,6 +31,8 @@
android:layout_weight="1"
android:textSize="18sp"
android:gravity="center_vertical"
+ android:maxLines="1"
+ android:ellipsize="end"
style="@style/info_label"/>
<ProgressBar
diff --git a/res/raw/gesture_silence.mp4 b/res/raw/gesture_silence.mp4
deleted file mode 100644
index e69de29..0000000
--- a/res/raw/gesture_silence.mp4
+++ /dev/null
diff --git a/res/raw/gesture_skip.mp4 b/res/raw/gesture_skip.mp4
deleted file mode 100644
index e69de29..0000000
--- a/res/raw/gesture_skip.mp4
+++ /dev/null
diff --git a/res/values/config.xml b/res/values/config.xml
index a6e5e1c..e6856ac 100755
--- a/res/values/config.xml
+++ b/res/values/config.xml
@@ -143,6 +143,15 @@
<!-- Whether or not homepage should display user's account avatar -->
<bool name="config_show_avatar_in_homepage">false</bool>
+ <!-- Whether or not emergency info tile should display in device info page -->
+ <bool name="config_show_emergency_info_in_device_info">true</bool>
+
+ <!-- Whether or not branded account info tile should display in device info page -->
+ <bool name="config_show_branded_account_in_device_info">true</bool>
+
+ <!-- Whether or not device header widget tile should display in device info page -->
+ <bool name="config_show_device_header_in_device_info">true</bool>
+
<!-- Whether or not TopLevelSettings should force rounded icon for injected tiles -->
<bool name="config_force_rounded_icon_TopLevelSettings">true</bool>
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index 416c8d7..dd06c37 100755
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -333,12 +333,21 @@
<dimen name="homepage_half_card_padding_top">12dp</dimen>
<dimen name="homepage_half_card_padding_bottom">16dp</dimen>
<dimen name="homepage_half_card_title_margin_top">12dp</dimen>
+ <dimen name="homepage_deferred_setup_card_padding_top">16dp</dimen>
+ <dimen name="homepage_deferred_setup_card_padding_bottom">12dp</dimen>
+ <dimen name="homepage_deferred_setup_card_title_margin_top">12dp</dimen>
+ <dimen name="homepage_deferred_setup_card_summary_margin_top">2dp</dimen>
+ <dimen name="homepage_deferred_setup_card_button_margin_top">8dp</dimen>
+ <dimen name="homepage_deferred_setup_card_button_padding_top">8dp</dimen>
+ <dimen name="homepage_deferred_setup_card_button_padding_bottom">8dp</dimen>
+ <dimen name="homepage_deferred_setup_card_button_padding_start">24dp</dimen>
+ <dimen name="homepage_deferred_setup_card_button_padding_end">24dp</dimen>
<!-- Homepage dismissal cards size and padding -->
- <dimen name="homepage_card_dismissal_margin_top">16dp</dimen>
- <dimen name="homepage_card_dismissal_margin_bottom">2dp</dimen>
+ <dimen name="homepage_card_dismissal_margin_top">12dp</dimen>
<dimen name="homepage_card_dismissal_side_margin">16dp</dimen>
- <dimen name="homepage_card_dismissal_button_side_margin">6dp</dimen>
+ <dimen name="homepage_card_dismissal_button_margin_start">4dp</dimen>
+ <dimen name="homepage_card_dismissal_button_margin_end">6dp</dimen>
<!-- Horizontal divider size and margin -->
<dimen name="horizontal_divider_margin_top">4dp</dimen>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index f77c10d..1a92f7b 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -1430,6 +1430,16 @@
<!-- Title shown on security settings to allow the user to change their lockscreen password [CHAR LIMIT=22]-->
<string name="unlock_change_lock_password_title">Change unlock password</string>
+ <!-- Footer preference text in the screen lock type picker to indicate which app is requesting a new screen lock and that it requests for a strong PIN or password [CHAR LIMIT=NONE] -->
+ <string name="unlock_footer_high_complexity_requested"><xliff:g id="app_name" example="Gmail">%1$s</xliff:g> requests a strong PIN or password.</string>
+ <!-- Footer preference text in the screen lock type picker to indicate which app is requesting a new screen lock and that it requests for a medium strength PIN or password [CHAR LIMIT=NONE] -->
+ <string name="unlock_footer_medium_complexity_requested"><xliff:g id="app_name" example="Gmail">%1$s</xliff:g> requests a new PIN or password.</string>
+ <!-- Footer preference text in the screen lock type picker to indicate which app is requesting a new screen lock and it requests for any screen lock [CHAR LIMIT=NONE] -->
+ <string name="unlock_footer_low_complexity_requested"><xliff:g id="app_name" example="Gmail">%1$s</xliff:g> requests a new pattern, PIN or password.</string>
+ <!-- Footer preference text in the screen lock type picker to indicate which app is requesting a new screen lock [CHAR LIMIT=NONE] -->
+ <string name="unlock_footer_none_complexity_requested"><xliff:g id="app_name" example="Gmail">%1$s</xliff:g> requests a new screen lock.</string>
+
+
<!-- Message shown on the lock screen when the user incorrectly enters their lock and it counts towards the max attempts before their data on the device is wiped. [CHAR LIMIT=NONE] -->
<string name="lock_failed_attempts_before_wipe">Try again. Attempt <xliff:g id="current_attempts">%1$d</xliff:g> of <xliff:g id="total_attempts">%2$d</xliff:g>.</string>
@@ -2678,6 +2688,15 @@
<!-- Display settings screen, display white balance settings title [CHAR LIMIT=30] -->
<string name="display_white_balance_title">Display white balance</string>
+ <!-- Display settings screen, setting option name to enable adaptive sleep [CHAR LIMIT=30] -->
+ <string name="adaptive_sleep_title">Adaptive sleep</string>
+ <!-- Setting option summary when adaptive sleep is on [CHAR LIMIT=NONE] -->
+ <string name="adaptive_sleep_summary_on">On</string>
+ <!-- Setting option summary when adaptive sleep is off [CHAR LIMIT=NONE] -->
+ <string name="adaptive_sleep_summary_off">Off</string>
+ <!-- Description about the feature adaptive sleep [CHAR LIMIT=NONE]-->
+ <string name="adaptive_sleep_description">Your screen would not dim and go to sleep if the device detects your present attention.</string>
+
<!-- Night display screen, setting option name to enable night display (renamed "Night Light" with title caps). [CHAR LIMIT=30] -->
<string name="night_display_title">Night Light</string>
@@ -2902,6 +2921,8 @@
<string name="kernel_version">Kernel version</string>
<!-- About phone screen, setting option name [CHAR LIMIT=40] -->
<string name="build_number">Build number</string>
+ <!-- About phone screen, mainline module versions [CHAR LIMIT=40] -->
+ <string name="module_version">Mainline module versions</string>
<!-- About phone screen, show when a value of some status item is unavailable. -->
<string name="device_info_not_available">Not available</string>
@@ -4444,6 +4465,10 @@
<string name="keyboard_shortcuts_helper">Keyboard shortcuts helper</string>
<!-- Summary text for the 'keyboard shortcuts helper' dialog. [CHAR LIMIT=100] -->
<string name="keyboard_shortcuts_helper_summary">Display available shortcuts</string>
+ <!-- Title for the 'Work profile' preference category inside Languages and inputs'. [CHAR LIMIT=45] -->
+ <string name="language_and_input_for_work_category_title">Work profile</string>
+ <!-- Title for the 'Virtual keyboards for work' preference. [CHAR LIMIT=45] -->
+ <string name="virtual_keyboards_for_work_title">Virtual keyboard for work</string>
<!-- Summary text for keyboards when no layout has been selected. [CHAR LIMIT=35] -->
<string name="default_keyboard_layout">Default</string>
@@ -4475,6 +4500,8 @@
<!-- User dictionary settings --><skip />
<!-- User dictionary settings. The title of the list item to go into the Personal dictionary settings screen. [CHAR LIMIT=35] -->
<string name="user_dict_settings_title">Personal dictionary</string>
+ <!-- Title for the 'Spell checker for work' preference. [CHAR LIMIT=45] -->
+ <string name="user_dict_settings_for_work_title">Personal dictionary for work</string>
<!-- User dictionary settings. The summary of the list item to go into the Personal dictionary settings screen. -->
<string name="user_dict_settings_summary">""</string>
<!-- User dictionary settings. The title of the menu item to add a new word to the user dictionary. -->
@@ -5731,10 +5758,6 @@
<string name="credentials_erased">Credential storage is erased.</string>
<!-- Toast message [CHAR LIMIT=30] when credential storage containing private keys and certificates could not be erased (opposite of string credentials_erased) -->
<string name="credentials_not_erased">Credential storage couldn\u2019t be erased.</string>
- <!-- This string is in a dialog, and the dialog shows up on a device that's managed by a user's company. It lets the user know that they need to have a secure lock screen (PIN, password, or pattern) before they can use credential storage [CHAR LIMIT=NONE] -->
- <string name="credentials_configure_lock_screen_hint">Before you can use credential storage, your device need to have a secure lock screen</string>
- <!-- This string is for the content of the button that leads user to lock screen settings [CHAR LIMIT=20] -->
- <string name="credentials_configure_lock_screen_button">SET LOCK</string>
<!-- Title of Usage Access preference item [CHAR LIMIT=30] -->
<string name="usage_access_title">Apps with usage access</string>
@@ -6368,6 +6391,8 @@
<!-- Title for spell checker settings -->
<string name="spellcheckers_settings_title">Spell checker</string>
+ <!-- Title for spell checker settings for work [CHAR LIMIT=45]-->
+ <string name="spellcheckers_settings_for_work_title">Spell checker for work</string>
<!-- Prompt for the user to enter their current full-backup password -->
<string name="current_backup_pw_prompt">Type your current full backup password here</string>
@@ -6691,6 +6716,8 @@
<string name="help_url_display_size" translatable="false"></string>
<!-- Help URL, Auto brightness [DO NOT TRANSLATE] -->
<string name="help_url_auto_brightness" translatable="false" />
+ <!-- Help URL, Adaptive sleep [DO NOT TRANSLATE] -->
+ <string name="help_url_adaptive_sleep" translatable="false" />
<!-- Help URL, Previously connected bluetooth devices [DO NOT TRANSLATE] -->
<string name="help_url_previously_connected_devices" translatable="false"></string>
<!-- Help URL, Top level privacy settings [DO NOT TRANSLATE] -->
@@ -7031,6 +7058,9 @@
<!-- Search keywords for adaptive brightness setting [CHAR LIMIT=NONE]-->
<string name="keywords_display_auto_brightness">dim screen, touchscreen, battery, smart brightness, dynamic brightness</string>
+ <!-- Search keywords for adaptive sleep setting [CHAR LIMIT=NONE]-->
+ <string name="keywords_display_adaptive_sleep">dim screen, sleep, battery, timeout, attention</string>
+
<!-- List of synonyms for the auto rotate (rotate the virtual display when the device rotates) setting, used to match in settings search [CHAR LIMIT=NONE] -->
<string name="keywords_auto_rotate">rotate, flip, rotation, portrait, landscape, orientation, vertical, horizontal</string>
@@ -7301,7 +7331,7 @@
<!-- Do not disturb: Hide notifications summary [CHAR LIMIT=NONE] -->
<string name="zen_mode_restrict_notifications_hide_summary">You won\u2019t see or hear notifications</string>
<!-- Do not disturb: Hide notifications footer [CHAR LIMIT=NONE] -->
- <string name="zen_mode_restrict_notifications_hide_footer">Your phone won\u2019t show new or existing notifications, and won\u2019t make a sound or vibrate. Notifications won\u2019t appear when you swipe down from the top of your screen.\n\nKeep in mind, critical notifications for phone activity and status will still appear.</string>
+ <string name="zen_mode_restrict_notifications_hide_footer">Your phone won\u2019t show, vibrate or make sound for new or existing notifications. Keep in mind, critical notifications for phone activity and status will still appear.\n\nWhen you turn off Do Not Disturb, find missed notifications by swiping down from the top of your screen.</string>
<!-- Do not disturb: Custom settings option [CHAR LIMIT=60] -->
<string name="zen_mode_restrict_notifications_custom">Custom</string>
<!-- Do not disturb: restrict notifications page, menu option [CHAR LIMIT=60] -->
@@ -8028,7 +8058,7 @@
<string name="zen_mode_calls_title">Calls</string>
<!-- [CHAR LIMIT=NONE] Zen mode settings: Calls screen footer -->
- <string name="zen_mode_calls_footer">When Do Not Disturb is on, incoming calls are blocked. You can adjust settings to allow your friends, family, or other contacts to reach you.</string>
+ <string name="zen_mode_calls_footer">To be sure allowed calls make sound, check whether your device is set to ring, vibrate, or silent.</string>
<!-- [CHAR LIMIT=NONE] Zen mode custom rule settings: Calls screen footer -->
<string name="zen_mode_custom_calls_footer">For \u2018<xliff:g id="schedule_name" example="Schedule 1">%1$s</xliff:g>\u2019 incoming calls are blocked. You can adjust settings to allow your friends, family, or other contacts to reach you.</string>
@@ -8046,13 +8076,13 @@
<string name="zen_mode_messages">Allow text messages</string>
<!-- Do not disturb settings, messages, events and reminders footer [CHAR LIMIT=NONE]-->
- <string name="zen_mode_messages_footer">When Do Not Disturb is on, incoming text messages are blocked. You can adjust settings to allow your friends, family, or other contacts to reach you.</string>
+ <string name="zen_mode_messages_footer">To be sure allowed messages make sound, check whether your device is set to ring, vibrate, or silent.</string>
<!-- [CHAR LIMIT=NONE] Zen mode custom rule settings: Messages screen footer -->
<string name="zen_mode_custom_messages_footer">For \u2018<xliff:g id="schedule_name" example="Schedule 1">%1$s</xliff:g>\u2019 incoming text messages are blocked. You can adjust settings to allow your friends, family, or other contacts to reach you.</string>
<!-- [CHAR LIMIT=40] Zen mode settings: Allow messages to bypass DND title -->
- <string name="zen_mode_messages_title">Text messages</string>
+ <string name="zen_mode_messages_title">SMS, MMS, and messaging apps</string>
<!-- [CHAR LIMIT=40] Zen mode settings: Calls or messages option value: From anyone -->
<string name="zen_mode_from_anyone">From anyone</string>
@@ -8088,7 +8118,7 @@
<string name="zen_mode_alarms_list">alarms</string>
<!-- [CHAR LIMIT=80] Zen mode settings: Allow media (sound from video) to bypass dnd -->
- <string name="zen_mode_media">Allow media sounds</string>
+ <string name="zen_mode_media">Play media sounds</string>
<!-- [CHAR LIMIT=50] Zen mode settings: Media (ie: sound from video) -->
<string name="zen_mode_media_list">media</string>
@@ -9541,6 +9571,8 @@
<!-- [CHAR_LIMIT=NONE] Developer Settings: Label for the option that turns off all overlays in a given category. -->
<string name="overlay_option_device_default">Device default</string>
+ <!-- [CHAR_LIMIT=NONE] Developer Settings: Toast displayed to the user when an overlay fails to apply. -->
+ <string name="overlay_toast_failed_to_apply">Failed to apply overlay</string>
<!-- [CHAR_LIMIT=60] Label for special access screen -->
<string name="special_access">Special app access</string>
@@ -9551,6 +9583,9 @@
<item quantity="other"><xliff:g id="count" example="10">%d</xliff:g> apps can use unrestricted data</item>
</plurals>
+ <!-- Title for the More preference item in Special app access settings [CHAR LIMIT=30] -->
+ <string name="special_access_more">More</string>
+
<!-- Developer option to convert to file encryption - final warning -->
<string name="confirm_convert_to_fbe_warning">Really wipe user data and convert to file encryption?</string>
<!-- Developer option to convert to file encryption - final button -->
@@ -10111,25 +10146,27 @@
<!-- UI debug setting: ANGLE enabled app has been set [CHAR LIMIT=NONE] -->
<string name="angle_enabled_app_set">ANGLE enabled application: <xliff:g id="app_name" example="com.company.app">%1$s</xliff:g></string>
- <!-- Title for Game Update Package dashboard where developers can configure apps to use GUP or not [CHAR LIMIT=50] -->
- <string name="gup_dashboard_title">Game Update Package Preferences</string>
- <!-- Summary for Game Update Package dashboard [CHAR LIMIT=50] -->
- <string name="gup_dashboard_summary">Modify Game Update Package settings</string>
- <!-- Title for Game Update Package all apps preference [CHAR LIMIT=50] -->
- <string name="gup_all_apps_switch_title">Enable for all apps</string>
- <!-- Title for Game Update Package preference [CHAR LIMIT=50] -->
- <string name="gup_app_preference_title">Select Graphics Driver</string>
- <!-- The default value for Game Update Package preference [CHAR LIMIT=50] -->
- <string name="gup_app_preference_default">Default</string>
- <!-- The gup value for Game Update Package preference [CHAR LIMIT=50] -->
- <string name="gup_app_preference_gup">Game Update Package</string>
- <!-- The system value for Game Update Package preference [CHAR LIMIT=50] -->
- <string name="gup_app_preference_system">System Graphics Driver</string>
- <!-- All the values for Game Update Package preference [CHAR LIMIT=50] -->
- <string-array name="gup_app_preference_values">
- <item>@string/gup_app_preference_default</item>
- <item>@string/gup_app_preference_gup</item>
- <item>@string/gup_app_preference_system</item>
+ <!-- Title for Game Driver dashboard where developers can configure apps to use game driver or not [CHAR LIMIT=50] -->
+ <string name="game_driver_dashboard_title">Game Driver Preferences</string>
+ <!-- Summary for Game Driver dashboard [CHAR LIMIT=50] -->
+ <string name="game_driver_dashboard_summary">Modify Game Driver settings</string>
+ <!-- Footer text for Game Driver dashboard [CHAR LIMIT=NONE] -->
+ <string name="game_driver_footer_text">When Game Driver is turned on, you can pick to use the updated graphics driver for Apps installed on the device.</string>
+ <!-- Title for Game Driver all apps preference [CHAR LIMIT=50] -->
+ <string name="game_driver_all_apps_preference_title">Enable for all apps</string>
+ <!-- Title for Game Driver app preference [CHAR LIMIT=50] -->
+ <string name="game_driver_app_preference_title">Select Graphics Driver</string>
+ <!-- The default value for Game Driver app preference [CHAR LIMIT=50] -->
+ <string name="game_driver_app_preference_default">Default</string>
+ <!-- The game driver value for Game Driver app preference [CHAR LIMIT=50] -->
+ <string name="game_driver_app_preference_game_driver">Game Driver</string>
+ <!-- The system value for Game Driver app preference [CHAR LIMIT=50] -->
+ <string name="game_driver_app_preference_system">System Graphics Driver</string>
+ <!-- All the values for Game Driver app preference [CHAR LIMIT=50] -->
+ <string-array name="game_driver_app_preference_values">
+ <item>@string/game_driver_app_preference_default</item>
+ <item>@string/game_driver_app_preference_game_driver</item>
+ <item>@string/game_driver_app_preference_system</item>
</string-array>
<!-- Slices Strings -->
@@ -10363,6 +10400,17 @@
<string name="mobile_data_settings_title">Mobile data</string>
<!-- Mobile network settings screen, title of Mobile data switch preference [CHAR LIMIT=NONE] -->
<string name="mobile_data_settings_summary">Access data using mobile network</string>
+ <!-- Mobile network settings screen, title of item showing the name of the default subscription
+ that will be used for calls. This only appears in multi-SIM mode. [CHAR LIMIT=NONE] -->
+ <string name="calls_preference">Calls preference</string>
+ <!-- Mobile network settings screen, title of item showing the name of the default subscription
+ that will be used for SMS messages. This only appears in multi-SIM mode. [CHAR LIMIT=NONE] -->
+ <string name="sms_preference">SMS preference</string>
+ <!-- Mobile network settings screen, a label in a chooser dialog that appears when choosing the
+ default subscription to use for either calls or SMS when in multi-SIM mode. This label means
+ that the user will be asked which mobile network subscription to use every time they place a
+ call or send an SMS, instead of defaulting to one particular subscription. [CHAR LIMIT=40]-->
+ <string name="calls_and_sms_ask_every_time">Ask every time</string>
<!-- Summary of the 'Mobile network' item on the Network & internet page when there is no mobile
service setup yet (eg no SIM card inserted and no eSIM configured). Tapping it leads to a
@@ -10450,8 +10498,8 @@
<!-- See less items in contextual homepage [CHAR LIMIT=30]-->
<string name="see_less">See less</string>
- <!-- Title for Network connection request Dialog [CHAR LIMIT=30] -->
- <string name="network_connection_request_dialog_title">Choose a device</string>
+ <!-- Title for Network connection request Dialog [CHAR LIMIT=60] -->
+ <string name="network_connection_request_dialog_title">Device to use with <xliff:g id="appName" example="ThirdPartyAppName">%1$s</xliff:g></string>
<!-- Message for Network connection timeout Dialog [CHAR LIMIT=NONE] -->
<string name="network_connection_timeout_dialog_message">No devices found. Make sure devices are turned on and available to connect.</string>
<!-- OK button for Network connection timeout Dialog [CHAR LIMIT=30] -->
@@ -10469,6 +10517,13 @@
<!-- Title for no bluetooth devices in Bluetooth devices slice. [CHAR LIMIT=NONE] -->
<string name="no_bluetooth_devices">No Bluetooth devices</string>
+ <!-- Title for left bluetooth device. [CHAR LIMIT=NONE] -->
+ <string name="bluetooth_left_name">Left</string>
+ <!-- Title for right bluetooth device. [CHAR LIMIT=NONE] -->
+ <string name="bluetooth_right_name">Right</string>
+ <!-- Title for middle bluetooth device. [CHAR LIMIT=NONE] -->
+ <string name="bluetooth_middle_name">Case</string>
+
<!-- Default title for the settings panel [CHAR LIMIT=NONE] -->
<string name="settings_panel_title">Settings Panel</string>
@@ -10514,12 +10569,6 @@
<!-- String for talkback on the account avatar of the search bar. [CHAR LIMIT=NONE] -->
<string name="search_bar_account_avatar_content_description"></string>
- <!-- Preference title text for skip media gesture [CHAR LIMIT=60]-->
- <string name="gesture_skip_title">Skip gesture</string>
-
- <!-- Preference title text for silence gesture [CHAR LIMIT=60]-->
- <string name="gesture_silence_title">Silence alerts gesture</string>
-
<!-- Text to display when no app used permission. [CHAR LIMIT=NONE] -->
<string name="permission_bar_chart_empty_text">0 apps used permissions</string>
@@ -10539,4 +10588,8 @@
<item quantity="other"><xliff:g id="notification_channel_count">%1$d</xliff:g> notification channels. Tap to manage all.</item>
</plurals>
+ <!-- Title for the Switch output dialog (settings panel) with media related devices [CHAR LIMIT=50] -->
+ <string name="media_output_panel_title">Switch output</string>
+ <!-- Summary for represent which device is playing media [CHAR LIMIT=NONE] -->
+ <string name="media_output_panel_summary_of_playing_device">Currently playing on <xliff:g id="device_name" example="Bose headphone">%1$s</xliff:g></string>
</resources>
diff --git a/res/values/styles.xml b/res/values/styles.xml
index 8b92d7e..6d153e1 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -284,14 +284,8 @@
<item name="android:textSize">@dimen/search_bar_text_size</item>
</style>
- <style name="TextAppearance.SuggestionHeader"
- parent="@*android:style/TextAppearance.DeviceDefault.Subhead">
- <item name="android:textSize">14sp</item>
- <item name="android:textColor">?android:attr/colorAccent</item>
- </style>
-
<style name="TextAppearance.ConditionCardTitle"
- parent="@*android:style/TextAppearance.DeviceDefault.Body2">
+ parent="@*android:style/TextAppearance.DeviceDefault.Subhead">
<item name="android:textSize">16sp</item>
</style>
@@ -304,7 +298,7 @@
<item name="android:fontFamily">sans-serif-medium</item>
<item name="android:textSize">14sp</item>
<item name="android:textColor">?android:attr/colorAccent</item>
- <item name="android:background">@drawable/btn_borderless_rect</item>
+ <item name="android:background">@*android:drawable/btn_borderless_rect</item>
<item name="android:gravity">center</item>
<item name="android:focusable">true</item>
<item name="android:padding">8dp</item>
@@ -460,8 +454,7 @@
<style name="ContextualCardDismissalButton"
parent="android:Widget.DeviceDefault.Button.Borderless.Colored">
- <item name="android:minWidth">10dp</item>
- <item name="android:minHeight">16dp</item>
+ <item name="android:minWidth">24dp</item>
<item name="android:textAllCaps">false</item>
</style>
@@ -469,4 +462,24 @@
<item name="titleSize">@*android:dimen/text_size_subhead_material</item>
</style>
+ <style name="TextAppearance.DeferredSetupCardTitle">
+ <item name="android:fontFamily">@*android:string/config_headlineFontFamilyMedium</item>
+ <item name="android:textSize">16sp</item>
+ </style>
+
+ <style name="TextAppearance.DeferredSetupCardSummary"
+ parent="@*android:style/TextAppearance.DeviceDefault.Body1">
+ <item name="android:textColor">?android:attr/textColorSecondary</item>
+ </style>
+
+ <style name="DeferredSetupCardButton" parent="android:Widget.DeviceDefault.Button.Colored">
+ <item name="android:fontFamily">@*android:string/config_headlineFontFamilyMedium</item>
+ <item name="android:paddingBottom">@dimen/homepage_deferred_setup_card_button_padding_bottom</item>
+ <item name="android:paddingEnd">@dimen/homepage_deferred_setup_card_button_padding_end</item>
+ <item name="android:paddingStart">@dimen/homepage_deferred_setup_card_button_padding_start</item>
+ <item name="android:paddingTop">@dimen/homepage_deferred_setup_card_button_padding_top</item>
+ <item name="android:textAllCaps">false</item>
+ <item name="android:textSize">14sp</item>
+ </style>
+
</resources>
diff --git a/res/xml/adaptive_sleep_detail.xml b/res/xml/adaptive_sleep_detail.xml
new file mode 100644
index 0000000..b7dabbb
--- /dev/null
+++ b/res/xml/adaptive_sleep_detail.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2019 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<PreferenceScreen
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:settings="http://schemas.android.com/apk/res-auto"
+ android:key="adaptive_sleep_detail"
+ android:title="@string/adaptive_sleep_title">
+
+ <!-- TODO(111939367): add correct animation -->
+ <com.android.settings.widget.VideoPreference
+ android:key="adaptive_sleep_video"
+ android:title="@string/summary_placeholder"
+ settings:animation="@raw/aab_brightness"
+ settings:preview="@drawable/aab_brightness"
+ settings:controller="com.android.settings.widget.VideoPreferenceController"/>
+
+ <com.android.settingslib.RestrictedSwitchPreference
+ android:key="adaptive_sleep"
+ android:title="@string/adaptive_sleep_title"
+ settings:keywords="@string/keywords_display_adaptive_sleep"
+ settings:controller="com.android.settings.display.AdaptiveSleepPreferenceController"
+ settings:useAdminDisabledSummary="true"
+ settings:allowDividerAbove="true" />
+
+</PreferenceScreen>
\ No newline at end of file
diff --git a/res/xml/bluetooth_device_details_fragment.xml b/res/xml/bluetooth_device_details_fragment.xml
index cf9fbf9..f485c6a 100644
--- a/res/xml/bluetooth_device_details_fragment.xml
+++ b/res/xml/bluetooth_device_details_fragment.xml
@@ -23,7 +23,16 @@
android:key="bluetooth_device_header"
android:layout="@layout/settings_entity_header"
android:selectable="false"
- settings:allowDividerBelow="true"/>
+ settings:allowDividerBelow="true"
+ settings:searchable="false"/>
+
+ <com.android.settingslib.widget.LayoutPreference
+ android:key="advanced_bluetooth_device_header"
+ android:layout="@layout/advanced_bt_entity_header"
+ android:selectable="false"
+ settings:allowDividerBelow="true"
+ settings:searchable="false"
+ settings:controller="com.android.settings.bluetooth.AdvancedBluetoothDetailsHeaderController"/>
<com.android.settingslib.widget.ActionButtonsPreference
android:key="action_buttons"
diff --git a/res/xml/connected_devices_advanced.xml b/res/xml/connected_devices_advanced.xml
index b5d2a99..28e9fdc 100644
--- a/res/xml/connected_devices_advanced.xml
+++ b/res/xml/connected_devices_advanced.xml
@@ -24,7 +24,7 @@
android:fragment="com.android.settings.connecteddevice.BluetoothDashboardFragment"
android:key="bluetooth_settings"
android:title="@string/bluetooth_settings_title"
- android:icon="@drawable/ic_settings_bluetooth"
+ android:icon="@*android:drawable/ic_settings_bluetooth"
android:order="-9"
settings:searchable="false"/>
@@ -48,7 +48,7 @@
android:key="connected_device_printing"
android:title="@string/print_settings"
android:summary="@string/summary_placeholder"
- android:icon="@drawable/ic_settings_print"
+ android:icon="@*android:drawable/ic_settings_print"
android:fragment="com.android.settings.print.PrintSettingsFragment"
android:order="-3"
settings:searchable="false"/>
diff --git a/res/xml/development_settings.xml b/res/xml/development_settings.xml
index 6d22a1d..9b43723 100644
--- a/res/xml/development_settings.xml
+++ b/res/xml/development_settings.xml
@@ -194,10 +194,10 @@
android:summary="@string/enable_gpu_debug_layers_summary" />
<Preference
- android:key="gup_dashboard"
- android:title="@string/gup_dashboard_title"
- android:summary="@string/gup_dashboard_summary"
- android:fragment="com.android.settings.development.gup.GupDashboard"
+ android:key="game_driver_dashboard"
+ android:title="@string/game_driver_dashboard_title"
+ android:summary="@string/game_driver_dashboard_summary"
+ android:fragment="com.android.settings.development.gamedriver.GameDriverDashboard"
settings:searchable="false" />
</PreferenceCategory>
diff --git a/res/xml/display_settings.xml b/res/xml/display_settings.xml
index 76b3d2e..b110b46 100644
--- a/res/xml/display_settings.xml
+++ b/res/xml/display_settings.xml
@@ -66,6 +66,13 @@
android:entryValues="@array/screen_timeout_values"
settings:keywords="@string/keywords_screen_timeout" />
+ <Preference
+ android:key="adaptive_sleep_entry"
+ android:title="@string/adaptive_sleep_title"
+ android:summary="@string/summary_placeholder"
+ android:fragment="com.android.settings.display.AdaptiveSleepSettings"
+ settings:controller="com.android.settings.display.AdaptiveSleepPreferenceController" />
+
<SwitchPreference
android:key="auto_rotate"
android:title="@string/accelerometer_title"
diff --git a/res/xml/game_driver_settings.xml b/res/xml/game_driver_settings.xml
new file mode 100644
index 0000000..a04724a
--- /dev/null
+++ b/res/xml/game_driver_settings.xml
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2019 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<PreferenceScreen
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:settings="http://schemas.android.com/apk/res-auto"
+ android:key="game_driver_settings"
+ android:title="@string/game_driver_dashboard_title">
+
+ <SwitchPreference
+ android:key="game_driver_all_apps_preference"
+ android:title="@string/game_driver_all_apps_preference_title"
+ settings:controller="com.android.settings.development.gamedriver.GameDriverEnableForAllAppsPreferenceController">
+ </SwitchPreference>
+
+ <PreferenceCategory
+ android:key="game_driver_category"
+ android:title="@string/game_driver_app_preference_title"
+ settings:controller="com.android.settings.development.gamedriver.GameDriverAppPreferenceController">
+ </PreferenceCategory>
+
+ <com.android.settingslib.widget.FooterPreference
+ android:key="footer_preference"
+ android:title="@string/game_driver_footer_text"
+ android:selectable="false"
+ settings:controller="com.android.settings.development.gamedriver.GameDriverFooterPreferenceController">
+ </com.android.settingslib.widget.FooterPreference>
+
+</PreferenceScreen>
diff --git a/res/xml/gestures.xml b/res/xml/gestures.xml
index cd834df..4b17bd9 100644
--- a/res/xml/gestures.xml
+++ b/res/xml/gestures.xml
@@ -28,18 +28,6 @@
settings:controller="com.android.settings.gestures.AssistGestureSettingsPreferenceController" />
<Preference
- android:key="gesture_skip_summary"
- android:title="@string/gesture_skip_title"
- android:fragment="com.android.settings.gestures.SkipGestureSettings"
- settings:controller="com.android.settings.gestures.SkipGesturePreferenceController" />
-
- <Preference
- android:key="gesture_silence_summary"
- android:title="@string/gesture_silence_title"
- android:fragment="com.android.settings.gestures.SilenceGestureSettings"
- settings:controller="com.android.settings.gestures.SilenceGesturePreferenceController" />
-
- <Preference
android:key="gesture_wake_screen_input_summary"
android:title="@string/ambient_display_wake_screen_title"
android:fragment="com.android.settings.gestures.WakeScreenGestureSettings"
diff --git a/res/xml/gup_settings.xml b/res/xml/gup_settings.xml
deleted file mode 100644
index 09bca71..0000000
--- a/res/xml/gup_settings.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- Copyright 2019 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- -->
-
-<PreferenceScreen
- xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:settings="http://schemas.android.com/apk/res-auto"
- android:key="gup_settings"
- android:title="@string/gup_dashboard_title">
-
- <SwitchPreference
- android:key="gup_all_apps_preference"
- android:title="@string/gup_all_apps_switch_title"
- settings:controller="com.android.settings.development.gup.GupEnableForAllAppsPreferenceController">
- </SwitchPreference>
-
- <PreferenceCategory
- android:key="gup_category"
- android:title="@string/gup_app_preference_title"
- settings:controller="com.android.settings.development.gup.GupPreferenceController">
- </PreferenceCategory>
-
-</PreferenceScreen>
diff --git a/res/xml/language_and_input.xml b/res/xml/language_and_input.xml
index 8b63e32..b04bdf8 100644
--- a/res/xml/language_and_input.xml
+++ b/res/xml/language_and_input.xml
@@ -92,4 +92,27 @@
android:summary="@string/vibrate_input_devices_summary"
settings:controller="com.android.settings.inputmethod.GameControllerPreferenceController" />
+ <com.android.settings.widget.WorkOnlyCategory
+ android:key="language_and_input_for_work_category"
+ android:title="@string/language_and_input_for_work_category_title">
+
+ <Preference
+ android:key="virtual_keyboards_for_work_pref"
+ android:title="@string/virtual_keyboards_for_work_title"
+ android:fragment="com.android.settings.inputmethod.VirtualKeyboardFragment"
+ settings:controller="com.android.settings.inputmethod.VirtualKeyboardForWorkPreferenceController" />
+
+ <Preference
+ android:key="spellcheckers_settings_for_work_pref"
+ android:title="@string/spellcheckers_settings_for_work_title"
+ android:fragment="com.android.settings.inputmethod.SpellCheckersSettings"
+ settings:controller="com.android.settings.language.UserDictionaryForWorkPreferenceController" />
+
+ <Preference
+ android:key="user_dictionary_settings_for_work_pref"
+ android:title="@string/user_dict_settings_for_work_title"
+ android:fragment="com.android.settings.inputmethod.UserDictionaryList"
+ settings:controller="com.android.settings.inputmethod.SpellCheckerForWorkPreferenceController" />
+ </com.android.settings.widget.WorkOnlyCategory>
+
</PreferenceScreen>
diff --git a/res/xml/manage_assist.xml b/res/xml/manage_assist.xml
index a2b2ad5..bb387b5 100644
--- a/res/xml/manage_assist.xml
+++ b/res/xml/manage_assist.xml
@@ -25,8 +25,7 @@
<com.android.settings.widget.GearPreference
android:key="default_assist"
android:title="@string/default_assist_title"
- android:summary="@string/summary_placeholder"
- android:fragment="com.android.settings.applications.assist.DefaultAssistPicker" />
+ android:summary="@string/summary_placeholder" />
<Preference
android:key="gesture_assist_application"
diff --git a/res/xml/mobile_network_settings_v2.xml b/res/xml/mobile_network_settings_v2.xml
index 7a19c32..6273ad9 100644
--- a/res/xml/mobile_network_settings_v2.xml
+++ b/res/xml/mobile_network_settings_v2.xml
@@ -17,24 +17,37 @@
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:settings="http://schemas.android.com/apk/res-auto"
android:key="mobile_network_pref_screen"
- settings:initialExpandedChildrenCount="5">
+ settings:initialExpandedChildrenCount="7">
<com.android.settings.datausage.DataUsageSummaryPreference
android:key="status_header"
android:visibility="gone"
android:selectable="false" />
+ <ListPreference
+ android:key="calls_preference"
+ android:title="@string/calls_preference"
+ settings:controller="com.android.settings.network.telephony.CallsDefaultSubscriptionController"
+ settings:allowDividerAbove="true" />
+
+ <ListPreference
+ android:key="sms_preference"
+ android:title="@string/sms_preference"
+ settings:controller="com.android.settings.network.telephony.SmsDefaultSubscriptionController" />
+
<Preference
android:key="cdma_lte_data_service_key"
android:title="@string/cdma_lte_data_service"
- settings:controller="com.android.settings.network.telephony.DataServiceSetupPreferenceController">
- </Preference>
+ settings:controller="com.android.settings.network.telephony.DataServiceSetupPreferenceController"
+ settings:allowDividerAbove="true"
+ settings:allowDividerBelow="false" />
<SwitchPreference
android:key="mobile_data_enable"
android:title="@string/mobile_data_settings_title"
android:summary="@string/mobile_data_settings_summary"
- settings:controller="com.android.settings.network.telephony.MobileDataPreferenceController"/>
+ settings:controller="com.android.settings.network.telephony.MobileDataPreferenceController"
+ settings:allowDividerAbove="true"/>
<com.android.settingslib.RestrictedSwitchPreference
android:key="button_roaming_key"
diff --git a/res/xml/my_device_info.xml b/res/xml/my_device_info.xml
index d669977..6323a14 100644
--- a/res/xml/my_device_info.xml
+++ b/res/xml/my_device_info.xml
@@ -25,7 +25,8 @@
android:key="my_device_info_header"
android:order="0"
android:layout="@layout/settings_entity_header"
- android:selectable="false"/>
+ android:selectable="false"
+ settings:isPreferenceVisible="false"/>
<!-- Device name -->
<com.android.settings.widget.ValidatedEditTextPreference
@@ -33,6 +34,7 @@
android:order="1"
android:title="@string/my_device_info_device_name_preference_title"
android:summary="@string/summary_placeholder"
+ settings:controller="com.android.settings.deviceinfo.DeviceNamePreferenceController"
settings:enableCopying="true"/>
<!-- Account name -->
@@ -40,7 +42,8 @@
android:key="branded_account"
android:order="2"
android:title="@string/my_device_info_account_preference_title"
- android:summary="@string/summary_placeholder"/>
+ android:summary="@string/summary_placeholder"
+ settings:controller="com.android.settings.deviceinfo.BrandedAccountPreferenceController"/>
<!-- Phone number -->
<Preference
@@ -50,15 +53,15 @@
android:summary="@string/summary_placeholder"
android:selectable="false"
settings:allowDynamicSummaryInSlice="true"
- settings:controller=
- "com.android.settings.deviceinfo.PhoneNumberPreferenceController"
+ settings:controller="com.android.settings.deviceinfo.PhoneNumberPreferenceController"
settings:enableCopying="true"/>
<Preference
android:key="emergency_info"
android:order="4"
android:title="@string/emergency_info_title"
- android:summary="@string/summary_placeholder"/>
+ android:summary="@string/summary_placeholder"
+ settings:controller="com.android.settings.accounts.EmergencyInfoPreferenceController"/>
<!-- Legal information -->
<Preference
diff --git a/res/xml/silence_gesture_settings.xml b/res/xml/silence_gesture_settings.xml
deleted file mode 100644
index 208a41d..0000000
--- a/res/xml/silence_gesture_settings.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2019 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<PreferenceScreen
- xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:app="http://schemas.android.com/apk/res-auto"
- android:key="silence_gesture"
- android:title="@string/gesture_silence_title">
-
- <com.android.settings.widget.VideoPreference
- android:key="gesture_silence_video"
- app:animation="@raw/gesture_silence"
- app:preview="@drawable/gesture_silence"/>
-</PreferenceScreen>
diff --git a/res/xml/skip_gesture_settings.xml b/res/xml/skip_gesture_settings.xml
deleted file mode 100644
index 3d88ac8..0000000
--- a/res/xml/skip_gesture_settings.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2019 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<PreferenceScreen
- xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:app="http://schemas.android.com/apk/res-auto"
- android:key="skip_gesture"
- android:title="@string/gesture_skip_title">
-
- <com.android.settings.widget.VideoPreference
- android:key="gesture_skip_video"
- app:animation="@raw/gesture_skip"
- app:preview="@drawable/gesture_skip"/>
-</PreferenceScreen>
diff --git a/res/xml/special_access.xml b/res/xml/special_access.xml
index cb76693..4417d0f 100644
--- a/res/xml/special_access.xml
+++ b/res/xml/special_access.xml
@@ -135,4 +135,9 @@
android:title="@string/financial_apps_sms_access_title"
android:fragment="com.android.settings.applications.specialaccess.financialapps.FinancialAppsSmsAccess"
settings:keywords="@string/keywords_financial_apps_sms_access" />
+
+ <Preference
+ android:key="special_access_more"
+ android:title="@string/special_access_more"
+ settings:controller="com.android.settings.applications.specialaccess.MoreSpecialAccessPreferenceController" />
</PreferenceScreen>
diff --git a/src/com/android/settings/EncryptionInterstitial.java b/src/com/android/settings/EncryptionInterstitial.java
index e80b6d3..317e3bd 100644
--- a/src/com/android/settings/EncryptionInterstitial.java
+++ b/src/com/android/settings/EncryptionInterstitial.java
@@ -40,8 +40,8 @@
import com.android.settings.core.instrumentation.InstrumentedDialogFragment;
import com.android.settings.password.ChooseLockSettingsHelper;
-import com.google.android.setupcompat.item.FooterButton;
-import com.google.android.setupcompat.template.ButtonFooterMixin;
+import com.google.android.setupcompat.template.FooterBarMixin;
+import com.google.android.setupcompat.template.FooterButton;
import com.google.android.setupdesign.GlifLayout;
import java.util.List;
@@ -150,8 +150,8 @@
GlifLayout layout = (GlifLayout) view;
layout.setHeaderText(getActivity().getTitle());
- final ButtonFooterMixin buttonFooterMixin = layout.getMixin(ButtonFooterMixin.class);
- buttonFooterMixin.setSecondaryButton(
+ final FooterBarMixin mixin = layout.getMixin(FooterBarMixin.class);
+ mixin.setSecondaryButton(
new FooterButton.Builder(getContext())
.setText(R.string.encryption_interstitial_no)
.setListener(this::onNoButtonClicked)
@@ -160,7 +160,7 @@
.build()
);
- buttonFooterMixin.setPrimaryButton(
+ mixin.setPrimaryButton(
new FooterButton.Builder(getContext())
.setText(R.string.encryption_interstitial_yes)
.setListener(this::onYesButtonClicked)
diff --git a/src/com/android/settings/MasterClear.java b/src/com/android/settings/MasterClear.java
index f9e4317..8dad57f 100644
--- a/src/com/android/settings/MasterClear.java
+++ b/src/com/android/settings/MasterClear.java
@@ -66,9 +66,9 @@
import com.android.settingslib.RestrictedLockUtilsInternal;
import com.google.android.setupcompat.TemplateLayout;
-import com.google.android.setupcompat.item.FooterButton;
-import com.google.android.setupcompat.item.FooterButton.ButtonType;
-import com.google.android.setupcompat.template.ButtonFooterMixin;
+import com.google.android.setupcompat.template.FooterBarMixin;
+import com.google.android.setupcompat.template.FooterButton;
+import com.google.android.setupcompat.template.FooterButton.ButtonType;
import java.util.List;
@@ -417,8 +417,8 @@
}
final TemplateLayout layout = mContentView.findViewById(R.id.setup_wizard_layout);
- final ButtonFooterMixin buttonFooterMixin = layout.getMixin(ButtonFooterMixin.class);
- buttonFooterMixin.setPrimaryButton(
+ final FooterBarMixin mixin = layout.getMixin(FooterBarMixin.class);
+ mixin.setPrimaryButton(
new FooterButton.Builder(getActivity())
.setText(R.string.master_clear_button_text)
.setListener(mInitiateListener)
@@ -426,7 +426,7 @@
.setTheme(R.style.SudGlifButton_Primary)
.build()
);
- mInitiateButton = buttonFooterMixin.getPrimaryButton();
+ mInitiateButton = mixin.getPrimaryButton();
}
private void getContentDescription(View v, StringBuffer description) {
diff --git a/src/com/android/settings/MasterClearConfirm.java b/src/com/android/settings/MasterClearConfirm.java
index de7cd06..c25f2af 100644
--- a/src/com/android/settings/MasterClearConfirm.java
+++ b/src/com/android/settings/MasterClearConfirm.java
@@ -45,9 +45,9 @@
import com.android.settingslib.RestrictedLockUtilsInternal;
import com.google.android.setupcompat.TemplateLayout;
-import com.google.android.setupcompat.item.FooterButton;
-import com.google.android.setupcompat.item.FooterButton.ButtonType;
-import com.google.android.setupcompat.template.ButtonFooterMixin;
+import com.google.android.setupcompat.template.FooterBarMixin;
+import com.google.android.setupcompat.template.FooterButton;
+import com.google.android.setupcompat.template.FooterButton.ButtonType;
/**
* Confirm and execute a reset of the device to a clean "just out of the box"
@@ -154,8 +154,8 @@
private void establishFinalConfirmationState() {
final TemplateLayout layout = mContentView.findViewById(R.id.setup_wizard_layout);
- final ButtonFooterMixin buttonFooterMixin = layout.getMixin(ButtonFooterMixin.class);
- buttonFooterMixin.setPrimaryButton(
+ final FooterBarMixin mixin = layout.getMixin(FooterBarMixin.class);
+ mixin.setPrimaryButton(
new FooterButton.Builder(getActivity())
.setText(R.string.master_clear_button_text)
.setListener(mFinalClickListener)
diff --git a/src/com/android/settings/SettingsActivity.java b/src/com/android/settings/SettingsActivity.java
index 9b5fc00..25ad73d 100644
--- a/src/com/android/settings/SettingsActivity.java
+++ b/src/com/android/settings/SettingsActivity.java
@@ -32,7 +32,6 @@
import android.os.UserHandle;
import android.os.UserManager;
import android.text.TextUtils;
-import android.transition.TransitionManager;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
@@ -103,8 +102,6 @@
*/
public static final String EXTRA_FRAGMENT_ARG_KEY = ":settings:fragment_args_key";
- public static final String BACK_STACK_PREFS = ":settings:prefs";
-
// extras that allow any preference activity to be launched as part of a wizard
// show Back and Next buttons? takes boolean parameter
@@ -374,14 +371,13 @@
setTitleFromIntent(intent);
Bundle initialArguments = intent.getBundleExtra(EXTRA_SHOW_FRAGMENT_ARGUMENTS);
- switchToFragment(initialFragmentName, initialArguments, true, false,
- mInitialTitleResId, mInitialTitle, false);
+ switchToFragment(initialFragmentName, initialArguments, true,
+ mInitialTitleResId, mInitialTitle);
} else {
// Show search icon as up affordance if we are displaying the main Dashboard
mInitialTitleResId = R.string.dashboard_title;
- switchToFragment(TopLevelSettings.class.getName(), null /* args */, false, false,
- mInitialTitleResId, mInitialTitle, false);
-
+ switchToFragment(TopLevelSettings.class.getName(), null /* args */, false,
+ mInitialTitleResId, mInitialTitle);
}
}
@@ -567,7 +563,7 @@
* Switch to a specific Fragment with taking care of validation, Title and BackStack
*/
private Fragment switchToFragment(String fragmentName, Bundle args, boolean validate,
- boolean addToBackStack, int titleResId, CharSequence title, boolean withTransition) {
+ int titleResId, CharSequence title) {
Log.d(LOG_TAG, "Switching to fragment " + fragmentName);
if (validate && !isValidFragment(fragmentName)) {
throw new IllegalArgumentException("Invalid fragment for this activity: "
@@ -576,12 +572,6 @@
Fragment f = Fragment.instantiate(this, fragmentName, args);
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
transaction.replace(R.id.main_content, f);
- if (withTransition) {
- TransitionManager.beginDelayedTransition(mContent);
- }
- if (addToBackStack) {
- transaction.addToBackStack(SettingsActivity.BACK_STACK_PREFS);
- }
if (titleResId > 0) {
transaction.setBreadCrumbTitle(titleResId);
} else if (title != null) {
diff --git a/src/com/android/settings/accounts/EmergencyInfoPreferenceController.java b/src/com/android/settings/accounts/EmergencyInfoPreferenceController.java
index 33e7771..7dc80d0 100644
--- a/src/com/android/settings/accounts/EmergencyInfoPreferenceController.java
+++ b/src/com/android/settings/accounts/EmergencyInfoPreferenceController.java
@@ -22,27 +22,25 @@
import android.content.res.Resources;
import android.os.UserHandle;
import android.os.UserManager;
+import android.text.TextUtils;
import android.util.FeatureFlagUtils;
import androidx.preference.Preference;
import com.android.settings.R;
-import com.android.settings.core.PreferenceControllerMixin;
+import com.android.settings.core.BasePreferenceController;
import com.android.settings.search.SearchIndexableRaw;
-import com.android.settingslib.core.AbstractPreferenceController;
import java.util.List;
-public class EmergencyInfoPreferenceController extends AbstractPreferenceController
- implements PreferenceControllerMixin {
+public class EmergencyInfoPreferenceController extends BasePreferenceController {
public static final String ACTION_EDIT_EMERGENCY_INFO = "android.settings.EDIT_EMERGENCY_INFO";
- private static final String KEY_EMERGENCY_INFO = "emergency_info";
private static final String PACKAGE_NAME_EMERGENCY = "com.android.emergency";
- public EmergencyInfoPreferenceController(Context context) {
- super(context);
+ public EmergencyInfoPreferenceController(Context context, String preferenceKey) {
+ super(context, preferenceKey);
}
@Override
@@ -56,6 +54,7 @@
}
}
+ @Override
public void updateState(Preference preference) {
UserInfo info = mContext.getSystemService(UserManager.class).getUserInfo(
UserHandle.myUserId());
@@ -64,7 +63,7 @@
@Override
public boolean handlePreferenceTreeClick(Preference preference) {
- if (KEY_EMERGENCY_INFO.equals(preference.getKey())) {
+ if (TextUtils.equals(getPreferenceKey(), preference.getKey())) {
Intent intent = new Intent(getIntentAction(mContext));
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
mContext.startActivity(intent);
@@ -74,18 +73,19 @@
}
@Override
- public boolean isAvailable() {
- Intent intent = new Intent(getIntentAction(mContext)).setPackage(getPackageName(mContext));
- List<ResolveInfo> infos = mContext.getPackageManager().queryIntentActivities(intent, 0);
- return infos != null && !infos.isEmpty();
+ public int getAvailabilityStatus() {
+ if (!mContext.getResources().getBoolean(R.bool.config_show_emergency_info_in_device_info)) {
+ return UNSUPPORTED_ON_DEVICE;
+ }
+ final Intent intent = new Intent(getIntentAction(mContext)).setPackage(
+ getPackageName(mContext));
+ final List<ResolveInfo> infos = mContext.getPackageManager().queryIntentActivities(intent,
+ 0);
+ return infos != null && !infos.isEmpty()
+ ? AVAILABLE : UNSUPPORTED_ON_DEVICE;
}
- @Override
- public String getPreferenceKey() {
- return KEY_EMERGENCY_INFO;
- }
-
- private String getIntentAction(Context context) {
+ private static String getIntentAction(Context context) {
if (FeatureFlagUtils.isEnabled(context, FeatureFlagUtils.SAFETY_HUB)) {
return context.getResources().getString(R.string.config_emergency_intent_action);
}
@@ -93,7 +93,7 @@
return ACTION_EDIT_EMERGENCY_INFO;
}
- private String getPackageName(Context context) {
+ private static String getPackageName(Context context) {
if (FeatureFlagUtils.isEnabled(context, FeatureFlagUtils.SAFETY_HUB)) {
return context.getResources().getString(R.string.config_emergency_package_name);
}
diff --git a/src/com/android/settings/applications/RecentAppsPreferenceController.java b/src/com/android/settings/applications/RecentAppsPreferenceController.java
index 81eefb3..c7d310e 100644
--- a/src/com/android/settings/applications/RecentAppsPreferenceController.java
+++ b/src/com/android/settings/applications/RecentAppsPreferenceController.java
@@ -314,6 +314,9 @@
Log.d(TAG, "System package, skipping " + pkgName);
return false;
}
+ if (AppUtils.isHiddenSystemModule(mContext, pkgName)) {
+ return false;
+ }
final Intent launchIntent = new Intent().addCategory(Intent.CATEGORY_LAUNCHER)
.setPackage(pkgName);
diff --git a/src/com/android/settings/applications/appinfo/DefaultAppShortcutPreferenceControllerBase.java b/src/com/android/settings/applications/appinfo/DefaultAppShortcutPreferenceControllerBase.java
index 804fdbe..20169d8 100644
--- a/src/com/android/settings/applications/appinfo/DefaultAppShortcutPreferenceControllerBase.java
+++ b/src/com/android/settings/applications/appinfo/DefaultAppShortcutPreferenceControllerBase.java
@@ -20,9 +20,11 @@
import android.content.Intent;
import android.os.Bundle;
import android.os.UserManager;
+import android.permission.PermissionControllerManager;
import android.text.TextUtils;
import androidx.preference.Preference;
+import androidx.preference.PreferenceScreen;
import com.android.internal.util.CollectionUtils;
import com.android.settings.R;
@@ -43,6 +45,10 @@
private final RoleManager mRoleManager;
+ private boolean mAppQualified;
+
+ private PreferenceScreen mPreferenceScreen;
+
public DefaultAppShortcutPreferenceControllerBase(Context context, String preferenceKey,
String roleName, String packageName) {
super(context, preferenceKey);
@@ -51,6 +57,17 @@
mPackageName = packageName;
mRoleManager = context.getSystemService(RoleManager.class);
+
+ // TODO: STOPSHIP(b/110557011): Remove this check once we have all default apps migrated.
+ if (mRoleName != null) {
+ final PermissionControllerManager permissionControllerManager =
+ mContext.getSystemService(PermissionControllerManager.class);
+ permissionControllerManager.isApplicationQualifiedForRole(mRoleName, mPackageName,
+ mContext.getMainExecutor(), qualified -> {
+ mAppQualified = qualified;
+ refreshAvailability();
+ });
+ }
}
// TODO: STOPSHIP(b/110557011): Remove this once we have all default apps migrated.
@@ -60,6 +77,23 @@
}
@Override
+ public void displayPreference(PreferenceScreen screen) {
+ super.displayPreference(screen);
+
+ mPreferenceScreen = screen;
+ }
+
+ private void refreshAvailability() {
+ if (mPreferenceScreen != null) {
+ final Preference preference = mPreferenceScreen.findPreference(getPreferenceKey());
+ if (preference != null) {
+ preference.setVisible(isAvailable());
+ updateState(preference);
+ }
+ }
+ }
+
+ @Override
public int getAvailabilityStatus() {
if (mContext.getSystemService(UserManager.class).isManagedProfile()) {
return DISABLED_FOR_USER;
@@ -104,7 +138,7 @@
protected boolean hasAppCapability() {
// TODO: STOPSHIP(b/110557011): Remove this check once we have all default apps migrated.
if (mRoleName != null) {
- return mRoleManager.isRoleAvailable(mRoleName);
+ return mAppQualified;
}
return false;
}
diff --git a/src/com/android/settings/applications/assist/DefaultAssistPicker.java b/src/com/android/settings/applications/assist/DefaultAssistPicker.java
deleted file mode 100644
index 6391aa8..0000000
--- a/src/com/android/settings/applications/assist/DefaultAssistPicker.java
+++ /dev/null
@@ -1,246 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.settings.applications.assist;
-
-import android.app.ActivityManager;
-import android.app.settings.SettingsEnums;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
-import android.provider.Settings;
-import android.service.voice.VoiceInteractionService;
-import android.service.voice.VoiceInteractionServiceInfo;
-import android.speech.RecognitionService;
-import android.text.TextUtils;
-import android.util.Log;
-
-import androidx.annotation.VisibleForTesting;
-
-import com.android.internal.app.AssistUtils;
-import com.android.settings.R;
-import com.android.settings.applications.defaultapps.DefaultAppPickerFragment;
-import com.android.settingslib.applications.DefaultAppInfo;
-import com.android.settingslib.widget.CandidateInfo;
-
-import java.util.ArrayList;
-import java.util.List;
-
-public class DefaultAssistPicker extends DefaultAppPickerFragment {
-
- private static final String TAG = "DefaultAssistPicker";
- private static final Intent ASSIST_SERVICE_PROBE =
- new Intent(VoiceInteractionService.SERVICE_INTERFACE);
- private static final Intent ASSIST_ACTIVITY_PROBE =
- new Intent(Intent.ACTION_ASSIST);
-
- @VisibleForTesting
- final List<Info> mAvailableAssistants = new ArrayList<>();
-
- private AssistUtils mAssistUtils;
- private ActivityManager mActivityManager;
-
- @Override
- public int getMetricsCategory() {
- return SettingsEnums.DEFAULT_ASSIST_PICKER;
- }
-
- @Override
- protected boolean shouldShowItemNone() {
- return true;
- }
-
- @Override
- public void onAttach(Context context) {
- super.onAttach(context);
- mAssistUtils = new AssistUtils(context);
- mActivityManager = context.getSystemService(ActivityManager.class);
- }
-
- @Override
- protected int getPreferenceScreenResId() {
- return R.xml.default_assist_settings;
- }
-
- @Override
- protected List<DefaultAppInfo> getCandidates() {
- mAvailableAssistants.clear();
- addAssistServices();
- addAssistActivities();
-
- final List<String> packages = new ArrayList<>();
- final List<DefaultAppInfo> candidates = new ArrayList<>();
- for (Info info : mAvailableAssistants) {
- final String packageName = info.component.getPackageName();
- if (packages.contains(packageName)) {
- // A service appears before an activity thus overrides it if from the same package.
- continue;
- }
- packages.add(packageName);
- candidates.add(new DefaultAppInfo(getContext(), mPm, mUserId, info.component));
- }
- return candidates;
- }
-
- @Override
- protected String getDefaultKey() {
- final ComponentName cn = getCurrentAssist();
- if (cn != null) {
- return new DefaultAppInfo(getContext(), mPm, mUserId, cn).getKey();
- }
- return null;
- }
-
- @Override
- protected String getConfirmationMessage(CandidateInfo appInfo) {
- if (appInfo == null) {
- return null;
- }
- return getContext().getString(R.string.assistant_security_warning, appInfo.loadLabel());
- }
-
- @Override
- protected boolean setDefaultKey(String key) {
- if (TextUtils.isEmpty(key)) {
- setAssistNone();
- return true;
- }
- ComponentName cn = ComponentName.unflattenFromString(key);
- final Info info = findAssistantByPackageName(cn.getPackageName());
- if (info == null) {
- setAssistNone();
- return true;
- }
-
- if (info.isVoiceInteractionService()) {
- setAssistService(info);
- } else {
- setAssistActivity(info);
- }
- return true;
- }
-
- public ComponentName getCurrentAssist() {
- return mAssistUtils.getAssistComponentForUser(mUserId);
- }
-
- @VisibleForTesting
- void addAssistServices() {
- if (mActivityManager.isLowRamDevice()) {
- return;
- }
- final List<ResolveInfo> services = mPm.queryIntentServices(
- ASSIST_SERVICE_PROBE, PackageManager.GET_META_DATA);
- for (ResolveInfo resolveInfo : services) {
- VoiceInteractionServiceInfo voiceInteractionServiceInfo =
- new VoiceInteractionServiceInfo(mPm, resolveInfo.serviceInfo);
- if (!voiceInteractionServiceInfo.getSupportsAssist()) {
- continue;
- }
-
- mAvailableAssistants.add(new Info(
- new ComponentName(resolveInfo.serviceInfo.packageName,
- resolveInfo.serviceInfo.name),
- voiceInteractionServiceInfo));
- }
- }
-
- private void addAssistActivities() {
- final List<ResolveInfo> activities = mPm.queryIntentActivities(
- ASSIST_ACTIVITY_PROBE, PackageManager.MATCH_DEFAULT_ONLY);
- for (ResolveInfo resolveInfo : activities) {
- mAvailableAssistants.add(new Info(
- new ComponentName(resolveInfo.activityInfo.packageName,
- resolveInfo.activityInfo.name)));
- }
- }
-
- private Info findAssistantByPackageName(String packageName) {
- for (Info info : mAvailableAssistants) {
- if (TextUtils.equals(info.component.getPackageName(), packageName)) {
- return info;
- }
- }
- return null;
- }
-
- private void setAssistNone() {
- Settings.Secure.putString(getContext().getContentResolver(),
- Settings.Secure.ASSISTANT, "");
- Settings.Secure.putString(getContext().getContentResolver(),
- Settings.Secure.VOICE_INTERACTION_SERVICE, "");
- Settings.Secure.putString(getContext().getContentResolver(),
- Settings.Secure.VOICE_RECOGNITION_SERVICE, getDefaultRecognizer());
- }
-
- private void setAssistService(Info serviceInfo) {
- final String serviceComponentName = serviceInfo.component.
- flattenToShortString();
- final String serviceRecognizerName = new ComponentName(
- serviceInfo.component.getPackageName(),
- serviceInfo.voiceInteractionServiceInfo.getRecognitionService())
- .flattenToShortString();
-
- Settings.Secure.putString(getContext().getContentResolver(),
- Settings.Secure.ASSISTANT, serviceComponentName);
- Settings.Secure.putString(getContext().getContentResolver(),
- Settings.Secure.VOICE_INTERACTION_SERVICE, serviceComponentName);
- Settings.Secure.putString(getContext().getContentResolver(),
- Settings.Secure.VOICE_RECOGNITION_SERVICE, serviceRecognizerName);
- }
-
- private void setAssistActivity(Info activityInfo) {
- Settings.Secure.putString(getContext().getContentResolver(),
- Settings.Secure.ASSISTANT, activityInfo.component.flattenToShortString());
- Settings.Secure.putString(getContext().getContentResolver(),
- Settings.Secure.VOICE_INTERACTION_SERVICE, "");
- Settings.Secure.putString(getContext().getContentResolver(),
- Settings.Secure.VOICE_RECOGNITION_SERVICE, getDefaultRecognizer());
- }
-
- private String getDefaultRecognizer() {
- final ResolveInfo resolveInfo = mPm.resolveService(
- new Intent(RecognitionService.SERVICE_INTERFACE), PackageManager.GET_META_DATA);
- if (resolveInfo == null || resolveInfo.serviceInfo == null) {
- Log.w(TAG, "Unable to resolve default voice recognition service.");
- return "";
- }
-
- return new ComponentName(resolveInfo.serviceInfo.packageName,
- resolveInfo.serviceInfo.name).flattenToShortString();
- }
-
- static class Info {
- public final ComponentName component;
- public final VoiceInteractionServiceInfo voiceInteractionServiceInfo;
-
- Info(ComponentName component) {
- this.component = component;
- this.voiceInteractionServiceInfo = null;
- }
-
- Info(ComponentName component, VoiceInteractionServiceInfo voiceInteractionServiceInfo) {
- this.component = component;
- this.voiceInteractionServiceInfo = voiceInteractionServiceInfo;
- }
-
- public boolean isVoiceInteractionService() {
- return voiceInteractionServiceInfo != null;
- }
- }
-}
diff --git a/src/com/android/settings/applications/assist/DefaultAssistPreferenceController.java b/src/com/android/settings/applications/assist/DefaultAssistPreferenceController.java
index f95f96a..b2e3644 100644
--- a/src/com/android/settings/applications/assist/DefaultAssistPreferenceController.java
+++ b/src/com/android/settings/applications/assist/DefaultAssistPreferenceController.java
@@ -16,15 +16,19 @@
package com.android.settings.applications.assist;
+import android.app.role.RoleManager;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
+import android.provider.Settings;
import android.service.voice.VoiceInteractionService;
import android.service.voice.VoiceInteractionServiceInfo;
+import android.text.TextUtils;
import androidx.annotation.VisibleForTesting;
+import androidx.preference.Preference;
import com.android.internal.app.AssistUtils;
import com.android.settings.R;
@@ -38,6 +42,7 @@
private final AssistUtils mAssistUtils;
private final boolean mShowSetting;
private final String mPrefKey;
+ private final Intent mIntent;
public DefaultAssistPreferenceController(Context context, String prefKey,
boolean showSetting) {
@@ -45,6 +50,15 @@
mPrefKey = prefKey;
mShowSetting = showSetting;
mAssistUtils = new AssistUtils(context);
+
+ final String packageName = mPackageManager.getPermissionControllerPackageName();
+ if (packageName != null) {
+ mIntent = new Intent(Intent.ACTION_MANAGE_DEFAULT_APP)
+ .setPackage(packageName)
+ .putExtra(Intent.EXTRA_ROLE_NAME, RoleManager.ROLE_ASSISTANT);
+ } else {
+ mIntent = null;
+ }
}
@Override
@@ -73,6 +87,17 @@
}
@Override
+ public boolean handlePreferenceTreeClick(Preference preference) {
+ if (TextUtils.equals(preference.getKey(), "default_assist")) {
+ if (mIntent != null) {
+ mContext.startActivity(mIntent);
+ }
+ return true;
+ }
+ return false;
+ }
+
+ @Override
public boolean isAvailable() {
return mContext.getResources().getBoolean(R.bool.config_show_assist_and_voice_input);
}
diff --git a/src/com/android/settings/applications/specialaccess/MoreSpecialAccessPreferenceController.java b/src/com/android/settings/applications/specialaccess/MoreSpecialAccessPreferenceController.java
new file mode 100644
index 0000000..10d5c36
--- /dev/null
+++ b/src/com/android/settings/applications/specialaccess/MoreSpecialAccessPreferenceController.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.applications.specialaccess;
+
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.text.TextUtils;
+
+import androidx.preference.Preference;
+
+import com.android.settings.core.BasePreferenceController;
+
+public class MoreSpecialAccessPreferenceController extends BasePreferenceController {
+
+ private final Intent mIntent;
+
+ public MoreSpecialAccessPreferenceController(Context context, String preferenceKey) {
+ super(context, preferenceKey);
+
+ final PackageManager packageManager = context.getPackageManager();
+ final String packageName = packageManager.getPermissionControllerPackageName();
+ if (packageName != null) {
+ Intent intent = new Intent(Intent.ACTION_MANAGE_SPECIAL_APP_ACCESSES)
+ .setPackage(packageName);
+ ResolveInfo resolveInfo = packageManager.resolveActivity(intent,
+ PackageManager.MATCH_DEFAULT_ONLY);
+ mIntent = resolveInfo != null ? intent : null;
+ } else {
+ mIntent = null;
+ }
+ }
+
+ @Override
+ public int getAvailabilityStatus() {
+ return mIntent != null ? AVAILABLE_UNSEARCHABLE : UNSUPPORTED_ON_DEVICE;
+ }
+
+ @Override
+ public boolean handlePreferenceTreeClick(Preference preference) {
+ if (TextUtils.equals(preference.getKey(), mPreferenceKey)) {
+ if (mIntent != null) {
+ mContext.startActivity(mIntent);
+ }
+ return true;
+ }
+ return false;
+ }
+}
diff --git a/src/com/android/settings/aware/AwareFeatureProvider.java b/src/com/android/settings/aware/AwareFeatureProvider.java
index a4db957..a24233f 100644
--- a/src/com/android/settings/aware/AwareFeatureProvider.java
+++ b/src/com/android/settings/aware/AwareFeatureProvider.java
@@ -21,4 +21,7 @@
public interface AwareFeatureProvider {
/** Returns true if the aware sensor is supported. */
boolean isSupported(Context context);
+
+ /** Returns true if the aware feature is enabled. */
+ boolean isEnabled(Context context);
}
diff --git a/src/com/android/settings/aware/AwareFeatureProviderImpl.java b/src/com/android/settings/aware/AwareFeatureProviderImpl.java
index af40634..44ec31b 100644
--- a/src/com/android/settings/aware/AwareFeatureProviderImpl.java
+++ b/src/com/android/settings/aware/AwareFeatureProviderImpl.java
@@ -23,4 +23,9 @@
public boolean isSupported(Context context) {
return false;
}
+
+ @Override
+ public boolean isEnabled(Context context) {
+ return false;
+ }
}
diff --git a/src/com/android/settings/biometrics/BiometricEnrollBase.java b/src/com/android/settings/biometrics/BiometricEnrollBase.java
index 4b1c9bc..bca70d7 100644
--- a/src/com/android/settings/biometrics/BiometricEnrollBase.java
+++ b/src/com/android/settings/biometrics/BiometricEnrollBase.java
@@ -32,8 +32,8 @@
import com.android.settings.core.InstrumentedActivity;
import com.android.settings.password.ChooseLockSettingsHelper;
-import com.google.android.setupcompat.item.FooterButton;
-import com.google.android.setupcompat.template.ButtonFooterMixin;
+import com.google.android.setupcompat.template.FooterBarMixin;
+import com.google.android.setupcompat.template.FooterButton;
import com.google.android.setupdesign.GlifLayout;
/**
@@ -78,7 +78,7 @@
protected boolean mLaunchedConfirmLock;
protected byte[] mToken;
protected int mUserId;
- protected ButtonFooterMixin mButtonFooterMixin;
+ protected FooterBarMixin mFooterBarMixin;
@Override
protected void onCreate(Bundle savedInstanceState) {
@@ -137,8 +137,8 @@
}
protected FooterButton getNextButton() {
- if (mButtonFooterMixin != null) {
- return mButtonFooterMixin.getPrimaryButton();
+ if (mFooterBarMixin != null) {
+ return mFooterBarMixin.getPrimaryButton();
}
return null;
}
diff --git a/src/com/android/settings/biometrics/BiometricEnrollIntroduction.java b/src/com/android/settings/biometrics/BiometricEnrollIntroduction.java
index 79e699d..e8cf809 100644
--- a/src/com/android/settings/biometrics/BiometricEnrollIntroduction.java
+++ b/src/com/android/settings/biometrics/BiometricEnrollIntroduction.java
@@ -28,7 +28,7 @@
import com.android.settings.password.ChooseLockGeneric;
import com.android.settings.password.ChooseLockSettingsHelper;
-import com.google.android.setupcompat.item.FooterButton;
+import com.google.android.setupcompat.template.FooterButton;
import com.google.android.setupdesign.span.LinkSpan;
/**
diff --git a/src/com/android/settings/biometrics/face/FaceEnrollEnrolling.java b/src/com/android/settings/biometrics/face/FaceEnrollEnrolling.java
index 8ec64e5..3456c23 100644
--- a/src/com/android/settings/biometrics/face/FaceEnrollEnrolling.java
+++ b/src/com/android/settings/biometrics/face/FaceEnrollEnrolling.java
@@ -33,8 +33,8 @@
import com.android.settings.biometrics.BiometricErrorDialog;
import com.android.settings.biometrics.BiometricsEnrollEnrolling;
-import com.google.android.setupcompat.item.FooterButton;
-import com.google.android.setupcompat.template.ButtonFooterMixin;
+import com.google.android.setupcompat.template.FooterBarMixin;
+import com.google.android.setupcompat.template.FooterButton;
import java.util.ArrayList;
@@ -91,8 +91,8 @@
mLinearOutSlowInInterpolator = AnimationUtils.loadInterpolator(
this, android.R.interpolator.linear_out_slow_in);
- mButtonFooterMixin = getLayout().getMixin(ButtonFooterMixin.class);
- mButtonFooterMixin.setSecondaryButton(
+ mFooterBarMixin = getLayout().getMixin(FooterBarMixin.class);
+ mFooterBarMixin.setSecondaryButton(
new FooterButton.Builder(this)
.setText(R.string.security_settings_face_enroll_enrolling_skip)
.setListener(this::onSkipButtonClick)
diff --git a/src/com/android/settings/biometrics/face/FaceEnrollFinish.java b/src/com/android/settings/biometrics/face/FaceEnrollFinish.java
index 4db9a4e..6e99cdb 100644
--- a/src/com/android/settings/biometrics/face/FaceEnrollFinish.java
+++ b/src/com/android/settings/biometrics/face/FaceEnrollFinish.java
@@ -23,8 +23,8 @@
import com.android.settings.R;
import com.android.settings.biometrics.BiometricEnrollBase;
-import com.google.android.setupcompat.item.FooterButton;
-import com.google.android.setupcompat.template.ButtonFooterMixin;
+import com.google.android.setupcompat.template.FooterBarMixin;
+import com.google.android.setupcompat.template.FooterButton;
/**
* Activity which concludes face enrollment.
@@ -37,8 +37,8 @@
setContentView(R.layout.face_enroll_finish);
setHeaderText(R.string.security_settings_face_enroll_finish_title);
- mButtonFooterMixin = getLayout().getMixin(ButtonFooterMixin.class);
- mButtonFooterMixin.setPrimaryButton(
+ mFooterBarMixin = getLayout().getMixin(FooterBarMixin.class);
+ mFooterBarMixin.setPrimaryButton(
new FooterButton.Builder(this)
.setText(R.string.security_settings_face_enroll_done)
.setListener(this::onNextButtonClick)
diff --git a/src/com/android/settings/biometrics/face/FaceEnrollIntroduction.java b/src/com/android/settings/biometrics/face/FaceEnrollIntroduction.java
index fc4f6ce..e45817d 100644
--- a/src/com/android/settings/biometrics/face/FaceEnrollIntroduction.java
+++ b/src/com/android/settings/biometrics/face/FaceEnrollIntroduction.java
@@ -34,8 +34,8 @@
import com.android.settings.password.ChooseLockSettingsHelper;
import com.android.settingslib.RestrictedLockUtilsInternal;
-import com.google.android.setupcompat.item.FooterButton;
-import com.google.android.setupcompat.template.ButtonFooterMixin;
+import com.google.android.setupcompat.template.FooterBarMixin;
+import com.google.android.setupcompat.template.FooterButton;
import com.google.android.setupdesign.span.LinkSpan;
public class FaceEnrollIntroduction extends BiometricEnrollIntroduction {
@@ -43,7 +43,6 @@
private static final String TAG = "FaceIntro";
private FaceManager mFaceManager;
- private FaceEnrollAccessibilityToggle mSwitchVision;
private FaceEnrollAccessibilityToggle mSwitchDiversity;
@Override
@@ -57,11 +56,10 @@
accessibilityLayout.setVisibility(View.VISIBLE);
});
- mSwitchVision = findViewById(R.id.toggle_vision);
mSwitchDiversity = findViewById(R.id.toggle_diversity);
- mButtonFooterMixin = getLayout().getMixin(ButtonFooterMixin.class);
- mButtonFooterMixin.setSecondaryButton(
+ mFooterBarMixin = getLayout().getMixin(FooterBarMixin.class);
+ mFooterBarMixin.setSecondaryButton(
new FooterButton.Builder(this)
.setText(R.string.security_settings_face_enroll_introduction_cancel)
.setListener(this::onCancelButtonClick)
@@ -70,7 +68,7 @@
.build()
);
- mButtonFooterMixin.setPrimaryButton(
+ mFooterBarMixin.setPrimaryButton(
new FooterButton.Builder(this)
.setText(R.string.wizard_next)
.setListener(this::onNextButtonClick)
@@ -108,16 +106,16 @@
@Override
protected FooterButton getCancelButton() {
- if (mButtonFooterMixin != null) {
- return mButtonFooterMixin.getSecondaryButton();
+ if (mFooterBarMixin != null) {
+ return mFooterBarMixin.getSecondaryButton();
}
return null;
}
@Override
protected FooterButton getNextButton() {
- if (mButtonFooterMixin != null) {
- return mButtonFooterMixin.getPrimaryButton();
+ if (mFooterBarMixin != null) {
+ return mFooterBarMixin.getPrimaryButton();
}
return null;
}
@@ -167,7 +165,6 @@
} else {
intent.setClass(this, FaceEnrollEnrolling.class);
}
- intent.putExtra(EXTRA_KEY_REQUIRE_VISION, mSwitchVision.isChecked());
intent.putExtra(EXTRA_KEY_REQUIRE_DIVERSITY, mSwitchDiversity.isChecked());
return intent;
}
diff --git a/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollEnrolling.java b/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollEnrolling.java
index 3292b8d..3d4ea16 100644
--- a/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollEnrolling.java
+++ b/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollEnrolling.java
@@ -47,8 +47,8 @@
import com.android.settings.biometrics.BiometricsEnrollEnrolling;
import com.android.settings.core.instrumentation.InstrumentedDialogFragment;
-import com.google.android.setupcompat.item.FooterButton;
-import com.google.android.setupcompat.template.ButtonFooterMixin;
+import com.google.android.setupcompat.template.FooterBarMixin;
+import com.google.android.setupcompat.template.FooterButton;
/**
* Activity which handles the actual enrolling for fingerprint.
@@ -137,8 +137,8 @@
mProgressBar = (ProgressBar) findViewById(R.id.fingerprint_progress_bar);
mVibrator = getSystemService(Vibrator.class);
- mButtonFooterMixin = getLayout().getMixin(ButtonFooterMixin.class);
- mButtonFooterMixin.setSecondaryButton(
+ mFooterBarMixin = getLayout().getMixin(FooterBarMixin.class);
+ mFooterBarMixin.setSecondaryButton(
new FooterButton.Builder(this)
.setText(R.string.security_settings_fingerprint_enroll_enrolling_skip)
.setListener(this::onSkipButtonClick)
diff --git a/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollFindSensor.java b/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollFindSensor.java
index 7ed8d7d..5589592 100644
--- a/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollFindSensor.java
+++ b/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollFindSensor.java
@@ -30,8 +30,8 @@
import com.android.settings.biometrics.BiometricEnrollSidecar.Listener;
import com.android.settings.password.ChooseLockSettingsHelper;
-import com.google.android.setupcompat.item.FooterButton;
-import com.google.android.setupcompat.template.ButtonFooterMixin;
+import com.google.android.setupcompat.template.FooterBarMixin;
+import com.google.android.setupcompat.template.FooterButton;
/**
* Activity explaining the fingerprint sensor location for fingerprint enrollment.
@@ -48,8 +48,8 @@
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(getContentView());
- mButtonFooterMixin = getLayout().getMixin(ButtonFooterMixin.class);
- mButtonFooterMixin.setSecondaryButton(
+ mFooterBarMixin = getLayout().getMixin(FooterBarMixin.class);
+ mFooterBarMixin.setSecondaryButton(
new FooterButton.Builder(this)
.setText(R.string.skip_label)
.setListener(this::onSkipButtonClick)
diff --git a/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollFinish.java b/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollFinish.java
index 61128a3..3f02b6f 100644
--- a/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollFinish.java
+++ b/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollFinish.java
@@ -26,8 +26,8 @@
import com.android.settings.Utils;
import com.android.settings.biometrics.BiometricEnrollBase;
-import com.google.android.setupcompat.item.FooterButton;
-import com.google.android.setupcompat.template.ButtonFooterMixin;
+import com.google.android.setupcompat.template.FooterBarMixin;
+import com.google.android.setupcompat.template.FooterButton;
/**
* Activity which concludes fingerprint enrollment.
@@ -42,8 +42,8 @@
setContentView(R.layout.fingerprint_enroll_finish);
setHeaderText(R.string.security_settings_fingerprint_enroll_finish_title);
- mButtonFooterMixin = getLayout().getMixin(ButtonFooterMixin.class);
- mButtonFooterMixin.setSecondaryButton(
+ mFooterBarMixin = getLayout().getMixin(FooterBarMixin.class);
+ mFooterBarMixin.setSecondaryButton(
new FooterButton.Builder(this)
.setText(R.string.fingerprint_enroll_button_add)
.setButtonType(FooterButton.ButtonType.SKIP)
@@ -51,7 +51,7 @@
.build()
);
- mButtonFooterMixin.setPrimaryButton(
+ mFooterBarMixin.setPrimaryButton(
new FooterButton.Builder(this)
.setText(R.string.security_settings_fingerprint_enroll_done)
.setListener(this::onNextButtonClick)
@@ -65,7 +65,7 @@
protected void onResume() {
super.onResume();
- FooterButton addButton = mButtonFooterMixin.getSecondaryButton();
+ FooterButton addButton = mFooterBarMixin.getSecondaryButton();
final FingerprintManager fpm = Utils.getFingerprintManagerOrNull(this);
boolean hideAddAnother = false;
diff --git a/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollIntroduction.java b/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollIntroduction.java
index 2ad4ada..d3618db 100644
--- a/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollIntroduction.java
+++ b/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollIntroduction.java
@@ -32,8 +32,8 @@
import com.android.settingslib.HelpUtils;
import com.android.settingslib.RestrictedLockUtilsInternal;
-import com.google.android.setupcompat.item.FooterButton;
-import com.google.android.setupcompat.template.ButtonFooterMixin;
+import com.google.android.setupcompat.template.FooterBarMixin;
+import com.google.android.setupcompat.template.FooterButton;
import com.google.android.setupdesign.span.LinkSpan;
public class FingerprintEnrollIntroduction extends BiometricEnrollIntroduction {
@@ -47,8 +47,8 @@
super.onCreate(savedInstanceState);
mFingerprintManager = Utils.getFingerprintManagerOrNull(this);
- mButtonFooterMixin = getLayout().getMixin(ButtonFooterMixin.class);
- mButtonFooterMixin.setSecondaryButton(
+ mFooterBarMixin = getLayout().getMixin(FooterBarMixin.class);
+ mFooterBarMixin.setSecondaryButton(
new FooterButton.Builder(this)
.setText(R.string.security_settings_face_enroll_introduction_cancel)
.setListener(this::onCancelButtonClick)
@@ -57,7 +57,7 @@
.build()
);
- mButtonFooterMixin.setPrimaryButton(
+ mFooterBarMixin.setPrimaryButton(
new FooterButton.Builder(this)
.setText(R.string.wizard_next)
.setListener(this::onNextButtonClick)
@@ -95,16 +95,16 @@
@Override
protected FooterButton getCancelButton() {
- if (mButtonFooterMixin != null) {
- return mButtonFooterMixin.getSecondaryButton();
+ if (mFooterBarMixin != null) {
+ return mFooterBarMixin.getSecondaryButton();
}
return null;
}
@Override
protected FooterButton getNextButton() {
- if (mButtonFooterMixin != null) {
- return mButtonFooterMixin.getPrimaryButton();
+ if (mFooterBarMixin != null) {
+ return mFooterBarMixin.getPrimaryButton();
}
return null;
}
diff --git a/src/com/android/settings/biometrics/fingerprint/FingerprintSuggestionActivity.java b/src/com/android/settings/biometrics/fingerprint/FingerprintSuggestionActivity.java
index 704ed13..307553d 100644
--- a/src/com/android/settings/biometrics/fingerprint/FingerprintSuggestionActivity.java
+++ b/src/com/android/settings/biometrics/fingerprint/FingerprintSuggestionActivity.java
@@ -23,7 +23,7 @@
import com.android.settings.R;
import com.android.settings.Utils;
-import com.google.android.setupcompat.item.FooterButton;
+import com.google.android.setupcompat.template.FooterButton;
public class FingerprintSuggestionActivity extends SetupFingerprintEnrollIntroduction {
diff --git a/src/com/android/settings/biometrics/fingerprint/SetupFingerprintEnrollFinish.java b/src/com/android/settings/biometrics/fingerprint/SetupFingerprintEnrollFinish.java
index 24a0069..971a410 100644
--- a/src/com/android/settings/biometrics/fingerprint/SetupFingerprintEnrollFinish.java
+++ b/src/com/android/settings/biometrics/fingerprint/SetupFingerprintEnrollFinish.java
@@ -24,7 +24,7 @@
import com.android.settings.SetupWizardUtils;
import com.android.settings.password.ChooseLockSettingsHelper;
-import com.google.android.setupcompat.item.FooterButton;
+import com.google.android.setupcompat.template.FooterButton;
public class SetupFingerprintEnrollFinish extends FingerprintEnrollFinish {
diff --git a/src/com/android/settings/biometrics/fingerprint/SetupFingerprintEnrollIntroduction.java b/src/com/android/settings/biometrics/fingerprint/SetupFingerprintEnrollIntroduction.java
index 6a92eba..7ccb47c 100644
--- a/src/com/android/settings/biometrics/fingerprint/SetupFingerprintEnrollIntroduction.java
+++ b/src/com/android/settings/biometrics/fingerprint/SetupFingerprintEnrollIntroduction.java
@@ -34,7 +34,7 @@
import com.android.settings.password.SetupChooseLockGeneric;
import com.android.settings.password.SetupSkipDialog;
-import com.google.android.setupcompat.item.FooterButton;
+import com.google.android.setupcompat.template.FooterButton;
public class SetupFingerprintEnrollIntroduction extends FingerprintEnrollIntroduction {
private static final String KEY_LOCK_SCREEN_PRESENT = "wasLockScreenPresent";
diff --git a/src/com/android/settings/bluetooth/AdvancedBluetoothDetailsHeaderController.java b/src/com/android/settings/bluetooth/AdvancedBluetoothDetailsHeaderController.java
new file mode 100644
index 0000000..4b8efd4
--- /dev/null
+++ b/src/com/android/settings/bluetooth/AdvancedBluetoothDetailsHeaderController.java
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.bluetooth;
+
+import android.bluetooth.BluetoothDevice;
+import android.content.Context;
+import android.graphics.PorterDuff;
+import android.graphics.PorterDuffColorFilter;
+import android.graphics.drawable.Drawable;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+import androidx.annotation.VisibleForTesting;
+import androidx.core.graphics.drawable.IconCompat;
+import androidx.preference.PreferenceScreen;
+
+import com.android.settings.R;
+import com.android.settings.core.BasePreferenceController;
+import com.android.settings.fuelgauge.BatteryMeterView;
+import com.android.settingslib.bluetooth.CachedBluetoothDevice;
+import com.android.settingslib.widget.LayoutPreference;
+
+/**
+ * This class adds a header with device name and status (connected/disconnected, etc.).
+ */
+public class AdvancedBluetoothDetailsHeaderController extends BasePreferenceController {
+
+ @VisibleForTesting
+ LayoutPreference mLayoutPreference;
+ private CachedBluetoothDevice mCachedDevice;
+
+ public AdvancedBluetoothDetailsHeaderController(Context context, String prefKey) {
+ super(context, prefKey);
+ }
+
+ @Override
+ public int getAvailabilityStatus() {
+ final boolean unthetheredHeadset = Utils.getBooleanMetaData(mCachedDevice.getDevice(),
+ BluetoothDevice.METADATA_IS_UNTHETHERED_HEADSET);
+ return unthetheredHeadset ? AVAILABLE : CONDITIONALLY_UNAVAILABLE;
+ }
+
+ @Override
+ public void displayPreference(PreferenceScreen screen) {
+ super.displayPreference(screen);
+ mLayoutPreference = screen.findPreference(getPreferenceKey());
+ mLayoutPreference.setVisible(isAvailable());
+ refresh();
+ }
+
+ public void init(CachedBluetoothDevice cachedBluetoothDevice) {
+ mCachedDevice = cachedBluetoothDevice;
+ }
+
+ @VisibleForTesting
+ void refresh() {
+ if (mLayoutPreference != null && mCachedDevice != null) {
+ final TextView title = mLayoutPreference.findViewById(R.id.entity_header_title);
+ title.setText(mCachedDevice.getName());
+ final TextView summary = mLayoutPreference.findViewById(R.id.entity_header_summary);
+ summary.setText(mCachedDevice.getConnectionSummary());
+
+ updateSubLayout(mLayoutPreference.findViewById(R.id.layout_left),
+ BluetoothDevice.METADATA_UNTHETHERED_LEFT_ICON,
+ BluetoothDevice.METADATA_UNTHETHERED_LEFT_BATTERY,
+ R.string.bluetooth_left_name);
+
+ updateSubLayout(mLayoutPreference.findViewById(R.id.layout_middle),
+ BluetoothDevice.METADATA_UNTHETHERED_CASE_ICON,
+ BluetoothDevice.METADATA_UNTHETHERED_CASE_BATTERY,
+ R.string.bluetooth_middle_name);
+
+ updateSubLayout(mLayoutPreference.findViewById(R.id.layout_right),
+ BluetoothDevice.METADATA_UNTHETHERED_RIGHT_ICON,
+ BluetoothDevice.METADATA_UNTHETHERED_RIGHT_BATTERY,
+ R.string.bluetooth_right_name);
+ }
+ }
+
+ @VisibleForTesting
+ Drawable createBtBatteryIcon(Context context, int level) {
+ final BatteryMeterView.BatteryMeterDrawable drawable =
+ new BatteryMeterView.BatteryMeterDrawable(context,
+ context.getColor(R.color.meter_background_color));
+ drawable.setBatteryLevel(level);
+ drawable.setShowPercent(false);
+ drawable.setBatteryColorFilter(new PorterDuffColorFilter(
+ com.android.settings.Utils.getColorAttrDefaultColor(context,
+ android.R.attr.colorControlNormal),
+ PorterDuff.Mode.SRC_IN));
+
+ return drawable;
+ }
+
+ private void updateSubLayout(LinearLayout linearLayout, int iconMetaKey, int batteryMetaKey,
+ int titleResId) {
+ if (linearLayout == null) {
+ return;
+ }
+ final BluetoothDevice bluetoothDevice = mCachedDevice.getDevice();
+ final String iconUri = Utils.getStringMetaData(bluetoothDevice, iconMetaKey);
+ if (iconUri != null) {
+ final ImageView imageView = linearLayout.findViewById(R.id.header_icon);
+ final IconCompat iconCompat = IconCompat.createWithContentUri(iconUri);
+ imageView.setImageBitmap(iconCompat.getBitmap());
+ }
+
+ final int batteryLevel = Utils.getIntMetaData(bluetoothDevice, batteryMetaKey);
+ if (batteryLevel != Utils.META_INT_ERROR) {
+ final ImageView imageView = linearLayout.findViewById(R.id.bt_battery_icon);
+ imageView.setImageDrawable(createBtBatteryIcon(mContext, batteryLevel));
+ final TextView textView = linearLayout.findViewById(R.id.bt_battery_summary);
+ textView.setText(com.android.settings.Utils.formatPercentage(batteryLevel));
+ }
+
+ final TextView textView = linearLayout.findViewById(R.id.header_title);
+ textView.setText(titleResId);
+ }
+}
diff --git a/src/com/android/settings/bluetooth/BluetoothDetailsButtonsController.java b/src/com/android/settings/bluetooth/BluetoothDetailsButtonsController.java
index a438f09..af15052 100644
--- a/src/com/android/settings/bluetooth/BluetoothDetailsButtonsController.java
+++ b/src/com/android/settings/bluetooth/BluetoothDetailsButtonsController.java
@@ -16,6 +16,7 @@
package com.android.settings.bluetooth;
+import android.bluetooth.BluetoothDevice;
import android.content.Context;
import androidx.preference.PreferenceFragmentCompat;
@@ -43,6 +44,13 @@
mIsConnected = device.isConnected();
}
+ @Override
+ public boolean isAvailable() {
+ final boolean unthetheredHeadset = Utils.getBooleanMetaData(mCachedDevice.getDevice(),
+ BluetoothDevice.METADATA_IS_UNTHETHERED_HEADSET);
+ return !unthetheredHeadset;
+ }
+
private void onForgetButtonPressed() {
ForgetDeviceDialogFragment fragment =
ForgetDeviceDialogFragment.newInstance(mCachedDevice.getAddress());
@@ -90,4 +98,4 @@
return KEY_ACTION_BUTTONS;
}
-}
+}
\ No newline at end of file
diff --git a/src/com/android/settings/bluetooth/BluetoothDetailsController.java b/src/com/android/settings/bluetooth/BluetoothDetailsController.java
index af5a628..bb48904 100644
--- a/src/com/android/settings/bluetooth/BluetoothDetailsController.java
+++ b/src/com/android/settings/bluetooth/BluetoothDetailsController.java
@@ -89,4 +89,4 @@
* should update the preferences it manages based on the new state.
*/
protected abstract void refresh();
-}
+}
\ No newline at end of file
diff --git a/src/com/android/settings/bluetooth/BluetoothDetailsHeaderController.java b/src/com/android/settings/bluetooth/BluetoothDetailsHeaderController.java
index a41b791..95b16b9 100644
--- a/src/com/android/settings/bluetooth/BluetoothDetailsHeaderController.java
+++ b/src/com/android/settings/bluetooth/BluetoothDetailsHeaderController.java
@@ -62,7 +62,8 @@
protected void setHeaderProperties() {
final Pair<Drawable, String> pair = BluetoothUtils
.getBtClassDrawableWithDescription(mContext, mCachedDevice,
- mContext.getResources().getFraction(R.fraction.bt_battery_scale_fraction, 1, 1));
+ mContext.getResources().getFraction(R.fraction.bt_battery_scale_fraction, 1,
+ 1));
String summaryText = mCachedDevice.getConnectionSummary();
// If both the hearing aids are connected, two device status should be shown.
// If Second Summary is unavailable, to set it to null.
@@ -84,4 +85,4 @@
public String getPreferenceKey() {
return KEY_DEVICE_HEADER;
}
-}
+}
\ No newline at end of file
diff --git a/src/com/android/settings/bluetooth/BluetoothDetailsMacAddressController.java b/src/com/android/settings/bluetooth/BluetoothDetailsMacAddressController.java
index 987dbe4..835961d 100644
--- a/src/com/android/settings/bluetooth/BluetoothDetailsMacAddressController.java
+++ b/src/com/android/settings/bluetooth/BluetoothDetailsMacAddressController.java
@@ -62,4 +62,4 @@
}
return mFooterPreference.getKey();
}
-}
+}
\ No newline at end of file
diff --git a/src/com/android/settings/bluetooth/BluetoothDetailsProfilesController.java b/src/com/android/settings/bluetooth/BluetoothDetailsProfilesController.java
index 88cebcb..5c609e6 100644
--- a/src/com/android/settings/bluetooth/BluetoothDetailsProfilesController.java
+++ b/src/com/android/settings/bluetooth/BluetoothDetailsProfilesController.java
@@ -264,4 +264,4 @@
public String getPreferenceKey() {
return KEY_PROFILES_GROUP;
}
-}
+}
\ No newline at end of file
diff --git a/src/com/android/settings/bluetooth/BluetoothDeviceDetailsFragment.java b/src/com/android/settings/bluetooth/BluetoothDeviceDetailsFragment.java
index 6ff4309..98455f2 100644
--- a/src/com/android/settings/bluetooth/BluetoothDeviceDetailsFragment.java
+++ b/src/com/android/settings/bluetooth/BluetoothDeviceDetailsFragment.java
@@ -108,6 +108,7 @@
mManager = getLocalBluetoothManager(context);
mCachedDevice = getCachedDevice(mDeviceAddress);
super.onAttach(context);
+ use(AdvancedBluetoothDetailsHeaderController.class).init(mCachedDevice);
final BluetoothFeatureProvider featureProvider = FeatureFactory.getFactory(
context).getBluetoothFeatureProvider(context);
@@ -137,7 +138,7 @@
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
MenuItem item = menu.add(0, EDIT_DEVICE_NAME_ITEM_ID, 0, R.string.bluetooth_rename_button);
- item.setIcon(R.drawable.ic_mode_edit);
+ item.setIcon(com.android.internal.R.drawable.ic_mode_edit);
item.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS);
super.onCreateOptionsMenu(menu, inflater);
}
diff --git a/src/com/android/settings/bluetooth/BluetoothSliceBuilder.java b/src/com/android/settings/bluetooth/BluetoothSliceBuilder.java
index 59b8007..18df872 100644
--- a/src/com/android/settings/bluetooth/BluetoothSliceBuilder.java
+++ b/src/com/android/settings/bluetooth/BluetoothSliceBuilder.java
@@ -73,7 +73,7 @@
final boolean isBluetoothEnabled = isBluetoothEnabled();
final CharSequence title = context.getText(R.string.bluetooth_settings);
final IconCompat icon = IconCompat.createWithResource(context,
- R.drawable.ic_settings_bluetooth);
+ com.android.internal.R.drawable.ic_settings_bluetooth);
@ColorInt final int color = com.android.settings.Utils.getColorAccent(
context).getDefaultColor();
final PendingIntent toggleAction = getBroadcastIntent(context);
diff --git a/src/com/android/settings/bluetooth/Utils.java b/src/com/android/settings/bluetooth/Utils.java
index d6e395e..ff4a98f 100755
--- a/src/com/android/settings/bluetooth/Utils.java
+++ b/src/com/android/settings/bluetooth/Utils.java
@@ -47,6 +47,8 @@
static final boolean V = BluetoothUtils.V; // verbose logging
static final boolean D = BluetoothUtils.D; // regular logging
+ public static final int META_INT_ERROR = -1;
+
private Utils() {
}
@@ -152,4 +154,29 @@
return Settings.Global.getInt(context.getContentResolver(),
Settings.Global.BLE_SCAN_ALWAYS_AVAILABLE, 0) == 1;
}
+
+ public static boolean getBooleanMetaData(BluetoothDevice bluetoothDevice, int key) {
+ if (bluetoothDevice == null) {
+ return false;
+ }
+ return Boolean.parseBoolean(bluetoothDevice.getMetadata(key));
+ }
+
+ public static String getStringMetaData(BluetoothDevice bluetoothDevice, int key) {
+ if (bluetoothDevice == null) {
+ return null;
+ }
+ return bluetoothDevice.getMetadata(key);
+ }
+
+ public static int getIntMetaData(BluetoothDevice bluetoothDevice, int key) {
+ if (bluetoothDevice == null) {
+ return META_INT_ERROR;
+ }
+ try {
+ return Integer.parseInt(bluetoothDevice.getMetadata(key));
+ } catch (NumberFormatException e) {
+ return META_INT_ERROR;
+ }
+ }
}
diff --git a/src/com/android/settings/core/SettingsBaseActivity.java b/src/com/android/settings/core/SettingsBaseActivity.java
index 23eb860..294e754 100644
--- a/src/com/android/settings/core/SettingsBaseActivity.java
+++ b/src/com/android/settings/core/SettingsBaseActivity.java
@@ -64,7 +64,6 @@
final TypedArray theme = getTheme().obtainStyledAttributes(android.R.styleable.Theme);
if (!theme.getBoolean(android.R.styleable.Theme_windowNoTitle, false)) {
- getWindow().addFlags(LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
requestWindowFeature(Window.FEATURE_NO_TITLE);
}
super.setContentView(R.layout.settings_base_layout);
diff --git a/src/com/android/settings/core/WorkProfilePreferenceController.java b/src/com/android/settings/core/WorkProfilePreferenceController.java
new file mode 100644
index 0000000..603af20
--- /dev/null
+++ b/src/com/android/settings/core/WorkProfilePreferenceController.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+package com.android.settings.core;
+
+import android.content.Context;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.text.TextUtils;
+
+import androidx.annotation.Nullable;
+import androidx.preference.Preference;
+
+import com.android.settings.Utils;
+
+/**
+ * Abstract class to provide additional logic to deal with optional {@link Preference} entries that
+ * are used only when work profile is enabled.
+ *
+ * <p>TODO(b/123376083): Consider merging this into {@link BasePreferenceController}.</p>
+ */
+public abstract class WorkProfilePreferenceController extends BasePreferenceController {
+ @Nullable
+ private final UserHandle mWorkProfileUser;
+
+ /**
+ * Constructor of {@link WorkProfilePreferenceController}. Called by
+ * {@link BasePreferenceController#createInstance(Context, String)} through reflection.
+ *
+ * @param context {@link Context} to instantiate this controller.
+ * @param preferenceKey Preference key to be associated with the {@link Preference}.
+ */
+ public WorkProfilePreferenceController(Context context, String preferenceKey) {
+ super(context, preferenceKey);
+ mWorkProfileUser = Utils.getManagedProfile(UserManager.get(context));
+ }
+
+ /**
+ * @return Non-{@code null} {@link UserHandle} when a work profile is enabled.
+ * Otherwise {@code null}.
+ */
+ @Nullable
+ protected UserHandle getWorkProfileUser() {
+ return mWorkProfileUser;
+ }
+
+ /**
+ * Called back from {@link #handlePreferenceTreeClick(Preference)} to associate source metrics
+ * category.
+ *
+ * @return One of {@link android.app.settings.SettingsEnums}.
+ */
+ protected abstract int getSourceMetricsCategory();
+
+ /**
+ * {@inheritDoc}
+ *
+ * <p>When you override this method, do not forget to check {@link #getWorkProfileUser()} to
+ * see if work profile user actually exists or not.</p>
+ */
+ @AvailabilityStatus
+ @Override
+ public int getAvailabilityStatus() {
+ return mWorkProfileUser != null ? AVAILABLE : DISABLED_FOR_USER;
+ }
+
+ /**
+ * Launches the specified fragment for the work profile user if the associated
+ * {@link Preference} is clicked. Otherwise just forward it to the super class.
+ *
+ * @param preference the preference being clicked.
+ * @return {@code true} if handled.
+ */
+ public boolean handlePreferenceTreeClick(Preference preference) {
+ if (!TextUtils.equals(preference.getKey(), getPreferenceKey())) {
+ return super.handlePreferenceTreeClick(preference);
+ }
+ new SubSettingLauncher(preference.getContext())
+ .setDestination(preference.getFragment())
+ .setSourceMetricsCategory(getSourceMetricsCategory())
+ .setArguments(preference.getExtras())
+ .setUserHandle(mWorkProfileUser)
+ .launch();
+ return true;
+ }
+}
diff --git a/src/com/android/settings/datausage/DataUsageList.java b/src/com/android/settings/datausage/DataUsageList.java
index aa66197..735532a 100644
--- a/src/com/android/settings/datausage/DataUsageList.java
+++ b/src/com/android/settings/datausage/DataUsageList.java
@@ -135,8 +135,8 @@
mUidDetailProvider = new UidDetailProvider(activity);
mTelephonyManager = activity.getSystemService(TelephonyManager.class);
mUsageAmount = findPreference(KEY_USAGE_AMOUNT);
- mChart = (ChartDataUsagePreference) findPreference(KEY_CHART_DATA);
- mApps = (PreferenceGroup) findPreference(KEY_APPS_GROUP);
+ mChart = findPreference(KEY_CHART_DATA);
+ mApps = findPreference(KEY_APPS_GROUP);
processArgument();
}
@@ -306,7 +306,7 @@
getLoaderManager().restartLoader(LOADER_SUMMARY, null /* args */,
mNetworkStatsDetailCallbacks);
- final long totalBytes = mCycleData != null
+ final long totalBytes = mCycleData != null && !mCycleData.isEmpty()
? mCycleData.get(mCycleSpinner.getSelectedItemPosition()).getTotalUsage() : 0;
final CharSequence totalPhrase = DataUsageUtils.formatDataUsage(getActivity(), totalBytes);
mUsageAmount.setTitle(getString(R.string.data_used_template, totalPhrase));
diff --git a/src/com/android/settings/datausage/DataUsageSummary.java b/src/com/android/settings/datausage/DataUsageSummary.java
index 3661410..ad4e1e2 100644
--- a/src/com/android/settings/datausage/DataUsageSummary.java
+++ b/src/com/android/settings/datausage/DataUsageSummary.java
@@ -87,7 +87,7 @@
boolean hasMobileData = DataUsageUtils.hasMobileData(context);
- int defaultSubId = DataUsageUtils.getDefaultSubscriptionId(context);
+ final int defaultSubId = SubscriptionManager.getDefaultDataSubscriptionId();
if (defaultSubId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
hasMobileData = false;
}
diff --git a/src/com/android/settings/datausage/DataUsageSummaryPreference.java b/src/com/android/settings/datausage/DataUsageSummaryPreference.java
index 3cbe1ea..481538d 100644
--- a/src/com/android/settings/datausage/DataUsageSummaryPreference.java
+++ b/src/com/android/settings/datausage/DataUsageSummaryPreference.java
@@ -21,6 +21,7 @@
import android.content.Context;
import android.content.Intent;
import android.graphics.Typeface;
+import android.net.ConnectivityManager;
import android.net.NetworkTemplate;
import android.os.Bundle;
import android.text.Spannable;
@@ -206,10 +207,12 @@
}
}
- private static void launchWifiDataUsage(Context context) {
+ @VisibleForTesting
+ static void launchWifiDataUsage(Context context) {
final Bundle args = new Bundle(1);
args.putParcelable(DataUsageList.EXTRA_NETWORK_TEMPLATE,
NetworkTemplate.buildTemplateWifiWildcard());
+ args.putInt(DataUsageList.EXTRA_NETWORK_TYPE, ConnectivityManager.TYPE_WIFI);
final SubSettingLauncher launcher = new SubSettingLauncher(context)
.setArguments(args)
.setDestination(DataUsageList.class.getName())
diff --git a/src/com/android/settings/development/OverlayCategoryPreferenceController.java b/src/com/android/settings/development/OverlayCategoryPreferenceController.java
index 9db8a2f..0ba9d79 100644
--- a/src/com/android/settings/development/OverlayCategoryPreferenceController.java
+++ b/src/com/android/settings/development/OverlayCategoryPreferenceController.java
@@ -22,9 +22,12 @@
import android.content.om.IOverlayManager;
import android.content.om.OverlayInfo;
import android.content.pm.PackageManager;
+import android.os.AsyncTask;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.text.TextUtils;
+import android.util.Log;
+import android.widget.Toast;
import androidx.annotation.VisibleForTesting;
import androidx.preference.ListPreference;
@@ -38,6 +41,7 @@
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
+import java.util.Optional;
/**
* Preference controller to allow users to choose an overlay from a list for a given category.
@@ -46,6 +50,7 @@
*/
public class OverlayCategoryPreferenceController extends DeveloperOptionsPreferenceController
implements Preference.OnPreferenceChangeListener, PreferenceControllerMixin {
+ private static final String TAG = "OverlayCategoryPC";
@VisibleForTesting
static final String PACKAGE_DEVICE_DEFAULT = "package_device_default";
private static final String OVERLAY_TARGET_PACKAGE = "android";
@@ -100,12 +105,11 @@
}
private boolean setOverlay(String packageName) {
- String currentPackageName = null;
- for (OverlayInfo o : getOverlayInfos()) {
- if (o.isEnabled()) {
- currentPackageName = o.packageName;
- }
- }
+ final String currentPackageName = getOverlayInfos().stream()
+ .filter(info -> info.isEnabled())
+ .map(info -> info.packageName)
+ .findFirst()
+ .orElse(null);
if (PACKAGE_DEVICE_DEFAULT.equals(packageName) && TextUtils.isEmpty(currentPackageName)
|| TextUtils.equals(packageName, currentPackageName)) {
@@ -113,18 +117,33 @@
return true;
}
- final boolean result;
- try {
- if (PACKAGE_DEVICE_DEFAULT.equals(packageName)) {
- result = mOverlayManager.setEnabled(currentPackageName, false, USER_SYSTEM);
- } else {
- result = mOverlayManager.setEnabledExclusiveInCategory(packageName, USER_SYSTEM);
+ new AsyncTask<Void, Void, Boolean>() {
+ @Override
+ protected Boolean doInBackground(Void... params) {
+ try {
+ if (PACKAGE_DEVICE_DEFAULT.equals(packageName)) {
+ return mOverlayManager.setEnabled(currentPackageName, false, USER_SYSTEM);
+ } else {
+ return mOverlayManager.setEnabledExclusiveInCategory(packageName, USER_SYSTEM);
+ }
+ } catch (RemoteException re) {
+ Log.w(TAG, "Error enabling overlay.", re);
+ return false;
+ }
}
- } catch (RemoteException re) {
- throw re.rethrowFromSystemServer();
- }
- updateState(mPreference);
- return result;
+
+ @Override
+ protected void onPostExecute(Boolean success) {
+ updateState(mPreference);
+ if (!success) {
+ Toast.makeText(
+ mContext, R.string.overlay_toast_failed_to_apply, Toast.LENGTH_LONG)
+ .show();
+ }
+ }
+ }.execute();
+
+ return true; // Assume success; toast on failure.
}
@Override
diff --git a/src/com/android/settings/development/gup/GupPreferenceController.java b/src/com/android/settings/development/gamedriver/GameDriverAppPreferenceController.java
similarity index 61%
rename from src/com/android/settings/development/gup/GupPreferenceController.java
rename to src/com/android/settings/development/gamedriver/GameDriverAppPreferenceController.java
index d4cd2f1..3877c45 100644
--- a/src/com/android/settings/development/gup/GupPreferenceController.java
+++ b/src/com/android/settings/development/gamedriver/GameDriverAppPreferenceController.java
@@ -14,13 +14,18 @@
* limitations under the License.
*/
-package com.android.settings.development.gup;
+package com.android.settings.development.gamedriver;
+
+import static com.android.settings.development.gamedriver.GameDriverEnableForAllAppsPreferenceController.GAME_DRIVER_DEFAULT;
+import static com.android.settings.development.gamedriver.GameDriverEnableForAllAppsPreferenceController.GAME_DRIVER_OFF;
import android.content.ContentResolver;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.res.Resources;
+import android.os.Handler;
+import android.os.Looper;
import android.provider.Settings;
import androidx.annotation.VisibleForTesting;
@@ -31,6 +36,9 @@
import com.android.settings.R;
import com.android.settings.core.BasePreferenceController;
+import com.android.settingslib.core.lifecycle.LifecycleObserver;
+import com.android.settingslib.core.lifecycle.events.OnStart;
+import com.android.settingslib.core.lifecycle.events.OnStop;
import com.android.settingslib.development.DevelopmentSettingsEnabler;
import java.text.Collator;
@@ -42,62 +50,94 @@
import java.util.List;
import java.util.Set;
-public class GupPreferenceController
- extends BasePreferenceController implements Preference.OnPreferenceChangeListener {
+/**
+ * Controller of all the per App based list preferences.
+ */
+public class GameDriverAppPreferenceController extends BasePreferenceController
+ implements Preference.OnPreferenceChangeListener,
+ GameDriverContentObserver.OnGameDriverContentChangedListener, LifecycleObserver,
+ OnStart, OnStop {
+
+ private final Context mContext;
+ private final ContentResolver mContentResolver;
private final CharSequence[] mEntryList;
private final String mPreferenceTitle;
private final String mPreferenceDefault;
- private final String mPreferenceGup;
+ private final String mPreferenceGameDriver;
private final String mPreferenceSystem;
+ @VisibleForTesting
+ GameDriverContentObserver mGameDriverContentObserver;
private final List<AppInfo> mAppInfos;
private final Set<String> mDevOptInApps;
private final Set<String> mDevOptOutApps;
- public GupPreferenceController(Context context, String key) {
+ private PreferenceGroup mPreferenceGroup;
+
+ public GameDriverAppPreferenceController(Context context, String key) {
super(context, key);
+ mContext = context;
+ mContentResolver = context.getContentResolver();
+ mGameDriverContentObserver =
+ new GameDriverContentObserver(new Handler(Looper.getMainLooper()), this);
+
final Resources resources = context.getResources();
- mEntryList = resources.getStringArray(R.array.gup_app_preference_values);
- mPreferenceTitle = resources.getString(R.string.gup_app_preference_title);
- mPreferenceDefault = resources.getString(R.string.gup_app_preference_default);
- mPreferenceGup = resources.getString(R.string.gup_app_preference_gup);
- mPreferenceSystem = resources.getString(R.string.gup_app_preference_system);
+ mEntryList = resources.getStringArray(R.array.game_driver_app_preference_values);
+ mPreferenceTitle = resources.getString(R.string.game_driver_app_preference_title);
+ mPreferenceDefault = resources.getString(R.string.game_driver_app_preference_default);
+ mPreferenceGameDriver =
+ resources.getString(R.string.game_driver_app_preference_game_driver);
+ mPreferenceSystem = resources.getString(R.string.game_driver_app_preference_system);
// TODO: Move this task to background if there's potential ANR/Jank.
// Update the UI when all the app infos are ready.
mAppInfos = getAppInfos(context);
- final ContentResolver contentResolver = context.getContentResolver();
mDevOptInApps =
- getGlobalSettingsString(contentResolver, Settings.Global.GUP_DEV_OPT_IN_APPS);
+ getGlobalSettingsString(mContentResolver, Settings.Global.GAME_DRIVER_OPT_IN_APPS);
mDevOptOutApps =
- getGlobalSettingsString(contentResolver, Settings.Global.GUP_DEV_OPT_OUT_APPS);
+ getGlobalSettingsString(mContentResolver, Settings.Global.GAME_DRIVER_OPT_OUT_APPS);
}
@Override
public int getAvailabilityStatus() {
return DevelopmentSettingsEnabler.isDevelopmentSettingsEnabled(mContext)
+ && (Settings.Global.getInt(mContentResolver,
+ Settings.Global.GAME_DRIVER_ALL_APPS, GAME_DRIVER_DEFAULT)
+ != GAME_DRIVER_OFF)
? AVAILABLE
- : DISABLED_DEPENDENT_SETTING;
+ : CONDITIONALLY_UNAVAILABLE;
}
@Override
public void displayPreference(PreferenceScreen screen) {
super.displayPreference(screen);
- final PreferenceGroup preferenceGroup =
- (PreferenceGroup) screen.findPreference(getPreferenceKey());
- if (preferenceGroup == null) {
- return;
- }
+ mPreferenceGroup = (PreferenceGroup) screen.findPreference(getPreferenceKey());
+ final Context context = mPreferenceGroup.getContext();
for (AppInfo appInfo : mAppInfos) {
- preferenceGroup.addPreference(
- createListPreference(appInfo.info.packageName, appInfo.label));
+ mPreferenceGroup.addPreference(
+ createListPreference(context, appInfo.info.packageName, appInfo.label));
}
}
@Override
+ public void onStart() {
+ mGameDriverContentObserver.register(mContentResolver);
+ }
+
+ @Override
+ public void onStop() {
+ mGameDriverContentObserver.unregister(mContentResolver);
+ }
+
+ @Override
+ public void updateState(Preference preference) {
+ preference.setVisible(isAvailable());
+ }
+
+ @Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
final ListPreference listPref = (ListPreference) preference;
final String value = newValue.toString();
@@ -108,7 +148,7 @@
if (value.equals(mPreferenceSystem)) {
mDevOptInApps.remove(packageName);
mDevOptOutApps.add(packageName);
- } else if (value.equals(mPreferenceGup)) {
+ } else if (value.equals(mPreferenceGameDriver)) {
mDevOptInApps.add(packageName);
mDevOptOutApps.remove(packageName);
} else {
@@ -119,15 +159,20 @@
listPref.setSummary(value);
// Push the updated Sets for opt-in and opt-out apps to
- // corresponding Settings.Global.GUP_DEV_OPT_(IN|OUT)_APPS
- Settings.Global.putString(mContext.getContentResolver(),
- Settings.Global.GUP_DEV_OPT_IN_APPS, String.join(",", mDevOptInApps));
- Settings.Global.putString(mContext.getContentResolver(),
- Settings.Global.GUP_DEV_OPT_OUT_APPS, String.join(",", mDevOptOutApps));
+ // corresponding Settings.Global.GAME_DRIVER_OPT_(IN|OUT)_APPS
+ Settings.Global.putString(mContentResolver, Settings.Global.GAME_DRIVER_OPT_IN_APPS,
+ String.join(",", mDevOptInApps));
+ Settings.Global.putString(mContentResolver, Settings.Global.GAME_DRIVER_OPT_OUT_APPS,
+ String.join(",", mDevOptOutApps));
return true;
}
+ @Override
+ public void onGameDriverContentChanged() {
+ updateState(mPreferenceGroup);
+ }
+
// AppInfo class to achieve loading the application label only once
class AppInfo {
AppInfo(PackageManager packageManager, ApplicationInfo applicationInfo) {
@@ -176,8 +221,9 @@
};
@VisibleForTesting
- protected ListPreference createListPreference(String packageName, String appName) {
- final ListPreference listPreference = new ListPreference(mContext);
+ protected ListPreference createListPreference(
+ Context context, String packageName, String appName) {
+ final ListPreference listPreference = new ListPreference(context);
listPreference.setKey(packageName);
listPreference.setTitle(appName);
@@ -186,13 +232,13 @@
listPreference.setEntryValues(mEntryList);
// Initialize preference default and summary with the opt in/out choices
- // from Settings.Global.GUP_DEV_OPT_(IN|OUT)_APPS
+ // from Settings.Global.GAME_DRIVER_OPT_(IN|OUT)_APPS
if (mDevOptOutApps.contains(packageName)) {
listPreference.setValue(mPreferenceSystem);
listPreference.setSummary(mPreferenceSystem);
} else if (mDevOptInApps.contains(packageName)) {
- listPreference.setValue(mPreferenceGup);
- listPreference.setSummary(mPreferenceGup);
+ listPreference.setValue(mPreferenceGameDriver);
+ listPreference.setSummary(mPreferenceGameDriver);
} else {
listPreference.setValue(mPreferenceDefault);
listPreference.setSummary(mPreferenceDefault);
diff --git a/src/com/android/settings/development/gamedriver/GameDriverContentObserver.java b/src/com/android/settings/development/gamedriver/GameDriverContentObserver.java
new file mode 100644
index 0000000..e31e046
--- /dev/null
+++ b/src/com/android/settings/development/gamedriver/GameDriverContentObserver.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.development.gamedriver;
+
+import android.content.ContentResolver;
+import android.database.ContentObserver;
+import android.os.Handler;
+import android.provider.Settings;
+
+import androidx.annotation.VisibleForTesting;
+
+/**
+ * Helper class to observe Game Driver settings global change.
+ */
+public class GameDriverContentObserver extends ContentObserver {
+
+ interface OnGameDriverContentChangedListener {
+ void onGameDriverContentChanged();
+ }
+
+ @VisibleForTesting
+ OnGameDriverContentChangedListener mListener;
+
+ public GameDriverContentObserver(Handler handler, OnGameDriverContentChangedListener listener) {
+ super(handler);
+ mListener = listener;
+ }
+
+ @Override
+ public void onChange(boolean selfChange) {
+ super.onChange(selfChange);
+ mListener.onGameDriverContentChanged();
+ }
+
+ public void register(ContentResolver contentResolver) {
+ contentResolver.registerContentObserver(
+ Settings.Global.getUriFor(Settings.Global.GAME_DRIVER_ALL_APPS), false, this);
+ }
+
+ public void unregister(ContentResolver contentResolver) {
+ contentResolver.unregisterContentObserver(this);
+ }
+}
diff --git a/src/com/android/settings/development/gup/GupDashboard.java b/src/com/android/settings/development/gamedriver/GameDriverDashboard.java
similarity index 65%
rename from src/com/android/settings/development/gup/GupDashboard.java
rename to src/com/android/settings/development/gamedriver/GameDriverDashboard.java
index 0ab57e6..db456bd 100644
--- a/src/com/android/settings/development/gup/GupDashboard.java
+++ b/src/com/android/settings/development/gamedriver/GameDriverDashboard.java
@@ -14,29 +14,37 @@
* limitations under the License.
*/
-package com.android.settings.development.gup;
+package com.android.settings.development.gamedriver;
import android.app.settings.SettingsEnums;
import android.content.Context;
+import android.os.Bundle;
import android.provider.SearchIndexableResource;
import com.android.settings.R;
+import com.android.settings.SettingsActivity;
import com.android.settings.dashboard.DashboardFragment;
import com.android.settings.search.BaseSearchIndexProvider;
import com.android.settings.search.Indexable;
+import com.android.settings.widget.SwitchBar;
+import com.android.settings.widget.SwitchBarController;
import com.android.settingslib.development.DevelopmentSettingsEnabler;
import com.android.settingslib.search.SearchIndexable;
import java.util.ArrayList;
import java.util.List;
+/**
+ * Dashboard for Game Driver preferences.
+ */
@SearchIndexable
-public class GupDashboard extends DashboardFragment {
- private static final String TAG = "GupDashboard";
+public class GameDriverDashboard extends DashboardFragment {
+
+ private static final String TAG = "GameDriverDashboard";
@Override
public int getMetricsCategory() {
- return SettingsEnums.SETTINGS_GUP_DASHBOARD;
+ return SettingsEnums.SETTINGS_GAME_DRIVER_DASHBOARD;
}
@Override
@@ -46,7 +54,7 @@
@Override
protected int getPreferenceScreenResId() {
- return R.xml.gup_settings;
+ return R.xml.game_driver_settings;
}
@Override
@@ -54,6 +62,19 @@
return 0;
}
+ @Override
+ public void onActivityCreated(Bundle savedInstanceState) {
+ super.onActivityCreated(savedInstanceState);
+
+ final SettingsActivity activity = (SettingsActivity) getActivity();
+ final SwitchBar switchBar = activity.getSwitchBar();
+ final GameDriverGlobalSwitchBarController switchBarController =
+ new GameDriverGlobalSwitchBarController(
+ activity, new SwitchBarController(switchBar));
+ getSettingsLifecycle().addObserver(switchBarController);
+ switchBar.show();
+ }
+
public static final Indexable.SearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
new BaseSearchIndexProvider() {
@Override
@@ -61,7 +82,7 @@
Context context, boolean enabled) {
final List<SearchIndexableResource> result = new ArrayList<>();
final SearchIndexableResource sir = new SearchIndexableResource(context);
- sir.xmlResId = R.xml.gup_settings;
+ sir.xmlResId = R.xml.game_driver_settings;
result.add(sir);
return result;
}
diff --git a/src/com/android/settings/development/gamedriver/GameDriverEnableForAllAppsPreferenceController.java b/src/com/android/settings/development/gamedriver/GameDriverEnableForAllAppsPreferenceController.java
new file mode 100644
index 0000000..68be526
--- /dev/null
+++ b/src/com/android/settings/development/gamedriver/GameDriverEnableForAllAppsPreferenceController.java
@@ -0,0 +1,111 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.development.gamedriver;
+
+import android.content.ContentResolver;
+import android.content.Context;
+import android.os.Handler;
+import android.os.Looper;
+import android.provider.Settings;
+
+import androidx.annotation.VisibleForTesting;
+import androidx.preference.Preference;
+import androidx.preference.PreferenceScreen;
+import androidx.preference.SwitchPreference;
+
+import com.android.settings.core.BasePreferenceController;
+import com.android.settingslib.core.lifecycle.LifecycleObserver;
+import com.android.settingslib.core.lifecycle.events.OnStart;
+import com.android.settingslib.core.lifecycle.events.OnStop;
+import com.android.settingslib.development.DevelopmentSettingsEnabler;
+
+/**
+ * Controller of global switch to enable Game Driver for all Apps.
+ */
+public class GameDriverEnableForAllAppsPreferenceController extends BasePreferenceController
+ implements Preference.OnPreferenceChangeListener,
+ GameDriverContentObserver.OnGameDriverContentChangedListener, LifecycleObserver,
+ OnStart, OnStop {
+
+ public static final int GAME_DRIVER_DEFAULT = 0;
+ public static final int GAME_DRIVER_ALL_APPS = 1;
+ public static final int GAME_DRIVER_OFF = 2;
+
+ private final Context mContext;
+ private final ContentResolver mContentResolver;
+ @VisibleForTesting
+ GameDriverContentObserver mGameDriverContentObserver;
+
+ private SwitchPreference mPreference;
+
+ public GameDriverEnableForAllAppsPreferenceController(Context context, String key) {
+ super(context, key);
+ mContext = context;
+ mContentResolver = context.getContentResolver();
+ mGameDriverContentObserver =
+ new GameDriverContentObserver(new Handler(Looper.getMainLooper()), this);
+ }
+
+ @Override
+ public int getAvailabilityStatus() {
+ return DevelopmentSettingsEnabler.isDevelopmentSettingsEnabled(mContext)
+ && (Settings.Global.getInt(mContentResolver,
+ Settings.Global.GAME_DRIVER_ALL_APPS, GAME_DRIVER_DEFAULT)
+ != GAME_DRIVER_OFF)
+ ? AVAILABLE
+ : CONDITIONALLY_UNAVAILABLE;
+ }
+
+ @Override
+ public void displayPreference(PreferenceScreen screen) {
+ super.displayPreference(screen);
+ mPreference = screen.findPreference(getPreferenceKey());
+ }
+
+ @Override
+ public void onStart() {
+ mGameDriverContentObserver.register(mContentResolver);
+ }
+
+ @Override
+ public void onStop() {
+ mGameDriverContentObserver.unregister(mContentResolver);
+ }
+
+ @Override
+ public void updateState(Preference preference) {
+ final SwitchPreference switchPreference = (SwitchPreference) preference;
+ switchPreference.setVisible(isAvailable());
+ switchPreference.setChecked(
+ Settings.Global.getInt(
+ mContentResolver, Settings.Global.GAME_DRIVER_ALL_APPS, GAME_DRIVER_DEFAULT)
+ == GAME_DRIVER_ALL_APPS);
+ }
+
+ @Override
+ public boolean onPreferenceChange(Preference preference, Object newValue) {
+ Settings.Global.putInt(mContentResolver, Settings.Global.GAME_DRIVER_ALL_APPS,
+ (boolean) newValue ? GAME_DRIVER_ALL_APPS : GAME_DRIVER_DEFAULT);
+
+ return true;
+ }
+
+ @Override
+ public void onGameDriverContentChanged() {
+ updateState(mPreference);
+ }
+}
diff --git a/src/com/android/settings/development/gamedriver/GameDriverFooterPreferenceController.java b/src/com/android/settings/development/gamedriver/GameDriverFooterPreferenceController.java
new file mode 100644
index 0000000..12156df
--- /dev/null
+++ b/src/com/android/settings/development/gamedriver/GameDriverFooterPreferenceController.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.development.gamedriver;
+
+import static com.android.settings.development.gamedriver.GameDriverEnableForAllAppsPreferenceController.GAME_DRIVER_DEFAULT;
+import static com.android.settings.development.gamedriver.GameDriverEnableForAllAppsPreferenceController.GAME_DRIVER_OFF;
+
+import android.content.ContentResolver;
+import android.content.Context;
+import android.os.Handler;
+import android.os.Looper;
+import android.provider.Settings;
+
+import androidx.annotation.VisibleForTesting;
+import androidx.preference.Preference;
+import androidx.preference.PreferenceScreen;
+
+import com.android.settings.core.BasePreferenceController;
+import com.android.settingslib.core.lifecycle.LifecycleObserver;
+import com.android.settingslib.core.lifecycle.events.OnStart;
+import com.android.settingslib.core.lifecycle.events.OnStop;
+import com.android.settingslib.widget.FooterPreference;
+
+/**
+ * Controller of footer preference for Game Driver.
+ */
+public class GameDriverFooterPreferenceController extends BasePreferenceController
+ implements GameDriverContentObserver.OnGameDriverContentChangedListener, LifecycleObserver,
+ OnStart, OnStop {
+
+ private final ContentResolver mContentResolver;
+ @VisibleForTesting
+ GameDriverContentObserver mGameDriverContentObserver;
+
+ private FooterPreference mPreference;
+
+ public GameDriverFooterPreferenceController(Context context) {
+ super(context, FooterPreference.KEY_FOOTER);
+ mContentResolver = context.getContentResolver();
+ mGameDriverContentObserver =
+ new GameDriverContentObserver(new Handler(Looper.getMainLooper()), this);
+ }
+
+ @Override
+ public int getAvailabilityStatus() {
+ return Settings.Global.getInt(
+ mContentResolver, Settings.Global.GAME_DRIVER_ALL_APPS, GAME_DRIVER_DEFAULT)
+ == GAME_DRIVER_OFF
+ ? AVAILABLE_UNSEARCHABLE
+ : CONDITIONALLY_UNAVAILABLE;
+ }
+
+ @Override
+ public void displayPreference(PreferenceScreen screen) {
+ super.displayPreference(screen);
+ mPreference = screen.findPreference(getPreferenceKey());
+ }
+
+ @Override
+ public void onStart() {
+ mGameDriverContentObserver.register(mContentResolver);
+ }
+
+ @Override
+ public void onStop() {
+ mGameDriverContentObserver.unregister(mContentResolver);
+ }
+
+ @Override
+ public void updateState(Preference preference) {
+ preference.setVisible(isAvailable());
+ }
+
+ @Override
+ public void onGameDriverContentChanged() {
+ updateState(mPreference);
+ }
+}
diff --git a/src/com/android/settings/development/gamedriver/GameDriverGlobalSwitchBarController.java b/src/com/android/settings/development/gamedriver/GameDriverGlobalSwitchBarController.java
new file mode 100644
index 0000000..125d95b
--- /dev/null
+++ b/src/com/android/settings/development/gamedriver/GameDriverGlobalSwitchBarController.java
@@ -0,0 +1,105 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.development.gamedriver;
+
+import static com.android.settings.development.gamedriver.GameDriverEnableForAllAppsPreferenceController.GAME_DRIVER_ALL_APPS;
+import static com.android.settings.development.gamedriver.GameDriverEnableForAllAppsPreferenceController.GAME_DRIVER_DEFAULT;
+import static com.android.settings.development.gamedriver.GameDriverEnableForAllAppsPreferenceController.GAME_DRIVER_OFF;
+
+import android.content.ContentResolver;
+import android.content.Context;
+import android.os.Handler;
+import android.os.Looper;
+import android.provider.Settings;
+
+import androidx.annotation.VisibleForTesting;
+
+import com.android.settings.widget.SwitchWidgetController;
+import com.android.settingslib.core.lifecycle.LifecycleObserver;
+import com.android.settingslib.core.lifecycle.events.OnStart;
+import com.android.settingslib.core.lifecycle.events.OnStop;
+import com.android.settingslib.development.DevelopmentSettingsEnabler;
+
+/**
+ * Controller of global switch bar used to fully turn off Game Driver.
+ */
+public class GameDriverGlobalSwitchBarController
+ implements SwitchWidgetController.OnSwitchChangeListener,
+ GameDriverContentObserver.OnGameDriverContentChangedListener, LifecycleObserver,
+ OnStart, OnStop {
+
+ private final Context mContext;
+ private final ContentResolver mContentResolver;
+ @VisibleForTesting
+ SwitchWidgetController mSwitchWidgetController;
+ @VisibleForTesting
+ GameDriverContentObserver mGameDriverContentObserver;
+
+ GameDriverGlobalSwitchBarController(
+ Context context, SwitchWidgetController switchWidgetController) {
+ mContext = context;
+ mContentResolver = context.getContentResolver();
+ mGameDriverContentObserver =
+ new GameDriverContentObserver(new Handler(Looper.getMainLooper()), this);
+ mSwitchWidgetController = switchWidgetController;
+ mSwitchWidgetController.setEnabled(
+ DevelopmentSettingsEnabler.isDevelopmentSettingsEnabled(context));
+ mSwitchWidgetController.setChecked(
+ Settings.Global.getInt(
+ mContentResolver, Settings.Global.GAME_DRIVER_ALL_APPS, GAME_DRIVER_DEFAULT)
+ != GAME_DRIVER_OFF);
+ mSwitchWidgetController.setListener(this);
+ }
+
+ @Override
+ public void onStart() {
+ mSwitchWidgetController.startListening();
+ mGameDriverContentObserver.register(mContentResolver);
+ }
+
+ @Override
+ public void onStop() {
+ mSwitchWidgetController.stopListening();
+ mGameDriverContentObserver.unregister(mContentResolver);
+ }
+
+ @Override
+ public boolean onSwitchToggled(boolean isChecked) {
+ if (!isChecked) {
+ Settings.Global.putInt(
+ mContentResolver, Settings.Global.GAME_DRIVER_ALL_APPS, GAME_DRIVER_OFF);
+ return true;
+ }
+
+ if (Settings.Global.getInt(
+ mContentResolver, Settings.Global.GAME_DRIVER_ALL_APPS, GAME_DRIVER_DEFAULT)
+ != GAME_DRIVER_ALL_APPS) {
+ Settings.Global.putInt(
+ mContentResolver, Settings.Global.GAME_DRIVER_ALL_APPS, GAME_DRIVER_DEFAULT);
+ }
+
+ return true;
+ }
+
+ @Override
+ public void onGameDriverContentChanged() {
+ mSwitchWidgetController.setChecked(
+ Settings.Global.getInt(
+ mContentResolver, Settings.Global.GAME_DRIVER_ALL_APPS, GAME_DRIVER_DEFAULT)
+ != GAME_DRIVER_OFF);
+ }
+}
diff --git a/src/com/android/settings/development/gup/GupEnableForAllAppsPreferenceController.java b/src/com/android/settings/development/gup/GupEnableForAllAppsPreferenceController.java
deleted file mode 100644
index 43a28b6..0000000
--- a/src/com/android/settings/development/gup/GupEnableForAllAppsPreferenceController.java
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * Copyright 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.settings.development.gup;
-
-import android.content.ContentResolver;
-import android.content.Context;
-import android.provider.Settings;
-
-import androidx.preference.Preference;
-import androidx.preference.PreferenceScreen;
-import androidx.preference.SwitchPreference;
-
-import com.android.settings.core.BasePreferenceController;
-import com.android.settingslib.development.DevelopmentSettingsEnabler;
-
-public class GupEnableForAllAppsPreferenceController
- extends BasePreferenceController implements Preference.OnPreferenceChangeListener {
- public static final int GUP_DEFAULT = 0;
- public static final int GUP_ALL_APPS = 1;
-
- private final ContentResolver mContentResolver;
-
- public GupEnableForAllAppsPreferenceController(Context context, String key) {
- super(context, key);
- mContentResolver = context.getContentResolver();
- }
-
- @Override
- public int getAvailabilityStatus() {
- return DevelopmentSettingsEnabler.isDevelopmentSettingsEnabled(mContext)
- ? AVAILABLE
- : DISABLED_DEPENDENT_SETTING;
- }
-
- @Override
- public void displayPreference(PreferenceScreen screen) {
- super.displayPreference(screen);
- final SwitchPreference switchPreference = screen.findPreference(getPreferenceKey());
- if (switchPreference == null) {
- return;
- }
-
- switchPreference.setChecked(Settings.Global.getInt(mContentResolver,
- Settings.Global.GUP_DEV_ALL_APPS, GUP_DEFAULT)
- == GUP_ALL_APPS);
- switchPreference.setOnPreferenceChangeListener(this);
- }
-
- @Override
- public boolean onPreferenceChange(Preference preference, Object newValue) {
- // When developer option is present, always overwrite GUP_DEV_ALL_APPS.
- Settings.Global.putInt(mContentResolver, Settings.Global.GUP_DEV_ALL_APPS,
- (boolean) newValue ? GUP_ALL_APPS : GUP_DEFAULT);
-
- return true;
- }
-}
diff --git a/src/com/android/settings/deviceinfo/BrandedAccountPreferenceController.java b/src/com/android/settings/deviceinfo/BrandedAccountPreferenceController.java
index b54b398..bdd76fc 100644
--- a/src/com/android/settings/deviceinfo/BrandedAccountPreferenceController.java
+++ b/src/com/android/settings/deviceinfo/BrandedAccountPreferenceController.java
@@ -32,11 +32,10 @@
import com.android.settings.overlay.FeatureFactory;
public class BrandedAccountPreferenceController extends BasePreferenceController {
- private static final String KEY_PREFERENCE_TITLE = "branded_account";
private final Account[] mAccounts;
- public BrandedAccountPreferenceController(Context context) {
- super(context, KEY_PREFERENCE_TITLE);
+ public BrandedAccountPreferenceController(Context context, String key) {
+ super(context, key);
final AccountFeatureProvider accountFeatureProvider = FeatureFactory.getFactory(
mContext).getAccountFeatureProvider();
mAccounts = accountFeatureProvider.getAccounts(mContext);
@@ -44,6 +43,10 @@
@Override
public int getAvailabilityStatus() {
+ if (!mContext.getResources().getBoolean(
+ R.bool.config_show_branded_account_in_device_info)) {
+ return UNSUPPORTED_ON_DEVICE;
+ }
if (mAccounts != null && mAccounts.length > 0) {
return AVAILABLE;
}
@@ -55,7 +58,7 @@
super.displayPreference(screen);
final AccountFeatureProvider accountFeatureProvider = FeatureFactory.getFactory(
mContext).getAccountFeatureProvider();
- final Preference accountPreference = screen.findPreference(KEY_PREFERENCE_TITLE);
+ final Preference accountPreference = screen.findPreference(getPreferenceKey());
if (accountPreference != null && (mAccounts == null || mAccounts.length == 0)) {
screen.removePreference(accountPreference);
return;
diff --git a/src/com/android/settings/deviceinfo/DeviceNamePreferenceController.java b/src/com/android/settings/deviceinfo/DeviceNamePreferenceController.java
index 0d7b1d3..fb20a2e 100644
--- a/src/com/android/settings/deviceinfo/DeviceNamePreferenceController.java
+++ b/src/com/android/settings/deviceinfo/DeviceNamePreferenceController.java
@@ -43,8 +43,6 @@
LifecycleObserver,
OnSaveInstanceState,
OnCreate {
- private static final String PREF_KEY = "device_name";
- public static final int DEVICE_NAME_SET_WARNING_ID = 1;
private static final String KEY_PENDING_DEVICE_NAME = "key_pending_device_name";
private String mDeviceName;
protected WifiManager mWifiManager;
@@ -54,8 +52,8 @@
private DeviceNamePreferenceHost mHost;
private String mPendingDeviceName;
- public DeviceNamePreferenceController(Context context) {
- super(context, PREF_KEY);
+ public DeviceNamePreferenceController(Context context, String key) {
+ super(context, key);
mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
mWifiDeviceNameTextValidator = new WifiDeviceNameTextValidator();
@@ -67,7 +65,7 @@
@Override
public void displayPreference(PreferenceScreen screen) {
super.displayPreference(screen);
- mPreference = (ValidatedEditTextPreference) screen.findPreference(PREF_KEY);
+ mPreference = screen.findPreference(getPreferenceKey());
final CharSequence deviceName = getSummary();
mPreference.setSummary(deviceName);
mPreference.setText(deviceName.toString());
@@ -95,11 +93,6 @@
}
@Override
- public String getPreferenceKey() {
- return PREF_KEY;
- }
-
- @Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
mPendingDeviceName = (String) newValue;
if (mHost != null) {
diff --git a/src/com/android/settings/deviceinfo/StorageWizardBase.java b/src/com/android/settings/deviceinfo/StorageWizardBase.java
index db0d0d0..48cdeeb 100644
--- a/src/com/android/settings/deviceinfo/StorageWizardBase.java
+++ b/src/com/android/settings/deviceinfo/StorageWizardBase.java
@@ -44,8 +44,8 @@
import com.android.settings.R;
import com.android.settingslib.Utils;
-import com.google.android.setupcompat.item.FooterButton;
-import com.google.android.setupcompat.template.ButtonFooterMixin;
+import com.google.android.setupcompat.template.FooterBarMixin;
+import com.google.android.setupcompat.template.FooterButton;
import com.google.android.setupdesign.GlifLayout;
import java.text.NumberFormat;
@@ -63,7 +63,7 @@
protected VolumeInfo mVolume;
protected DiskInfo mDisk;
- private ButtonFooterMixin mButtonFooterMixin;
+ private FooterBarMixin mFooterBarMixin;
private FooterButton mBack;
private FooterButton mNext;
@@ -94,8 +94,8 @@
public void setContentView(@LayoutRes int layoutResID) {
super.setContentView(layoutResID);
- mButtonFooterMixin = getGlifLayout().getMixin(ButtonFooterMixin.class);
- mButtonFooterMixin.setSecondaryButton(
+ mFooterBarMixin = getGlifLayout().getMixin(FooterBarMixin.class);
+ mFooterBarMixin.setSecondaryButton(
new FooterButton.Builder(this)
.setText(R.string.wizard_back)
.setListener(this::onNavigateBack)
@@ -103,7 +103,7 @@
.setTheme(R.style.SudGlifButton_Secondary)
.build()
);
- mButtonFooterMixin.setPrimaryButton(
+ mFooterBarMixin.setPrimaryButton(
new FooterButton.Builder(this)
.setText(R.string.wizard_next)
.setListener(this::onNavigateNext)
@@ -111,8 +111,8 @@
.setTheme(R.style.SudGlifButton_Primary)
.build()
);
- mBack = mButtonFooterMixin.getSecondaryButton();
- mNext = mButtonFooterMixin.getPrimaryButton();
+ mBack = mFooterBarMixin.getSecondaryButton();
+ mNext = mFooterBarMixin.getPrimaryButton();
setIcon(com.android.internal.R.drawable.ic_sd_card_48dp);
}
diff --git a/src/com/android/settings/deviceinfo/aboutphone/MyDeviceInfoFragment.java b/src/com/android/settings/deviceinfo/aboutphone/MyDeviceInfoFragment.java
index b61cb3c..0116c42 100644
--- a/src/com/android/settings/deviceinfo/aboutphone/MyDeviceInfoFragment.java
+++ b/src/com/android/settings/deviceinfo/aboutphone/MyDeviceInfoFragment.java
@@ -28,10 +28,8 @@
import com.android.settings.R;
import com.android.settings.Utils;
-import com.android.settings.accounts.EmergencyInfoPreferenceController;
import com.android.settings.dashboard.DashboardFragment;
import com.android.settings.deviceinfo.BluetoothAddressPreferenceController;
-import com.android.settings.deviceinfo.BrandedAccountPreferenceController;
import com.android.settings.deviceinfo.BuildNumberPreferenceController;
import com.android.settings.deviceinfo.DeviceModelPreferenceController;
import com.android.settings.deviceinfo.DeviceNamePreferenceController;
@@ -82,6 +80,7 @@
use(FirmwareVersionPreferenceController.class).setHost(this /* parent */);
use(DeviceModelPreferenceController.class).setHost(this /* parent */);
use(ImeiInfoPreferenceController.class).setHost(this /* parent */);
+ use(DeviceNamePreferenceController.class).setHost(this /* parent */);
mBuildNumberPreferenceController = use(BuildNumberPreferenceController.class);
mBuildNumberPreferenceController.setHost(this /* parent */);
}
@@ -104,23 +103,12 @@
@Override
protected List<AbstractPreferenceController> createPreferenceControllers(Context context) {
- return buildPreferenceControllers(context, getActivity(), this /* fragment */,
- getSettingsLifecycle());
+ return buildPreferenceControllers(context, this /* fragment */, getSettingsLifecycle());
}
private static List<AbstractPreferenceController> buildPreferenceControllers(
- Context context, Activity activity, MyDeviceInfoFragment fragment,
- Lifecycle lifecycle) {
+ Context context, MyDeviceInfoFragment fragment, Lifecycle lifecycle) {
final List<AbstractPreferenceController> controllers = new ArrayList<>();
- controllers.add(new EmergencyInfoPreferenceController(context));
- controllers.add(new BrandedAccountPreferenceController(context));
- DeviceNamePreferenceController deviceNamePreferenceController =
- new DeviceNamePreferenceController(context);
- deviceNamePreferenceController.setHost(fragment);
- if (lifecycle != null) {
- lifecycle.addObserver(deviceNamePreferenceController);
- }
- controllers.add(deviceNamePreferenceController);
controllers.add(new SimStatusPreferenceController(context, fragment));
controllers.add(new IpAddressPreferenceController(context, lifecycle));
controllers.add(new WifiMacAddressPreferenceController(context, lifecycle));
@@ -145,12 +133,18 @@
private void initHeader() {
// TODO: Migrate into its own controller.
final LayoutPreference headerPreference =
- (LayoutPreference) getPreferenceScreen().findPreference(KEY_MY_DEVICE_INFO_HEADER);
- final View appSnippet = headerPreference.findViewById(R.id.entity_header);
+ getPreferenceScreen().findPreference(KEY_MY_DEVICE_INFO_HEADER);
+ final boolean shouldDisplayHeader = getContext().getResources().getBoolean(
+ R.bool.config_show_device_header_in_device_info);
+ headerPreference.setVisible(shouldDisplayHeader);
+ if (!shouldDisplayHeader) {
+ return;
+ }
+ final View headerView = headerPreference.findViewById(R.id.entity_header);
final Activity context = getActivity();
final Bundle bundle = getArguments();
final EntityHeaderController controller = EntityHeaderController
- .newInstance(context, this, appSnippet)
+ .newInstance(context, this, headerView)
.setRecyclerView(getListView(), getSettingsLifecycle())
.setButtonActions(EntityHeaderController.ActionType.ACTION_NONE,
EntityHeaderController.ActionType.ACTION_NONE);
@@ -197,8 +191,8 @@
@Override
public List<AbstractPreferenceController> createPreferenceControllers(
Context context) {
- return buildPreferenceControllers(context, null /* activity */,
- null /* fragment */, null /* lifecycle */);
+ return buildPreferenceControllers(context, null /* fragment */,
+ null /* lifecycle */);
}
};
}
diff --git a/src/com/android/settings/deviceinfo/aboutphone/TopLevelAboutDevicePreferenceController.java b/src/com/android/settings/deviceinfo/aboutphone/TopLevelAboutDevicePreferenceController.java
index d2ffd0d..dbee443 100644
--- a/src/com/android/settings/deviceinfo/aboutphone/TopLevelAboutDevicePreferenceController.java
+++ b/src/com/android/settings/deviceinfo/aboutphone/TopLevelAboutDevicePreferenceController.java
@@ -35,7 +35,7 @@
@Override
public CharSequence getSummary() {
final DeviceNamePreferenceController deviceNamePreferenceController =
- new DeviceNamePreferenceController(mContext);
+ new DeviceNamePreferenceController(mContext, "dummy_key");
return deviceNamePreferenceController.getSummary();
}
}
diff --git a/src/com/android/settings/deviceinfo/firmwareversion/FirmwareVersionDialogFragment.java b/src/com/android/settings/deviceinfo/firmwareversion/FirmwareVersionDialogFragment.java
index f615968..2093c3e 100644
--- a/src/com/android/settings/deviceinfo/firmwareversion/FirmwareVersionDialogFragment.java
+++ b/src/com/android/settings/deviceinfo/firmwareversion/FirmwareVersionDialogFragment.java
@@ -90,5 +90,6 @@
new BasebandVersionDialogController(this).initialize();
new KernelVersionDialogController(this).initialize();
new BuildNumberDialogController(this).initialize();
+ new ModuleVersionDialogController(this).initialize();
}
}
diff --git a/src/com/android/settings/deviceinfo/firmwareversion/ModuleVersionDialogController.java b/src/com/android/settings/deviceinfo/firmwareversion/ModuleVersionDialogController.java
new file mode 100644
index 0000000..d6fcc38
--- /dev/null
+++ b/src/com/android/settings/deviceinfo/firmwareversion/ModuleVersionDialogController.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.deviceinfo.firmwareversion;
+
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.text.TextUtils;
+import android.util.Log;
+
+import com.android.settings.R;
+
+import androidx.annotation.VisibleForTesting;
+
+public class ModuleVersionDialogController {
+
+ private static final String TAG = "MainlineModuleControl";
+
+ @VisibleForTesting
+ static final int MODULE_VERSION_LABEL_ID = R.id.module_version_label;
+ @VisibleForTesting
+ static final int MODULE_VERSION_VALUE_ID = R.id.module_version_value;
+
+ private final FirmwareVersionDialogFragment mDialog;
+ private final Context mContext;
+ private final PackageManager mPackageManager;
+
+ public ModuleVersionDialogController(FirmwareVersionDialogFragment dialog) {
+ mDialog = dialog;
+ mContext = mDialog.getContext();
+ mPackageManager = mContext.getPackageManager();
+ }
+
+ /**
+ * Updates the mainline module version field of the dialog.
+ */
+ public void initialize() {
+ final String moduleProvider = mContext.getString(
+ com.android.internal.R.string.config_defaultModuleMetadataProvider);
+ if (!TextUtils.isEmpty(moduleProvider)) {
+ try {
+ mDialog.setText(MODULE_VERSION_VALUE_ID,
+ mPackageManager.getPackageInfo(moduleProvider, 0 /* flags */).versionName);
+ return;
+ } catch (PackageManager.NameNotFoundException e) {
+ Log.e(TAG, "Failed to get mainline version.", e);
+ }
+ }
+ mDialog.removeSettingFromScreen(MODULE_VERSION_LABEL_ID);
+ mDialog.removeSettingFromScreen(MODULE_VERSION_VALUE_ID);
+ }
+}
diff --git a/src/com/android/settings/display/AdaptiveSleepPreferenceController.java b/src/com/android/settings/display/AdaptiveSleepPreferenceController.java
new file mode 100644
index 0000000..97bdb9e
--- /dev/null
+++ b/src/com/android/settings/display/AdaptiveSleepPreferenceController.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+package com.android.settings.display;
+
+import static android.provider.Settings.System.ADAPTIVE_SLEEP;
+
+import android.content.Context;
+import android.provider.Settings;
+import android.text.TextUtils;
+
+import com.android.settings.R;
+import com.android.settings.core.TogglePreferenceController;
+
+
+public class AdaptiveSleepPreferenceController extends TogglePreferenceController {
+
+ private final String SYSTEM_KEY = ADAPTIVE_SLEEP;
+ private final int DEFAULT_VALUE = 0;
+
+ public AdaptiveSleepPreferenceController(Context context, String key) {
+ super(context, key);
+ }
+
+ @Override
+ public boolean isChecked() {
+ return Settings.System.getInt(mContext.getContentResolver(),
+ SYSTEM_KEY, DEFAULT_VALUE) != DEFAULT_VALUE;
+ }
+
+ @Override
+ public boolean setChecked(boolean isChecked) {
+ Settings.System.putInt(mContext.getContentResolver(), SYSTEM_KEY,
+ isChecked ? 1 : DEFAULT_VALUE);
+ return true;
+ }
+
+ @Override
+ @AvailabilityStatus
+ public int getAvailabilityStatus() {
+ return mContext.getResources().getBoolean(
+ com.android.internal.R.bool.config_adaptive_sleep_available)
+ ? AVAILABLE
+ : UNSUPPORTED_ON_DEVICE;
+ }
+
+ @Override
+ public boolean isSliceable() {
+ return true;
+ }
+
+ @Override
+ public CharSequence getSummary() {
+ return mContext.getText(isChecked()
+ ? R.string.adaptive_sleep_summary_on
+ : R.string.adaptive_sleep_summary_off);
+ }
+}
diff --git a/src/com/android/settings/gestures/SkipGestureSettings.java b/src/com/android/settings/display/AdaptiveSleepSettings.java
similarity index 68%
rename from src/com/android/settings/gestures/SkipGestureSettings.java
rename to src/com/android/settings/display/AdaptiveSleepSettings.java
index 7d1090b..097d7dc 100644
--- a/src/com/android/settings/gestures/SkipGestureSettings.java
+++ b/src/com/android/settings/display/AdaptiveSleepSettings.java
@@ -14,10 +14,11 @@
* limitations under the License.
*/
-package com.android.settings.gestures;
+package com.android.settings.display;
import android.app.settings.SettingsEnums;
import android.content.Context;
+import android.os.Bundle;
import android.provider.SearchIndexableResource;
import com.android.settings.R;
@@ -28,14 +29,21 @@
import java.util.Arrays;
import java.util.List;
-@SearchIndexable
-public class SkipGestureSettings extends DashboardFragment {
+@SearchIndexable(forTarget = SearchIndexable.ALL & ~SearchIndexable.ARC)
+public class AdaptiveSleepSettings extends DashboardFragment {
- private static final String TAG = "SkipGestureSettings";
+ private static final String TAG = "AdaptiveSleepSettings";
@Override
- public int getMetricsCategory() {
- return SettingsEnums.SETTINGS_GESTURE_SKIP;
+ public void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+ mFooterPreferenceMixin.createFooterPreference()
+ .setTitle(R.string.adaptive_sleep_description);
+ }
+
+ @Override
+ protected int getPreferenceScreenResId() {
+ return R.xml.adaptive_sleep_detail;
}
@Override
@@ -44,8 +52,13 @@
}
@Override
- protected int getPreferenceScreenResId() {
- return R.xml.skip_gesture_settings;
+ public int getMetricsCategory() {
+ return SettingsEnums.SETTINGS_ADAPTIVE_SLEEP;
+ }
+
+ @Override
+ public int getHelpResource() {
+ return R.string.help_url_adaptive_sleep;
}
public static final SearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
@@ -54,10 +67,8 @@
public List<SearchIndexableResource> getXmlResourcesToIndex(
Context context, boolean enabled) {
final SearchIndexableResource sir = new SearchIndexableResource(context);
- sir.xmlResId = R.xml.skip_gesture_settings;
+ sir.xmlResId = R.xml.adaptive_sleep_detail;
return Arrays.asList(sir);
}
};
-
}
-
diff --git a/src/com/android/settings/display/ColorModePreferenceController.java b/src/com/android/settings/display/ColorModePreferenceController.java
index 5d6a412..234cc98 100644
--- a/src/com/android/settings/display/ColorModePreferenceController.java
+++ b/src/com/android/settings/display/ColorModePreferenceController.java
@@ -18,14 +18,12 @@
import androidx.annotation.VisibleForTesting;
-import com.android.internal.app.ColorDisplayController;
import com.android.settings.R;
import com.android.settings.core.BasePreferenceController;
public class ColorModePreferenceController extends BasePreferenceController {
- private static final String TAG = "ColorModePreference";
- private ColorDisplayController mColorDisplayController;
+ private ColorDisplayManager mColorDisplayManager;
public ColorModePreferenceController(Context context, String key) {
super(context, key);
@@ -35,30 +33,30 @@
public int getAvailabilityStatus() {
return mContext.getSystemService(ColorDisplayManager.class)
.isDeviceColorManaged()
- && !getColorDisplayController().getAccessibilityTransformActivated() ?
+ && !ColorDisplayManager.areAccessibilityTransformsEnabled(mContext) ?
AVAILABLE_UNSEARCHABLE : DISABLED_FOR_USER;
}
@Override
public CharSequence getSummary() {
- final int colorMode = getColorDisplayController().getColorMode();
- if (colorMode == ColorDisplayController.COLOR_MODE_AUTOMATIC) {
+ final int colorMode = getColorDisplayManager().getColorMode();
+ if (colorMode == ColorDisplayManager.COLOR_MODE_AUTOMATIC) {
return mContext.getText(R.string.color_mode_option_automatic);
}
- if (colorMode == ColorDisplayController.COLOR_MODE_SATURATED) {
+ if (colorMode == ColorDisplayManager.COLOR_MODE_SATURATED) {
return mContext.getText(R.string.color_mode_option_saturated);
}
- if (colorMode == ColorDisplayController.COLOR_MODE_BOOSTED) {
+ if (colorMode == ColorDisplayManager.COLOR_MODE_BOOSTED) {
return mContext.getText(R.string.color_mode_option_boosted);
}
return mContext.getText(R.string.color_mode_option_natural);
}
@VisibleForTesting
- ColorDisplayController getColorDisplayController() {
- if (mColorDisplayController == null) {
- mColorDisplayController = new ColorDisplayController(mContext);
+ ColorDisplayManager getColorDisplayManager() {
+ if (mColorDisplayManager == null) {
+ mColorDisplayManager = mContext.getSystemService(ColorDisplayManager.class);
}
- return mColorDisplayController;
+ return mColorDisplayManager;
}
}
diff --git a/src/com/android/settings/display/ColorModePreferenceFragment.java b/src/com/android/settings/display/ColorModePreferenceFragment.java
index e8fc1c5..c28de73 100644
--- a/src/com/android/settings/display/ColorModePreferenceFragment.java
+++ b/src/com/android/settings/display/ColorModePreferenceFragment.java
@@ -14,14 +14,20 @@
package com.android.settings.display;
import android.app.settings.SettingsEnums;
+import android.content.ContentResolver;
import android.content.Context;
+import android.database.ContentObserver;
import android.graphics.drawable.Drawable;
+import android.hardware.display.ColorDisplayManager;
+import android.net.Uri;
+import android.os.Handler;
+import android.os.Looper;
import android.provider.SearchIndexableResource;
+import android.provider.Settings.Secure;
import androidx.annotation.VisibleForTesting;
import androidx.preference.PreferenceScreen;
-import com.android.internal.app.ColorDisplayController;
import com.android.settings.R;
import com.android.settings.search.BaseSearchIndexProvider;
import com.android.settings.search.Indexable;
@@ -36,8 +42,7 @@
@SuppressWarnings("WeakerAccess")
@SearchIndexable
-public class ColorModePreferenceFragment extends RadioButtonPickerFragment
- implements ColorDisplayController.Callback {
+public class ColorModePreferenceFragment extends RadioButtonPickerFragment {
@VisibleForTesting
static final String KEY_COLOR_MODE_NATURAL = "color_mode_natural";
@@ -48,21 +53,41 @@
@VisibleForTesting
static final String KEY_COLOR_MODE_AUTOMATIC = "color_mode_automatic";
- private ColorDisplayController mController;
+ private ContentObserver mContentObserver;
+ private ColorDisplayManager mColorDisplayManager;
@Override
public void onAttach(Context context) {
super.onAttach(context);
- mController = new ColorDisplayController(context);
- mController.setListener(this);
+
+ mColorDisplayManager = context.getSystemService(ColorDisplayManager.class);
+
+ final ContentResolver cr = context.getContentResolver();
+ mContentObserver = new ContentObserver(new Handler(Looper.getMainLooper())) {
+ @Override
+ public void onChange(boolean selfChange, Uri uri) {
+ super.onChange(selfChange, uri);
+ if (ColorDisplayManager.areAccessibilityTransformsEnabled(getContext())) {
+ // Color modes are not configurable when Accessibility transforms are enabled.
+ // Close this fragment in that case.
+ getActivity().finish();
+ }
+ }
+ };
+ cr.registerContentObserver(
+ Secure.getUriFor(Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED),
+ false /* notifyForDescendants */, mContentObserver, mUserId);
+ cr.registerContentObserver(
+ Secure.getUriFor(Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED),
+ false /* notifyForDescendants */, mContentObserver, mUserId);
}
@Override
public void onDetach() {
super.onDetach();
- if (mController != null) {
- mController.setListener(null);
- mController = null;
+ if (mContentObserver != null) {
+ getContext().getContentResolver().unregisterContentObserver(mContentObserver);
+ mContentObserver = null;
}
}
@@ -90,22 +115,22 @@
final int[] availableColorModes = c.getResources().getIntArray(
com.android.internal.R.array.config_availableColorModes);
- List<ColorModeCandidateInfo> candidates = new ArrayList<ColorModeCandidateInfo>();
+ List<ColorModeCandidateInfo> candidates = new ArrayList<>();
if (availableColorModes != null) {
for (int colorMode : availableColorModes) {
- if (colorMode == ColorDisplayController.COLOR_MODE_NATURAL) {
+ if (colorMode == ColorDisplayManager.COLOR_MODE_NATURAL) {
candidates.add(new ColorModeCandidateInfo(
c.getText(R.string.color_mode_option_natural),
KEY_COLOR_MODE_NATURAL, true /* enabled */));
- } else if (colorMode == ColorDisplayController.COLOR_MODE_BOOSTED) {
+ } else if (colorMode == ColorDisplayManager.COLOR_MODE_BOOSTED) {
candidates.add(new ColorModeCandidateInfo(
c.getText(R.string.color_mode_option_boosted),
KEY_COLOR_MODE_BOOSTED, true /* enabled */));
- } else if (colorMode == ColorDisplayController.COLOR_MODE_SATURATED) {
+ } else if (colorMode == ColorDisplayManager.COLOR_MODE_SATURATED) {
candidates.add(new ColorModeCandidateInfo(
c.getText(R.string.color_mode_option_saturated),
KEY_COLOR_MODE_SATURATED, true /* enabled */));
- } else if (colorMode == ColorDisplayController.COLOR_MODE_AUTOMATIC) {
+ } else if (colorMode == ColorDisplayManager.COLOR_MODE_AUTOMATIC) {
candidates.add(new ColorModeCandidateInfo(
c.getText(R.string.color_mode_option_automatic),
KEY_COLOR_MODE_AUTOMATIC, true /* enabled */));
@@ -117,12 +142,12 @@
@Override
protected String getDefaultKey() {
- final int colorMode = mController.getColorMode();
- if (colorMode == ColorDisplayController.COLOR_MODE_AUTOMATIC) {
+ final int colorMode = mColorDisplayManager.getColorMode();
+ if (colorMode == ColorDisplayManager.COLOR_MODE_AUTOMATIC) {
return KEY_COLOR_MODE_AUTOMATIC;
- } else if (colorMode == ColorDisplayController.COLOR_MODE_SATURATED) {
+ } else if (colorMode == ColorDisplayManager.COLOR_MODE_SATURATED) {
return KEY_COLOR_MODE_SATURATED;
- } else if (colorMode == ColorDisplayController.COLOR_MODE_BOOSTED) {
+ } else if (colorMode == ColorDisplayManager.COLOR_MODE_BOOSTED) {
return KEY_COLOR_MODE_BOOSTED;
}
return KEY_COLOR_MODE_NATURAL;
@@ -132,16 +157,16 @@
protected boolean setDefaultKey(String key) {
switch (key) {
case KEY_COLOR_MODE_NATURAL:
- mController.setColorMode(ColorDisplayController.COLOR_MODE_NATURAL);
+ mColorDisplayManager.setColorMode(ColorDisplayManager.COLOR_MODE_NATURAL);
break;
case KEY_COLOR_MODE_BOOSTED:
- mController.setColorMode(ColorDisplayController.COLOR_MODE_BOOSTED);
+ mColorDisplayManager.setColorMode(ColorDisplayManager.COLOR_MODE_BOOSTED);
break;
case KEY_COLOR_MODE_SATURATED:
- mController.setColorMode(ColorDisplayController.COLOR_MODE_SATURATED);
+ mColorDisplayManager.setColorMode(ColorDisplayManager.COLOR_MODE_SATURATED);
break;
case KEY_COLOR_MODE_AUTOMATIC:
- mController.setColorMode(ColorDisplayController.COLOR_MODE_AUTOMATIC);
+ mColorDisplayManager.setColorMode(ColorDisplayManager.COLOR_MODE_AUTOMATIC);
break;
}
return true;
@@ -179,15 +204,6 @@
}
}
- @Override
- public void onAccessibilityTransformChanged(boolean state) {
- // Color modes are no not configurable when Accessibility transforms are enabled. Close
- // this fragment in that case.
- if (state) {
- getActivity().onBackPressed();
- }
- }
-
public static final Indexable.SearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
new BaseSearchIndexProvider() {
@Override
diff --git a/src/com/android/settings/display/DisplayWhiteBalancePreferenceController.java b/src/com/android/settings/display/DisplayWhiteBalancePreferenceController.java
index bf2b347..c603dee 100644
--- a/src/com/android/settings/display/DisplayWhiteBalancePreferenceController.java
+++ b/src/com/android/settings/display/DisplayWhiteBalancePreferenceController.java
@@ -17,12 +17,13 @@
import android.hardware.display.ColorDisplayManager;
import android.os.UserHandle;
import android.provider.Settings.Secure;
+import androidx.annotation.VisibleForTesting;
-import com.android.internal.app.ColorDisplayController;
import com.android.settings.core.TogglePreferenceController;
public class DisplayWhiteBalancePreferenceController extends TogglePreferenceController {
- private ColorDisplayController mColorDisplayController;
+
+ private ColorDisplayManager mColorDisplayManager;
public DisplayWhiteBalancePreferenceController(Context context, String key) {
super(context, key);
@@ -33,8 +34,8 @@
// Display white balance is only valid in linear light space. COLOR_MODE_SATURATED implies
// unmanaged color mode, and hence unknown color processing conditions.
return ColorDisplayManager.isDisplayWhiteBalanceAvailable(mContext) &&
- getColorDisplayController().getColorMode() !=
- ColorDisplayController.COLOR_MODE_SATURATED ?
+ getColorDisplayManager().getColorMode() !=
+ ColorDisplayManager.COLOR_MODE_SATURATED ?
AVAILABLE : DISABLED_FOR_USER;
}
@@ -51,10 +52,11 @@
return true;
}
- ColorDisplayController getColorDisplayController() {
- if (mColorDisplayController == null) {
- mColorDisplayController = new ColorDisplayController(mContext);
+ @VisibleForTesting
+ ColorDisplayManager getColorDisplayManager() {
+ if (mColorDisplayManager == null) {
+ mColorDisplayManager = mContext.getSystemService(ColorDisplayManager.class);
}
- return mColorDisplayController;
+ return mColorDisplayManager;
}
}
diff --git a/src/com/android/settings/display/NightDisplayActivationPreferenceController.java b/src/com/android/settings/display/NightDisplayActivationPreferenceController.java
index 35cb5ed..17c16e7 100644
--- a/src/com/android/settings/display/NightDisplayActivationPreferenceController.java
+++ b/src/com/android/settings/display/NightDisplayActivationPreferenceController.java
@@ -67,8 +67,7 @@
public void displayPreference(PreferenceScreen screen) {
super.displayPreference(screen);
- final LayoutPreference preference = (LayoutPreference) screen.findPreference(
- getPreferenceKey());
+ final LayoutPreference preference = screen.findPreference(getPreferenceKey());
mTurnOnButton = preference.findViewById(R.id.night_display_turn_on_button);
mTurnOnButton.setOnClickListener(mListener);
mTurnOffButton = preference.findViewById(R.id.night_display_turn_off_button);
@@ -106,14 +105,14 @@
final int autoMode = mController.getAutoMode();
String buttonText;
- if (autoMode == ColorDisplayController.AUTO_MODE_CUSTOM) {
+ if (autoMode == ColorDisplayManager.AUTO_MODE_CUSTOM_TIME) {
buttonText = mContext.getString(isActivated
? R.string.night_display_activation_off_custom
: R.string.night_display_activation_on_custom,
mTimeFormatter.getFormattedTimeString(isActivated
? mController.getCustomStartTime()
: mController.getCustomEndTime()));
- } else if (autoMode == ColorDisplayController.AUTO_MODE_TWILIGHT) {
+ } else if (autoMode == ColorDisplayManager.AUTO_MODE_TWILIGHT) {
buttonText = mContext.getString(isActivated
? R.string.night_display_activation_off_twilight
: R.string.night_display_activation_on_twilight);
diff --git a/src/com/android/settings/display/NightDisplayAutoModePreferenceController.java b/src/com/android/settings/display/NightDisplayAutoModePreferenceController.java
index 1710f51..33e3e6f 100644
--- a/src/com/android/settings/display/NightDisplayAutoModePreferenceController.java
+++ b/src/com/android/settings/display/NightDisplayAutoModePreferenceController.java
@@ -23,7 +23,6 @@
import androidx.preference.Preference;
import androidx.preference.PreferenceScreen;
-import com.android.internal.app.ColorDisplayController;
import com.android.settings.R;
import com.android.settings.core.BasePreferenceController;
@@ -31,11 +30,11 @@
implements Preference.OnPreferenceChangeListener {
private DropDownPreference mPreference;
- private ColorDisplayController mController;
+ private ColorDisplayManager mManager;
public NightDisplayAutoModePreferenceController(Context context, String key) {
super(context, key);
- mController = new ColorDisplayController(context);
+ mManager = context.getSystemService(ColorDisplayManager.class);
}
@Override
@@ -48,7 +47,7 @@
public void displayPreference(PreferenceScreen screen) {
super.displayPreference(screen);
- mPreference = (DropDownPreference) screen.findPreference(getPreferenceKey());
+ mPreference = screen.findPreference(getPreferenceKey());
mPreference.setEntries(new CharSequence[]{
mContext.getString(R.string.night_display_auto_mode_never),
@@ -56,19 +55,19 @@
mContext.getString(R.string.night_display_auto_mode_twilight)
});
mPreference.setEntryValues(new CharSequence[]{
- String.valueOf(ColorDisplayController.AUTO_MODE_DISABLED),
- String.valueOf(ColorDisplayController.AUTO_MODE_CUSTOM),
- String.valueOf(ColorDisplayController.AUTO_MODE_TWILIGHT)
+ String.valueOf(ColorDisplayManager.AUTO_MODE_DISABLED),
+ String.valueOf(ColorDisplayManager.AUTO_MODE_CUSTOM_TIME),
+ String.valueOf(ColorDisplayManager.AUTO_MODE_TWILIGHT)
});
}
@Override
public final void updateState(Preference preference) {
- mPreference.setValue(String.valueOf(mController.getAutoMode()));
+ mPreference.setValue(String.valueOf(mManager.getNightDisplayAutoMode()));
}
@Override
public final boolean onPreferenceChange(Preference preference, Object newValue) {
- return mController.setAutoMode(Integer.parseInt((String) newValue));
+ return mManager.setNightDisplayAutoMode(Integer.parseInt((String) newValue));
}
}
diff --git a/src/com/android/settings/display/NightDisplayCustomEndTimePreferenceController.java b/src/com/android/settings/display/NightDisplayCustomEndTimePreferenceController.java
index 2fa0ef5..b12c18a 100644
--- a/src/com/android/settings/display/NightDisplayCustomEndTimePreferenceController.java
+++ b/src/com/android/settings/display/NightDisplayCustomEndTimePreferenceController.java
@@ -18,9 +18,7 @@
import android.content.Context;
import android.hardware.display.ColorDisplayManager;
-
import androidx.preference.Preference;
-
import com.android.internal.app.ColorDisplayController;
import com.android.settings.core.BasePreferenceController;
@@ -44,7 +42,8 @@
@Override
public final void updateState(Preference preference) {
- preference.setVisible(mController.getAutoMode() == ColorDisplayController.AUTO_MODE_CUSTOM);
+ preference
+ .setVisible(mController.getAutoMode() == ColorDisplayManager.AUTO_MODE_CUSTOM_TIME);
preference.setSummary(mTimeFormatter.getFormattedTimeString(
mController.getCustomEndTime()));
}
diff --git a/src/com/android/settings/display/NightDisplayCustomStartTimePreferenceController.java b/src/com/android/settings/display/NightDisplayCustomStartTimePreferenceController.java
index cf740fd..10fb3a1 100644
--- a/src/com/android/settings/display/NightDisplayCustomStartTimePreferenceController.java
+++ b/src/com/android/settings/display/NightDisplayCustomStartTimePreferenceController.java
@@ -18,9 +18,7 @@
import android.content.Context;
import android.hardware.display.ColorDisplayManager;
-
import androidx.preference.Preference;
-
import com.android.internal.app.ColorDisplayController;
import com.android.settings.core.BasePreferenceController;
@@ -44,7 +42,8 @@
@Override
public final void updateState(Preference preference) {
- preference.setVisible(mController.getAutoMode() == ColorDisplayController.AUTO_MODE_CUSTOM);
+ preference
+ .setVisible(mController.getAutoMode() == ColorDisplayManager.AUTO_MODE_CUSTOM_TIME);
preference.setSummary(mTimeFormatter.getFormattedTimeString(
mController.getCustomStartTime()));
}
diff --git a/src/com/android/settings/display/NightDisplayIntensityPreferenceController.java b/src/com/android/settings/display/NightDisplayIntensityPreferenceController.java
index 6adaf23..7487873 100644
--- a/src/com/android/settings/display/NightDisplayIntensityPreferenceController.java
+++ b/src/com/android/settings/display/NightDisplayIntensityPreferenceController.java
@@ -22,6 +22,7 @@
import androidx.preference.Preference;
import androidx.preference.PreferenceScreen;
+import androidx.annotation.VisibleForTesting;
import com.android.internal.app.ColorDisplayController;
import com.android.settings.core.SliderPreferenceController;
@@ -54,8 +55,7 @@
@Override
public void displayPreference(PreferenceScreen screen) {
super.displayPreference(screen);
- final SeekBarPreference preference = (SeekBarPreference) screen.findPreference(
- getPreferenceKey());
+ final SeekBarPreference preference = screen.findPreference(getPreferenceKey());
preference.setContinuousUpdates(true);
preference.setMax(getMaxSteps());
}
diff --git a/src/com/android/settings/display/NightDisplayPreferenceController.java b/src/com/android/settings/display/NightDisplayPreferenceController.java
index 162a648..ab0250d 100644
--- a/src/com/android/settings/display/NightDisplayPreferenceController.java
+++ b/src/com/android/settings/display/NightDisplayPreferenceController.java
@@ -38,7 +38,7 @@
return true;
}
final ColorDisplayController controller = new ColorDisplayController(context);
- return controller.getAutoMode() != ColorDisplayController.AUTO_MODE_DISABLED;
+ return controller.getAutoMode() != ColorDisplayManager.AUTO_MODE_DISABLED;
}
@Override
diff --git a/src/com/android/settings/display/NightDisplayTimeFormatter.java b/src/com/android/settings/display/NightDisplayTimeFormatter.java
index 48a1994..1b82e0a 100644
--- a/src/com/android/settings/display/NightDisplayTimeFormatter.java
+++ b/src/com/android/settings/display/NightDisplayTimeFormatter.java
@@ -18,6 +18,7 @@
import android.content.Context;
+import android.hardware.display.ColorDisplayManager;
import com.android.internal.app.ColorDisplayController;
import com.android.settings.R;
@@ -54,7 +55,7 @@
private String getAutoModeSummary(Context context, ColorDisplayController controller) {
final boolean isActivated = controller.isActivated();
final int autoMode = controller.getAutoMode();
- if (autoMode == ColorDisplayController.AUTO_MODE_CUSTOM) {
+ if (autoMode == ColorDisplayManager.AUTO_MODE_CUSTOM_TIME) {
if (isActivated) {
return context.getString(R.string.night_display_summary_on_auto_mode_custom,
getFormattedTimeString(controller.getCustomEndTime()));
@@ -62,7 +63,7 @@
return context.getString(R.string.night_display_summary_off_auto_mode_custom,
getFormattedTimeString(controller.getCustomStartTime()));
}
- } else if (autoMode == ColorDisplayController.AUTO_MODE_TWILIGHT) {
+ } else if (autoMode == ColorDisplayManager.AUTO_MODE_TWILIGHT) {
return context.getString(isActivated
? R.string.night_display_summary_on_auto_mode_twilight
: R.string.night_display_summary_off_auto_mode_twilight);
diff --git a/src/com/android/settings/fuelgauge/BatteryAppListPreferenceController.java b/src/com/android/settings/fuelgauge/BatteryAppListPreferenceController.java
index 65181c4..e2d1c53 100644
--- a/src/com/android/settings/fuelgauge/BatteryAppListPreferenceController.java
+++ b/src/com/android/settings/fuelgauge/BatteryAppListPreferenceController.java
@@ -46,6 +46,7 @@
import com.android.settings.SettingsActivity;
import com.android.settings.core.InstrumentedPreferenceFragment;
import com.android.settings.core.PreferenceControllerMixin;
+import com.android.settingslib.applications.AppUtils;
import com.android.settingslib.core.AbstractPreferenceController;
import com.android.settingslib.core.lifecycle.Lifecycle;
import com.android.settingslib.core.lifecycle.LifecycleObserver;
@@ -351,6 +352,12 @@
@VisibleForTesting
boolean shouldHideSipper(BatterySipper sipper) {
+ // Don't show hidden system module
+ final String packageName = mBatteryUtils.getPackageName(sipper.getUid());
+ if (!TextUtils.isEmpty(packageName)
+ && AppUtils.isHiddenSystemModule(mContext, packageName)) {
+ return true;
+ }
// Don't show over-counted and unaccounted in any condition
return sipper.drainType == BatterySipper.DrainType.OVERCOUNTED
|| sipper.drainType == BatterySipper.DrainType.UNACCOUNTED;
diff --git a/src/com/android/settings/fuelgauge/BatteryEntry.java b/src/com/android/settings/fuelgauge/BatteryEntry.java
index a93d522..c91cc8f 100644
--- a/src/com/android/settings/fuelgauge/BatteryEntry.java
+++ b/src/com/android/settings/fuelgauge/BatteryEntry.java
@@ -157,7 +157,7 @@
break;
case BLUETOOTH:
name = context.getResources().getString(R.string.power_bluetooth);
- iconId = R.drawable.ic_settings_bluetooth;
+ iconId = com.android.internal.R.drawable.ic_settings_bluetooth;
break;
case SCREEN:
name = context.getResources().getString(R.string.power_screen);
diff --git a/src/com/android/settings/gestures/SilenceGesturePreferenceController.java b/src/com/android/settings/gestures/SilenceGesturePreferenceController.java
deleted file mode 100644
index 8059304..0000000
--- a/src/com/android/settings/gestures/SilenceGesturePreferenceController.java
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.settings.gestures;
-
-import static android.provider.Settings.Secure.SILENCE_GESTURE;
-
-import android.content.Context;
-import android.provider.Settings;
-import android.text.TextUtils;
-
-public class SilenceGesturePreferenceController extends GesturePreferenceController {
-
- private static final int ON = 1;
- private static final int OFF = 0;
-
- private static final String PREF_KEY_VIDEO = "gesture_silence_video";
-
- public SilenceGesturePreferenceController(Context context, String key) {
- super(context, key);
- }
-
- @Override
- public int getAvailabilityStatus() {
- return mContext.getResources()
- .getBoolean(com.android.internal.R.bool.config_silenceSensorAvailable)
- ? AVAILABLE : UNSUPPORTED_ON_DEVICE;
- }
-
- @Override
- public boolean isSliceable() {
- return true;
- }
-
- @Override
- protected String getVideoPrefKey() {
- return PREF_KEY_VIDEO;
- }
-
- @Override
- public boolean isChecked() {
- return Settings.Secure.getInt(mContext.getContentResolver(), SILENCE_GESTURE, ON) == ON;
- }
-
- @Override
- public boolean setChecked(boolean isChecked) {
- return Settings.Secure.putInt(mContext.getContentResolver(), SILENCE_GESTURE,
- isChecked ? ON : OFF);
- }
-}
diff --git a/src/com/android/settings/gestures/SilenceGestureSettings.java b/src/com/android/settings/gestures/SilenceGestureSettings.java
deleted file mode 100644
index e4acab7..0000000
--- a/src/com/android/settings/gestures/SilenceGestureSettings.java
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.settings.gestures;
-
-import android.app.settings.SettingsEnums;
-import android.content.Context;
-import android.provider.SearchIndexableResource;
-
-import com.android.settings.R;
-import com.android.settings.dashboard.DashboardFragment;
-import com.android.settings.search.BaseSearchIndexProvider;
-import com.android.settingslib.search.SearchIndexable;
-
-import java.util.Arrays;
-import java.util.List;
-
-@SearchIndexable
-public class SilenceGestureSettings extends DashboardFragment {
-
- private static final String TAG = "SilenceGestureSettings";
-
- @Override
- public int getMetricsCategory() {
- return SettingsEnums.SETTINGS_GESTURE_SILENCE;
- }
-
- @Override
- protected String getLogTag() {
- return TAG;
- }
-
- @Override
- protected int getPreferenceScreenResId() {
- return R.xml.silence_gesture_settings;
- }
-
- public static final SearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
- new BaseSearchIndexProvider() {
- @Override
- public List<SearchIndexableResource> getXmlResourcesToIndex(
- Context context, boolean enabled) {
- final SearchIndexableResource sir = new SearchIndexableResource(context);
- sir.xmlResId = R.xml.silence_gesture_settings;
- return Arrays.asList(sir);
- }
- };
-
-}
diff --git a/src/com/android/settings/gestures/SkipGesturePreferenceController.java b/src/com/android/settings/gestures/SkipGesturePreferenceController.java
deleted file mode 100644
index d1c0a03..0000000
--- a/src/com/android/settings/gestures/SkipGesturePreferenceController.java
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.settings.gestures;
-
-import static android.provider.Settings.Secure.SKIP_GESTURE;
-
-import android.content.Context;
-import android.provider.Settings;
-import android.text.TextUtils;
-
-public class SkipGesturePreferenceController extends GesturePreferenceController {
-
- private static final int ON = 1;
- private static final int OFF = 0;
-
- private static final String PREF_KEY_VIDEO = "gesture_silence_video";
-
- public SkipGesturePreferenceController(Context context, String key) {
- super(context, key);
- }
-
- @Override
- public int getAvailabilityStatus() {
- return mContext.getResources()
- .getBoolean(com.android.internal.R.bool.config_skipSensorAvailable) ? AVAILABLE
- : UNSUPPORTED_ON_DEVICE;
- }
-
- @Override
- public boolean isSliceable() {
- return true;
- }
-
- @Override
- protected String getVideoPrefKey() {
- return PREF_KEY_VIDEO;
- }
-
- @Override
- public boolean isChecked() {
- return Settings.Secure.getInt(mContext.getContentResolver(), SKIP_GESTURE, ON) == ON;
- }
-
- @Override
- public boolean setChecked(boolean isChecked) {
- return Settings.Secure.putInt(mContext.getContentResolver(), SKIP_GESTURE,
- isChecked ? ON : OFF);
- }
-}
diff --git a/src/com/android/settings/homepage/SettingsHomepageActivity.java b/src/com/android/settings/homepage/SettingsHomepageActivity.java
index d40006f..9acda68 100644
--- a/src/com/android/settings/homepage/SettingsHomepageActivity.java
+++ b/src/com/android/settings/homepage/SettingsHomepageActivity.java
@@ -53,7 +53,7 @@
final Toolbar toolbar = findViewById(R.id.search_action_bar);
FeatureFactory.getFactory(this).getSearchFeatureProvider()
- .initSearchToolbar(this, toolbar);
+ .initSearchToolbar(this /* activity */, toolbar);
final ImageView avatarView = findViewById(R.id.account_avatar);
final AvatarViewMixin avatarViewMixin = new AvatarViewMixin(this, avatarView);
diff --git a/src/com/android/settings/homepage/contextualcards/ContextualCardLookupTable.java b/src/com/android/settings/homepage/contextualcards/ContextualCardLookupTable.java
index 1f2e89b..e11ce30 100644
--- a/src/com/android/settings/homepage/contextualcards/ContextualCardLookupTable.java
+++ b/src/com/android/settings/homepage/contextualcards/ContextualCardLookupTable.java
@@ -80,6 +80,10 @@
LegacySuggestionContextualCardController.class,
LegacySuggestionContextualCardRenderer.class));
add(new ControllerRendererMapping(CardType.SLICE,
+ SliceContextualCardRenderer.VIEW_TYPE_DEFERRED_SETUP,
+ SliceContextualCardController.class,
+ SliceContextualCardRenderer.class));
+ add(new ControllerRendererMapping(CardType.SLICE,
SliceContextualCardRenderer.VIEW_TYPE_FULL_WIDTH,
SliceContextualCardController.class,
SliceContextualCardRenderer.class));
diff --git a/src/com/android/settings/homepage/contextualcards/ContextualCardManager.java b/src/com/android/settings/homepage/contextualcards/ContextualCardManager.java
index 7a2c2e9..b35a38a 100644
--- a/src/com/android/settings/homepage/contextualcards/ContextualCardManager.java
+++ b/src/com/android/settings/homepage/contextualcards/ContextualCardManager.java
@@ -17,6 +17,7 @@
package com.android.settings.homepage.contextualcards;
import static com.android.settings.homepage.contextualcards.ContextualCardLoader.CARD_CONTENT_LOADER_ID;
+import static com.android.settings.intelligence.ContextualCardProto.ContextualCard.Category.DEFERRED_SETUP_VALUE;
import static com.android.settings.intelligence.ContextualCardProto.ContextualCard.Category.SUGGESTION_VALUE;
import static java.util.stream.Collectors.groupingBy;
@@ -71,17 +72,15 @@
@VisibleForTesting
final List<ContextualCard> mContextualCards;
+ private final Context mContext;
+ private final ControllerRendererPool mControllerRendererPool;
+ private final Lifecycle mLifecycle;
+ private final List<LifecycleObserver> mLifecycleObservers;
@VisibleForTesting
long mStartTime;
boolean mIsFirstLaunch;
@VisibleForTesting
List<String> mSavedCards;
-
- private final Context mContext;
- private final ControllerRendererPool mControllerRendererPool;
- private final Lifecycle mLifecycle;
- private final List<LifecycleObserver> mLifecycleObservers;
-
private ContextualCardUpdateListener mListener;
public ContextualCardManager(Context context, Lifecycle lifecycle, Bundle savedInstanceState) {
@@ -175,7 +174,7 @@
//replace with the new data
mContextualCards.clear();
final List<ContextualCard> sortedCards = sortCards(allCards);
- mContextualCards.addAll(assignCardWidth(sortedCards));
+ mContextualCards.addAll(getCardsWithViewType(sortedCards));
loadCardControllers();
@@ -228,10 +227,19 @@
}
@VisibleForTesting
- List<ContextualCard> assignCardWidth(List<ContextualCard> cards) {
- final List<ContextualCard> result = new ArrayList<>(cards);
+ List<ContextualCard> getCardsWithViewType(List<ContextualCard> cards) {
+ if (cards.isEmpty()) {
+ return cards;
+ }
+
+ final List<ContextualCard> result = getCardsWithDeferredSetupViewType(cards);
+ return getCardsWithSuggestionViewType(result);
+ }
+
+ private List<ContextualCard> getCardsWithSuggestionViewType(List<ContextualCard> cards) {
// Shows as half cards if 2 suggestion type of cards are next to each other.
// Shows as full card if 1 suggestion type of card lives alone.
+ final List<ContextualCard> result = new ArrayList<>(cards);
for (int index = 1; index < result.size(); index++) {
final ContextualCard previous = result.get(index - 1);
final ContextualCard current = result.get(index);
@@ -247,6 +255,22 @@
return result;
}
+ private List<ContextualCard> getCardsWithDeferredSetupViewType(List<ContextualCard> cards) {
+ // Find the deferred setup card and assign it with proper view type.
+ // Reason: The returned card list will mix deferred setup card and other suggestion cards
+ // after device running 1 days.
+ final List<ContextualCard> result = new ArrayList<>(cards);
+ for (int index = 0; index < result.size(); index++) {
+ final ContextualCard card = cards.get(index);
+ if (card.getCategory() == DEFERRED_SETUP_VALUE) {
+ result.set(index, card.mutate().setViewType(
+ SliceContextualCardRenderer.VIEW_TYPE_DEFERRED_SETUP).build());
+ return result;
+ }
+ }
+ return result;
+ }
+
private List<ContextualCard> getCardsToKeep(List<ContextualCard> cards) {
if (mSavedCards != null) {
//screen rotate
diff --git a/src/com/android/settings/homepage/contextualcards/slices/BluetoothDevicesSlice.java b/src/com/android/settings/homepage/contextualcards/slices/BluetoothDevicesSlice.java
index 03868ee..ea2a308 100644
--- a/src/com/android/settings/homepage/contextualcards/slices/BluetoothDevicesSlice.java
+++ b/src/com/android/settings/homepage/contextualcards/slices/BluetoothDevicesSlice.java
@@ -103,7 +103,7 @@
@Override
public Slice getSlice() {
final IconCompat icon = IconCompat.createWithResource(mContext,
- R.drawable.ic_settings_bluetooth);
+ com.android.internal.R.drawable.ic_settings_bluetooth);
final CharSequence title = mContext.getText(R.string.bluetooth_devices);
final CharSequence titleNoBluetoothDevices = mContext.getText(
R.string.no_bluetooth_devices);
@@ -236,7 +236,8 @@
if (pair.first != null) {
return IconCompat.createWithBitmap(getBitmapFromVectorDrawable(pair.first));
} else {
- return IconCompat.createWithResource(mContext, R.drawable.ic_settings_bluetooth);
+ return IconCompat.createWithResource(mContext,
+ com.android.internal.R.drawable.ic_settings_bluetooth);
}
}
@@ -303,4 +304,4 @@
return PendingIntent.getActivity(mContext, 0 /* requestCode */, intent, 0 /* flags */);
}
-}
\ No newline at end of file
+}
diff --git a/src/com/android/settings/homepage/contextualcards/slices/BluetoothUpdateWorker.java b/src/com/android/settings/homepage/contextualcards/slices/BluetoothUpdateWorker.java
index ff26888..1602f56 100644
--- a/src/com/android/settings/homepage/contextualcards/slices/BluetoothUpdateWorker.java
+++ b/src/com/android/settings/homepage/contextualcards/slices/BluetoothUpdateWorker.java
@@ -30,16 +30,11 @@
private static final String TAG = "BluetoothUpdateWorker";
- private final Context mContext;
- private final Uri mUri;
private final LocalBluetoothManager mLocalBluetoothManager;
public BluetoothUpdateWorker(Context context, Uri uri) {
super(context, uri);
-
- mContext = context;
- mUri = uri;
- mLocalBluetoothManager = Utils.getLocalBtManager(mContext);
+ mLocalBluetoothManager = Utils.getLocalBtManager(context);
}
@Override
@@ -89,8 +84,4 @@
int bluetoothProfile) {
notifySliceChange();
}
-
- private void notifySliceChange() {
- mContext.getContentResolver().notifyChange(mUri, null);
- }
}
\ No newline at end of file
diff --git a/src/com/android/settings/homepage/contextualcards/slices/SliceContextualCardRenderer.java b/src/com/android/settings/homepage/contextualcards/slices/SliceContextualCardRenderer.java
index 66e0465..2d40efe 100644
--- a/src/com/android/settings/homepage/contextualcards/slices/SliceContextualCardRenderer.java
+++ b/src/com/android/settings/homepage/contextualcards/slices/SliceContextualCardRenderer.java
@@ -52,6 +52,7 @@
public class SliceContextualCardRenderer implements ContextualCardRenderer, LifecycleObserver {
public static final int VIEW_TYPE_FULL_WIDTH = R.layout.homepage_slice_tile;
public static final int VIEW_TYPE_HALF_WIDTH = R.layout.homepage_slice_half_tile;
+ public static final int VIEW_TYPE_DEFERRED_SETUP = R.layout.homepage_slice_deferred_setup_tile;
private static final String TAG = "SliceCardRenderer";
@@ -64,6 +65,7 @@
private final LifecycleOwner mLifecycleOwner;
private final ControllerRendererPool mControllerRendererPool;
private final Set<ContextualCard> mCardSet;
+ private final SliceDeferredSetupCardRendererHelper mDeferredSetupCardHelper;
private final SliceFullCardRendererHelper mFullCardHelper;
private final SliceHalfCardRendererHelper mHalfCardHelper;
@@ -78,11 +80,14 @@
mLifecycleOwner.getLifecycle().addObserver(this);
mFullCardHelper = new SliceFullCardRendererHelper(context);
mHalfCardHelper = new SliceHalfCardRendererHelper(context);
+ mDeferredSetupCardHelper = new SliceDeferredSetupCardRendererHelper(context);
}
@Override
public RecyclerView.ViewHolder createViewHolder(View view, @LayoutRes int viewType) {
switch (viewType) {
+ case VIEW_TYPE_DEFERRED_SETUP:
+ return mDeferredSetupCardHelper.createViewHolder(view);
case VIEW_TYPE_HALF_WIDTH:
return mHalfCardHelper.createViewHolder(view);
default:
@@ -119,17 +124,25 @@
//TODO(b/120629936): Take this out once blank card issue is fixed.
Log.d(TAG, "Slice callback - uri = " + slice.getUri());
}
- if (holder.getItemViewType() == VIEW_TYPE_HALF_WIDTH) {
- mHalfCardHelper.bindView(holder, card, slice);
- } else {
- mFullCardHelper.bindView(holder, card, slice, mCardSet);
+ switch (holder.getItemViewType()) {
+ case VIEW_TYPE_DEFERRED_SETUP:
+ mDeferredSetupCardHelper.bindView(holder, card, slice);
+ break;
+ case VIEW_TYPE_HALF_WIDTH:
+ mHalfCardHelper.bindView(holder, card, slice);
+ break;
+ default:
+ mFullCardHelper.bindView(holder, card, slice, mCardSet);
}
});
- if (holder.getItemViewType() == VIEW_TYPE_HALF_WIDTH) {
- initDismissalActions(holder, card, R.id.content);
- } else {
- initDismissalActions(holder, card, R.id.slice_view);
+ switch (holder.getItemViewType()) {
+ case VIEW_TYPE_DEFERRED_SETUP:
+ case VIEW_TYPE_HALF_WIDTH:
+ initDismissalActions(holder, card, R.id.content);
+ break;
+ default:
+ initDismissalActions(holder, card, R.id.slice_view);
}
}
diff --git a/src/com/android/settings/homepage/contextualcards/slices/SliceDeferredSetupCardRendererHelper.java b/src/com/android/settings/homepage/contextualcards/slices/SliceDeferredSetupCardRendererHelper.java
new file mode 100644
index 0000000..d0d51e7
--- /dev/null
+++ b/src/com/android/settings/homepage/contextualcards/slices/SliceDeferredSetupCardRendererHelper.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.homepage.contextualcards.slices;
+
+import android.app.PendingIntent;
+import android.content.Context;
+import android.util.Log;
+import android.view.View;
+import android.widget.Button;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+import androidx.recyclerview.widget.RecyclerView;
+import androidx.slice.Slice;
+import androidx.slice.SliceMetadata;
+import androidx.slice.core.SliceAction;
+import androidx.slice.widget.EventInfo;
+
+import com.android.settings.R;
+import com.android.settings.homepage.contextualcards.ContextualCard;
+import com.android.settings.homepage.contextualcards.ContextualCardFeatureProvider;
+import com.android.settings.overlay.FeatureFactory;
+
+/**
+ * Card renderer helper for {@link ContextualCard} built as slice deferred setup card.
+ */
+class SliceDeferredSetupCardRendererHelper {
+ private static final String TAG = "SliceDSCRendererHelper";
+
+ private final Context mContext;
+
+ SliceDeferredSetupCardRendererHelper(Context context) {
+ mContext = context;
+ }
+
+ RecyclerView.ViewHolder createViewHolder(View view) {
+ return new DeferredSetupCardViewHolder(view);
+ }
+
+ void bindView(RecyclerView.ViewHolder holder, ContextualCard card, Slice slice) {
+ final DeferredSetupCardViewHolder view = (DeferredSetupCardViewHolder) holder;
+ final SliceMetadata sliceMetadata = SliceMetadata.from(mContext, slice);
+ final SliceAction primaryAction = sliceMetadata.getPrimaryAction();
+ view.icon.setImageDrawable(primaryAction.getIcon().loadDrawable(mContext));
+ view.title.setText(primaryAction.getTitle());
+ view.summary.setText(sliceMetadata.getSubtitle());
+ view.button.setOnClickListener(v -> {
+ try {
+ primaryAction.getAction().send();
+ } catch (PendingIntent.CanceledException e) {
+ Log.w(TAG, "Failed to start intent " + primaryAction.getTitle());
+ }
+ final ContextualCardFeatureProvider contextualCardFeatureProvider =
+ FeatureFactory.getFactory(mContext).getContextualCardFeatureProvider(mContext);
+ contextualCardFeatureProvider.logContextualCardClick(card, 0 /* row */,
+ EventInfo.ACTION_TYPE_CONTENT);
+ });
+ }
+
+ static class DeferredSetupCardViewHolder extends RecyclerView.ViewHolder {
+ public final LinearLayout content;
+ public final ImageView icon;
+ public final TextView title;
+ public final TextView summary;
+ public final Button button;
+
+ public DeferredSetupCardViewHolder(View itemView) {
+ super(itemView);
+ content = itemView.findViewById(R.id.content);
+ icon = itemView.findViewById(android.R.id.icon);
+ title = itemView.findViewById(android.R.id.title);
+ summary = itemView.findViewById(android.R.id.summary);
+ button = itemView.findViewById(R.id.finish_setup);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/com/android/settings/inputmethod/SpellCheckerForWorkPreferenceController.java b/src/com/android/settings/inputmethod/SpellCheckerForWorkPreferenceController.java
new file mode 100644
index 0000000..327af5b
--- /dev/null
+++ b/src/com/android/settings/inputmethod/SpellCheckerForWorkPreferenceController.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.inputmethod;
+
+import android.app.settings.SettingsEnums;
+import android.content.Context;
+import android.view.inputmethod.InputMethodSystemProperty;
+
+import com.android.settings.R;
+import com.android.settings.core.WorkProfilePreferenceController;
+
+/**
+ * Preference controller for "Spell checker for work".
+ *
+ * @see SpellCheckerPreferenceController
+ */
+public final class SpellCheckerForWorkPreferenceController extends WorkProfilePreferenceController {
+
+ public SpellCheckerForWorkPreferenceController(Context context, String preferenceKey) {
+ super(context, preferenceKey);
+ }
+
+ @Override
+ protected int getSourceMetricsCategory() {
+ return SettingsEnums.SETTINGS_LANGUAGE_CATEGORY;
+ }
+
+ @AvailabilityStatus
+ @Override
+ public int getAvailabilityStatus() {
+ if (!mContext.getResources().getBoolean(R.bool.config_show_spellcheckers_settings)
+ || !InputMethodSystemProperty.PER_PROFILE_IME_ENABLED) {
+ return UNSUPPORTED_ON_DEVICE;
+ }
+ return super.getAvailabilityStatus();
+ }
+}
diff --git a/src/com/android/settings/inputmethod/VirtualKeyboardForWorkPreferenceController.java b/src/com/android/settings/inputmethod/VirtualKeyboardForWorkPreferenceController.java
new file mode 100644
index 0000000..6cdd386
--- /dev/null
+++ b/src/com/android/settings/inputmethod/VirtualKeyboardForWorkPreferenceController.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.inputmethod;
+
+import android.app.settings.SettingsEnums;
+import android.content.Context;
+import android.view.inputmethod.InputMethodSystemProperty;
+
+import com.android.settings.R;
+import com.android.settings.core.WorkProfilePreferenceController;
+
+public final class VirtualKeyboardForWorkPreferenceController
+ extends WorkProfilePreferenceController {
+
+ public VirtualKeyboardForWorkPreferenceController(Context context,
+ String preferenceKey) {
+ super(context, preferenceKey);
+ }
+
+ @Override
+ protected int getSourceMetricsCategory() {
+ return SettingsEnums.SETTINGS_LANGUAGE_CATEGORY;
+ }
+
+ @AvailabilityStatus
+ @Override
+ public int getAvailabilityStatus() {
+ if (!mContext.getResources().getBoolean(R.bool.config_show_virtual_keyboard_pref)
+ || !InputMethodSystemProperty.PER_PROFILE_IME_ENABLED) {
+ return UNSUPPORTED_ON_DEVICE;
+ }
+ return super.getAvailabilityStatus();
+ }
+}
diff --git a/src/com/android/settings/language/UserDictionaryForWorkPreferenceController.java b/src/com/android/settings/language/UserDictionaryForWorkPreferenceController.java
new file mode 100644
index 0000000..7ff8aec
--- /dev/null
+++ b/src/com/android/settings/language/UserDictionaryForWorkPreferenceController.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.language;
+
+import android.app.settings.SettingsEnums;
+import android.content.Context;
+import android.view.inputmethod.InputMethodSystemProperty;
+
+import com.android.settings.R;
+import com.android.settings.core.WorkProfilePreferenceController;
+
+/**
+ * Preference controller for "UserDictionary for work".
+ *
+ * @see UserDictionaryPreferenceController
+ */
+public final class UserDictionaryForWorkPreferenceController
+ extends WorkProfilePreferenceController {
+
+ public UserDictionaryForWorkPreferenceController(Context context, String preferenceKey) {
+ super(context, preferenceKey);
+ }
+
+ @Override
+ protected int getSourceMetricsCategory() {
+ return SettingsEnums.SETTINGS_LANGUAGE_CATEGORY;
+ }
+
+ @AvailabilityStatus
+ @Override
+ public int getAvailabilityStatus() {
+ if (!InputMethodSystemProperty.PER_PROFILE_IME_ENABLED) {
+ return UNSUPPORTED_ON_DEVICE;
+ }
+ return super.getAvailabilityStatus();
+ }
+}
diff --git a/src/com/android/settings/location/LocationSlice.java b/src/com/android/settings/location/LocationSlice.java
index e2078e3..2759690 100644
--- a/src/com/android/settings/location/LocationSlice.java
+++ b/src/com/android/settings/location/LocationSlice.java
@@ -55,7 +55,7 @@
@Override
public Slice getSlice() {
final IconCompat icon = IconCompat.createWithResource(mContext,
- R.drawable.ic_signal_location);
+ com.android.internal.R.drawable.ic_signal_location);
final CharSequence title = mContext.getText(R.string.location_settings_title);
@ColorInt final int color = Utils.getColorAccentDefaultColor(mContext);
final PendingIntent primaryAction = getPrimaryAction();
diff --git a/src/com/android/settings/location/RecentLocationAccessPreferenceController.java b/src/com/android/settings/location/RecentLocationAccessPreferenceController.java
index 2d84e21..3adc489 100644
--- a/src/com/android/settings/location/RecentLocationAccessPreferenceController.java
+++ b/src/com/android/settings/location/RecentLocationAccessPreferenceController.java
@@ -13,6 +13,8 @@
*/
package com.android.settings.location;
+import static java.util.concurrent.TimeUnit.DAYS;
+
import android.Manifest;
import android.content.Context;
import android.content.Intent;
@@ -74,6 +76,7 @@
final Intent intent = new Intent(Intent.ACTION_REVIEW_PERMISSION_USAGE);
intent.putExtra(Intent.EXTRA_PERMISSION_NAME,
Manifest.permission.ACCESS_FINE_LOCATION);
+ intent.putExtra(Intent.EXTRA_DURATION_MILLIS, DAYS.toMillis(1));
mContext.startActivity(intent);
});
}
diff --git a/src/com/android/settings/media/MediaDeviceUpdateWorker.java b/src/com/android/settings/media/MediaDeviceUpdateWorker.java
new file mode 100644
index 0000000..7416018
--- /dev/null
+++ b/src/com/android/settings/media/MediaDeviceUpdateWorker.java
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.media;
+
+import android.content.Context;
+import android.net.Uri;
+
+import androidx.annotation.VisibleForTesting;
+
+import com.android.settings.slices.SliceBackgroundWorker;
+import com.android.settingslib.media.LocalMediaManager;
+import com.android.settingslib.media.MediaDevice;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * SliceBackgroundWorker for get MediaDevice list and handle MediaDevice state change event.
+ */
+public class MediaDeviceUpdateWorker extends SliceBackgroundWorker
+ implements LocalMediaManager.DeviceCallback {
+
+ private final Context mContext;
+ private final List<MediaDevice> mMediaDevices = new ArrayList<>();
+
+ private String mPackageName;
+
+ @VisibleForTesting
+ LocalMediaManager mLocalMediaManager;
+
+ public MediaDeviceUpdateWorker(Context context, Uri uri) {
+ super(context, uri);
+ mContext = context;
+ }
+
+ public void setPackageName(String packageName) {
+ mPackageName = packageName;
+ }
+
+ @Override
+ protected void onSlicePinned() {
+ mMediaDevices.clear();
+ if (mLocalMediaManager == null) {
+ mLocalMediaManager = new LocalMediaManager(mContext, mPackageName, null);
+ }
+
+ mLocalMediaManager.registerCallback(this);
+ mLocalMediaManager.startScan();
+ }
+
+ @Override
+ protected void onSliceUnpinned() {
+ mLocalMediaManager.unregisterCallback(this);
+ mLocalMediaManager.stopScan();
+ }
+
+ @Override
+ public void close() {
+
+ }
+
+ @Override
+ public void onDeviceListUpdate(List<MediaDevice> devices) {
+ buildMediaDevices(devices);
+ notifySliceChange();
+ }
+
+ private void buildMediaDevices(List<MediaDevice> devices) {
+ mMediaDevices.clear();
+ mMediaDevices.addAll(devices);
+ }
+
+ @Override
+ public void onSelectedDeviceStateChanged(MediaDevice device, int state) {
+ notifySliceChange();
+ }
+
+ public List<MediaDevice> getMediaDevices() {
+ return new ArrayList<>(mMediaDevices);
+ }
+
+ public void connectDevice(MediaDevice device) {
+ mLocalMediaManager.connectDevice(device);
+ }
+
+ public MediaDevice getMediaDeviceById(String id) {
+ return mLocalMediaManager.getMediaDeviceById(mMediaDevices, id);
+ }
+
+ public MediaDevice getCurrentConnectedMediaDevice() {
+ return mLocalMediaManager.getCurrentConnectedDevice();
+ }
+}
diff --git a/src/com/android/settings/media/MediaOutputSlice.java b/src/com/android/settings/media/MediaOutputSlice.java
new file mode 100644
index 0000000..5c5eb88
--- /dev/null
+++ b/src/com/android/settings/media/MediaOutputSlice.java
@@ -0,0 +1,195 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.media;
+
+import static com.android.settings.slices.CustomSliceRegistry.MEDIA_OUTPUT_SLICE_URI;
+
+import android.annotation.ColorInt;
+import android.app.PendingIntent;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.drawable.Drawable;
+import android.net.Uri;
+import android.os.UserHandle;
+import android.util.IconDrawableFactory;
+import android.util.Log;
+
+import androidx.annotation.VisibleForTesting;
+import androidx.core.graphics.drawable.IconCompat;
+import androidx.slice.Slice;
+import androidx.slice.builders.ListBuilder;
+import androidx.slice.builders.SliceAction;
+
+import com.android.settings.R;
+import com.android.settings.Utils;
+import com.android.settings.slices.CustomSliceable;
+import com.android.settings.slices.SliceBackgroundWorker;
+import com.android.settings.slices.SliceBroadcastReceiver;
+import com.android.settingslib.media.MediaDevice;
+
+import java.util.List;
+
+/**
+ * Show the Media device that can be transfer the media.
+ */
+public class MediaOutputSlice implements CustomSliceable {
+
+ private static final String TAG = "MediaOutputSlice";
+ private static final String MEDIA_DEVICE_ID = "media_device_id";
+
+ public static final String MEDIA_PACKAGE_NAME = "media_package_name";
+
+ private final Context mContext;
+
+ private MediaDeviceUpdateWorker mWorker;
+ private String mPackageName;
+ private IconDrawableFactory mIconDrawableFactory;
+
+ public MediaOutputSlice(Context context) {
+ mContext = context;
+ mPackageName = getUri().getQueryParameter(MEDIA_PACKAGE_NAME);
+ mIconDrawableFactory = IconDrawableFactory.newInstance(mContext);
+ }
+
+ @VisibleForTesting
+ void init(String packageName, MediaDeviceUpdateWorker worker, IconDrawableFactory factory) {
+ mPackageName = packageName;
+ mWorker = worker;
+ mIconDrawableFactory = factory;
+ }
+
+ @Override
+ public Slice getSlice() {
+ final PackageManager pm = mContext.getPackageManager();
+
+ final List<MediaDevice> devices = getMediaDevices();
+ final CharSequence title = Utils.getApplicationLabel(mContext, mPackageName);
+ final CharSequence summary =
+ mContext.getString(R.string.media_output_panel_summary_of_playing_device,
+ getConnectedDeviceName());
+
+ final Drawable drawable =
+ Utils.getBadgedIcon(mIconDrawableFactory, pm, mPackageName, UserHandle.myUserId());
+ final IconCompat icon = IconCompat.createWithBitmap(getBitmapFromDrawable(drawable));
+
+ @ColorInt final int color = Utils.getColorAccentDefaultColor(mContext);
+ final SliceAction primarySliceAction = SliceAction.createDeeplink(getPrimaryAction(), icon,
+ ListBuilder.ICON_IMAGE, title);
+
+ final ListBuilder listBuilder = new ListBuilder(mContext, MEDIA_OUTPUT_SLICE_URI,
+ ListBuilder.INFINITY)
+ .setAccentColor(color)
+ .addRow(new ListBuilder.RowBuilder()
+ .setTitleItem(icon, ListBuilder.ICON_IMAGE)
+ .setTitle(title)
+ .setSubtitle(summary)
+ .setPrimaryAction(primarySliceAction));
+
+ for (MediaDevice device : devices) {
+ listBuilder.addRow(getMediaDeviceRow(device));
+ }
+
+ return listBuilder.build();
+ }
+
+ private MediaDeviceUpdateWorker getWorker() {
+ if (mWorker == null) {
+ mWorker = (MediaDeviceUpdateWorker) SliceBackgroundWorker.getInstance(getUri());
+ mWorker.setPackageName(mPackageName);
+ }
+ return mWorker;
+ }
+
+ private List<MediaDevice> getMediaDevices() {
+ List<MediaDevice> devices = getWorker().getMediaDevices();
+ return devices;
+ }
+
+ private String getConnectedDeviceName() {
+ final MediaDevice device = getWorker().getCurrentConnectedMediaDevice();
+ return device != null ? device.getName() : "";
+ }
+
+ private PendingIntent getPrimaryAction() {
+ final PackageManager pm = mContext.getPackageManager();
+ final Intent launchIntent = pm.getLaunchIntentForPackage(mPackageName);
+ final Intent intent = launchIntent;
+ return PendingIntent.getActivity(mContext, 0 /* requestCode */, intent, 0 /* flags */);
+ }
+
+ private Bitmap getBitmapFromDrawable(Drawable drawable) {
+ final Bitmap bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(),
+ drawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
+ final Canvas canvas = new Canvas(bitmap);
+
+ drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
+ drawable.draw(canvas);
+
+ return bitmap;
+ }
+
+ private ListBuilder.RowBuilder getMediaDeviceRow(MediaDevice device) {
+ final String title = device.getName();
+ final PendingIntent broadcastAction =
+ getBroadcastIntent(mContext, device.getId(), device.hashCode());
+ final IconCompat deviceIcon = IconCompat.createWithResource(mContext, device.getIcon());
+ final ListBuilder.RowBuilder rowBuilder = new ListBuilder.RowBuilder()
+ .setTitleItem(deviceIcon, ListBuilder.ICON_IMAGE)
+ .setPrimaryAction(SliceAction.create(broadcastAction, deviceIcon,
+ ListBuilder.ICON_IMAGE, title))
+ .setTitle(title);
+
+ return rowBuilder;
+ }
+
+ private PendingIntent getBroadcastIntent(Context context, String id, int requestCode) {
+ final Intent intent = new Intent(getUri().toString());
+ intent.setClass(context, SliceBroadcastReceiver.class);
+ intent.putExtra(MEDIA_DEVICE_ID, id);
+ return PendingIntent.getBroadcast(context, requestCode /* requestCode */, intent,
+ PendingIntent.FLAG_CANCEL_CURRENT);
+ }
+
+ @Override
+ public Uri getUri() {
+ return MEDIA_OUTPUT_SLICE_URI;
+ }
+
+ @Override
+ public void onNotifyChange(Intent intent) {
+ final MediaDeviceUpdateWorker worker = getWorker();
+ final String id = intent != null ? intent.getStringExtra(MEDIA_DEVICE_ID) : "";
+ final MediaDevice device = worker.getMediaDeviceById(id);
+ if (device != null) {
+ Log.d(TAG, "onNotifyChange() device name : " + device.getName());
+ worker.connectDevice(device);
+ }
+ }
+
+ @Override
+ public Intent getIntent() {
+ return null;
+ }
+
+ @Override
+ public Class getBackgroundWorkerClass() {
+ return MediaDeviceUpdateWorker.class;
+ }
+}
diff --git a/src/com/android/settings/network/SubscriptionUtil.java b/src/com/android/settings/network/SubscriptionUtil.java
index fbc6edd..237e08a 100644
--- a/src/com/android/settings/network/SubscriptionUtil.java
+++ b/src/com/android/settings/network/SubscriptionUtil.java
@@ -30,7 +30,7 @@
private static List<SubscriptionInfo> sResultsForTesting;
@VisibleForTesting
- static void setAvailableSubscriptionsForTesting(List<SubscriptionInfo> results) {
+ public static void setAvailableSubscriptionsForTesting(List<SubscriptionInfo> results) {
sResultsForTesting = results;
}
diff --git a/src/com/android/settings/network/telephony/CallsDefaultSubscriptionController.java b/src/com/android/settings/network/telephony/CallsDefaultSubscriptionController.java
new file mode 100644
index 0000000..008a3e4
--- /dev/null
+++ b/src/com/android/settings/network/telephony/CallsDefaultSubscriptionController.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.network.telephony;
+
+import android.content.Context;
+import android.telephony.SubscriptionInfo;
+import android.telephony.SubscriptionManager;
+
+public class CallsDefaultSubscriptionController extends DefaultSubscriptionController {
+
+ public CallsDefaultSubscriptionController(Context context, String preferenceKey) {
+ super(context, preferenceKey);
+ }
+
+ @Override
+ protected SubscriptionInfo getDefaultSubscriptionInfo() {
+ return mManager.getDefaultVoiceSubscriptionInfo();
+ }
+
+ @Override
+ protected int getDefaultSubscriptionId() {
+ return SubscriptionManager.getDefaultVoiceSubscriptionId();
+ }
+
+ @Override
+ protected void setDefaultSubscription(int subscriptionId) {
+ mManager.setDefaultVoiceSubId(subscriptionId);
+ }
+}
diff --git a/src/com/android/settings/network/telephony/CarrierPreferenceController.java b/src/com/android/settings/network/telephony/CarrierPreferenceController.java
index 61232f5..fbbfb9e 100644
--- a/src/com/android/settings/network/telephony/CarrierPreferenceController.java
+++ b/src/com/android/settings/network/telephony/CarrierPreferenceController.java
@@ -41,7 +41,6 @@
public CarrierPreferenceController(Context context, String key) {
super(context, key);
- mSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
mCarrierConfigManager = new CarrierConfigManager(context);
mSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
}
@@ -88,6 +87,7 @@
final Intent intent = new Intent(Intent.ACTION_MAIN);
intent.setComponent(cn);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ intent.putExtra(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX, subId);
final PackageManager pm = mContext.getPackageManager();
final ResolveInfo resolveInfo = pm.resolveActivity(intent, 0 /* flags */);
diff --git a/src/com/android/settings/network/telephony/DefaultSubscriptionController.java b/src/com/android/settings/network/telephony/DefaultSubscriptionController.java
new file mode 100644
index 0000000..bca6750
--- /dev/null
+++ b/src/com/android/settings/network/telephony/DefaultSubscriptionController.java
@@ -0,0 +1,175 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.network.telephony;
+
+import static androidx.lifecycle.Lifecycle.Event.ON_PAUSE;
+import static androidx.lifecycle.Lifecycle.Event.ON_RESUME;
+
+import android.content.Context;
+import android.telephony.SubscriptionInfo;
+import android.telephony.SubscriptionManager;
+
+import com.android.settings.R;
+import com.android.settings.core.BasePreferenceController;
+import com.android.settings.network.SubscriptionUtil;
+import com.android.settings.network.SubscriptionsChangeListener;
+
+import java.util.List;
+
+import androidx.lifecycle.Lifecycle;
+import androidx.lifecycle.LifecycleObserver;
+import androidx.lifecycle.OnLifecycleEvent;
+import androidx.preference.ListPreference;
+import androidx.preference.Preference;
+import androidx.preference.PreferenceScreen;
+
+/**
+ * This implements common controller functionality for a Preference letting the user see/change
+ * what mobile network subscription is used by default for some service controlled by the
+ * SubscriptionManager. This can be used for services such as Calls or SMS.
+ */
+public abstract class DefaultSubscriptionController extends BasePreferenceController implements
+ LifecycleObserver, Preference.OnPreferenceChangeListener,
+ SubscriptionsChangeListener.SubscriptionsChangeListenerClient {
+ private static final String TAG = "DefaultSubController";
+
+ protected SubscriptionsChangeListener mChangeListener;
+ protected ListPreference mPreference;
+ protected SubscriptionManager mManager;
+
+ public DefaultSubscriptionController(Context context, String preferenceKey) {
+ super(context, preferenceKey);
+ mManager = context.getSystemService(SubscriptionManager.class);
+ mChangeListener = new SubscriptionsChangeListener(context, this);
+ }
+
+ public void init(Lifecycle lifecycle) {
+ lifecycle.addObserver(this);
+ }
+
+ /** @return SubscriptionInfo for the default subscription for the service, or null if there
+ * isn't one. */
+ protected abstract SubscriptionInfo getDefaultSubscriptionInfo();
+
+ /** @return the id of the default subscription for the service, or
+ * SubscriptionManager.INVALID_SUBSCRIPTION_ID if there isn't one. */
+ protected abstract int getDefaultSubscriptionId();
+
+ /** Called to change the default subscription for the service. */
+ protected abstract void setDefaultSubscription(int subscriptionId);
+
+ @Override
+ public int getAvailabilityStatus() {
+ final List<SubscriptionInfo> subs = SubscriptionUtil.getAvailableSubscriptions(mManager);
+ if (subs.size() > 1) {
+ return AVAILABLE;
+ } else {
+ return CONDITIONALLY_UNAVAILABLE;
+ }
+ }
+
+ @OnLifecycleEvent(ON_RESUME)
+ public void onResume() {
+ mChangeListener.start();
+ updateEntries();
+ }
+
+ @OnLifecycleEvent(ON_PAUSE)
+ public void onPause() {
+ mChangeListener.stop();
+ }
+
+ @Override
+ public void displayPreference(PreferenceScreen screen) {
+ super.displayPreference(screen);
+ mPreference = screen.findPreference(getPreferenceKey());
+ updateEntries();
+ }
+
+ @Override
+ public CharSequence getSummary() {
+ final SubscriptionInfo info = getDefaultSubscriptionInfo();
+ if (info != null) {
+ return info.getDisplayName();
+ } else {
+ return mContext.getString(R.string.calls_and_sms_ask_every_time);
+ }
+ }
+
+ private void updateEntries() {
+ if (mPreference == null) {
+ return;
+ }
+ if (!isAvailable()) {
+ mPreference.setVisible(false);
+ return;
+ }
+ mPreference.setVisible(true);
+
+ final List<SubscriptionInfo> subs = SubscriptionUtil.getAvailableSubscriptions(mManager);
+
+ // We'll have one entry for each available subscription, plus one for a "ask me every
+ // time" entry at the end.
+ final CharSequence[] displayNames = new CharSequence[subs.size() + 1];
+ final CharSequence[] subscriptionIds = new CharSequence[subs.size() + 1];
+
+ final int serviceDefaultSubId = getDefaultSubscriptionId();
+ boolean subIsAvailable = false;
+
+ int i = 0;
+ for (; i < subs.size(); i++) {
+ displayNames[i] = subs.get(i).getDisplayName();
+ final int subId = subs.get(i).getSubscriptionId();
+ subscriptionIds[i] = Integer.toString(subId);
+ if (subId == serviceDefaultSubId) {
+ subIsAvailable = true;
+ }
+ }
+ // Add the extra "Ask every time" value at the end.
+ displayNames[i] = mContext.getString(R.string.calls_and_sms_ask_every_time);
+ subscriptionIds[i] = Integer.toString(SubscriptionManager.INVALID_SUBSCRIPTION_ID);
+
+ mPreference.setEntries(displayNames);
+ mPreference.setEntryValues(subscriptionIds);
+
+ if (subIsAvailable) {
+ mPreference.setValue(Integer.toString(serviceDefaultSubId));
+ } else {
+ mPreference.setValue(Integer.toString(SubscriptionManager.INVALID_SUBSCRIPTION_ID));
+ }
+ }
+
+ @Override
+ public boolean onPreferenceChange(Preference preference, Object newValue) {
+ final int subscriptionId = Integer.parseInt((String) newValue);
+ setDefaultSubscription(subscriptionId);
+ refreshSummary(mPreference);
+ return true;
+ }
+
+ @Override
+ public void onAirplaneModeChanged(boolean airplaneModeEnabled) {
+ }
+
+ @Override
+ public void onSubscriptionsChanged() {
+ if (mPreference != null) {
+ updateEntries();
+ refreshSummary(mPreference);
+ }
+ }
+}
diff --git a/src/com/android/settings/network/telephony/MobileNetworkSettings.java b/src/com/android/settings/network/telephony/MobileNetworkSettings.java
index 9665c09..5201586 100644
--- a/src/com/android/settings/network/telephony/MobileNetworkSettings.java
+++ b/src/com/android/settings/network/telephony/MobileNetworkSettings.java
@@ -126,6 +126,10 @@
public void onAttach(Context context) {
super.onAttach(context);
+ if (FeatureFlagPersistent.isEnabled(getContext(), FeatureFlags.NETWORK_INTERNET_V2)) {
+ use(CallsDefaultSubscriptionController.class).init(getLifecycle());
+ use(SmsDefaultSubscriptionController.class).init(getLifecycle());
+ }
use(MobileDataPreferenceController.class).init(getFragmentManager(), mSubId);
use(RoamingPreferenceController.class).init(getFragmentManager(), mSubId);
use(ApnPreferenceController.class).init(mSubId);
diff --git a/src/com/android/settings/network/telephony/SmsDefaultSubscriptionController.java b/src/com/android/settings/network/telephony/SmsDefaultSubscriptionController.java
new file mode 100644
index 0000000..b999219
--- /dev/null
+++ b/src/com/android/settings/network/telephony/SmsDefaultSubscriptionController.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.network.telephony;
+
+import android.content.Context;
+import android.telephony.SubscriptionInfo;
+import android.telephony.SubscriptionManager;
+
+public class SmsDefaultSubscriptionController extends DefaultSubscriptionController {
+
+ public SmsDefaultSubscriptionController(Context context, String preferenceKey) {
+ super(context, preferenceKey);
+ }
+
+ @Override
+ protected SubscriptionInfo getDefaultSubscriptionInfo() {
+ return mManager.getDefaultSmsSubscriptionInfo();
+ }
+
+ @Override
+ protected int getDefaultSubscriptionId() {
+ return SubscriptionManager.getDefaultSmsSubscriptionId();
+ }
+
+ @Override
+ protected void setDefaultSubscription(int subscriptionId) {
+ mManager.setDefaultSmsSubId(subscriptionId);
+ }
+}
diff --git a/src/com/android/settings/notification/RedactionInterstitial.java b/src/com/android/settings/notification/RedactionInterstitial.java
index cc26f8a..f765694 100644
--- a/src/com/android/settings/notification/RedactionInterstitial.java
+++ b/src/com/android/settings/notification/RedactionInterstitial.java
@@ -47,8 +47,8 @@
import com.android.settings.Utils;
import com.android.settingslib.RestrictedLockUtilsInternal;
-import com.google.android.setupcompat.item.FooterButton;
-import com.google.android.setupcompat.template.ButtonFooterMixin;
+import com.google.android.setupcompat.template.FooterBarMixin;
+import com.google.android.setupcompat.template.FooterButton;
import com.google.android.setupdesign.GlifLayout;
public class RedactionInterstitial extends SettingsActivity {
@@ -133,8 +133,8 @@
}
final GlifLayout layout = view.findViewById(R.id.setup_wizard_layout);
- final ButtonFooterMixin buttonFooterMixin = layout.getMixin(ButtonFooterMixin.class);
- buttonFooterMixin.setPrimaryButton(
+ final FooterBarMixin mixin = layout.getMixin(FooterBarMixin.class);
+ mixin.setPrimaryButton(
new FooterButton.Builder(getContext())
.setText(R.string.app_notifications_dialog_done)
.setListener(this::onDoneButtonClicked)
diff --git a/src/com/android/settings/notification/ZenRuleButtonsPreferenceController.java b/src/com/android/settings/notification/ZenRuleButtonsPreferenceController.java
index a773908..a014ec9 100644
--- a/src/com/android/settings/notification/ZenRuleButtonsPreferenceController.java
+++ b/src/com/android/settings/notification/ZenRuleButtonsPreferenceController.java
@@ -62,7 +62,7 @@
if (isAvailable()) {
mButtonsPref = ((ActionButtonsPreference) screen.findPreference(KEY))
.setButton1Text(R.string.zen_mode_rule_name_edit)
- .setButton1Icon(R.drawable.ic_mode_edit)
+ .setButton1Icon(com.android.internal.R.drawable.ic_mode_edit)
.setButton1OnClickListener(new EditRuleNameClickListener())
.setButton2Text(R.string.zen_mode_delete_rule_button)
.setButton2Icon(R.drawable.ic_settings_delete)
diff --git a/src/com/android/settings/panel/MediaOutputPanel.java b/src/com/android/settings/panel/MediaOutputPanel.java
new file mode 100644
index 0000000..f7639d9
--- /dev/null
+++ b/src/com/android/settings/panel/MediaOutputPanel.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.panel;
+
+import static com.android.settings.media.MediaOutputSlice.MEDIA_PACKAGE_NAME;
+import static com.android.settings.slices.CustomSliceRegistry.MEDIA_OUTPUT_SLICE_URI;
+
+import android.content.Context;
+import android.content.Intent;
+import android.net.Uri;
+
+import com.android.settings.R;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Represents the Media output Panel.
+ *
+ * <p>
+ * Displays Media output item
+ * </p>
+ */
+public class MediaOutputPanel implements PanelContent {
+
+ private final Context mContext;
+ private final String mPackageName;
+
+ public static MediaOutputPanel create(Context context, String packageName) {
+ return new MediaOutputPanel(context, packageName);
+ }
+
+ private MediaOutputPanel(Context context, String packageName) {
+ mContext = context.getApplicationContext();
+ mPackageName = packageName;
+ }
+
+ @Override
+ public CharSequence getTitle() {
+ return mContext.getText(R.string.media_output_panel_title);
+ }
+
+ @Override
+ public List<Uri> getSlices() {
+ final List<Uri> uris = new ArrayList<>();
+ MEDIA_OUTPUT_SLICE_URI =
+ MEDIA_OUTPUT_SLICE_URI
+ .buildUpon()
+ .clearQuery()
+ .appendQueryParameter(MEDIA_PACKAGE_NAME, mPackageName)
+ .build();
+ uris.add(MEDIA_OUTPUT_SLICE_URI);
+ return uris;
+ }
+
+ @Override
+ public Intent getSeeMoreIntent() {
+ return null;
+ }
+}
diff --git a/src/com/android/settings/panel/NfcPanel.java b/src/com/android/settings/panel/NfcPanel.java
new file mode 100644
index 0000000..70452a3
--- /dev/null
+++ b/src/com/android/settings/panel/NfcPanel.java
@@ -0,0 +1,53 @@
+package com.android.settings.panel;
+
+import android.app.settings.SettingsEnums;
+import android.content.Context;
+import android.content.Intent;
+import android.net.Uri;
+
+import com.android.settings.R;
+import com.android.settings.SubSettings;
+import com.android.settings.connecteddevice.AdvancedConnectedDeviceDashboardFragment;
+import com.android.settings.slices.CustomSliceRegistry;
+import com.android.settings.slices.SliceBuilderUtils;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class NfcPanel implements PanelContent {
+
+ private final Context mContext;
+
+ public static NfcPanel create(Context context) {
+ return new NfcPanel(context);
+ }
+
+ private NfcPanel(Context context) {
+ mContext = context.getApplicationContext();
+ }
+
+ @Override
+ public CharSequence getTitle() {
+ return mContext.getText(R.string.nfc_quick_toggle_title);
+ }
+
+ @Override
+ public List<Uri> getSlices() {
+ final List<Uri> uris = new ArrayList<>();
+ uris.add(CustomSliceRegistry.NFC_SLICE_URI);
+ return uris;
+ }
+
+ @Override
+ public Intent getSeeMoreIntent() {
+ final String screenTitle =
+ mContext.getText(R.string.connected_device_connections_title).toString();
+ Intent intent = SliceBuilderUtils.buildSearchResultPageIntent(mContext,
+ AdvancedConnectedDeviceDashboardFragment.class.getName(),
+ null /* key */,
+ screenTitle,
+ SettingsEnums.SETTINGS_CONNECTED_DEVICE_CATEGORY);
+ intent.setClassName(mContext.getPackageName(), SubSettings.class.getName());
+ return intent;
+ }
+}
diff --git a/src/com/android/settings/panel/PanelFeatureProvider.java b/src/com/android/settings/panel/PanelFeatureProvider.java
index 7d6c558..5af5ac8 100644
--- a/src/com/android/settings/panel/PanelFeatureProvider.java
+++ b/src/com/android/settings/panel/PanelFeatureProvider.java
@@ -21,7 +21,7 @@
public interface PanelFeatureProvider {
/**
- * Returns {@link PanelContent} as specified by the {@param panelType}.
+ * Returns {@link PanelContent} as specified by the {@code panelType} and {@code packageName}.
*/
- PanelContent getPanel(Context context, String panelType);
+ PanelContent getPanel(Context context, String panelType, String packageName);
}
diff --git a/src/com/android/settings/panel/PanelFeatureProviderImpl.java b/src/com/android/settings/panel/PanelFeatureProviderImpl.java
index ade2ffd..c3d611d 100644
--- a/src/com/android/settings/panel/PanelFeatureProviderImpl.java
+++ b/src/com/android/settings/panel/PanelFeatureProviderImpl.java
@@ -16,18 +16,24 @@
package com.android.settings.panel;
+import static com.android.settingslib.media.MediaOutputSliceConstants.ACTION_MEDIA_OUTPUT;
+
import android.content.Context;
import android.provider.Settings;
public class PanelFeatureProviderImpl implements PanelFeatureProvider {
@Override
- public PanelContent getPanel(Context context, String panelType) {
+ public PanelContent getPanel(Context context, String panelType, String packageName) {
switch (panelType) {
case Settings.Panel.ACTION_INTERNET_CONNECTIVITY:
return InternetConnectivityPanel.create(context);
case Settings.Panel.ACTION_VOLUME:
return VolumePanel.create(context);
+ case Settings.Panel.ACTION_NFC:
+ return NfcPanel.create(context);
+ case ACTION_MEDIA_OUTPUT:
+ return MediaOutputPanel.create(context, packageName);
}
throw new IllegalStateException("No matching panel for: " + panelType);
diff --git a/src/com/android/settings/panel/PanelFragment.java b/src/com/android/settings/panel/PanelFragment.java
index 3d302fc..db0bf0e 100644
--- a/src/com/android/settings/panel/PanelFragment.java
+++ b/src/com/android/settings/panel/PanelFragment.java
@@ -70,10 +70,12 @@
final Bundle arguments = getArguments();
final String panelType = arguments.getString(SettingsPanelActivity.KEY_PANEL_TYPE_ARGUMENT);
+ final String packageName =
+ arguments.getString(SettingsPanelActivity.KEY_PANEL_PACKAGE_NAME);
final PanelContent panel = FeatureFactory.getFactory(activity)
.getPanelFeatureProvider()
- .getPanel(activity, panelType);
+ .getPanel(activity, panelType, packageName);
mAdapter = new PanelSlicesAdapter(this, panel.getSlices());
@@ -86,6 +88,11 @@
mSeeMoreButton.setOnClickListener(getSeeMoreListener(panel.getSeeMoreIntent()));
mDoneButton.setOnClickListener(mDoneButtonListener);
+ //If getSeeMoreIntent() is null, hide the mSeeMoreButton.
+ if (panel.getSeeMoreIntent() == null) {
+ mSeeMoreButton.setVisibility(View.GONE);
+ }
+
return view;
}
diff --git a/src/com/android/settings/panel/SettingsPanelActivity.java b/src/com/android/settings/panel/SettingsPanelActivity.java
index 02e14e8..4cf535e 100644
--- a/src/com/android/settings/panel/SettingsPanelActivity.java
+++ b/src/com/android/settings/panel/SettingsPanelActivity.java
@@ -16,8 +16,12 @@
package com.android.settings.panel;
+import static com.android.settingslib.media.MediaOutputSliceConstants.ACTION_MEDIA_OUTPUT;
+import static com.android.settingslib.media.MediaOutputSliceConstants.EXTRA_PACKAGE_NAME;
+
import android.content.Intent;
import android.os.Bundle;
+import android.text.TextUtils;
import android.util.Log;
import android.view.Gravity;
import android.view.Window;
@@ -28,6 +32,7 @@
import androidx.fragment.app.FragmentActivity;
import androidx.fragment.app.FragmentManager;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.settings.R;
/**
@@ -37,10 +42,14 @@
private final String TAG = "panel_activity";
+ @VisibleForTesting
+ final Bundle mBundle = new Bundle();
+
/**
* Key specifying which Panel the app is requesting.
*/
public static final String KEY_PANEL_TYPE_ARGUMENT = "PANEL_TYPE_ARGUMENT";
+ public static final String KEY_PANEL_PACKAGE_NAME = "PANEL_PACKAGE_NAME";
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
@@ -53,6 +62,16 @@
return;
}
+ final String packageName =
+ callingIntent.getStringExtra(EXTRA_PACKAGE_NAME);
+
+ if (TextUtils.equals(ACTION_MEDIA_OUTPUT, callingIntent.getAction())
+ && TextUtils.isEmpty(packageName)) {
+ Log.e(TAG, "Null package name, closing Panel Activity");
+ finish();
+ return;
+ }
+
setContentView(R.layout.settings_panel);
// Move the window to the bottom of screen, and make it take up the entire screen width.
@@ -61,11 +80,11 @@
window.setLayout(WindowManager.LayoutParams.MATCH_PARENT,
WindowManager.LayoutParams.WRAP_CONTENT);
- final Bundle bundle = new Bundle();
- bundle.putString(KEY_PANEL_TYPE_ARGUMENT, callingIntent.getAction());
+ mBundle.putString(KEY_PANEL_TYPE_ARGUMENT, callingIntent.getAction());
+ mBundle.putString(KEY_PANEL_PACKAGE_NAME, packageName);
final PanelFragment panelFragment = new PanelFragment();
- panelFragment.setArguments(bundle);
+ panelFragment.setArguments(mBundle);
final FragmentManager fragmentManager = getSupportFragmentManager();
final Fragment fragment = fragmentManager.findFragmentById(R.id.main_content);
diff --git a/src/com/android/settings/password/BiometricFragment.java b/src/com/android/settings/password/BiometricFragment.java
index 13ec543..3809a4a 100644
--- a/src/com/android/settings/password/BiometricFragment.java
+++ b/src/com/android/settings/password/BiometricFragment.java
@@ -30,6 +30,7 @@
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
+import com.android.settings.R;
import com.android.settings.core.InstrumentedFragment;
import java.util.concurrent.Executor;
@@ -39,11 +40,6 @@
*/
public class BiometricFragment extends InstrumentedFragment {
- private static final String KEY_TITLE = "title";
- private static final String KEY_SUBTITLE = "subtitle";
- private static final String KEY_DESCRIPTION = "description";
- private static final String KEY_NEGATIVE_TEXT = "negative_text";
-
// Re-set by the application. Should be done upon orientation changes, etc
private Executor mClientExecutor;
private AuthenticationCallback mClientCallback;
@@ -53,7 +49,7 @@
// Created/Initialized once and retained
private final Handler mHandler = new Handler(Looper.getMainLooper());
- private PromptInfo mPromptInfo;
+ private Bundle mBundle;
private BiometricPrompt mBiometricPrompt;
private CancellationSignal mCancellationSignal;
@@ -82,13 +78,17 @@
public void onClick(DialogInterface dialog, int which) {
mAuthenticationCallback.onAuthenticationError(
BiometricConstants.BIOMETRIC_ERROR_NEGATIVE_BUTTON,
- mPromptInfo.getNegativeButtonText());
+ mBundle.getString(BiometricPrompt.KEY_NEGATIVE_TEXT));
}
};
- public static BiometricFragment newInstance(PromptInfo info) {
+ /**
+ * @param bundle Bundle passed from {@link BiometricPrompt.Builder#buildIntent()}
+ * @return
+ */
+ public static BiometricFragment newInstance(Bundle bundle) {
BiometricFragment biometricFragment = new BiometricFragment();
- biometricFragment.setArguments(info.getBundle());
+ biometricFragment.setArguments(bundle);
return biometricFragment;
}
@@ -119,14 +119,16 @@
super.onCreate(savedInstanceState);
setRetainInstance(true);
- mPromptInfo = new PromptInfo(getArguments());
+ mBundle = getArguments();
mBiometricPrompt = new BiometricPrompt.Builder(getContext())
- .setTitle(mPromptInfo.getTitle())
+ .setTitle(mBundle.getString(BiometricPrompt.KEY_TITLE))
.setUseDefaultTitle() // use default title if title is null/empty
- .setSubtitle(mPromptInfo.getSubtitle())
- .setDescription(mPromptInfo.getDescription())
- .setNegativeButton(mPromptInfo.getNegativeButtonText(), mClientExecutor,
- mNegativeButtonListener)
+ .setSubtitle(mBundle.getString(BiometricPrompt.KEY_SUBTITLE))
+ .setDescription(mBundle.getString(BiometricPrompt.KEY_DESCRIPTION))
+ .setRequireConfirmation(mBundle.getBoolean(BiometricPrompt.KEY_REQUIRE_CONFIRMATION))
+ .setNegativeButton(getResources().getString(
+ R.string.confirm_device_credential_use_alternate_method),
+ mClientExecutor, mNegativeButtonListener)
.build();
mCancellationSignal = new CancellationSignal();
@@ -139,65 +141,5 @@
public int getMetricsCategory() {
return SettingsEnums.BIOMETRIC_FRAGMENT;
}
-
- /**
- * A simple wrapper for BiometricPrompt.PromptInfo. Since we want to manage the lifecycle
- * of BiometricPrompt correctly, the information needs to be stored in here.
- */
- static class PromptInfo {
- private final Bundle mBundle;
-
- private PromptInfo(Bundle bundle) {
- mBundle = bundle;
- }
-
- Bundle getBundle() {
- return mBundle;
- }
-
- public CharSequence getTitle() {
- return mBundle.getCharSequence(KEY_TITLE);
- }
-
- public CharSequence getSubtitle() {
- return mBundle.getCharSequence(KEY_SUBTITLE);
- }
-
- public CharSequence getDescription() {
- return mBundle.getCharSequence(KEY_DESCRIPTION);
- }
-
- public CharSequence getNegativeButtonText() {
- return mBundle.getCharSequence(KEY_NEGATIVE_TEXT);
- }
-
- public static class Builder {
- private final Bundle mBundle = new Bundle();
-
- public Builder setTitle(@NonNull CharSequence title) {
- mBundle.putCharSequence(KEY_TITLE, title);
- return this;
- }
-
- public Builder setSubtitle(@Nullable CharSequence subtitle) {
- mBundle.putCharSequence(KEY_SUBTITLE, subtitle);
- return this;
- }
-
- public Builder setDescription(@Nullable CharSequence description) {
- mBundle.putCharSequence(KEY_DESCRIPTION, description);
- return this;
- }
-
- public Builder setNegativeButtonText(@NonNull CharSequence text) {
- mBundle.putCharSequence(KEY_NEGATIVE_TEXT, text);
- return this;
- }
-
- public PromptInfo build() {
- return new PromptInfo(mBundle);
- }
- }
- }
}
diff --git a/src/com/android/settings/password/ChooseLockGeneric.java b/src/com/android/settings/password/ChooseLockGeneric.java
index ca96344..cae7d33 100644
--- a/src/com/android/settings/password/ChooseLockGeneric.java
+++ b/src/com/android/settings/password/ChooseLockGeneric.java
@@ -18,13 +18,20 @@
import static android.app.admin.DevicePolicyManager.ACTION_SET_NEW_PARENT_PROFILE_PASSWORD;
import static android.app.admin.DevicePolicyManager.ACTION_SET_NEW_PASSWORD;
+import static android.app.admin.DevicePolicyManager.PASSWORD_COMPLEXITY_HIGH;
+import static android.app.admin.DevicePolicyManager.PASSWORD_COMPLEXITY_LOW;
+import static android.app.admin.DevicePolicyManager.PASSWORD_COMPLEXITY_MEDIUM;
+import static android.app.admin.DevicePolicyManager.PASSWORD_COMPLEXITY_NONE;
import static com.android.settings.password.ChooseLockPassword.ChooseLockPasswordFragment.RESULT_FINISHED;
+import static com.android.settings.password.ChooseLockSettingsHelper.EXTRA_KEY_CALLER_APP_NAME;
+import static com.android.settings.password.ChooseLockSettingsHelper.EXTRA_KEY_REQUESTED_MIN_COMPLEXITY;
import android.accessibilityservice.AccessibilityServiceInfo;
import android.app.Activity;
import android.app.Dialog;
import android.app.admin.DevicePolicyManager;
+import android.app.admin.DevicePolicyManager.PasswordComplexity;
import android.app.settings.SettingsEnums;
import android.content.Context;
import android.content.Intent;
@@ -66,6 +73,8 @@
import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
import com.android.settingslib.RestrictedLockUtilsInternal;
import com.android.settingslib.RestrictedPreference;
+import com.android.settingslib.widget.FooterPreference;
+import com.android.settingslib.widget.FooterPreferenceMixinCompat;
import java.util.List;
@@ -152,6 +161,14 @@
private UserManager mUserManager;
private ChooseLockGenericController mController;
+ /**
+ * From intent extra {@link ChooseLockSettingsHelper#EXTRA_KEY_REQUESTED_MIN_COMPLEXITY}.
+ */
+ @PasswordComplexity private int mRequestedMinComplexity;
+
+ /** From intent extra {@link ChooseLockSettingsHelper#EXTRA_KEY_CALLER_APP_NAME}. */
+ private String mCallerAppName = null;
+
protected boolean mForFingerprint = false;
protected boolean mForFace = false;
@@ -195,6 +212,10 @@
ChooseLockSettingsHelper.EXTRA_KEY_FOR_FINGERPRINT, false);
mForFace = getActivity().getIntent().getBooleanExtra(
ChooseLockSettingsHelper.EXTRA_KEY_FOR_FACE, false);
+ mRequestedMinComplexity = getActivity().getIntent()
+ .getIntExtra(EXTRA_KEY_REQUESTED_MIN_COMPLEXITY, PASSWORD_COMPLEXITY_NONE);
+ mCallerAppName =
+ getActivity().getIntent().getStringExtra(EXTRA_KEY_CALLER_APP_NAME);
mForChangeCredRequiredForBoot = getArguments() != null && getArguments().getBoolean(
ChooseLockSettingsHelper.EXTRA_KEY_FOR_CHANGE_CRED_REQUIRED_FOR_BOOT);
mUserManager = UserManager.get(getActivity());
@@ -217,7 +238,8 @@
UserManager.get(getActivity()),
getArguments(),
getActivity().getIntent().getExtras()).getIdentifier();
- mController = new ChooseLockGenericController(getContext(), mUserId);
+ mController =
+ new ChooseLockGenericController(getContext(), mUserId, mRequestedMinComplexity);
if (ACTION_SET_NEW_PASSWORD.equals(chooseLockAction)
&& UserManager.get(getActivity()).isManagedProfile(mUserId)
&& mLockPatternUtils.isSeparateProfileChallengeEnabled(mUserId)) {
@@ -291,6 +313,9 @@
// Forward the target user id to ChooseLockGeneric.
chooseLockGenericIntent.putExtra(Intent.EXTRA_USER_ID, mUserId);
chooseLockGenericIntent.putExtra(CONFIRM_CREDENTIALS, !mPasswordConfirmed);
+ chooseLockGenericIntent.putExtra(EXTRA_KEY_REQUESTED_MIN_COMPLEXITY,
+ mRequestedMinComplexity);
+ chooseLockGenericIntent.putExtra(EXTRA_KEY_CALLER_APP_NAME, mCallerAppName);
if (mUserPassword != null) {
chooseLockGenericIntent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_PASSWORD,
mUserPassword);
@@ -461,6 +486,13 @@
protected void addPreferences() {
addPreferencesFromResource(R.xml.security_settings_picker);
+ if (!TextUtils.isEmpty(mCallerAppName)) {
+ FooterPreferenceMixinCompat footerMixin =
+ new FooterPreferenceMixinCompat(this, getSettingsLifecycle());
+ FooterPreference footer = footerMixin.createFooterPreference();
+ footer.setTitle(getFooterString());
+ }
+
// Used for testing purposes
findPreference(ScreenLockType.NONE.preferenceKey).setViewId(R.id.lock_none);
findPreference(KEY_SKIP_FINGERPRINT).setViewId(R.id.lock_none);
@@ -469,6 +501,27 @@
findPreference(ScreenLockType.PASSWORD.preferenceKey).setViewId(R.id.lock_password);
}
+ private String getFooterString() {
+ @StringRes int stringId;
+ switch (mRequestedMinComplexity) {
+ case PASSWORD_COMPLEXITY_HIGH:
+ stringId = R.string.unlock_footer_high_complexity_requested;
+ break;
+ case PASSWORD_COMPLEXITY_MEDIUM:
+ stringId = R.string.unlock_footer_medium_complexity_requested;
+ break;
+ case PASSWORD_COMPLEXITY_LOW:
+ stringId = R.string.unlock_footer_low_complexity_requested;
+ break;
+ case PASSWORD_COMPLEXITY_NONE:
+ default:
+ stringId = R.string.unlock_footer_none_complexity_requested;
+ break;
+ }
+
+ return getResources().getString(stringId, mCallerAppName);
+ }
+
private void updatePreferenceText() {
if (mForFingerprint) {
setPreferenceTitle(ScreenLockType.PATTERN,
@@ -624,6 +677,7 @@
ChooseLockPassword.IntentBuilder builder =
new ChooseLockPassword.IntentBuilder(getContext())
.setPasswordQuality(quality)
+ .setRequestedMinComplexity(mRequestedMinComplexity)
.setForFingerprint(mForFingerprint)
.setForFace(mForFace)
.setUserId(mUserId);
diff --git a/src/com/android/settings/password/ChooseLockGenericController.java b/src/com/android/settings/password/ChooseLockGenericController.java
index eb7ff4e..91ca957 100644
--- a/src/com/android/settings/password/ChooseLockGenericController.java
+++ b/src/com/android/settings/password/ChooseLockGenericController.java
@@ -16,7 +16,11 @@
package com.android.settings.password;
+import static android.app.admin.DevicePolicyManager.PASSWORD_COMPLEXITY_NONE;
+
import android.app.admin.DevicePolicyManager;
+import android.app.admin.DevicePolicyManager.PasswordComplexity;
+import android.app.admin.PasswordMetrics;
import android.content.Context;
import android.os.UserHandle;
@@ -36,6 +40,7 @@
private final Context mContext;
private final int mUserId;
+ @PasswordComplexity private final int mRequestedMinComplexity;
private ManagedLockPasswordProvider mManagedPasswordProvider;
private DevicePolicyManager mDpm;
@@ -43,6 +48,19 @@
this(
context,
userId,
+ PASSWORD_COMPLEXITY_NONE);
+ }
+
+ /**
+ * @param requestedMinComplexity specifies the min password complexity to be taken into account
+ * when determining the available screen lock types
+ */
+ public ChooseLockGenericController(Context context, int userId,
+ @PasswordComplexity int requestedMinComplexity) {
+ this(
+ context,
+ userId,
+ requestedMinComplexity,
context.getSystemService(DevicePolicyManager.class),
ManagedLockPasswordProvider.get(context, userId));
}
@@ -51,21 +69,26 @@
ChooseLockGenericController(
Context context,
int userId,
+ @PasswordComplexity int requestedMinComplexity,
DevicePolicyManager dpm,
ManagedLockPasswordProvider managedLockPasswordProvider) {
mContext = context;
mUserId = userId;
+ mRequestedMinComplexity = requestedMinComplexity;
mManagedPasswordProvider = managedLockPasswordProvider;
mDpm = dpm;
}
/**
- * @return The higher quality of either the specified {@code quality} or the quality required
- * by {@link DevicePolicyManager#getPasswordQuality}.
+ * Returns the highest quality among the specified {@code quality}, the quality required by
+ * {@link DevicePolicyManager#getPasswordQuality}, and the quality required by min password
+ * complexity.
*/
public int upgradeQuality(int quality) {
- // Compare min allowed password quality
- return Math.max(quality, mDpm.getPasswordQuality(null, mUserId));
+ // Compare specified quality and dpm quality
+ int dpmUpgradedQuality = Math.max(quality, mDpm.getPasswordQuality(null, mUserId));
+ return Math.max(dpmUpgradedQuality,
+ PasswordMetrics.complexityLevelToMinQuality(mRequestedMinComplexity));
}
/**
diff --git a/src/com/android/settings/password/ChooseLockPassword.java b/src/com/android/settings/password/ChooseLockPassword.java
index 0ae664c..cd48182 100644
--- a/src/com/android/settings/password/ChooseLockPassword.java
+++ b/src/com/android/settings/password/ChooseLockPassword.java
@@ -16,14 +16,18 @@
package com.android.settings.password;
+import static android.app.admin.DevicePolicyManager.PASSWORD_COMPLEXITY_NONE;
import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC;
import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC;
import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_COMPLEX;
import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_NUMERIC;
import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX;
+import static com.android.settings.password.ChooseLockSettingsHelper.EXTRA_KEY_REQUESTED_MIN_COMPLEXITY;
+
import android.app.Activity;
import android.app.admin.DevicePolicyManager;
+import android.app.admin.DevicePolicyManager.PasswordComplexity;
import android.app.admin.PasswordMetrics;
import android.app.settings.SettingsEnums;
import android.content.Context;
@@ -56,6 +60,7 @@
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.widget.LockPatternUtils;
import com.android.internal.widget.LockPatternUtils.RequestThrottledException;
import com.android.internal.widget.TextViewInputDisabler;
@@ -68,8 +73,8 @@
import com.android.settings.notification.RedactionInterstitial;
import com.android.settings.widget.ImeAwareEditText;
-import com.google.android.setupcompat.item.FooterButton;
-import com.google.android.setupcompat.template.ButtonFooterMixin;
+import com.google.android.setupcompat.template.FooterBarMixin;
+import com.google.android.setupcompat.template.FooterButton;
import com.google.android.setupdesign.GlifLayout;
import java.util.ArrayList;
@@ -133,6 +138,11 @@
return this;
}
+ public IntentBuilder setRequestedMinComplexity(@PasswordComplexity int level) {
+ mIntent.putExtra(EXTRA_KEY_REQUESTED_MIN_COMPLEXITY, level);
+ return this;
+ }
+
public Intent build() {
return mIntent;
}
@@ -190,12 +200,10 @@
private int mPasswordMinNumeric = 0;
private int mPasswordMinNonLetter = 0;
private int mPasswordMinLengthToFulfillAllPolicies = 0;
+ private boolean mPasswordNumSequenceAllowed = true;
+ @PasswordComplexity private int mRequestedMinComplexity = PASSWORD_COMPLEXITY_NONE;
protected int mUserId;
private byte[] mPasswordHistoryHashFactor;
- /**
- * Password requirements that we need to verify.
- */
- private int[] mPasswordRequirements;
private LockPatternUtils mLockPatternUtils;
private SaveAndFinishWorker mSaveAndFinishWorker;
@@ -372,7 +380,13 @@
mForFingerprint = intent.getBooleanExtra(
ChooseLockSettingsHelper.EXTRA_KEY_FOR_FINGERPRINT, false);
mForFace = intent.getBooleanExtra(ChooseLockSettingsHelper.EXTRA_KEY_FOR_FACE, false);
- processPasswordRequirements(intent);
+ mRequestedMinComplexity = intent.getIntExtra(
+ EXTRA_KEY_REQUESTED_MIN_COMPLEXITY, PASSWORD_COMPLEXITY_NONE);
+ mRequestedQuality = Math.max(
+ intent.getIntExtra(LockPatternUtils.PASSWORD_TYPE_KEY, mRequestedQuality),
+ mLockPatternUtils.getRequestedPasswordQuality(mUserId));
+
+ loadDpmPasswordRequirements();
mChooseLockSettingsHelper = new ChooseLockSettingsHelper(getActivity());
if (intent.getBooleanExtra(
@@ -407,7 +421,7 @@
ViewGroup container = view.findViewById(R.id.password_container);
container.setOpticalInsets(Insets.NONE);
- final ButtonFooterMixin mixin = mLayout.getMixin(ButtonFooterMixin.class);
+ final FooterBarMixin mixin = mLayout.getMixin(FooterBarMixin.class);
mixin.setSecondaryButton(
new FooterButton.Builder(getActivity())
.setText(R.string.lockpassword_clear_label)
@@ -504,31 +518,6 @@
}
private void setupPasswordRequirementsView(View view) {
- final List<Integer> passwordRequirements = new ArrayList<>();
- if (mPasswordMinUpperCase > 0) {
- passwordRequirements.add(MIN_UPPER_LETTERS_IN_PASSWORD);
- }
- if (mPasswordMinLowerCase > 0) {
- passwordRequirements.add(MIN_LOWER_LETTERS_IN_PASSWORD);
- }
- if (mPasswordMinLetters > 0) {
- if (mPasswordMinLetters > mPasswordMinUpperCase + mPasswordMinLowerCase) {
- passwordRequirements.add(MIN_LETTER_IN_PASSWORD);
- }
- }
- if (mPasswordMinNumeric > 0) {
- passwordRequirements.add(MIN_NUMBER_IN_PASSWORD);
- }
- if (mPasswordMinSymbols > 0) {
- passwordRequirements.add(MIN_SYMBOLS_IN_PASSWORD);
- }
- if (mPasswordMinNonLetter > 0) {
- if (mPasswordMinNonLetter > mPasswordMinNumeric + mPasswordMinSymbols) {
- passwordRequirements.add(MIN_NON_LETTER_IN_PASSWORD);
- }
- }
- // Convert list to array.
- mPasswordRequirements = passwordRequirements.stream().mapToInt(i -> i).toArray();
mPasswordRestrictionView = view.findViewById(R.id.password_requirements_view);
mPasswordRestrictionView.setLayoutManager(new LinearLayoutManager(getActivity()));
mPasswordRequirementAdapter = new PasswordRequirementAdapter();
@@ -603,13 +592,12 @@
/**
* Read the requirements from {@link DevicePolicyManager} and intent and aggregate them.
- *
- * @param intent the incoming intent
*/
- private void processPasswordRequirements(Intent intent) {
+ private void loadDpmPasswordRequirements() {
final int dpmPasswordQuality = mLockPatternUtils.getRequestedPasswordQuality(mUserId);
- mRequestedQuality = Math.max(intent.getIntExtra(LockPatternUtils.PASSWORD_TYPE_KEY,
- mRequestedQuality), dpmPasswordQuality);
+ if (dpmPasswordQuality == PASSWORD_QUALITY_NUMERIC_COMPLEX) {
+ mPasswordNumSequenceAllowed = false;
+ }
mPasswordMinLength = Math.max(LockPatternUtils.MIN_LOCK_PASSWORD_SIZE,
mLockPatternUtils.getRequestedMinimumPasswordLength(mUserId));
mPasswordMaxLength = mLockPatternUtils.getMaximumPasswordLength(mRequestedQuality);
@@ -620,7 +608,7 @@
mPasswordMinSymbols = mLockPatternUtils.getRequestedPasswordMinimumSymbols(mUserId);
mPasswordMinNonLetter = mLockPatternUtils.getRequestedPasswordMinimumNonLetter(mUserId);
- // Modify the value based on dpm policy.
+ // Modify the value based on dpm policy
switch (dpmPasswordQuality) {
case PASSWORD_QUALITY_ALPHABETIC:
if (mPasswordMinLetters == 0) {
@@ -646,19 +634,88 @@
mPasswordMinSymbols = 0;
mPasswordMinNonLetter = 0;
}
+
mPasswordMinLengthToFulfillAllPolicies = getMinLengthToFulfillAllPolicies();
}
/**
+ * Merges the dpm requirements and the min complexity requirements.
+ *
+ * <p>Since there are more than one set of metrics to meet the min complexity requirement,
+ * and we are not hard-coding any one of them to be the requirements the user must fulfil,
+ * we are taking what the user has already entered into account when compiling the list of
+ * requirements from min complexity. Then we merge this list with the DPM requirements, and
+ * present the merged set as validation results to the user on the UI.
+ *
+ * <p>For example, suppose min complexity requires either ALPHABETIC(8+), or
+ * ALPHANUMERIC(6+). If the user has entered "a", the length requirement displayed on the UI
+ * would be 8. Then the user appends "1" to make it "a1". We now know the user is entering
+ * an alphanumeric password so we would update the min complexity required min length to 6.
+ * This might result in a little confusion for the user but the UI does not support showing
+ * multiple sets of requirements / validation results as options to users, this is the best
+ * we can do now.
+ */
+ private void mergeMinComplexityAndDpmRequirements(int userEnteredPasswordQuality) {
+ if (mRequestedMinComplexity == PASSWORD_COMPLEXITY_NONE) {
+ // dpm requirements are dominant if min complexity is none
+ return;
+ }
+
+ // reset dpm requirements
+ loadDpmPasswordRequirements();
+
+ PasswordMetrics minMetrics = PasswordMetrics.getMinimumMetrics(
+ mRequestedMinComplexity, userEnteredPasswordQuality, mRequestedQuality,
+ requiresNumeric(), requiresLettersOrSymbols());
+ mPasswordNumSequenceAllowed = mPasswordNumSequenceAllowed
+ && minMetrics.quality != PASSWORD_QUALITY_NUMERIC_COMPLEX;
+ mPasswordMinLength = Math.max(mPasswordMinLength, minMetrics.length);
+ mPasswordMinLetters = Math.max(mPasswordMinLetters, minMetrics.letters);
+ mPasswordMinUpperCase = Math.max(mPasswordMinUpperCase, minMetrics.upperCase);
+ mPasswordMinLowerCase = Math.max(mPasswordMinLowerCase, minMetrics.lowerCase);
+ mPasswordMinNumeric = Math.max(mPasswordMinNumeric, minMetrics.numeric);
+ mPasswordMinSymbols = Math.max(mPasswordMinSymbols, minMetrics.symbols);
+ mPasswordMinNonLetter = Math.max(mPasswordMinNonLetter, minMetrics.nonLetter);
+
+ if (minMetrics.quality == PASSWORD_QUALITY_ALPHABETIC) {
+ if (!requiresLettersOrSymbols()) {
+ mPasswordMinLetters = 1;
+ }
+ }
+ if (minMetrics.quality == PASSWORD_QUALITY_ALPHANUMERIC) {
+ if (!requiresLettersOrSymbols()) {
+ mPasswordMinLetters = 1;
+ }
+ if (!requiresNumeric()) {
+ mPasswordMinNumeric = 1;
+ }
+ }
+
+ mPasswordMinLengthToFulfillAllPolicies = getMinLengthToFulfillAllPolicies();
+ }
+
+ private boolean requiresLettersOrSymbols() {
+ // This is the condition for the password to be considered ALPHABETIC according to
+ // PasswordMetrics.computeForPassword()
+ return mPasswordMinLetters + mPasswordMinUpperCase
+ + mPasswordMinLowerCase + mPasswordMinSymbols + mPasswordMinNonLetter > 0;
+ }
+
+ private boolean requiresNumeric() {
+ return mPasswordMinNumeric > 0;
+ }
+
+ /**
* Validates PIN/Password and returns the validation result.
*
* @param password the raw password the user typed in
* @return the validation result.
*/
- private int validatePassword(String password) {
+ @VisibleForTesting
+ int validatePassword(String password) {
int errorCode = NO_ERROR;
final PasswordMetrics metrics = PasswordMetrics.computeForPassword(password);
-
+ mergeMinComplexityAndDpmRequirements(metrics.quality);
if (password.length() < mPasswordMinLength) {
if (mPasswordMinLength > mPasswordMinLengthToFulfillAllPolicies) {
@@ -668,14 +725,25 @@
errorCode |= TOO_LONG;
} else {
// The length requirements are fulfilled.
- final int dpmQuality = mLockPatternUtils.getRequestedPasswordQuality(mUserId);
- if (dpmQuality == PASSWORD_QUALITY_NUMERIC_COMPLEX &&
- metrics.numeric == password.length()) {
+ if (!mPasswordNumSequenceAllowed
+ && !requiresLettersOrSymbols()
+ && metrics.numeric == password.length()) {
// Check for repeated characters or sequences (e.g. '1234', '0000', '2468')
- // if DevicePolicyManager requires a complex numeric password. There can be
- // two cases in the UI: 1. User chooses to enroll a PIN, 2. User chooses to
- // enroll a password but enters a numeric-only pin. We should carry out the
- // sequence check in both cases.
+ // if DevicePolicyManager or min password complexity requires a complex numeric
+ // password. There can be two cases in the UI: 1. User chooses to enroll a
+ // PIN, 2. User chooses to enroll a password but enters a numeric-only pin. We
+ // should carry out the sequence check in both cases.
+ //
+ // Conditions for the !requiresLettersOrSymbols() to be necessary:
+ // - DPM requires NUMERIC_COMPLEX
+ // - min complexity not NONE, user picks PASSWORD type so ALPHABETIC or
+ // ALPHANUMERIC is required
+ // Imagine user has entered "12345678", if we don't skip the sequence check, the
+ // validation result would show both "requires a letter" and "sequence not
+ // allowed", while the only requirement the user needs to know is "requires a
+ // letter" because once the user has fulfilled the alphabetic requirement, the
+ // password would not be containing only digits so this check would not be
+ // performed anyway.
final int sequence = PasswordMetrics.maxLengthSequence(password);
if (sequence > PasswordMetrics.MAX_ALLOWED_SEQUENCE) {
errorCode |= CONTAIN_SEQUENTIAL_DIGITS;
@@ -706,43 +774,24 @@
}
}
- // Check the requirements one by one.
- for (int i = 0; i < mPasswordRequirements.length; i++) {
- int passwordRestriction = mPasswordRequirements[i];
- switch (passwordRestriction) {
- case MIN_LETTER_IN_PASSWORD:
- if (metrics.letters < mPasswordMinLetters) {
- errorCode |= NOT_ENOUGH_LETTER;
- }
- break;
- case MIN_UPPER_LETTERS_IN_PASSWORD:
- if (metrics.upperCase < mPasswordMinUpperCase) {
- errorCode |= NOT_ENOUGH_UPPER_CASE;
- }
- break;
- case MIN_LOWER_LETTERS_IN_PASSWORD:
- if (metrics.lowerCase < mPasswordMinLowerCase) {
- errorCode |= NOT_ENOUGH_LOWER_CASE;
- }
- break;
- case MIN_SYMBOLS_IN_PASSWORD:
- if (metrics.symbols < mPasswordMinSymbols) {
- errorCode |= NOT_ENOUGH_SYMBOLS;
- }
- break;
- case MIN_NUMBER_IN_PASSWORD:
- if (metrics.numeric < mPasswordMinNumeric) {
- errorCode |= NOT_ENOUGH_DIGITS;
- }
- break;
- case MIN_NON_LETTER_IN_PASSWORD:
- if (metrics.nonLetter < mPasswordMinNonLetter) {
- errorCode |= NOT_ENOUGH_NON_LETTER;
- }
- break;
- }
+ if (metrics.letters < mPasswordMinLetters) {
+ errorCode |= NOT_ENOUGH_LETTER;
}
-
+ if (metrics.upperCase < mPasswordMinUpperCase) {
+ errorCode |= NOT_ENOUGH_UPPER_CASE;
+ }
+ if (metrics.lowerCase < mPasswordMinLowerCase) {
+ errorCode |= NOT_ENOUGH_LOWER_CASE;
+ }
+ if (metrics.symbols < mPasswordMinSymbols) {
+ errorCode |= NOT_ENOUGH_SYMBOLS;
+ }
+ if (metrics.numeric < mPasswordMinNumeric) {
+ errorCode |= NOT_ENOUGH_DIGITS;
+ }
+ if (metrics.nonLetter < mPasswordMinNonLetter) {
+ errorCode |= NOT_ENOUGH_NON_LETTER;
+ }
return errorCode;
}
diff --git a/src/com/android/settings/password/ChooseLockPattern.java b/src/com/android/settings/password/ChooseLockPattern.java
index 1f0bb4e..584cc61 100644
--- a/src/com/android/settings/password/ChooseLockPattern.java
+++ b/src/com/android/settings/password/ChooseLockPattern.java
@@ -50,8 +50,8 @@
import com.android.settings.notification.RedactionInterstitial;
import com.google.android.collect.Lists;
-import com.google.android.setupcompat.item.FooterButton;
-import com.google.android.setupcompat.template.ButtonFooterMixin;
+import com.google.android.setupcompat.template.FooterBarMixin;
+import com.google.android.setupcompat.template.FooterButton;
import com.google.android.setupdesign.GlifLayout;
import java.util.ArrayList;
@@ -489,7 +489,7 @@
}
}
- final ButtonFooterMixin mixin = layout.getMixin(ButtonFooterMixin.class);
+ final FooterBarMixin mixin = layout.getMixin(FooterBarMixin.class);
mixin.setSecondaryButton(
new FooterButton.Builder(getActivity())
.setText(R.string.lockpattern_tutorial_cancel_label)
@@ -512,7 +512,6 @@
return layout;
}
-
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
diff --git a/src/com/android/settings/password/ChooseLockSettingsHelper.java b/src/com/android/settings/password/ChooseLockSettingsHelper.java
index 8d0fa60..32e8eaf 100644
--- a/src/com/android/settings/password/ChooseLockSettingsHelper.java
+++ b/src/com/android/settings/password/ChooseLockSettingsHelper.java
@@ -46,6 +46,18 @@
public static final String EXTRA_KEY_FOR_CHANGE_CRED_REQUIRED_FOR_BOOT = "for_cred_req_boot";
/**
+ * Intent extra for passing the requested min password complexity to later steps in the set new
+ * screen lock flow.
+ */
+ public static final String EXTRA_KEY_REQUESTED_MIN_COMPLEXITY = "requested_min_complexity";
+
+ /**
+ * Intent extra for passing the label of the calling app to later steps in the set new screen
+ * lock flow.
+ */
+ public static final String EXTRA_KEY_CALLER_APP_NAME = "caller_app_name";
+
+ /**
* When invoked via {@link ConfirmLockPassword.InternalActivity}, this flag
* controls if we relax the enforcement of
* {@link Utils#enforceSameOwner(android.content.Context, int)}.
diff --git a/src/com/android/settings/password/ConfirmDeviceCredentialActivity.java b/src/com/android/settings/password/ConfirmDeviceCredentialActivity.java
index 5eb1f32..3fa2f6a 100644
--- a/src/com/android/settings/password/ConfirmDeviceCredentialActivity.java
+++ b/src/com/android/settings/password/ConfirmDeviceCredentialActivity.java
@@ -23,6 +23,7 @@
import android.app.trust.TrustManager;
import android.content.Context;
import android.content.Intent;
+import android.hardware.biometrics.BiometricConstants;
import android.hardware.biometrics.BiometricManager;
import android.hardware.biometrics.BiometricPrompt;
import android.hardware.biometrics.BiometricPrompt.AuthenticationCallback;
@@ -87,6 +88,8 @@
private TrustManager mTrustManager;
private ChooseLockSettingsHelper mChooseLockSettingsHelper;
private Handler mHandler = new Handler(Looper.getMainLooper());
+ private boolean mIsFallback; // BiometricPrompt fallback
+ private boolean mCCLaunched;
private String mTitle;
private String mDetails;
@@ -102,6 +105,13 @@
public void onAuthenticationError(int errorCode, @NonNull CharSequence errString) {
if (!mGoingToBackground) {
if (errorCode == BiometricPrompt.BIOMETRIC_ERROR_USER_CANCELED) {
+ if (mIsFallback) {
+ mBiometricManager.onConfirmDeviceCredentialError(
+ BiometricConstants.BIOMETRIC_ERROR_USER_CANCELED,
+ getString(
+ com.android.internal.R.string
+ .biometric_error_user_canceled));
+ }
finish();
} else {
// All other errors go to some version of CC
@@ -118,6 +128,10 @@
ConfirmDeviceCredentialUtils.checkForPendingIntent(
ConfirmDeviceCredentialActivity.this);
+ if (mIsFallback) {
+ mBiometricManager.onConfirmDeviceCredentialSuccess();
+ }
+
setResult(Activity.RESULT_OK);
finish();
}
@@ -158,6 +172,19 @@
mChooseLockSettingsHelper = new ChooseLockSettingsHelper(this);
final LockPatternUtils lockPatternUtils = new LockPatternUtils(this);
+ Bundle bpBundle =
+ intent.getBundleExtra(KeyguardManager.EXTRA_BIOMETRIC_PROMPT_BUNDLE);
+ if (bpBundle != null) {
+ mIsFallback = true;
+ // TODO: CDC maybe should show description as well.
+ mTitle = bpBundle.getString(BiometricPrompt.KEY_TITLE);
+ mDetails = bpBundle.getString(BiometricPrompt.KEY_SUBTITLE);
+ } else {
+ bpBundle = new Bundle();
+ bpBundle.putString(BiometricPrompt.KEY_TITLE, mTitle);
+ bpBundle.putString(BiometricPrompt.KEY_SUBTITLE, mDetails);
+ }
+
boolean launchedBiometric = false;
boolean launchedCDC = false;
// If the target is a managed user and user key not unlocked yet, we will force unlock
@@ -170,7 +197,7 @@
&& !lockPatternUtils.isSeparateProfileChallengeEnabled(mUserId)) {
mCredentialMode = CREDENTIAL_MANAGED;
if (isBiometricAllowed(effectiveUserId)) {
- showBiometricPrompt();
+ showBiometricPrompt(bpBundle);
launchedBiometric = true;
} else {
showConfirmCredentials();
@@ -181,7 +208,7 @@
if (isBiometricAllowed(effectiveUserId)) {
// Don't need to check if biometrics / pin/pattern/pass are enrolled. It will go to
// onAuthenticationError and do the right thing automatically.
- showBiometricPrompt();
+ showBiometricPrompt(bpBundle);
launchedBiometric = true;
} else {
showConfirmCredentials();
@@ -216,6 +243,13 @@
if (mBiometricFragment != null) {
mBiometricFragment.cancel();
}
+
+ if (mIsFallback && !mCCLaunched) {
+ mBiometricManager.onConfirmDeviceCredentialError(
+ BiometricConstants.BIOMETRIC_ERROR_CANCELED,
+ getString(com.android.internal.R.string.biometric_error_user_canceled));
+ }
+
finish();
} else {
mGoingToBackground = false;
@@ -242,7 +276,7 @@
&& !isBiometricDisabledByAdmin(effectiveUserId);
}
- private void showBiometricPrompt() {
+ private void showBiometricPrompt(Bundle bundle) {
mBiometricManager.setActiveUser(mUserId);
mBiometricFragment = (BiometricFragment) getSupportFragmentManager()
@@ -250,13 +284,7 @@
boolean newFragment = false;
if (mBiometricFragment == null) {
- final BiometricFragment.PromptInfo info = new BiometricFragment.PromptInfo.Builder()
- .setTitle(mTitle)
- .setSubtitle(mDetails)
- .setNegativeButtonText(getResources()
- .getString(R.string.confirm_device_credential_use_alternate_method))
- .build();
- mBiometricFragment = BiometricFragment.newInstance(info);
+ mBiometricFragment = BiometricFragment.newInstance(bundle);
newFragment = true;
}
mBiometricFragment.setCallbacks(mExecutor, mAuthenticationCallback);
@@ -272,6 +300,7 @@
* Shows ConfirmDeviceCredentials for normal apps.
*/
private void showConfirmCredentials() {
+ mCCLaunched = true;
boolean launched = false;
if (mCredentialMode == CREDENTIAL_MANAGED) {
// We set the challenge as 0L, so it will force to unlock managed profile when it
diff --git a/src/com/android/settings/password/ConfirmDeviceCredentialBaseActivity.java b/src/com/android/settings/password/ConfirmDeviceCredentialBaseActivity.java
index c00f9ab..56e6573 100644
--- a/src/com/android/settings/password/ConfirmDeviceCredentialBaseActivity.java
+++ b/src/com/android/settings/password/ConfirmDeviceCredentialBaseActivity.java
@@ -17,6 +17,8 @@
package com.android.settings.password;
import android.app.KeyguardManager;
+import android.hardware.biometrics.BiometricConstants;
+import android.hardware.biometrics.BiometricManager;
import android.os.Bundle;
import android.os.UserManager;
import android.view.MenuItem;
@@ -45,6 +47,7 @@
private boolean mFirstTimeVisible = true;
private boolean mIsKeyguardLocked = false;
private ConfirmCredentialTheme mConfirmCredentialTheme;
+ private BiometricManager mBiometricManager;
private boolean isInternalActivity() {
return (this instanceof ConfirmLockPassword.InternalActivity)
@@ -68,6 +71,8 @@
}
super.onCreate(savedState);
+ mBiometricManager = getSystemService(BiometricManager.class);
+
if (mConfirmCredentialTheme == ConfirmCredentialTheme.NORMAL) {
// Prevent the content parent from consuming the window insets because GlifLayout uses
// it to show the status bar background.
@@ -141,6 +146,17 @@
}
@Override
+ public void onStop() {
+ super.onStop();
+ // TODO(b/123378871): Remove when moved.
+ if (!isChangingConfigurations()) {
+ mBiometricManager.onConfirmDeviceCredentialError(
+ BiometricConstants.BIOMETRIC_ERROR_USER_CANCELED,
+ getString(com.android.internal.R.string.biometric_error_user_canceled));
+ }
+ }
+
+ @Override
public void finish() {
super.finish();
if (getIntent().getBooleanExtra(
diff --git a/src/com/android/settings/password/ConfirmDeviceCredentialBaseFragment.java b/src/com/android/settings/password/ConfirmDeviceCredentialBaseFragment.java
index 2de7625..e14ec81 100644
--- a/src/com/android/settings/password/ConfirmDeviceCredentialBaseFragment.java
+++ b/src/com/android/settings/password/ConfirmDeviceCredentialBaseFragment.java
@@ -29,6 +29,7 @@
import android.graphics.PorterDuff;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
+import android.hardware.biometrics.BiometricManager;
import android.os.Bundle;
import android.os.Handler;
import android.os.UserManager;
@@ -84,6 +85,7 @@
protected final Handler mHandler = new Handler();
protected boolean mFrp;
private CharSequence mFrpAlternateButtonText;
+ protected BiometricManager mBiometricManager;
private boolean isInternalActivity() {
return (getActivity() instanceof ConfirmLockPassword.InternalActivity)
@@ -107,6 +109,7 @@
mLockPatternUtils = new LockPatternUtils(getActivity());
mDevicePolicyManager = (DevicePolicyManager) getActivity().getSystemService(
Context.DEVICE_POLICY_SERVICE);
+ mBiometricManager = getActivity().getSystemService(BiometricManager.class);
}
@Override
diff --git a/src/com/android/settings/password/ConfirmLockPassword.java b/src/com/android/settings/password/ConfirmLockPassword.java
index 7344077..f893870 100644
--- a/src/com/android/settings/password/ConfirmLockPassword.java
+++ b/src/com/android/settings/password/ConfirmLockPassword.java
@@ -437,6 +437,7 @@
ConfirmDeviceCredentialUtils.reportSuccessfulAttempt(mLockPatternUtils,
mUserManager, mEffectiveUserId);
}
+ mBiometricManager.onConfirmDeviceCredentialSuccess();
startDisappearAnimation(intent);
ConfirmDeviceCredentialUtils.checkForPendingIntent(getActivity());
} else {
diff --git a/src/com/android/settings/password/ConfirmLockPattern.java b/src/com/android/settings/password/ConfirmLockPattern.java
index 5645193..29cdfef 100644
--- a/src/com/android/settings/password/ConfirmLockPattern.java
+++ b/src/com/android/settings/password/ConfirmLockPattern.java
@@ -490,6 +490,7 @@
ConfirmDeviceCredentialUtils.reportSuccessfulAttempt(mLockPatternUtils,
mUserManager, mEffectiveUserId);
}
+ mBiometricManager.onConfirmDeviceCredentialSuccess();
startDisappearAnimation(intent);
ConfirmDeviceCredentialUtils.checkForPendingIntent(getActivity());
} else {
diff --git a/src/com/android/settings/password/PasswordUtils.java b/src/com/android/settings/password/PasswordUtils.java
new file mode 100644
index 0000000..5f118cf
--- /dev/null
+++ b/src/com/android/settings/password/PasswordUtils.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.password;
+
+import android.annotation.Nullable;
+import android.app.ActivityManager;
+import android.app.IActivityManager;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.util.Log;
+
+import com.android.settings.Utils;
+
+public final class PasswordUtils extends com.android.settingslib.Utils {
+
+ private static final String TAG = "Settings";
+
+ private static final String SETTINGS_PACKAGE_NAME = "com.android.settings";
+
+ /**
+ * Returns whether the uid which the activity with {@code activityToken} is launched from has
+ * been granted the {@code permission}.
+ */
+ public static boolean isCallingAppPermitted(Context context, IBinder activityToken,
+ String permission) {
+ try {
+ return context.checkPermission(permission, /* pid= */ -1,
+ ActivityManager.getService().getLaunchedFromUid(activityToken))
+ == PackageManager.PERMISSION_GRANTED;
+ } catch (RemoteException e) {
+ Log.v(TAG, "Could not talk to activity manager.", e);
+ return false;
+ }
+ }
+
+ /**
+ * Returns the label of the package which the activity with {@code activityToken} is launched
+ * from or {@code null} if it is launched from the settings app itself.
+ */
+ @Nullable
+ public static CharSequence getCallingAppLabel(Context context, IBinder activityToken) {
+ String pkg = getCallingAppPackageName(activityToken);
+ if (pkg == null || pkg.equals(SETTINGS_PACKAGE_NAME)) {
+ return null;
+ }
+
+ return Utils.getApplicationLabel(context, pkg);
+ }
+
+ /**
+ * Returns the package name which the activity with {@code activityToken} is launched from.
+ */
+ @Nullable
+ private static String getCallingAppPackageName(IBinder activityToken) {
+ String pkg = null;
+ try {
+ pkg = ActivityManager.getService().getLaunchedFromPackage(activityToken);
+ } catch (RemoteException e) {
+ Log.v(TAG, "Could not talk to activity manager.", e);
+ }
+ return pkg;
+ }
+
+ /** Crashes the calling application and provides it with {@code message}. */
+ public static void crashCallingApplication(IBinder activityToken, String message) {
+ IActivityManager am = ActivityManager.getService();
+ try {
+ int uid = am.getLaunchedFromUid(activityToken);
+ int userId = UserHandle.getUserId(uid);
+ am.crashApplication(
+ uid,
+ /* initialPid= */ -1,
+ getCallingAppPackageName(activityToken),
+ userId,
+ message);
+ } catch (RemoteException e) {
+ Log.v(TAG, "Could not talk to activity manager.", e);
+ }
+ }
+}
diff --git a/src/com/android/settings/password/SetNewPasswordActivity.java b/src/com/android/settings/password/SetNewPasswordActivity.java
index 99f67cb..8ea8514 100644
--- a/src/com/android/settings/password/SetNewPasswordActivity.java
+++ b/src/com/android/settings/password/SetNewPasswordActivity.java
@@ -16,13 +16,22 @@
package com.android.settings.password;
+import static android.Manifest.permission.GET_AND_REQUEST_SCREEN_LOCK_COMPLEXITY;
import static android.app.admin.DevicePolicyManager.ACTION_SET_NEW_PARENT_PROFILE_PASSWORD;
import static android.app.admin.DevicePolicyManager.ACTION_SET_NEW_PASSWORD;
+import static android.app.admin.DevicePolicyManager.EXTRA_PASSWORD_COMPLEXITY;
+import static android.app.admin.DevicePolicyManager.PASSWORD_COMPLEXITY_NONE;
+
+import static com.android.settings.password.ChooseLockSettingsHelper.EXTRA_KEY_CALLER_APP_NAME;
+import static com.android.settings.password.ChooseLockSettingsHelper.EXTRA_KEY_REQUESTED_MIN_COMPLEXITY;
import android.app.Activity;
import android.app.admin.DevicePolicyManager;
+import android.app.admin.DevicePolicyManager.PasswordComplexity;
+import android.app.admin.PasswordMetrics;
import android.content.Intent;
import android.os.Bundle;
+import android.os.IBinder;
import android.util.Log;
import com.android.settings.Utils;
@@ -37,6 +46,21 @@
private String mNewPasswordAction;
private SetNewPasswordController mSetNewPasswordController;
+ /**
+ * From intent extra {@link DevicePolicyManager#EXTRA_PASSWORD_COMPLEXITY}.
+ *
+ * <p>This is used only if caller has the required permission and activity is launched by
+ * {@link DevicePolicyManager#ACTION_SET_NEW_PASSWORD}.
+ */
+ private @PasswordComplexity int mRequestedMinComplexity = PASSWORD_COMPLEXITY_NONE;
+
+ /**
+ * Label of the app which launches this activity.
+ *
+ * <p>Value would be {@code null} if launched from settings app.
+ */
+ private String mCallerAppName = null;
+
@Override
protected void onCreate(Bundle savedState) {
super.onCreate(savedState);
@@ -48,6 +72,25 @@
finish();
return;
}
+
+ IBinder activityToken = getActivityToken();
+ mCallerAppName = (String) PasswordUtils.getCallingAppLabel(this, activityToken);
+ if (ACTION_SET_NEW_PASSWORD.equals(mNewPasswordAction)
+ && getIntent().hasExtra(EXTRA_PASSWORD_COMPLEXITY)) {
+ boolean hasPermission = PasswordUtils.isCallingAppPermitted(
+ this, activityToken, GET_AND_REQUEST_SCREEN_LOCK_COMPLEXITY);
+ if (hasPermission) {
+ mRequestedMinComplexity = PasswordMetrics.sanitizeComplexityLevel(getIntent()
+ .getIntExtra(EXTRA_PASSWORD_COMPLEXITY, PASSWORD_COMPLEXITY_NONE));
+ } else {
+ PasswordUtils.crashCallingApplication(activityToken,
+ "Must have permission " + GET_AND_REQUEST_SCREEN_LOCK_COMPLEXITY
+ + " to use extra " + EXTRA_PASSWORD_COMPLEXITY);
+ finish();
+ return;
+ }
+ }
+
mSetNewPasswordController = SetNewPasswordController.create(
this, this, getIntent(), getActivityToken());
mSetNewPasswordController.dispatchSetNewPasswordIntent();
@@ -60,6 +103,12 @@
: new Intent(this, ChooseLockGeneric.class);
intent.setAction(mNewPasswordAction);
intent.putExtras(chooseLockFingerprintExtras);
+ if (mCallerAppName != null) {
+ intent.putExtra(EXTRA_KEY_CALLER_APP_NAME, mCallerAppName);
+ }
+ if (mRequestedMinComplexity != PASSWORD_COMPLEXITY_NONE) {
+ intent.putExtra(EXTRA_KEY_REQUESTED_MIN_COMPLEXITY, mRequestedMinComplexity);
+ }
startActivity(intent);
finish();
}
diff --git a/src/com/android/settings/password/SetupChooseLockGeneric.java b/src/com/android/settings/password/SetupChooseLockGeneric.java
index a0f8bae..33c3edb 100644
--- a/src/com/android/settings/password/SetupChooseLockGeneric.java
+++ b/src/com/android/settings/password/SetupChooseLockGeneric.java
@@ -16,11 +16,17 @@
package com.android.settings.password;
+import static android.Manifest.permission.GET_AND_REQUEST_SCREEN_LOCK_COMPLEXITY;
+import static android.app.admin.DevicePolicyManager.EXTRA_PASSWORD_COMPLEXITY;
+
+import static com.android.settings.password.ChooseLockSettingsHelper.EXTRA_KEY_REQUESTED_MIN_COMPLEXITY;
+
import android.app.admin.DevicePolicyManager;
import android.content.Context;
import android.content.Intent;
import android.content.res.Resources;
import android.os.Bundle;
+import android.os.IBinder;
import android.os.UserHandle;
import android.view.LayoutInflater;
import android.view.View;
@@ -48,6 +54,7 @@
* Other changes should be done to ChooseLockGeneric class instead and let this class inherit
* those changes.
*/
+// TODO(b/123225425): Restrict SetupChooseLockGeneric to be accessible by SUW only
public class SetupChooseLockGeneric extends ChooseLockGeneric {
private static final String KEY_UNLOCK_SET_DO_LATER = "unlock_set_do_later";
@@ -71,6 +78,20 @@
@Override
protected void onCreate(Bundle savedInstance) {
super.onCreate(savedInstance);
+
+ if(getIntent().hasExtra(EXTRA_KEY_REQUESTED_MIN_COMPLEXITY)) {
+ IBinder activityToken = getActivityToken();
+ boolean hasPermission = PasswordUtils.isCallingAppPermitted(
+ this, activityToken, GET_AND_REQUEST_SCREEN_LOCK_COMPLEXITY);
+ if (!hasPermission) {
+ PasswordUtils.crashCallingApplication(activityToken,
+ "Must have permission " + GET_AND_REQUEST_SCREEN_LOCK_COMPLEXITY
+ + " to use extra " + EXTRA_PASSWORD_COMPLEXITY);
+ finish();
+ return;
+ }
+ }
+
LinearLayout layout = (LinearLayout) findViewById(R.id.content_parent);
layout.setFitsSystemWindows(false);
}
diff --git a/src/com/android/settings/privacy/PermissionBarChartPreferenceController.java b/src/com/android/settings/privacy/PermissionBarChartPreferenceController.java
index 3fac672..e43140f 100644
--- a/src/com/android/settings/privacy/PermissionBarChartPreferenceController.java
+++ b/src/com/android/settings/privacy/PermissionBarChartPreferenceController.java
@@ -76,6 +76,7 @@
.setEmptyText(R.string.permission_bar_chart_empty_text)
.setDetailsOnClickListener((View v) -> {
final Intent intent = new Intent(Intent.ACTION_REVIEW_PERMISSION_USAGE);
+ intent.putExtra(Intent.EXTRA_DURATION_MILLIS, DAYS.toMillis(1));
mContext.startActivity(intent);
})
.build();
@@ -102,7 +103,7 @@
private void retrievePermissionUsageData() {
mContext.getSystemService(PermissionControllerManager.class).getPermissionUsages(
- false /* countSystem */, (int) DAYS.toSeconds(1),
+ false /* countSystem */, (int) DAYS.toMillis(1),
mContext.getMainExecutor() /* executor */, this /* callback */);
}
@@ -111,6 +112,9 @@
return null;
}
+ // STOPSHIP: Ignore the STORAGE group since it's going away.
+ usageInfos.removeIf(usage -> usage.getName().equals("android.permission-group.STORAGE"));
+
final BarViewInfo[] barViewInfos = new BarViewInfo[
Math.min(BarChartPreference.MAXIMUM_BAR_VIEWS, usageInfos.size())];
diff --git a/src/com/android/settings/security/ConfigureKeyGuardDialog.java b/src/com/android/settings/security/ConfigureKeyGuardDialog.java
deleted file mode 100644
index fff106c..0000000
--- a/src/com/android/settings/security/ConfigureKeyGuardDialog.java
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.settings.security;
-
-import android.app.Activity;
-import android.app.Dialog;
-import android.app.admin.DevicePolicyManager;
-import android.app.settings.SettingsEnums;
-import android.content.DialogInterface;
-import android.content.Intent;
-import android.os.Bundle;
-
-import androidx.annotation.VisibleForTesting;
-import androidx.appcompat.app.AlertDialog;
-
-import com.android.settings.CredentialStorage;
-import com.android.settings.R;
-import com.android.settings.core.instrumentation.InstrumentedDialogFragment;
-import com.android.settings.password.ChooseLockGeneric;
-
-/**
- * Prompt for key guard configuration confirmation.
- */
-public class ConfigureKeyGuardDialog extends InstrumentedDialogFragment
- implements DialogInterface.OnClickListener, DialogInterface.OnDismissListener {
-
- public static final String TAG = "ConfigureKeyGuardDialog";
-
- private boolean mConfigureConfirmed;
-
- @Override
- public int getMetricsCategory() {
- return SettingsEnums.CONFIGURE_KEYGUARD_DIALOG;
- }
-
- @Override
- public Dialog onCreateDialog(Bundle savedInstanceState) {
- return new AlertDialog.Builder(getActivity())
- .setTitle(android.R.string.dialog_alert_title)
- .setMessage(R.string.credentials_configure_lock_screen_hint)
- .setPositiveButton(R.string.credentials_configure_lock_screen_button, this)
- .setNegativeButton(android.R.string.cancel, this)
- .create();
- }
-
- @Override
- public void onClick(DialogInterface dialog, int button) {
- mConfigureConfirmed = (button == DialogInterface.BUTTON_POSITIVE);
- }
-
- @Override
- public void onDismiss(DialogInterface dialog) {
- if (mConfigureConfirmed) {
- mConfigureConfirmed = false;
- startPasswordSetup();
- return;
- } else {
- final Activity activity = getActivity();
- if (activity != null) {
- activity.finish();
- }
- }
- }
-
- @VisibleForTesting
- void startPasswordSetup() {
- Intent intent = new Intent(DevicePolicyManager.ACTION_SET_NEW_PASSWORD);
- intent.putExtra(ChooseLockGeneric.ChooseLockGenericFragment.MINIMUM_QUALITY_KEY,
- CredentialStorage.MIN_PASSWORD_QUALITY);
- startActivity(intent);
- }
-}
diff --git a/src/com/android/settings/CredentialStorage.java b/src/com/android/settings/security/CredentialStorage.java
similarity index 75%
rename from src/com/android/settings/CredentialStorage.java
rename to src/com/android/settings/security/CredentialStorage.java
index 5ab543f..99937ee 100644
--- a/src/com/android/settings/CredentialStorage.java
+++ b/src/com/android/settings/security/CredentialStorage.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.settings;
+package com.android.settings.security;
import android.app.Activity;
import android.app.admin.DevicePolicyManager;
@@ -44,8 +44,8 @@
import com.android.internal.widget.LockPatternUtils;
import com.android.org.bouncycastle.asn1.ASN1InputStream;
import com.android.org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
+import com.android.settings.R;
import com.android.settings.password.ChooseLockSettingsHelper;
-import com.android.settings.security.ConfigureKeyGuardDialog;
import com.android.settings.vpn2.VpnUtils;
import java.io.ByteArrayInputStream;
@@ -55,46 +55,12 @@
import sun.security.x509.AlgorithmId;
/**
- * CredentialStorage handles KeyStore reset, unlock, and install.
- *
- * CredentialStorage has a pretty convoluted state machine to migrate
- * from the old style separate keystore password to a new key guard
- * based password, as well as to deal with setting up the key guard if
- * necessary.
- *
- * KeyStore: UNINITALIZED
- * KeyGuard: OFF
- * Action: set up key guard
- * Notes: factory state
- *
- * KeyStore: UNINITALIZED
- * KeyGuard: ON
- * Action: confirm key guard
- * Notes: user had key guard but no keystore and upgraded from pre-ICS
- * OR user had key guard and pre-ICS keystore password which was then reset
- *
- * KeyStore: LOCKED
- * KeyGuard: OFF/ON
- * Action: confirm key guard
- * Notes: request normal unlock to unlock the keystore.
- * if unlock, ensure key guard before install.
- * if reset, treat as UNINITALIZED/OFF
- *
- * KeyStore: UNLOCKED
- * KeyGuard: OFF
- * Action: set up key guard
- * Notes: ensure key guard, then proceed
- *
- * KeyStore: UNLOCKED
- * keyguard: ON
- * Action: normal unlock/install
- * Notes: this is the common case
+ * CredentialStorage handles resetting and installing keys into KeyStore.
*/
public final class CredentialStorage extends FragmentActivity {
private static final String TAG = "CredentialStorage";
- public static final String ACTION_UNLOCK = "com.android.credentials.UNLOCK";
public static final String ACTION_INSTALL = "com.android.credentials.INSTALL";
public static final String ACTION_RESET = "com.android.credentials.RESET";
@@ -102,8 +68,7 @@
// lower than this, keystore should not be activated.
public static final int MIN_PASSWORD_QUALITY = DevicePolicyManager.PASSWORD_QUALITY_SOMETHING;
- private static final int CONFIRM_KEY_GUARD_REQUEST = 1;
- private static final int CONFIRM_CLEAR_SYSTEM_CREDENTIAL_REQUEST = 2;
+ private static final int CONFIRM_CLEAR_SYSTEM_CREDENTIAL_REQUEST = 1;
private final KeyStore mKeyStore = KeyStore.getInstance();
private LockPatternUtils mUtils;
@@ -133,75 +98,26 @@
if (ACTION_INSTALL.equals(action) && checkCallerIsCertInstallerOrSelfInProfile()) {
mInstallBundle = intent.getExtras();
}
- // ACTION_UNLOCK also handled here in addition to ACTION_INSTALL
- handleUnlockOrInstall();
+ handleInstall();
}
} else {
- // Users can set a screen lock if there is none even if they can't modify the
- // credentials store.
- if (ACTION_UNLOCK.equals(action) && mKeyStore.state() == KeyStore.State.UNINITIALIZED) {
- ensureKeyGuard();
- } else {
- finish();
- }
+ finish();
}
}
/**
- * Based on the current state of the KeyStore and key guard, try to
- * make progress on unlocking or installing to the keystore.
+ * Install credentials from mInstallBundle into Keystore.
*/
- private void handleUnlockOrInstall() {
+ private void handleInstall() {
// something already decided we are done, do not proceed
if (isFinishing()) {
return;
}
- switch (mKeyStore.state()) {
- case UNINITIALIZED: {
- ensureKeyGuard();
- return;
- }
- case LOCKED: {
- // Force key guard confirmation
- confirmKeyGuard(CONFIRM_KEY_GUARD_REQUEST);
- return;
- }
- case UNLOCKED: {
- if (!mUtils.isSecure(UserHandle.myUserId())) {
- final ConfigureKeyGuardDialog dialog = new ConfigureKeyGuardDialog();
- dialog.show(getSupportFragmentManager(), ConfigureKeyGuardDialog.TAG);
- return;
- }
- if (installIfAvailable()) {
- finish();
- }
- return;
- }
+ if (installIfAvailable()) {
+ finish();
}
}
- /**
- * Make sure the user enters the key guard to set or change the
- * keystore password. This can be used in UNINITIALIZED to set the
- * keystore password or UNLOCKED to change the password (as is the
- * case after unlocking with an old-style password).
- */
- private void ensureKeyGuard() {
- if (!mUtils.isSecure(UserHandle.myUserId())) {
- // key guard not setup, doing so will initialize keystore
- final ConfigureKeyGuardDialog dialog = new ConfigureKeyGuardDialog();
- dialog.show(getSupportFragmentManager(), ConfigureKeyGuardDialog.TAG);
- // will return to onResume after Activity
- return;
- }
- // force key guard confirmation
- if (confirmKeyGuard(CONFIRM_KEY_GUARD_REQUEST)) {
- // will return password value via onActivityResult
- return;
- }
- finish();
- }
-
private boolean isHardwareBackedKey(byte[] keyData) {
try {
final ASN1InputStream bIn = new ASN1InputStream(new ByteArrayInputStream(keyData));
@@ -254,15 +170,7 @@
final String key = bundle.getString(Credentials.EXTRA_USER_PRIVATE_KEY_NAME);
final byte[] value = bundle.getByteArray(Credentials.EXTRA_USER_PRIVATE_KEY_DATA);
- int flags = KeyStore.FLAG_ENCRYPTED;
- if (uid == Process.WIFI_UID && isHardwareBackedKey(value)) {
- // Hardware backed keystore is secure enough to allow for WIFI stack
- // to enable access to secure networks without user intervention
- Log.d(TAG, "Saving private key with FLAG_NONE for WIFI_UID");
- flags = KeyStore.FLAG_NONE;
- }
-
- if (!mKeyStore.importKey(key, value, uid, flags)) {
+ if (!mKeyStore.importKey(key, value, uid, KeyStore.FLAG_NONE)) {
Log.e(TAG, "Failed to install " + key + " as uid " + uid);
return true;
}
@@ -475,20 +383,7 @@
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
- // Receive key guard password initiated by confirmKeyGuard.
- if (requestCode == CONFIRM_KEY_GUARD_REQUEST) {
- if (resultCode == Activity.RESULT_OK) {
- final String password = data.getStringExtra(ChooseLockSettingsHelper.EXTRA_KEY_PASSWORD);
- if (!TextUtils.isEmpty(password)) {
- // success
- mKeyStore.unlock(password);
- // return to onResume
- return;
- }
- }
- // failed confirmation, bail
- finish();
- } else if (requestCode == CONFIRM_CLEAR_SYSTEM_CREDENTIAL_REQUEST) {
+ if (requestCode == CONFIRM_CLEAR_SYSTEM_CREDENTIAL_REQUEST) {
if (resultCode == Activity.RESULT_OK) {
new ResetKeyStoreAndKeyChain().execute();
return;
diff --git a/src/com/android/settings/security/OWNERS b/src/com/android/settings/security/OWNERS
new file mode 100644
index 0000000..6e4f553
--- /dev/null
+++ b/src/com/android/settings/security/OWNERS
@@ -0,0 +1,7 @@
+# Enterprise security reviewers
+eranm@google.com
+pgrafov@google.com
+rubinxu@google.com
+
+# Emergency
+sandness@google.com
diff --git a/src/com/android/settings/slices/CustomSliceManager.java b/src/com/android/settings/slices/CustomSliceManager.java
index 8d07276..3786c5c 100644
--- a/src/com/android/settings/slices/CustomSliceManager.java
+++ b/src/com/android/settings/slices/CustomSliceManager.java
@@ -18,6 +18,7 @@
import android.content.Context;
import android.net.Uri;
+import android.text.TextUtils;
import android.util.ArrayMap;
import androidx.annotation.VisibleForTesting;
@@ -33,6 +34,7 @@
import com.android.settings.homepage.contextualcards.slices.LowStorageSlice;
import com.android.settings.homepage.contextualcards.slices.NotificationChannelSlice;
import com.android.settings.location.LocationSlice;
+import com.android.settings.media.MediaOutputSlice;
import com.android.settings.wifi.slice.ContextualWifiSlice;
import com.android.settings.wifi.slice.WifiSlice;
@@ -65,20 +67,25 @@
* the only thing that should be needed to create the object.
*/
public CustomSliceable getSliceableFromUri(Uri uri) {
- if (mSliceableCache.containsKey(uri)) {
- return mSliceableCache.get(uri);
+ final Uri newUri = removeParameterFromUri(uri);
+ if (mSliceableCache.containsKey(newUri)) {
+ return mSliceableCache.get(newUri);
}
- final Class clazz = mUriMap.get(uri);
+ final Class clazz = mUriMap.get(newUri);
if (clazz == null) {
throw new IllegalArgumentException("No Slice found for uri: " + uri);
}
final CustomSliceable sliceable = CustomSliceable.createInstance(mContext, clazz);
- mSliceableCache.put(uri, sliceable);
+ mSliceableCache.put(newUri, sliceable);
return sliceable;
}
+ private Uri removeParameterFromUri(Uri uri) {
+ return uri != null ? uri.buildUpon().clearQuery().build() : null;
+ }
+
/**
* Return a {@link CustomSliceable} associated to the Action.
* <p>
@@ -94,7 +101,7 @@
* {@link CustomSliceManager}.
*/
public boolean isValidUri(Uri uri) {
- return mUriMap.containsKey(uri);
+ return mUriMap.containsKey(removeParameterFromUri(uri));
}
/**
@@ -120,5 +127,6 @@
NotificationChannelSlice.class);
mUriMap.put(CustomSliceRegistry.STORAGE_SLICE_URI, StorageSlice.class);
mUriMap.put(CustomSliceRegistry.WIFI_SLICE_URI, WifiSlice.class);
+ mUriMap.put(CustomSliceRegistry.MEDIA_OUTPUT_SLICE_URI, MediaOutputSlice.class);
}
}
diff --git a/src/com/android/settings/slices/CustomSliceRegistry.java b/src/com/android/settings/slices/CustomSliceRegistry.java
index e842cb9..66e85c0 100644
--- a/src/com/android/settings/slices/CustomSliceRegistry.java
+++ b/src/com/android/settings/slices/CustomSliceRegistry.java
@@ -27,6 +27,7 @@
import com.android.settings.fuelgauge.batterytip.BatteryTipPreferenceController;
import com.android.settings.wifi.calling.WifiCallingSliceHelper;
+import com.android.settingslib.media.MediaOutputSliceConstants;
/**
* A registry of custom slice Uris.
@@ -155,6 +156,15 @@
.appendPath("low_storage")
.build();
/**
+ * Backing Uri for NFC Slice
+ */
+ public static final Uri NFC_SLICE_URI = new Uri.Builder()
+ .scheme(ContentResolver.SCHEME_CONTENT)
+ .authority(SettingsSliceProvider.SLICE_AUTHORITY)
+ .appendPath(SettingsSlicesContract.PATH_SETTING_ACTION)
+ .appendPath("toggle_nfc")
+ .build();
+ /**
* Backing Uri for Notification channel Slice.
*/
public static final Uri NOTIFICATION_CHANNEL_SLICE_URI = new Uri.Builder()
@@ -246,4 +256,14 @@
.appendPath(SettingsSlicesContract.PATH_SETTING_ACTION)
.appendPath(ZEN_MODE_KEY)
.build();
+
+ /**
+ * Backing Uri for the Media output Slice.
+ */
+ public static Uri MEDIA_OUTPUT_SLICE_URI = new Uri.Builder()
+ .scheme(ContentResolver.SCHEME_CONTENT)
+ .authority(SettingsSliceProvider.SLICE_AUTHORITY)
+ .appendPath(SettingsSlicesContract.PATH_SETTING_ACTION)
+ .appendPath(MediaOutputSliceConstants.KEY_MEDIA_OUTPUT)
+ .build();
}
diff --git a/src/com/android/settings/slices/SliceBackgroundWorker.java b/src/com/android/settings/slices/SliceBackgroundWorker.java
index 284fd23..6df45ba 100644
--- a/src/com/android/settings/slices/SliceBackgroundWorker.java
+++ b/src/com/android/settings/slices/SliceBackgroundWorker.java
@@ -59,10 +59,6 @@
mUri = uri;
}
- protected Uri getUri() {
- return mUri;
- }
-
/**
* Returns the singleton instance of the {@link SliceBackgroundWorker} for specified {@link Uri}
* if exists
@@ -148,7 +144,14 @@
if (needNotify) {
mCachedResults = results;
- mContext.getContentResolver().notifyChange(mUri, null);
+ notifySliceChange();
}
}
-}
+
+ /**
+ * Notify that data was updated and attempt to sync changes to the Slice.
+ */
+ protected void notifySliceChange() {
+ mContext.getContentResolver().notifyChange(mUri, null);
+ }
+}
\ No newline at end of file
diff --git a/src/com/android/settings/vpn2/AppDialogFragment.java b/src/com/android/settings/vpn2/AppDialogFragment.java
index 0d0022f..2f9cd7a 100644
--- a/src/com/android/settings/vpn2/AppDialogFragment.java
+++ b/src/com/android/settings/vpn2/AppDialogFragment.java
@@ -164,7 +164,8 @@
final int userId = getUserId();
try {
if (mPackageInfo.packageName.equals(VpnUtils.getConnectedPackage(mService, userId))) {
- mService.setAlwaysOnVpnPackage(userId, null, /* lockdownEnabled */ false);
+ mService.setAlwaysOnVpnPackage(userId, null, /* lockdownEnabled */ false,
+ /* lockdownWhitelist */ null);
mService.prepareVpn(mPackageInfo.packageName, VpnConfig.LEGACY_VPN, userId);
}
} catch (RemoteException e) {
diff --git a/src/com/android/settings/vpn2/AppManagementFragment.java b/src/com/android/settings/vpn2/AppManagementFragment.java
index 1571216..5f46446 100644
--- a/src/com/android/settings/vpn2/AppManagementFragment.java
+++ b/src/com/android/settings/vpn2/AppManagementFragment.java
@@ -225,7 +225,7 @@
private boolean setAlwaysOnVpn(boolean isEnabled, boolean isLockdown) {
return mConnectivityManager.setAlwaysOnVpnPackageForUser(mUserId,
- isEnabled ? mPackageName : null, isLockdown);
+ isEnabled ? mPackageName : null, isLockdown, /* lockdownWhitelist */ null);
}
private void updateUI() {
diff --git a/src/com/android/settings/vpn2/ConfigDialogFragment.java b/src/com/android/settings/vpn2/ConfigDialogFragment.java
index ec927ae..c032fe5 100644
--- a/src/com/android/settings/vpn2/ConfigDialogFragment.java
+++ b/src/com/android/settings/vpn2/ConfigDialogFragment.java
@@ -56,8 +56,6 @@
ServiceManager.getService(Context.CONNECTIVITY_SERVICE));
private Context mContext;
- private boolean mUnlocking = false;
-
@Override
public int getMetricsCategory() {
@@ -85,27 +83,6 @@
}
@Override
- public void onResume() {
- super.onResume();
-
- // Check KeyStore here, so others do not need to deal with it.
- if (!KeyStore.getInstance().isUnlocked()) {
- if (!mUnlocking) {
- // Let us unlock KeyStore. See you later!
- Credentials.getInstance().unlock(mContext);
- } else {
- // We already tried, but it is still not working!
- dismiss();
- }
- mUnlocking = !mUnlocking;
- return;
- }
-
- // Now KeyStore is always unlocked. Reset the flag.
- mUnlocking = false;
- }
-
- @Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
Bundle args = getArguments();
VpnProfile profile = (VpnProfile) args.getParcelable(ARG_PROFILE);
@@ -199,7 +176,7 @@
final ConnectivityManager conn = ConnectivityManager.from(mContext);
conn.setAlwaysOnVpnPackageForUser(UserHandle.myUserId(), null,
- /* lockdownEnabled */ false);
+ /* lockdownEnabled */ false, /* lockdownWhitelist */ null);
VpnUtils.setLockdownVpn(mContext, profile.key);
} else {
// update only if lockdown vpn has been changed
diff --git a/src/com/android/settings/wallpaper/WallpaperSuggestionActivity.java b/src/com/android/settings/wallpaper/WallpaperSuggestionActivity.java
index 50819e2..14564b1 100644
--- a/src/com/android/settings/wallpaper/WallpaperSuggestionActivity.java
+++ b/src/com/android/settings/wallpaper/WallpaperSuggestionActivity.java
@@ -29,6 +29,8 @@
import com.android.settings.R;
import com.android.settings.core.SubSettingLauncher;
+import com.google.android.setupcompat.util.WizardManagerHelper;
+
public class WallpaperSuggestionActivity extends Activity {
@Override
@@ -39,6 +41,10 @@
.setClassName(getString(R.string.config_wallpaper_picker_package),
getString(R.string.config_wallpaper_picker_class))
.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT);
+
+ // passing the necessary extra to next page
+ WizardManagerHelper.copyWizardManagerExtras(getIntent(), intent);
+
if (pm.resolveActivity(intent, 0) != null) {
startActivity(intent);
} else {
diff --git a/src/com/android/settings/widget/EntityHeaderController.java b/src/com/android/settings/widget/EntityHeaderController.java
index c110107..2714859 100644
--- a/src/com/android/settings/widget/EntityHeaderController.java
+++ b/src/com/android/settings/widget/EntityHeaderController.java
@@ -344,7 +344,7 @@
if (mEditOnClickListener == null) {
button.setVisibility(View.GONE);
} else {
- button.setImageResource(R.drawable.ic_mode_edit);
+ button.setImageResource(com.android.internal.R.drawable.ic_mode_edit);
button.setVisibility(View.VISIBLE);
button.setOnClickListener(mEditOnClickListener);
}
diff --git a/src/com/android/settings/wifi/NetworkRequestDialogFragment.java b/src/com/android/settings/wifi/NetworkRequestDialogFragment.java
index 921552d..d1df7f0 100644
--- a/src/com/android/settings/wifi/NetworkRequestDialogFragment.java
+++ b/src/com/android/settings/wifi/NetworkRequestDialogFragment.java
@@ -21,6 +21,7 @@
import android.app.settings.SettingsEnums;
import android.content.Context;
import android.content.DialogInterface;
+import android.content.Intent;
import android.graphics.drawable.Drawable;
import android.net.wifi.ScanResult;
import android.net.wifi.WifiConfiguration;
@@ -74,6 +75,9 @@
/** Delayed time to stop scanning wifi. */
private static final int DELAY_TIME_STOP_SCAN_MS = 30 * 1000;
+ @VisibleForTesting
+ final static String EXTRA_APP_NAME = "com.android.settings.wifi.extra.APP_NAME";
+
private List<AccessPoint> mAccessPointList;
private FilterWifiTracker mFilterWifiTracker;
private AccessPointAdapter mDialogAdapter;
@@ -93,7 +97,8 @@
final View customTitle = inflater.inflate(R.layout.network_request_dialog_title, null);
final TextView title = customTitle.findViewById(R.id.network_request_title_text);
- title.setText(R.string.network_connection_request_dialog_title);
+ title.setText(getTitle());
+
final ProgressBar progressBar = customTitle.findViewById(
R.id.network_request_title_progress);
progressBar.setVisibility(View.VISIBLE);
@@ -115,6 +120,16 @@
return dialog;
}
+ private String getTitle() {
+ final Intent intent = getActivity().getIntent();
+ String appName = "";
+ if (intent != null) {
+ appName = intent.getStringExtra(EXTRA_APP_NAME);
+ }
+
+ return getString(R.string.network_connection_request_dialog_title, appName);
+ }
+
@NonNull
List<AccessPoint> getAccessPointList() {
// Initials list for adapter, in case of display crashing.
diff --git a/src/com/android/settings/wifi/WifiConfigController.java b/src/com/android/settings/wifi/WifiConfigController.java
index b0d09e4..a679d37 100644
--- a/src/com/android/settings/wifi/WifiConfigController.java
+++ b/src/com/android/settings/wifi/WifiConfigController.java
@@ -63,6 +63,7 @@
import com.android.settings.ProxySelector;
import com.android.settings.R;
+import com.android.settings.wifi.details.WifiPrivacyPreferenceController;
import com.android.settingslib.Utils;
import com.android.settingslib.utils.ThreadUtils;
import com.android.settingslib.wifi.AccessPoint;
@@ -251,8 +252,6 @@
com.android.settings.core.FeatureFlags.WIFI_MAC_RANDOMIZATION)) {
View privacySettingsLayout = mView.findViewById(R.id.privacy_settings_fields);
privacySettingsLayout.setVisibility(View.VISIBLE);
- // Set default value
- mPrivacySettingsSpinner.setSelection(WifiConfiguration.RANDOMIZATION_PERSISTENT);
}
mHiddenSettingsSpinner.setOnItemSelectedListener(this);
mHiddenWarningView = mView.findViewById(R.id.hidden_settings_warning);
@@ -281,7 +280,12 @@
mHiddenSettingsSpinner.setSelection(config.hiddenSSID
? HIDDEN_NETWORK
: NOT_HIDDEN_NETWORK);
- mPrivacySettingsSpinner.setSelection(config.macRandomizationSetting);
+
+ final int prefMacValue =
+ WifiPrivacyPreferenceController.translateMacRandomizedValueToPrefValue(
+ config.macRandomizationSetting);
+ mPrivacySettingsSpinner.setSelection(prefMacValue);
+
if (config.getIpAssignment() == IpAssignment.STATIC) {
mIpSettingsSpinner.setSelection(STATIC_IP);
showAdvancedFields = true;
@@ -766,7 +770,10 @@
}
if (mPrivacySettingsSpinner != null) {
- config.macRandomizationSetting = mPrivacySettingsSpinner.getSelectedItemPosition();
+ final int macValue =
+ WifiPrivacyPreferenceController.translatePrefValueToMacRandomizedValue(
+ mPrivacySettingsSpinner.getSelectedItemPosition());
+ config.macRandomizationSetting = macValue;
}
return config;
diff --git a/src/com/android/settings/wifi/details/WifiDetailPreferenceController.java b/src/com/android/settings/wifi/details/WifiDetailPreferenceController.java
index 1105f74..27db7cd 100644
--- a/src/com/android/settings/wifi/details/WifiDetailPreferenceController.java
+++ b/src/com/android/settings/wifi/details/WifiDetailPreferenceController.java
@@ -290,7 +290,8 @@
.setButton2OnClickListener(view -> signIntoNetwork())
.setButton3Text(R.string.share)
.setButton3Icon(R.drawable.ic_qrcode_24dp)
- .setButton3OnClickListener(view -> shareNetwork());
+ .setButton3OnClickListener(view -> shareNetwork())
+ .setButton3Visible(WifiDppUtils.isSuportConfigurator(mContext, mAccessPoint));
mSignalStrengthPref = screen.findPreference(KEY_SIGNAL_STRENGTH_PREF);
mTxLinkSpeedPref = screen.findPreference(KEY_TX_LINK_SPEED);
@@ -558,10 +559,15 @@
/**
* Show QR code to share the network represented by this preference.
*/
- public void launchQRCodeGenerator() {
- Intent intent = WifiDppUtils.getConfiguratorQrCodeGeneratorIntent(mContext, mWifiManager,
+ public void launchWifiDppConfiguratorActivity() {
+ final Intent intent = WifiDppUtils.getConfiguratorIntentOrNull(mContext, mWifiManager,
mAccessPoint);
- mContext.startActivity(intent);
+
+ if (intent == null) {
+ Log.e(TAG, "Launch Wi-Fi DPP configurator with a wrong Wi-Fi network!");
+ } else {
+ mContext.startActivity(intent);
+ }
}
/**
@@ -584,7 +590,7 @@
WifiNetworkDetailsFragment.REQUEST_CODE_CONFIRM_DEVICE_CREDENTIALS);
}
} else {
- launchQRCodeGenerator();
+ launchWifiDppConfiguratorActivity();
}
}
diff --git a/src/com/android/settings/wifi/details/WifiNetworkDetailsFragment.java b/src/com/android/settings/wifi/details/WifiNetworkDetailsFragment.java
index 2f45526..ec43b0f 100644
--- a/src/com/android/settings/wifi/details/WifiNetworkDetailsFragment.java
+++ b/src/com/android/settings/wifi/details/WifiNetworkDetailsFragment.java
@@ -101,7 +101,7 @@
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
MenuItem item = menu.add(0, Menu.FIRST, 0, R.string.wifi_modify);
- item.setIcon(R.drawable.ic_mode_edit);
+ item.setIcon(com.android.internal.R.drawable.ic_mode_edit);
item.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS);
super.onCreateOptionsMenu(menu, inflater);
}
@@ -152,7 +152,7 @@
if (requestCode == REQUEST_CODE_CONFIRM_DEVICE_CREDENTIALS
&& resultCode == Activity.RESULT_OK) {
- mWifiDetailPreferenceController.launchQRCodeGenerator();
+ mWifiDetailPreferenceController.launchWifiDppConfiguratorActivity();
}
}
}
diff --git a/src/com/android/settings/wifi/details/WifiPrivacyPreferenceController.java b/src/com/android/settings/wifi/details/WifiPrivacyPreferenceController.java
index 3bcdc5f..a20adc9 100644
--- a/src/com/android/settings/wifi/details/WifiPrivacyPreferenceController.java
+++ b/src/com/android/settings/wifi/details/WifiPrivacyPreferenceController.java
@@ -85,15 +85,29 @@
return WifiConfiguration.RANDOMIZATION_PERSISTENT;
}
- private final int PREF_RANDOMIZATION_PERSISTENT = 0;
- private final int PREF_RANDOMIZATION_NONE = 1;
- @VisibleForTesting
- protected int translateMacRandomizedValueToPrefValue(int macRandomized) {
- if (macRandomized == WifiConfiguration.RANDOMIZATION_PERSISTENT) {
- return PREF_RANDOMIZATION_PERSISTENT;
- } else {
- return PREF_RANDOMIZATION_NONE;
- }
+ private static final int PREF_RANDOMIZATION_PERSISTENT = 0;
+ private static final int PREF_RANDOMIZATION_NONE = 1;
+
+ /**
+ * Returns preference index value.
+ *
+ * @param macRandomized is mac randomized value
+ * @return index value of preference
+ */
+ public static int translateMacRandomizedValueToPrefValue(int macRandomized) {
+ return (macRandomized == WifiConfiguration.RANDOMIZATION_PERSISTENT)
+ ? PREF_RANDOMIZATION_PERSISTENT : PREF_RANDOMIZATION_NONE;
+ }
+
+ /**
+ * Returns mac randomized value.
+ *
+ * @param prefMacRandomized is preference index value
+ * @return mac randomized value
+ */
+ public static int translatePrefValueToMacRandomizedValue(int prefMacRandomized) {
+ return (prefMacRandomized == PREF_RANDOMIZATION_PERSISTENT)
+ ? WifiConfiguration.RANDOMIZATION_PERSISTENT : WifiConfiguration.RANDOMIZATION_NONE;
}
private void updateSummary(DropDownPreference preference, int macRandomized) {
diff --git a/src/com/android/settings/wifi/dpp/WifiDppAddDeviceFragment.java b/src/com/android/settings/wifi/dpp/WifiDppAddDeviceFragment.java
index 9864ea9..52243d4 100644
--- a/src/com/android/settings/wifi/dpp/WifiDppAddDeviceFragment.java
+++ b/src/com/android/settings/wifi/dpp/WifiDppAddDeviceFragment.java
@@ -133,7 +133,8 @@
mChooseDifferentNetwork = view.findViewById(R.id.choose_different_network);
mChooseDifferentNetwork.setOnClickListener(v ->
- mClickChooseDifferentNetworkListener.onClickChooseDifferentNetwork());
+ mClickChooseDifferentNetworkListener.onClickChooseDifferentNetwork()
+ );
mButtonLeft = view.findViewById(R.id.button_left);
mButtonLeft.setText(R.string.cancel);
diff --git a/src/com/android/settings/wifi/dpp/WifiDppChooseSavedWifiNetworkFragment.java b/src/com/android/settings/wifi/dpp/WifiDppChooseSavedWifiNetworkFragment.java
index 3817615..6a229a1 100644
--- a/src/com/android/settings/wifi/dpp/WifiDppChooseSavedWifiNetworkFragment.java
+++ b/src/com/android/settings/wifi/dpp/WifiDppChooseSavedWifiNetworkFragment.java
@@ -61,6 +61,10 @@
* WifiDppChooseSavedWifiNetworkFragment. */
final FragmentManager fragmentManager = getChildFragmentManager();
final WifiNetworkListFragment fragment = new WifiNetworkListFragment();
+ final Bundle args = getArguments();
+ if (args != null) {
+ fragment.setArguments(args);
+ }
final FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.wifi_network_list_container, fragment,
TAG_FRAGMENT_WIFI_NETWORK_LIST);
diff --git a/src/com/android/settings/wifi/dpp/WifiDppConfiguratorActivity.java b/src/com/android/settings/wifi/dpp/WifiDppConfiguratorActivity.java
index 3955456..e5beea0 100644
--- a/src/com/android/settings/wifi/dpp/WifiDppConfiguratorActivity.java
+++ b/src/com/android/settings/wifi/dpp/WifiDppConfiguratorActivity.java
@@ -21,6 +21,7 @@
import android.app.settings.SettingsEnums;
import android.content.Intent;
import android.os.Bundle;
+import android.provider.Settings;
import android.util.Log;
import androidx.annotation.VisibleForTesting;
@@ -45,7 +46,7 @@
* {@code WifiDppUtils.EXTRA_WIFI_PRE_SHARED_KEY}
* {@code WifiDppUtils.EXTRA_WIFI_HIDDEN_SSID}
*
- * For intent action {@code ACTION_PROCESS_WIFI_DPP_QR_CODE}, specify Wi-Fi (DPP)
+ * For intent action {@link Settings#ACTION_PROCESS_WIFI_EASY_CONNECT_QR_CODE}, specify Wi-Fi (DPP)
* QR code in {@code WifiDppUtils.EXTRA_QR_CODE}
*/
public class WifiDppConfiguratorActivity extends InstrumentedActivity implements
@@ -62,8 +63,6 @@
"android.settings.WIFI_DPP_CONFIGURATOR_QR_CODE_SCANNER";
public static final String ACTION_CONFIGURATOR_QR_CODE_GENERATOR =
"android.settings.WIFI_DPP_CONFIGURATOR_QR_CODE_GENERATOR";
- public static final String ACTION_PROCESS_WIFI_DPP_QR_CODE =
- "android.settings.PROCESS_WIFI_DPP_QR_CODE";
// Key for Bundle usage
private static final String KEY_QR_CODE = "key_qr_code";
@@ -78,8 +77,10 @@
/** The Wi-Fi network which will be configured */
private WifiNetworkConfig mWifiNetworkConfig;
- /** The Wi-Fi DPP QR code from intent ACTION_PROCESS_WIFI_DPP_QR_CODE */
+ /** The Wi-Fi DPP QR code from intent ACTION_PROCESS_WIFI_EASY_CONNECT_QR_CODE */
private WifiQrCode mWifiDppQrCode;
+ /** Secret extra that allows fake networks to show in UI for testing purposes */
+ private boolean mIsTest;
@Override
public int getMetricsCategory() {
@@ -139,8 +140,9 @@
showQrCodeGeneratorFragment();
}
break;
- case ACTION_PROCESS_WIFI_DPP_QR_CODE:
- String qrCode = intent.getStringExtra(WifiDppUtils.EXTRA_QR_CODE);
+ case Settings.ACTION_PROCESS_WIFI_EASY_CONNECT_QR_CODE:
+ String qrCode = intent.getStringExtra(Settings.EXTRA_QR_CODE);
+ mIsTest = intent.getBooleanExtra(WifiDppUtils.EXTRA_TEST, false);
mWifiDppQrCode = getValidWifiDppQrCodeOrNull(qrCode);
final boolean isDppSupported = WifiDppUtils.isWifiDppEnabled(this);
if (!isDppSupported) {
@@ -164,12 +166,17 @@
}
private void showQrCodeScannerFragment(boolean addToBackStack) {
+ WifiDppQrCodeScannerFragment fragment =
+ (WifiDppQrCodeScannerFragment) mFragmentManager.findFragmentByTag(
+ WifiDppUtils.TAG_FRAGMENT_QR_CODE_SCANNER);
// Avoid to replace the same fragment during configuration change
- if (mFragmentManager.findFragmentByTag(WifiDppUtils.TAG_FRAGMENT_QR_CODE_SCANNER) != null) {
+ if (fragment != null && fragment.isVisible()) {
return;
}
- final WifiDppQrCodeScannerFragment fragment = new WifiDppQrCodeScannerFragment();
+ if (fragment == null) {
+ fragment = new WifiDppQrCodeScannerFragment();
+ }
final FragmentTransaction fragmentTransaction = mFragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.fragment_container, fragment,
@@ -181,13 +188,15 @@
}
private void showQrCodeGeneratorFragment() {
+ WifiDppQrCodeGeneratorFragment fragment =
+ (WifiDppQrCodeGeneratorFragment) mFragmentManager.findFragmentByTag(
+ WifiDppUtils.TAG_FRAGMENT_QR_CODE_GENERATOR);
// Avoid to replace the same fragment during configuration change
- if (mFragmentManager.findFragmentByTag(
- WifiDppUtils.TAG_FRAGMENT_QR_CODE_GENERATOR) != null) {
+ if (fragment != null && fragment.isVisible()) {
return;
}
- final WifiDppQrCodeGeneratorFragment fragment = new WifiDppQrCodeGeneratorFragment();
+ fragment = new WifiDppQrCodeGeneratorFragment();
final FragmentTransaction fragmentTransaction = mFragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.fragment_container, fragment,
@@ -196,14 +205,22 @@
}
private void showChooseSavedWifiNetworkFragment(boolean addToBackStack) {
+ WifiDppChooseSavedWifiNetworkFragment fragment =
+ (WifiDppChooseSavedWifiNetworkFragment) mFragmentManager.findFragmentByTag(
+ WifiDppUtils.TAG_FRAGMENT_CHOOSE_SAVED_WIFI_NETWORK);
// Avoid to replace the same fragment during configuration change
- if (mFragmentManager.findFragmentByTag(
- WifiDppUtils.TAG_FRAGMENT_CHOOSE_SAVED_WIFI_NETWORK) != null) {
+ if (fragment != null && fragment.isVisible()) {
return;
}
- final WifiDppChooseSavedWifiNetworkFragment fragment =
- new WifiDppChooseSavedWifiNetworkFragment();
+ if (fragment == null) {
+ fragment = new WifiDppChooseSavedWifiNetworkFragment();
+ if (mIsTest) {
+ Bundle bundle = new Bundle();
+ bundle.putBoolean(WifiDppUtils.EXTRA_TEST, true);
+ fragment.setArguments(bundle);
+ }
+ }
final FragmentTransaction fragmentTransaction = mFragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.fragment_container, fragment,
@@ -215,14 +232,19 @@
}
private void showAddDeviceFragment(boolean addToBackStack) {
+ WifiDppAddDeviceFragment fragment =
+ (WifiDppAddDeviceFragment) mFragmentManager.findFragmentByTag(
+ WifiDppUtils.TAG_FRAGMENT_ADD_DEVICE);
+
// Avoid to replace the same fragment during configuration change
if (mFragmentManager.findFragmentByTag(
WifiDppUtils.TAG_FRAGMENT_ADD_DEVICE) != null) {
return;
}
- final WifiDppAddDeviceFragment fragment =
- new WifiDppAddDeviceFragment();
+ if (fragment == null) {
+ fragment = new WifiDppAddDeviceFragment();
+ }
final FragmentTransaction fragmentTransaction = mFragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.fragment_container, fragment,
diff --git a/src/com/android/settings/wifi/dpp/WifiDppQrCodeGeneratorFragment.java b/src/com/android/settings/wifi/dpp/WifiDppQrCodeGeneratorFragment.java
index f2ca24e..d0a9638 100644
--- a/src/com/android/settings/wifi/dpp/WifiDppQrCodeGeneratorFragment.java
+++ b/src/com/android/settings/wifi/dpp/WifiDppQrCodeGeneratorFragment.java
@@ -84,9 +84,18 @@
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
- MenuItem item = menu.add(0, Menu.FIRST, 0, R.string.next_label);
- item.setIcon(R.drawable.ic_scan_24dp);
- item.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS);
+ final WifiNetworkConfig wifiNetworkConfig = getWifiNetworkConfigFromHostActivity();
+ MenuItem menuItem;
+ if (wifiNetworkConfig.isSupportConfiguratorQrCodeScanner(getActivity())) {
+ menuItem = menu.add(0, Menu.FIRST, 0, R.string.next_label);
+ menuItem.setIcon(R.drawable.ic_scan_24dp);
+ menuItem.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS);
+ } else {
+ menuItem = menu.findItem(Menu.FIRST);
+ if (menuItem != null) {
+ menuItem.setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER);
+ }
+ }
super.onCreateOptionsMenu(menu, inflater);
}
@@ -116,11 +125,7 @@
mQrCodeView = view.findViewById(R.id.qrcode_view);
mHeaderIcon.setImageResource(R.drawable.ic_qrcode_24dp);
- WifiNetworkConfig wifiNetworkConfig = ((WifiNetworkConfig.Retriever) getActivity())
- .getWifiNetworkConfig();
- if (!WifiNetworkConfig.isValidConfig(wifiNetworkConfig)) {
- throw new IllegalStateException("Invalid Wi-Fi network for configuring");
- }
+ final WifiNetworkConfig wifiNetworkConfig = getWifiNetworkConfigFromHostActivity();
mTitle.setText(R.string.wifi_dpp_share_wifi);
mSummary.setText(getString(R.string.wifi_dpp_scan_qr_code_with_another_device,
wifiNetworkConfig.getSsid()));
@@ -139,4 +144,14 @@
Log.e(TAG, "Error generatting QR code bitmap " + e);
}
}
+
+ WifiNetworkConfig getWifiNetworkConfigFromHostActivity() {
+ final WifiNetworkConfig wifiNetworkConfig = ((WifiNetworkConfig.Retriever) getActivity())
+ .getWifiNetworkConfig();
+ if (!WifiNetworkConfig.isValidConfig(wifiNetworkConfig)) {
+ throw new IllegalStateException("Invalid Wi-Fi network for configuring");
+ }
+
+ return wifiNetworkConfig;
+ }
}
diff --git a/src/com/android/settings/wifi/dpp/WifiDppUtils.java b/src/com/android/settings/wifi/dpp/WifiDppUtils.java
index ef7a1c9..b43ee92 100644
--- a/src/com/android/settings/wifi/dpp/WifiDppUtils.java
+++ b/src/com/android/settings/wifi/dpp/WifiDppUtils.java
@@ -29,6 +29,8 @@
/**
* Here are the items shared by both WifiDppConfiguratorActivity & WifiDppEnrolleeActivity
+ *
+ * @see WifiQrCode
*/
public class WifiDppUtils {
/**
@@ -67,8 +69,9 @@
/** The data corresponding to {@code WifiConfiguration} networkId */
public static final String EXTRA_WIFI_NETWORK_ID = "networkId";
- /** @see WifiQrCode */
- public static final String EXTRA_QR_CODE = "qrCode";
+ /** Used by {@link android.provider.Settings#ACTION_PROCESS_WIFI_EASY_CONNECT_QR_CODE} to
+ * indicate test mode UI should be shown. Test UI does not make API calls. Value is a boolean.*/
+ public static final String EXTRA_TEST = "test";
/**
* Returns whether the user can share the network represented by this preference with QR code.
@@ -134,26 +137,36 @@
private static String getSecurityString(AccessPoint accessPoint) {
switch(accessPoint.getSecurity()) {
case AccessPoint.SECURITY_WEP:
- return "WEP";
+ return WifiQrCode.SECURITY_WEP;
case AccessPoint.SECURITY_PSK:
- return "WPA";
+ return WifiQrCode.SECURITY_WPA;
+ case AccessPoint.SECURITY_SAE:
+ return WifiQrCode.SECURITY_SAE;
default:
- return "nopass";
+ return WifiQrCode.SECURITY_NO_PASSWORD;
}
}
/**
- * Returns an intent to launch QR code generator.
+ * Returns an intent to launch QR code generator or scanner according to the Wi-Fi network
+ * security. It may return null if the security is not supported by QR code generator nor
+ * scanner.
*
* @param context The context to use for the content resolver
* @param wifiManager An instance of {@link WifiManager}
* @param accessPoint An instance of {@link AccessPoint}
* @return Intent for launching QR code generator
*/
- public static Intent getConfiguratorQrCodeGeneratorIntent(Context context,
+ public static Intent getConfiguratorIntentOrNull(Context context,
WifiManager wifiManager, AccessPoint accessPoint) {
final Intent intent = new Intent(context, WifiDppConfiguratorActivity.class);
- intent.setAction(WifiDppConfiguratorActivity.ACTION_CONFIGURATOR_QR_CODE_GENERATOR);
+ if (isSupportConfiguratorQrCodeGenerator(accessPoint)) {
+ intent.setAction(WifiDppConfiguratorActivity.ACTION_CONFIGURATOR_QR_CODE_GENERATOR);
+ } else if (isSupportConfiguratorQrCodeScanner(context, accessPoint)) {
+ intent.setAction(WifiDppConfiguratorActivity.ACTION_CONFIGURATOR_QR_CODE_SCANNER);
+ } else {
+ return null;
+ }
final WifiConfiguration wifiConfig = accessPoint.getConfig();
final String ssid = removeFirstAndLastDoubleQuotes(wifiConfig.SSID);
@@ -183,4 +196,43 @@
return intent;
}
+
+ /**
+ * Android Q supports Wi-Fi configurator by:
+ *
+ * 1. QR code generator of ZXing's Wi-Fi network config format.
+ * and
+ * 2. QR code scanner of Wi-Fi DPP QR code format.
+ */
+ public static boolean isSuportConfigurator(Context context, AccessPoint accessPoint) {
+ return isSupportConfiguratorQrCodeScanner(context, accessPoint) ||
+ isSupportConfiguratorQrCodeGenerator(accessPoint);
+ }
+
+ private static boolean isSupportConfiguratorQrCodeScanner(Context context,
+ AccessPoint accessPoint) {
+ if (!isWifiDppEnabled(context)) {
+ return false;
+ }
+
+ // DPP 1.0 only supports SAE and PSK.
+ final int security = accessPoint.getSecurity();
+ if (security == AccessPoint.SECURITY_SAE || security == AccessPoint.SECURITY_PSK) {
+ return true;
+ }
+
+ return false;
+ }
+
+ private static boolean isSupportConfiguratorQrCodeGenerator(AccessPoint accessPoint) {
+ // QR code generator produces QR code with ZXing's Wi-Fi network config format,
+ // it supports PSK and WEP and non security
+ final int security = accessPoint.getSecurity();
+ if (security == AccessPoint.SECURITY_PSK || security == AccessPoint.SECURITY_WEP ||
+ security == AccessPoint.SECURITY_NONE) {
+ return true;
+ }
+
+ return false;
+ }
}
diff --git a/src/com/android/settings/wifi/dpp/WifiNetworkConfig.java b/src/com/android/settings/wifi/dpp/WifiNetworkConfig.java
index 915e90d..8e95b3e 100644
--- a/src/com/android/settings/wifi/dpp/WifiNetworkConfig.java
+++ b/src/com/android/settings/wifi/dpp/WifiNetworkConfig.java
@@ -17,6 +17,7 @@
package com.android.settings.wifi.dpp;
import static com.android.settings.wifi.dpp.WifiQrCode.SECURITY_NO_PASSWORD;
+import static com.android.settings.wifi.dpp.WifiQrCode.SECURITY_SAE;
import static com.android.settings.wifi.dpp.WifiQrCode.SECURITY_WEP;
import static com.android.settings.wifi.dpp.WifiQrCode.SECURITY_WPA;
@@ -41,6 +42,9 @@
* EXTRA_QR_CODE
*/
public class WifiNetworkConfig {
+
+ static final String FAKE_SSID = "fake network";
+ static final String FAKE_PASSWORD = "password";
private static final String TAG = "WifiNetworkConfig";
private String mSecurity;
@@ -208,6 +212,19 @@
wifiManager.connect(wifiConfiguration, listener);
}
+ public boolean isSupportConfiguratorQrCodeScanner(Context context) {
+ if (!WifiDppUtils.isWifiDppEnabled(context)) {
+ return false;
+ }
+
+ // DPP 1.0 only supports SAE and PSK.
+ if (SECURITY_SAE.equals(mSecurity) || SECURITY_WPA.equals(mSecurity)) {
+ return true;
+ }
+
+ return false;
+ }
+
/**
* This is a simplified method from {@code WifiConfigController.getConfig()}
*/
diff --git a/src/com/android/settings/wifi/dpp/WifiNetworkListFragment.java b/src/com/android/settings/wifi/dpp/WifiNetworkListFragment.java
index 7ea4906..b078b01 100644
--- a/src/com/android/settings/wifi/dpp/WifiNetworkListFragment.java
+++ b/src/com/android/settings/wifi/dpp/WifiNetworkListFragment.java
@@ -48,7 +48,6 @@
private static final String TAG = "WifiNetworkListFragment";
private static final String WIFI_CONFIG_KEY = "wifi_config_key";
- private static final String PREF_KEY_EMPTY_WIFI_LIST = "wifi_empty_list";
private static final String PREF_KEY_ACCESS_POINTS = "access_points";
static final int ADD_NETWORK_REQUEST = 1;
@@ -56,11 +55,14 @@
private PreferenceCategory mAccessPointsPreferenceCategory;
private AccessPointPreference.UserBadgeCache mUserBadgeCache;
private Preference mAddPreference;
+ // Only shows up if mIsTest == true
+ private Preference mFakeNetworkPreference;
private WifiManager mWifiManager;
private WifiTracker mWifiTracker;
private WifiManager.ActionListener mSaveListener;
+ private boolean mIsTest;
@VisibleForTesting
boolean mUseConnectedAccessPointDirectly;
@@ -100,6 +102,11 @@
getSettingsLifecycle(), /* includeSaved */true, /* includeScans */ true);
mWifiManager = mWifiTracker.getManager();
+ final Bundle args = getArguments();
+ if (args != null) {
+ mIsTest = args.getBoolean(WifiDppUtils.EXTRA_TEST, false);
+ }
+
mSaveListener = new WifiManager.ActionListener() {
@Override
public void onSuccess() {
@@ -139,6 +146,11 @@
mAccessPointsPreferenceCategory = (PreferenceCategory) findPreference(
PREF_KEY_ACCESS_POINTS);
+ mFakeNetworkPreference = new Preference(getPrefContext());
+ mFakeNetworkPreference.setIcon(R.drawable.ic_wifi_signal_0);
+ mFakeNetworkPreference.setKey("fake_key");
+ mFakeNetworkPreference.setTitle("fake network");
+
mAddPreference = new Preference(getPrefContext());
mAddPreference.setIcon(R.drawable.ic_menu_add);
mAddPreference.setTitle(R.string.wifi_add_network);
@@ -219,6 +231,16 @@
}
} else if (preference == mAddPreference) {
launchAddNetworkFragment();
+ } else if (preference == mFakeNetworkPreference) {
+ if (mOnChooseNetworkListener != null) {
+ mOnChooseNetworkListener.onChooseNetwork(
+ new WifiNetworkConfig(
+ WifiQrCode.SECURITY_WPA,
+ /* ssid */ WifiNetworkConfig.FAKE_SSID,
+ /* preSharedKey */ WifiNetworkConfig.FAKE_PASSWORD,
+ /* hiddenSsid */ true,
+ /* networkId */ WifiConfiguration.INVALID_NETWORK_ID));
+ }
} else {
return super.onPreferenceTreeClick(preference);
}
@@ -277,7 +299,6 @@
// AccessPoints are sorted by the WifiTracker
final List<AccessPoint> accessPoints = mWifiTracker.getAccessPoints();
- boolean hasAvailableAccessPoints = false;
mAccessPointsPreferenceCategory.setVisible(true);
cacheRemoveAllPrefs(mAccessPointsPreferenceCategory);
@@ -299,7 +320,6 @@
return;
}
- hasAvailableAccessPoints = true;
final AccessPointPreference pref = (AccessPointPreference) getCachedPreference(key);
if (pref != null) {
pref.setOrder(index);
@@ -318,13 +338,9 @@
mAddPreference.setOrder(index);
mAccessPointsPreferenceCategory.addPreference(mAddPreference);
- if (!hasAvailableAccessPoints) {
- final Preference pref = new Preference(getPrefContext());
- pref.setSelectable(false);
- pref.setSummary(R.string.wifi_empty_list_wifi_on);
- pref.setOrder(index++);
- pref.setKey(PREF_KEY_EMPTY_WIFI_LIST);
- mAccessPointsPreferenceCategory.addPreference(pref);
+ if (mIsTest) {
+ mFakeNetworkPreference.setOrder(index + 1);
+ mAccessPointsPreferenceCategory.addPreference(mFakeNetworkPreference);
}
}
diff --git a/src/com/android/settings/wifi/dpp/WifiQrCode.java b/src/com/android/settings/wifi/dpp/WifiQrCode.java
index 5ccb81e..d3f8ebf 100644
--- a/src/com/android/settings/wifi/dpp/WifiQrCode.java
+++ b/src/com/android/settings/wifi/dpp/WifiQrCode.java
@@ -67,6 +67,7 @@
public static final String SECURITY_NO_PASSWORD = "nopass";
public static final String SECURITY_WEP = "WEP";
public static final String SECURITY_WPA = "WPA";
+ public static final String SECURITY_SAE = "WPA3";
private String mQrCode;
diff --git a/src/com/android/settings/wifi/slice/WifiSlice.java b/src/com/android/settings/wifi/slice/WifiSlice.java
index 1c79c1d..88fa8b2 100644
--- a/src/com/android/settings/wifi/slice/WifiSlice.java
+++ b/src/com/android/settings/wifi/slice/WifiSlice.java
@@ -292,11 +292,12 @@
@Override
public void onWifiStateChanged(int state) {
- mContext.getContentResolver().notifyChange(getUri(), null);
+ notifySliceChange();
}
@Override
public void onConnectedChanged() {
+ notifySliceChange();
}
@Override
diff --git a/tests/robotests/res/values-mcc999/config.xml b/tests/robotests/res/values-mcc999/config.xml
index 101a6b8..da71273 100644
--- a/tests/robotests/res/values-mcc999/config.xml
+++ b/tests/robotests/res/values-mcc999/config.xml
@@ -67,10 +67,13 @@
<bool name="config_show_device_name">false</bool>
<bool name="config_use_legacy_suggestion">false</bool>
<bool name="config_show_avatar_in_homepage">true</bool>
+ <bool name="config_show_branded_account_in_device_info">false</bool>
+ <bool name="config_show_emergency_info_in_device_info">false</bool>
<!-- Whether or not extra preview panels should be used for screen zoom setting. -->
<bool name="config_enable_extra_screen_zoom_preview">false</bool>
+
<!-- List of a11y components on the device allowed to be enabled by Settings Slices -->
<string-array name="config_settings_slices_accessibility_components" translatable="false">
<item>fake_package/fake_service</item>
diff --git a/tests/robotests/src/com/android/settings/accounts/CrossProfileCalendarPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/accounts/CrossProfileCalendarPreferenceControllerTest.java
index bf4dec6..c6a48a8 100644
--- a/tests/robotests/src/com/android/settings/accounts/CrossProfileCalendarPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/accounts/CrossProfileCalendarPreferenceControllerTest.java
@@ -32,6 +32,7 @@
import android.content.Context;
import android.os.UserHandle;
import android.provider.Settings;
+import android.util.ArraySet;
import com.android.settingslib.RestrictedSwitchPreference;
@@ -45,6 +46,9 @@
import org.robolectric.Shadows;
import org.robolectric.shadows.ShadowDevicePolicyManager;
+import java.util.Arrays;
+import java.util.Collections;
+
@RunWith(RobolectricTestRunner.class)
public class CrossProfileCalendarPreferenceControllerTest {
@@ -123,7 +127,17 @@
@Test
public void updateState_somePackagesAllowed_preferenceShouldNotBeDisabled() throws Exception {
dpm.setProfileOwner(TEST_COMPONENT_NAME);
- dpm.addCrossProfileCalendarPackage(TEST_COMPONENT_NAME, TEST_PACKAGE_NAME);
+ dpm.setCrossProfileCalendarPackages(TEST_COMPONENT_NAME,
+ Collections.singleton(TEST_PACKAGE_NAME));
+
+ mController.updateState(mPreference);
+ verify(mPreference).setDisabledByAdmin(null);
+ }
+
+ @Test
+ public void updateState_allPackagesAllowed_preferenceShouldNotBeDisabled() throws Exception {
+ dpm.setProfileOwner(TEST_COMPONENT_NAME);
+ dpm.setCrossProfileCalendarPackages(TEST_COMPONENT_NAME, null);
mController.updateState(mPreference);
verify(mPreference).setDisabledByAdmin(null);
diff --git a/tests/robotests/src/com/android/settings/accounts/EmergencyInfoPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/accounts/EmergencyInfoPreferenceControllerTest.java
index 5901f55..65da1f7 100644
--- a/tests/robotests/src/com/android/settings/accounts/EmergencyInfoPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/accounts/EmergencyInfoPreferenceControllerTest.java
@@ -70,10 +70,12 @@
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
- mController = new EmergencyInfoPreferenceController(mContext);
+ mController = new EmergencyInfoPreferenceController(mContext, "test_key");
mPreference = new Preference(Robolectric.setupActivity(Activity.class));
mPreference.setKey(mController.getPreferenceKey());
when(mScreen.findPreference(mPreference.getKey())).thenReturn(mPreference);
+ when(mContext.getResources().getBoolean(R.bool.config_show_emergency_info_in_device_info))
+ .thenReturn(true);
}
@After
@@ -104,6 +106,7 @@
mController.updateRawDataToIndex(data);
+ assertThat(mController.isAvailable()).isTrue();
assertThat(data).isNotEmpty();
}
@@ -152,7 +155,7 @@
final Activity activity = Robolectric.setupActivity(Activity.class);
final Preference preference = new Preference(activity);
preference.setKey("emergency_info");
- mController = new EmergencyInfoPreferenceController(activity);
+ mController = new EmergencyInfoPreferenceController(activity, preference.getKey());
mController.handlePreferenceTreeClick(preference);
diff --git a/tests/robotests/src/com/android/settings/applications/RecentAppsPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/applications/RecentAppsPreferenceControllerTest.java
index aab2156..3fd4369 100644
--- a/tests/robotests/src/com/android/settings/applications/RecentAppsPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/applications/RecentAppsPreferenceControllerTest.java
@@ -38,6 +38,7 @@
import android.content.Context;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
+import android.content.pm.ModuleInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.os.PowerManager;
@@ -102,10 +103,13 @@
public void setUp() {
MockitoAnnotations.initMocks(this);
mContext = spy(RuntimeEnvironment.application);
+ when(mContext.getApplicationContext()).thenReturn(mContext);
+ ReflectionHelpers.setStaticField(ApplicationsState.class, "sInstance", mAppState);
doReturn(mUsageStatsManager).when(mContext).getSystemService(Context.USAGE_STATS_SERVICE);
doReturn(mUserManager).when(mContext).getSystemService(Context.USER_SERVICE);
doReturn(mPackageManager).when(mContext).getPackageManager();
doReturn(mPowerManager).when(mContext).getSystemService(PowerManager.class);
+ when(mUserManager.getProfileIdsWithDisabled(anyInt())).thenReturn(new int[] {});
mController = new RecentAppsPreferenceController(mContext, mAppState, null);
when(mScreen.findPreference(anyString())).thenReturn(mCategory);
@@ -350,6 +354,57 @@
verify(mCategory).addPreference(argThat(summaryMatches("0 minutes ago")));
}
+ @Test
+ public void displayPreference_shouldNotShowHiddenSystemModule() {
+ final List<UsageStats> stats = new ArrayList<>();
+ // Regular app.
+ final UsageStats stat1 = new UsageStats();
+ stat1.mLastTimeUsed = System.currentTimeMillis();
+ stat1.mPackageName = "com.foo.bar";
+ stats.add(stat1);
+
+ // Hidden system module.
+ final UsageStats stat2 = new UsageStats();
+ stat2.mLastTimeUsed = System.currentTimeMillis() + 200;
+ stat2.mPackageName = "com.foo.hidden";
+ stats.add(stat2);
+
+ ApplicationsState.AppEntry stat1Entry = mock(ApplicationsState.AppEntry.class);
+ ApplicationsState.AppEntry stat2Entry = mock(ApplicationsState.AppEntry.class);
+ stat1Entry.info = mApplicationInfo;
+ stat2Entry.info = mApplicationInfo;
+
+ when(mAppState.getEntry(stat1.mPackageName, UserHandle.myUserId())).thenReturn(stat1Entry);
+ when(mAppState.getEntry(stat2.mPackageName, UserHandle.myUserId())).thenReturn(stat2Entry);
+
+ final ModuleInfo moduleInfo1 = new ModuleInfo();
+ moduleInfo1.setPackageName(stat1.mPackageName);
+ moduleInfo1.setHidden(false);
+
+ final ModuleInfo moduleInfo2 = new ModuleInfo();
+ moduleInfo2.setPackageName(stat2.mPackageName);
+ moduleInfo2.setHidden(true);
+
+ ReflectionHelpers.setStaticField(ApplicationsState.class, "sInstance", null);
+ final List<ModuleInfo> modules = new ArrayList<>();
+ modules.add(moduleInfo2);
+ when(mPackageManager.getInstalledModules(anyInt() /* flags */))
+ .thenReturn(modules);
+
+ when(mPackageManager.resolveActivity(any(Intent.class), anyInt()))
+ .thenReturn(new ResolveInfo());
+ when(mUsageStatsManager.queryUsageStats(anyInt(), anyLong(), anyLong()))
+ .thenReturn(stats);
+
+ mController.displayPreference(mScreen);
+
+ // Only add stat1. stat2 is skipped because it is hidden module.
+ final ArgumentCaptor<Preference> prefCaptor = ArgumentCaptor.forClass(Preference.class);
+ verify(mCategory).addPreference(prefCaptor.capture());
+ final Preference pref = prefCaptor.getValue();
+ assertThat(pref.getKey()).isEqualTo(stat1.mPackageName);
+ }
+
private static ArgumentMatcher<Preference> summaryMatches(String expected) {
return preference -> TextUtils.equals(expected, preference.getSummary());
}
diff --git a/tests/robotests/src/com/android/settings/applications/SpecialAppAccessPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/applications/SpecialAppAccessPreferenceControllerTest.java
index e2035e3..75302d8 100644
--- a/tests/robotests/src/com/android/settings/applications/SpecialAppAccessPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/applications/SpecialAppAccessPreferenceControllerTest.java
@@ -20,11 +20,16 @@
import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;
import android.content.Context;
import android.content.pm.ApplicationInfo;
+import android.content.pm.ModuleInfo;
+import android.content.pm.PackageManager;
import androidx.preference.Preference;
import androidx.preference.PreferenceScreen;
@@ -55,6 +60,8 @@
private ApplicationsState.Session mSession;
@Mock
private PreferenceScreen mScreen;
+ @Mock
+ private PackageManager mPackageManager;
private SpecialAppAccessPreferenceController mController;
private Preference mPreference;
@@ -62,8 +69,11 @@
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
- mContext = RuntimeEnvironment.application;
+ mContext = spy(RuntimeEnvironment.application);
+ when(mContext.getApplicationContext()).thenReturn(mContext);
ShadowUserManager.getShadow().setProfileIdsWithDisabled(new int[]{0});
+ doReturn(mPackageManager).when(mContext).getPackageManager();
+ doReturn(new ArrayList<ModuleInfo>()).when(mPackageManager).getInstalledModules(anyInt());
mController = new SpecialAppAccessPreferenceController(mContext, "test_key");
mPreference = new Preference(mContext);
when(mScreen.findPreference(mController.getPreferenceKey())).thenReturn(mPreference);
diff --git a/tests/robotests/src/com/android/settings/applications/appinfo/DefaultAppShortcutPreferenceControllerBaseTest.java b/tests/robotests/src/com/android/settings/applications/appinfo/DefaultAppShortcutPreferenceControllerBaseTest.java
index 719b737..89beede 100644
--- a/tests/robotests/src/com/android/settings/applications/appinfo/DefaultAppShortcutPreferenceControllerBaseTest.java
+++ b/tests/robotests/src/com/android/settings/applications/appinfo/DefaultAppShortcutPreferenceControllerBaseTest.java
@@ -18,6 +18,7 @@
import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -28,6 +29,7 @@
import android.content.Context;
import android.content.Intent;
import android.os.UserManager;
+import android.permission.PermissionControllerManager;
import androidx.preference.Preference;
@@ -38,6 +40,7 @@
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.Robolectric;
@@ -48,6 +51,8 @@
import org.robolectric.shadows.ShadowUserManager;
import java.util.Collections;
+import java.util.concurrent.Executor;
+import java.util.function.Consumer;
@RunWith(RobolectricTestRunner.class)
@Config(shadows = ShadowUserManager.class)
@@ -60,6 +65,8 @@
@Mock
private RoleManager mRoleManager;
@Mock
+ private PermissionControllerManager mPermissionControllerManager;
+ @Mock
private Preference mPreference;
private Activity mActivity;
@@ -71,7 +78,10 @@
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
- ShadowApplication.getInstance().setSystemService(Context.ROLE_SERVICE, mRoleManager);
+ ShadowApplication shadowApplication = ShadowApplication.getInstance();
+ shadowApplication.setSystemService(Context.ROLE_SERVICE, mRoleManager);
+ shadowApplication.setSystemService(Context.PERMISSION_CONTROLLER_SERVICE,
+ mPermissionControllerManager);
mActivity = Robolectric.setupActivity(Activity.class);
mShadowUserManager = shadowOf(mActivity.getSystemService(UserManager.class));
mController = new TestRolePreferenceController(mActivity);
@@ -80,6 +90,12 @@
}
@Test
+ public void constructor_callsIsApplicationQualifiedForRole() {
+ verify(mPermissionControllerManager).isApplicationQualifiedForRole(eq(TEST_ROLE_NAME), eq(
+ TEST_PACKAGE_NAME), any(Executor.class), any(Consumer.class));
+ }
+
+ @Test
public void getAvailabilityStatus_isManagedProfile_shouldReturnDisabled() {
mShadowUserManager.setManagedProfile(true);
@@ -88,24 +104,39 @@
}
@Test
- public void getAvailabilityStatus_roleIsAvailable_shouldReturnAvailable() {
- mShadowUserManager.setManagedProfile(false);
- when(mRoleManager.isRoleAvailable(eq(TEST_ROLE_NAME))).thenReturn(true);
-
+ public void
+ getAvailabilityStatus_noCallbackForIsApplicationNotQualifiedForRole_shouldReturnUnsupported() {
assertThat(mController.getAvailabilityStatus()).isEqualTo(
- DefaultAppShortcutPreferenceControllerBase.AVAILABLE);
+ DefaultAppShortcutPreferenceControllerBase.UNSUPPORTED_ON_DEVICE);
}
@Test
- public void getAvailabilityStatus_roleNotAvailable_shouldReturnDisabled() {
- mShadowUserManager.setManagedProfile(false);
- when(mRoleManager.isRoleAvailable(eq(TEST_ROLE_NAME))).thenReturn(false);
+ public void getAvailabilityStatus_applicationIsNotQualifiedForRole_shouldReturnUnsupported() {
+ final ArgumentCaptor<Consumer<Boolean>> callbackCaptor = ArgumentCaptor.forClass(
+ Consumer.class);
+ verify(mPermissionControllerManager).isApplicationQualifiedForRole(eq(TEST_ROLE_NAME), eq(
+ TEST_PACKAGE_NAME), any(Executor.class), callbackCaptor.capture());
+ final Consumer<Boolean> callback = callbackCaptor.getValue();
+ callback.accept(false);
assertThat(mController.getAvailabilityStatus()).isEqualTo(
DefaultAppShortcutPreferenceControllerBase.UNSUPPORTED_ON_DEVICE);
}
@Test
+ public void getAvailabilityStatus_applicationIsQualifiedForRole_shouldReturnAvailable() {
+ final ArgumentCaptor<Consumer<Boolean>> callbackCaptor = ArgumentCaptor.forClass(
+ Consumer.class);
+ verify(mPermissionControllerManager).isApplicationQualifiedForRole(eq(TEST_ROLE_NAME), eq(
+ TEST_PACKAGE_NAME), any(Executor.class), callbackCaptor.capture());
+ final Consumer<Boolean> callback = callbackCaptor.getValue();
+ callback.accept(true);
+
+ assertThat(mController.getAvailabilityStatus()).isEqualTo(
+ DefaultAppShortcutPreferenceControllerBase.AVAILABLE);
+ }
+
+ @Test
public void updateState_isRoleHolder_shouldSetSummaryToYes() {
when(mRoleManager.getRoleHolders(eq(TEST_ROLE_NAME))).thenReturn(Collections.singletonList(
TEST_PACKAGE_NAME));
diff --git a/tests/robotests/src/com/android/settings/applications/appinfo/DefaultSmsShortcutPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/applications/appinfo/DefaultSmsShortcutPreferenceControllerTest.java
index 6c8435f..b31a10d 100644
--- a/tests/robotests/src/com/android/settings/applications/appinfo/DefaultSmsShortcutPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/applications/appinfo/DefaultSmsShortcutPreferenceControllerTest.java
@@ -18,11 +18,17 @@
import static com.google.common.truth.Truth.assertThat;
+import android.content.Context;
+import android.permission.PermissionControllerManager;
+
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;
import org.robolectric.RuntimeEnvironment;
+import org.robolectric.shadows.ShadowApplication;
@RunWith(RobolectricTestRunner.class)
public class DefaultSmsShortcutPreferenceControllerTest {
@@ -30,10 +36,16 @@
private static final String TEST_PACKAGE_NAME = "TestPackage";
private static final String PREFERENCE_KEY = "default_sms_app";
+ @Mock
+ private PermissionControllerManager mPermissionControllerManager;
+
private DefaultSmsShortcutPreferenceController mController;
@Before
public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ ShadowApplication.getInstance().setSystemService(Context.PERMISSION_CONTROLLER_SERVICE,
+ mPermissionControllerManager);
mController = new DefaultSmsShortcutPreferenceController(RuntimeEnvironment.application,
TEST_PACKAGE_NAME);
}
diff --git a/tests/robotests/src/com/android/settings/applications/assist/DefaultAssistPickerTest.java b/tests/robotests/src/com/android/settings/applications/assist/DefaultAssistPickerTest.java
deleted file mode 100644
index 3804d6d..0000000
--- a/tests/robotests/src/com/android/settings/applications/assist/DefaultAssistPickerTest.java
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.settings.applications.assist;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.spy;
-
-import android.app.ActivityManager;
-import android.content.ComponentName;
-import android.content.Context;
-import android.provider.Settings;
-
-import org.junit.Before;
-import org.junit.BeforeClass;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.robolectric.RobolectricTestRunner;
-import org.robolectric.RuntimeEnvironment;
-import org.robolectric.shadow.api.Shadow;
-import org.robolectric.shadows.ShadowActivityManager;
-import org.robolectric.util.ReflectionHelpers;
-
-import java.util.ArrayList;
-import java.util.List;
-
-@RunWith(RobolectricTestRunner.class)
-public class DefaultAssistPickerTest {
-
- private static ComponentName sTestAssist;
-
- @BeforeClass
- public static void beforeClass() {
- sTestAssist = new ComponentName("com.android.settings", "assist");
- }
-
- private Context mContext;
- private DefaultAssistPicker mPicker;
- private ShadowActivityManager mShadowActivityManager;
-
- @Before
- public void setUp() {
- mContext = RuntimeEnvironment.application;
- mShadowActivityManager = Shadow.extract(mContext.getSystemService(ActivityManager.class));
- mPicker = spy(new DefaultAssistPicker());
- mPicker.onAttach(mContext);
- doReturn(mContext).when(mPicker).getContext();
- }
-
- @Test
- public void setDefaultAppKey_shouldUpdateDefaultAssist() {
- final List<DefaultAssistPicker.Info> assistants = new ArrayList<>();
- assistants.add(new DefaultAssistPicker.Info(sTestAssist));
- ReflectionHelpers.setField(mPicker, "mAvailableAssistants", assistants);
- mPicker.setDefaultKey(sTestAssist.flattenToString());
-
- assertThat(Settings.Secure.getString(mContext.getContentResolver(),
- Settings.Secure.ASSISTANT))
- .isEqualTo(sTestAssist.flattenToString());
- assertThat(mPicker.getDefaultKey()).isEqualTo(sTestAssist.flattenToString());
- }
-
- @Test
- public void setDefaultAppKey_noAvailableAssist_shouldClearDefaultAssist() {
- final List<DefaultAssistPicker.Info> assistants = new ArrayList<>();
- ReflectionHelpers.setField(mPicker, "mAvailableAssistants", assistants);
- mPicker.setDefaultKey(sTestAssist.flattenToString());
-
- assertThat(Settings.Secure.getString(mContext.getContentResolver(),
- Settings.Secure.ASSISTANT))
- .isEmpty();
- assertThat(mPicker.getDefaultKey()).isNull();
- }
-
- @Test
- public void setDefaultAppKeyToNull_shouldClearDefaultAssist() {
- final List<DefaultAssistPicker.Info> assistants = new ArrayList<>();
- assistants.add(new DefaultAssistPicker.Info(sTestAssist));
- ReflectionHelpers.setField(mPicker, "mAvailableAssistants", assistants);
- mPicker.setDefaultKey(null);
-
- assertThat(Settings.Secure.getString(mContext.getContentResolver(),
- Settings.Secure.ASSISTANT))
- .isEmpty();
- assertThat(mPicker.getDefaultKey()).isNull();
- }
-
- @Test
- public void addAssistService_lowRamDevice_shouldDoNothing() {
- mShadowActivityManager.setIsLowRamDevice(true);
- mPicker.addAssistServices();
-
- assertThat(mPicker.mAvailableAssistants).hasSize(0);
- }
-}
diff --git a/tests/robotests/src/com/android/settings/applications/specialaccess/MoreSpecialAccessPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/applications/specialaccess/MoreSpecialAccessPreferenceControllerTest.java
new file mode 100644
index 0000000..534fdaf
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/applications/specialaccess/MoreSpecialAccessPreferenceControllerTest.java
@@ -0,0 +1,179 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.applications.specialaccess;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+
+import androidx.preference.Preference;
+
+import com.android.settings.core.BasePreferenceController;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RobolectricTestRunner;
+
+@RunWith(RobolectricTestRunner.class)
+public class MoreSpecialAccessPreferenceControllerTest {
+
+ private static final String PREFERENCE_KEY = "more";
+ private static final String DIFFERENT_PREFERENCE_KEY = "different";
+
+ private static final String PERMISSION_CONTROLLER_PACKAGE_NAME =
+ "com.android.permissioncontroller";
+
+ @Mock
+ private Context mContext;
+ @Mock
+ private PackageManager mPackageManager;
+
+ @Before
+ public void setUp() throws PackageManager.NameNotFoundException {
+ MockitoAnnotations.initMocks(this);
+
+ when(mContext.getPackageManager()).thenReturn(mPackageManager);
+ }
+
+ @Test
+ public void constructor_shouldResolveActivityWithPermissionControllerPackageName() {
+ when(mPackageManager.getPermissionControllerPackageName()).thenReturn(
+ PERMISSION_CONTROLLER_PACKAGE_NAME);
+ new MoreSpecialAccessPreferenceController(mContext, PREFERENCE_KEY);
+
+ ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
+ verify(mPackageManager).resolveActivity(intentCaptor.capture(), anyInt());
+ final Intent intent = intentCaptor.getValue();
+ assertThat(intent.getPackage()).isEqualTo(PERMISSION_CONTROLLER_PACKAGE_NAME);
+ }
+
+ @Test
+ public void getAvailabilityStatus_noPermissionController_shouldReturnUnsupportedOnDevice() {
+ when(mPackageManager.getPermissionControllerPackageName()).thenReturn(null);
+ MoreSpecialAccessPreferenceController preferenceController =
+ new MoreSpecialAccessPreferenceController(mContext, PREFERENCE_KEY);
+
+ assertThat(preferenceController.getAvailabilityStatus()).isEqualTo(
+ BasePreferenceController.UNSUPPORTED_ON_DEVICE);
+ }
+
+ @Test
+ public void getAvailabilityStatus_canNotResolveActivity_shouldReturnUnsupportedOnDevice() {
+ when(mPackageManager.getPermissionControllerPackageName()).thenReturn(
+ PERMISSION_CONTROLLER_PACKAGE_NAME);
+ MoreSpecialAccessPreferenceController preferenceController =
+ new MoreSpecialAccessPreferenceController(mContext, PREFERENCE_KEY);
+
+ assertThat(preferenceController.getAvailabilityStatus()).isEqualTo(
+ BasePreferenceController.UNSUPPORTED_ON_DEVICE);
+ }
+
+ @Test
+ public void getAvailabilityStatus_canResolveActivity_shouldReturnAvailableUnsearchable() {
+ when(mPackageManager.getPermissionControllerPackageName()).thenReturn(
+ PERMISSION_CONTROLLER_PACKAGE_NAME);
+ when(mPackageManager.resolveActivity(any(Intent.class), anyInt())).thenReturn(
+ new ResolveInfo());
+ MoreSpecialAccessPreferenceController preferenceController =
+ new MoreSpecialAccessPreferenceController(mContext, PREFERENCE_KEY);
+
+ assertThat(preferenceController.getAvailabilityStatus()).isEqualTo(
+ BasePreferenceController.AVAILABLE_UNSEARCHABLE);
+ }
+
+ @Test
+ public void handlePreferenceTreeClick_differentKey_shouldReturnFalse() {
+ when(mPackageManager.getPermissionControllerPackageName())
+ .thenReturn(PERMISSION_CONTROLLER_PACKAGE_NAME);
+ MoreSpecialAccessPreferenceController preferenceController =
+ new MoreSpecialAccessPreferenceController(mContext, PREFERENCE_KEY);
+ Preference preference = mock(Preference.class);
+ when(preference.getKey()).thenReturn(DIFFERENT_PREFERENCE_KEY);
+
+ assertThat(preferenceController.handlePreferenceTreeClick(preference)).isFalse();
+ }
+
+ @Test
+ public void handlePreferenceTreeClick_sameKey_shouldReturnTrue() {
+ when(mPackageManager.getPermissionControllerPackageName())
+ .thenReturn(PERMISSION_CONTROLLER_PACKAGE_NAME);
+ MoreSpecialAccessPreferenceController preferenceController =
+ new MoreSpecialAccessPreferenceController(mContext, PREFERENCE_KEY);
+ Preference preference = mock(Preference.class);
+ when(preference.getKey()).thenReturn(PREFERENCE_KEY);
+
+ assertThat(preferenceController.handlePreferenceTreeClick(preference)).isTrue();
+ }
+
+ @Test
+ public void handlePreferenceTreeClick_noPermissionController_shouldNotStartActivity() {
+ when(mPackageManager.getPermissionControllerPackageName()).thenReturn(null);
+ MoreSpecialAccessPreferenceController preferenceController =
+ new MoreSpecialAccessPreferenceController(mContext, PREFERENCE_KEY);
+ Preference preference = mock(Preference.class);
+ when(preference.getKey()).thenReturn(PREFERENCE_KEY);
+ preferenceController.handlePreferenceTreeClick(preference);
+
+ verify(mContext, never()).startActivity(any(Intent.class));
+ }
+
+ @Test
+ public void handlePreferenceTreeClick_canNotResolveActivity_shouldNotStartActivity() {
+ when(mPackageManager.getPermissionControllerPackageName()).thenReturn(
+ PERMISSION_CONTROLLER_PACKAGE_NAME);
+ MoreSpecialAccessPreferenceController preferenceController =
+ new MoreSpecialAccessPreferenceController(mContext, PREFERENCE_KEY);
+ Preference preference = mock(Preference.class);
+ when(preference.getKey()).thenReturn(PREFERENCE_KEY);
+ preferenceController.handlePreferenceTreeClick(preference);
+
+ verify(mContext, never()).startActivity(any(Intent.class));
+ }
+
+ @Test
+ public void handlePreferenceTreeClick_canResolveActivity_shouldStartActivityWithIntent() {
+ when(mPackageManager.getPermissionControllerPackageName())
+ .thenReturn(PERMISSION_CONTROLLER_PACKAGE_NAME);
+ when(mPackageManager.resolveActivity(any(Intent.class), anyInt())).thenReturn(
+ new ResolveInfo());
+ MoreSpecialAccessPreferenceController preferenceController =
+ new MoreSpecialAccessPreferenceController(mContext, PREFERENCE_KEY);
+ Preference preference = mock(Preference.class);
+ when(preference.getKey()).thenReturn(PREFERENCE_KEY);
+ preferenceController.handlePreferenceTreeClick(preference);
+ ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
+
+ verify(mContext).startActivity(intentCaptor.capture());
+ final Intent intent = intentCaptor.getValue();
+ assertThat(intent.getAction()).isEqualTo(Intent.ACTION_MANAGE_SPECIAL_APP_ACCESSES);
+ assertThat(intent.getPackage()).isEqualTo(PERMISSION_CONTROLLER_PACKAGE_NAME);
+ }
+}
diff --git a/tests/robotests/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollFindSensorTest.java b/tests/robotests/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollFindSensorTest.java
index 67c03d5..8be6b30 100644
--- a/tests/robotests/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollFindSensorTest.java
+++ b/tests/robotests/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollFindSensorTest.java
@@ -38,7 +38,7 @@
import com.android.settings.testutils.shadow.ShadowUtils;
import com.google.android.setupcompat.PartnerCustomizationLayout;
-import com.google.android.setupcompat.template.ButtonFooterMixin;
+import com.google.android.setupcompat.template.FooterBarMixin;
import org.junit.After;
import org.junit.Before;
@@ -137,7 +137,7 @@
@Test
public void clickSkip_shouldReturnResultSkip() {
PartnerCustomizationLayout layout = mActivity.findViewById(R.id.setup_wizard_layout);
- layout.getMixin(ButtonFooterMixin.class).getSecondaryButtonView().performClick();
+ layout.getMixin(FooterBarMixin.class).getSecondaryButtonView().performClick();
ShadowActivity shadowActivity = Shadows.shadowOf(mActivity);
assertThat(shadowActivity.getResultCode()).named("result code")
diff --git a/tests/robotests/src/com/android/settings/biometrics/fingerprint/FingerprintSuggestionActivityTest.java b/tests/robotests/src/com/android/settings/biometrics/fingerprint/FingerprintSuggestionActivityTest.java
index 82124f9..9fa6099 100644
--- a/tests/robotests/src/com/android/settings/biometrics/fingerprint/FingerprintSuggestionActivityTest.java
+++ b/tests/robotests/src/com/android/settings/biometrics/fingerprint/FingerprintSuggestionActivityTest.java
@@ -32,7 +32,7 @@
import com.android.settings.testutils.shadow.ShadowUserManager;
import com.google.android.setupcompat.PartnerCustomizationLayout;
-import com.google.android.setupcompat.template.ButtonFooterMixin;
+import com.google.android.setupcompat.template.FooterBarMixin;
import org.junit.Before;
import org.junit.Test;
@@ -68,7 +68,7 @@
PartnerCustomizationLayout layout =
mController.get().findViewById(R.id.setup_wizard_layout);
final Button cancelButton =
- layout.getMixin(ButtonFooterMixin.class).getSecondaryButtonView();
+ layout.getMixin(FooterBarMixin.class).getSecondaryButtonView();
assertThat(cancelButton.getText().toString()).isEqualTo("Cancel");
assertThat(cancelButton.getVisibility()).named("Cancel visible").isEqualTo(View.VISIBLE);
cancelButton.performClick();
diff --git a/tests/robotests/src/com/android/settings/biometrics/fingerprint/SetupFingerprintEnrollFindSensorTest.java b/tests/robotests/src/com/android/settings/biometrics/fingerprint/SetupFingerprintEnrollFindSensorTest.java
index b112c8a..a198d86 100644
--- a/tests/robotests/src/com/android/settings/biometrics/fingerprint/SetupFingerprintEnrollFindSensorTest.java
+++ b/tests/robotests/src/com/android/settings/biometrics/fingerprint/SetupFingerprintEnrollFindSensorTest.java
@@ -33,7 +33,7 @@
import com.android.settings.testutils.shadow.ShadowUtils;
import com.google.android.setupcompat.PartnerCustomizationLayout;
-import com.google.android.setupcompat.template.ButtonFooterMixin;
+import com.google.android.setupcompat.template.FooterBarMixin;
import org.junit.After;
import org.junit.Before;
@@ -75,7 +75,7 @@
intent).setup().get();
PartnerCustomizationLayout layout = activity.findViewById(R.id.setup_wizard_layout);
- layout.getMixin(ButtonFooterMixin.class).getSecondaryButtonView().performClick();
+ layout.getMixin(FooterBarMixin.class).getSecondaryButtonView().performClick();
final AlertDialog alertDialog = ShadowAlertDialogCompat.getLatestAlertDialog();
assertThat(alertDialog).isNotNull();
diff --git a/tests/robotests/src/com/android/settings/biometrics/fingerprint/SetupFingerprintEnrollIntroductionTest.java b/tests/robotests/src/com/android/settings/biometrics/fingerprint/SetupFingerprintEnrollIntroductionTest.java
index 12bf1e2..c817749 100644
--- a/tests/robotests/src/com/android/settings/biometrics/fingerprint/SetupFingerprintEnrollIntroductionTest.java
+++ b/tests/robotests/src/com/android/settings/biometrics/fingerprint/SetupFingerprintEnrollIntroductionTest.java
@@ -38,7 +38,7 @@
import com.android.settings.testutils.shadow.ShadowUserManager;
import com.google.android.setupcompat.PartnerCustomizationLayout;
-import com.google.android.setupcompat.template.ButtonFooterMixin;
+import com.google.android.setupcompat.template.FooterBarMixin;
import org.junit.After;
import org.junit.Before;
@@ -89,7 +89,7 @@
PartnerCustomizationLayout layout =
mController.get().findViewById(R.id.setup_wizard_layout);
final Button skipButton =
- layout.getMixin(ButtonFooterMixin.class).getSecondaryButtonView();
+ layout.getMixin(FooterBarMixin.class).getSecondaryButtonView();
assertThat(skipButton.getVisibility()).named("Skip visible").isEqualTo(View.VISIBLE);
skipButton.performClick();
@@ -108,7 +108,7 @@
PartnerCustomizationLayout layout =
mController.get().findViewById(R.id.setup_wizard_layout);
final Button skipButton =
- layout.getMixin(ButtonFooterMixin.class).getSecondaryButtonView();
+ layout.getMixin(FooterBarMixin.class).getSecondaryButtonView();
assertThat(skipButton.getVisibility()).named("Skip visible").isEqualTo(View.VISIBLE);
skipButton.performClick();
@@ -152,7 +152,7 @@
SetupFingerprintEnrollIntroduction activity = mController.create().resume().get();
PartnerCustomizationLayout layout = activity.findViewById(R.id.setup_wizard_layout);
final Button skipButton =
- layout.getMixin(ButtonFooterMixin.class).getSecondaryButtonView();
+ layout.getMixin(FooterBarMixin.class).getSecondaryButtonView();
getShadowKeyguardManager().setIsKeyguardSecure(true);
skipButton.performClick();
@@ -169,7 +169,7 @@
SetupFingerprintEnrollIntroduction activity = mController.create().resume().get();
PartnerCustomizationLayout layout = activity.findViewById(R.id.setup_wizard_layout);
final Button skipButton =
- layout.getMixin(ButtonFooterMixin.class).getSecondaryButtonView();
+ layout.getMixin(FooterBarMixin.class).getSecondaryButtonView();
skipButton.performClick();
ShadowActivity shadowActivity = Shadows.shadowOf(activity);
@@ -213,7 +213,7 @@
SetupFingerprintEnrollIntroduction activity = mController.get();
PartnerCustomizationLayout layout = activity.findViewById(R.id.setup_wizard_layout);
- layout.getMixin(ButtonFooterMixin.class).getPrimaryButtonView().performClick();
+ layout.getMixin(FooterBarMixin.class).getPrimaryButtonView().performClick();
ShadowActivity shadowActivity = Shadows.shadowOf(activity);
diff --git a/tests/robotests/src/com/android/settings/bluetooth/AdvancedBluetoothDetailsHeaderControllerTest.java b/tests/robotests/src/com/android/settings/bluetooth/AdvancedBluetoothDetailsHeaderControllerTest.java
new file mode 100644
index 0000000..a74610e
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/bluetooth/AdvancedBluetoothDetailsHeaderControllerTest.java
@@ -0,0 +1,127 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.bluetooth;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.when;
+
+import android.bluetooth.BluetoothDevice;
+import android.content.Context;
+import android.graphics.drawable.Drawable;
+import android.view.LayoutInflater;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+import com.android.settings.R;
+import com.android.settings.core.BasePreferenceController;
+import com.android.settings.fuelgauge.BatteryMeterView;
+import com.android.settings.testutils.shadow.ShadowEntityHeaderController;
+import com.android.settingslib.bluetooth.CachedBluetoothDevice;
+import com.android.settingslib.widget.LayoutPreference;
+
+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;
+import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.Config;
+
+@RunWith(RobolectricTestRunner.class)
+@Config(shadows = ShadowEntityHeaderController.class)
+public class AdvancedBluetoothDetailsHeaderControllerTest{
+ private static final int BATTERY_LEVEL_MAIN = 30;
+ private static final int BATTERY_LEVEL_LEFT = 25;
+ private static final int BATTERY_LEVEL_RIGHT = 45;
+
+ private Context mContext;
+
+ @Mock
+ private BluetoothDevice mBluetoothDevice;
+ @Mock
+ private CachedBluetoothDevice mCachedDevice;
+ private AdvancedBluetoothDetailsHeaderController mController;
+ private LayoutPreference mLayoutPreference;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+
+ mContext = RuntimeEnvironment.application;
+ mController = new AdvancedBluetoothDetailsHeaderController(mContext, "pref_Key");
+ mController.init(mCachedDevice);
+ mLayoutPreference = new LayoutPreference(mContext,
+ LayoutInflater.from(mContext).inflate(R.layout.advanced_bt_entity_header, null));
+ mController.mLayoutPreference = mLayoutPreference;
+ when(mCachedDevice.getDevice()).thenReturn(mBluetoothDevice);
+ }
+
+ @Test
+ public void createBatteryIcon_hasCorrectInfo() {
+ final Drawable drawable = mController.createBtBatteryIcon(mContext, BATTERY_LEVEL_MAIN);
+ assertThat(drawable).isInstanceOf(BatteryMeterView.BatteryMeterDrawable.class);
+
+ final BatteryMeterView.BatteryMeterDrawable iconDrawable =
+ (BatteryMeterView.BatteryMeterDrawable) drawable;
+ assertThat(iconDrawable.getBatteryLevel()).isEqualTo(BATTERY_LEVEL_MAIN);
+ }
+
+ @Test
+ public void refresh_updateCorrectInfo() {
+ when(mBluetoothDevice.getMetadata(
+ BluetoothDevice.METADATA_UNTHETHERED_LEFT_BATTERY)).thenReturn(
+ String.valueOf(BATTERY_LEVEL_LEFT));
+ when(mBluetoothDevice.getMetadata(
+ BluetoothDevice.METADATA_UNTHETHERED_RIGHT_BATTERY)).thenReturn(
+ String.valueOf(BATTERY_LEVEL_RIGHT));
+ when(mBluetoothDevice.getMetadata(
+ BluetoothDevice.METADATA_UNTHETHERED_CASE_BATTERY)).thenReturn(
+ String.valueOf(BATTERY_LEVEL_MAIN));
+ mController.refresh();
+
+ assertBatteryLevel(mLayoutPreference.findViewById(R.id.layout_left), BATTERY_LEVEL_LEFT);
+ assertBatteryLevel(mLayoutPreference.findViewById(R.id.layout_right), BATTERY_LEVEL_RIGHT);
+ assertBatteryLevel(mLayoutPreference.findViewById(R.id.layout_middle), BATTERY_LEVEL_MAIN);
+ }
+
+ @Test
+ public void getAvailabilityStatus_unthetheredHeadset_returnAvailable() {
+ when(mBluetoothDevice.getMetadata(BluetoothDevice.METADATA_IS_UNTHETHERED_HEADSET))
+ .thenReturn("true");
+
+ assertThat(mController.getAvailabilityStatus()).isEqualTo(
+ BasePreferenceController.AVAILABLE);
+ }
+
+ @Test
+ public void getAvailabilityStatus_notUnthetheredHeadset_returnUnavailable() {
+ when(mBluetoothDevice.getMetadata(BluetoothDevice.METADATA_IS_UNTHETHERED_HEADSET))
+ .thenReturn("false");
+
+ assertThat(mController.getAvailabilityStatus()).isEqualTo(
+ BasePreferenceController.CONDITIONALLY_UNAVAILABLE);
+ }
+
+ private void assertBatteryLevel(LinearLayout linearLayout, int batteryLevel) {
+ final TextView textView = linearLayout.findViewById(R.id.bt_battery_summary);
+ assertThat(textView.getText().toString()).isEqualTo(
+ com.android.settings.Utils.formatPercentage(batteryLevel));
+ }
+
+}
diff --git a/tests/robotests/src/com/android/settings/bluetooth/BluetoothDetailsHeaderControllerTest.java b/tests/robotests/src/com/android/settings/bluetooth/BluetoothDetailsHeaderControllerTest.java
index 1e78075..930d9cb 100644
--- a/tests/robotests/src/com/android/settings/bluetooth/BluetoothDetailsHeaderControllerTest.java
+++ b/tests/robotests/src/com/android/settings/bluetooth/BluetoothDetailsHeaderControllerTest.java
@@ -50,7 +50,6 @@
import org.robolectric.annotation.Config;
@RunWith(RobolectricTestRunner.class)
-
@Config(shadows = ShadowEntityHeaderController.class)
public class BluetoothDetailsHeaderControllerTest extends BluetoothDetailsControllerTestBase {
diff --git a/tests/robotests/src/com/android/settings/bluetooth/BluetoothDevicePreferenceTest.java b/tests/robotests/src/com/android/settings/bluetooth/BluetoothDevicePreferenceTest.java
index 9e5b617..f6969ec 100644
--- a/tests/robotests/src/com/android/settings/bluetooth/BluetoothDevicePreferenceTest.java
+++ b/tests/robotests/src/com/android/settings/bluetooth/BluetoothDevicePreferenceTest.java
@@ -171,7 +171,8 @@
.thenReturn(new BluetoothClass(BluetoothClass.Device.Major.IMAGING));
mPreference.onDeviceAttributesChanged();
- DrawableTestHelper.assertDrawableResId(mPreference.getIcon(), R.drawable.ic_settings_print);
+ DrawableTestHelper.assertDrawableResId(mPreference.getIcon(),
+ com.android.internal.R.drawable.ic_settings_print);
}
@Test
diff --git a/tests/robotests/src/com/android/settings/bluetooth/BluetoothSliceBuilderTest.java b/tests/robotests/src/com/android/settings/bluetooth/BluetoothSliceBuilderTest.java
index 4504d84..f4a9d36 100644
--- a/tests/robotests/src/com/android/settings/bluetooth/BluetoothSliceBuilderTest.java
+++ b/tests/robotests/src/com/android/settings/bluetooth/BluetoothSliceBuilderTest.java
@@ -68,7 +68,7 @@
final SliceAction primaryAction = metadata.getPrimaryAction();
final IconCompat expectedToggleIcon = IconCompat.createWithResource(mContext,
- R.drawable.ic_settings_bluetooth);
+ com.android.internal.R.drawable.ic_settings_bluetooth);
assertThat(primaryAction.getIcon().toString()).isEqualTo(expectedToggleIcon.toString());
}
diff --git a/tests/robotests/src/com/android/settings/bluetooth/UtilsTest.java b/tests/robotests/src/com/android/settings/bluetooth/UtilsTest.java
index 1337f66..51e559f 100644
--- a/tests/robotests/src/com/android/settings/bluetooth/UtilsTest.java
+++ b/tests/robotests/src/com/android/settings/bluetooth/UtilsTest.java
@@ -15,6 +15,8 @@
*/
package com.android.settings.bluetooth;
+import static com.google.common.truth.Truth.assertThat;
+
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
@@ -22,6 +24,7 @@
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import android.bluetooth.BluetoothDevice;
import android.content.Context;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
@@ -40,23 +43,68 @@
@RunWith(RobolectricTestRunner.class)
public class UtilsTest {
+ private static final String STRING_METADATA = "string_metadata";
+ private static final String BOOL_METADATA = "true";
+ private static final String INT_METADATA = "25";
+
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
private Context mContext;
+ @Mock
+ private BluetoothDevice mBluetoothDevice;
private MetricsFeatureProvider mMetricsFeatureProvider;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
+
mMetricsFeatureProvider = FakeFeatureFactory.setupForTest().getMetricsFeatureProvider();
}
@Test
- public void testShowConnectingError_shouldLogBluetoothConnectError() {
+ public void showConnectingError_shouldLogBluetoothConnectError() {
when(mContext.getString(anyInt(), anyString())).thenReturn("testMessage");
Utils.showConnectingError(mContext, "testName", mock(LocalBluetoothManager.class));
verify(mMetricsFeatureProvider).visible(eq(mContext), anyInt(),
eq(MetricsEvent.ACTION_SETTINGS_BLUETOOTH_CONNECT_ERROR));
}
+
+ @Test
+ public void getStringMetaData_hasMetaData_getCorrectMetaData() {
+ when(mBluetoothDevice.getMetadata(
+ BluetoothDevice.METADATA_UNTHETHERED_LEFT_ICON)).thenReturn(STRING_METADATA);
+
+ assertThat(Utils.getStringMetaData(mBluetoothDevice,
+ BluetoothDevice.METADATA_UNTHETHERED_LEFT_ICON)).isEqualTo(STRING_METADATA);
+ }
+
+ @Test
+ public void getIntMetaData_hasMetaData_getCorrectMetaData() {
+ when(mBluetoothDevice.getMetadata(
+ BluetoothDevice.METADATA_UNTHETHERED_LEFT_BATTERY)).thenReturn(INT_METADATA);
+
+ assertThat(Utils.getIntMetaData(mBluetoothDevice,
+ BluetoothDevice.METADATA_UNTHETHERED_LEFT_BATTERY))
+ .isEqualTo(Integer.parseInt(INT_METADATA));
+ }
+
+ @Test
+ public void getIntMetaData_invalidMetaData_getErrorCode() {
+ when(mBluetoothDevice.getMetadata(
+ BluetoothDevice.METADATA_UNTHETHERED_LEFT_BATTERY)).thenReturn(STRING_METADATA);
+
+ assertThat(Utils.getIntMetaData(mBluetoothDevice,
+ BluetoothDevice.METADATA_UNTHETHERED_LEFT_ICON)).isEqualTo(Utils.META_INT_ERROR);
+ }
+
+ @Test
+ public void getBooleanMetaData_hasMetaData_getCorrectMetaData() {
+ when(mBluetoothDevice.getMetadata(
+ BluetoothDevice.METADATA_IS_UNTHETHERED_HEADSET)).thenReturn(BOOL_METADATA);
+
+ assertThat(Utils.getBooleanMetaData(mBluetoothDevice,
+ BluetoothDevice.METADATA_IS_UNTHETHERED_HEADSET)).isEqualTo(true);
+ }
+
}
diff --git a/tests/robotests/src/com/android/settings/datausage/DataUsageSummaryPreferenceTest.java b/tests/robotests/src/com/android/settings/datausage/DataUsageSummaryPreferenceTest.java
index ae11954..525b82e 100644
--- a/tests/robotests/src/com/android/settings/datausage/DataUsageSummaryPreferenceTest.java
+++ b/tests/robotests/src/com/android/settings/datausage/DataUsageSummaryPreferenceTest.java
@@ -26,6 +26,7 @@
import android.content.ComponentName;
import android.content.Intent;
import android.graphics.Typeface;
+import android.net.ConnectivityManager;
import android.net.NetworkTemplate;
import android.os.Bundle;
import android.telephony.SubscriptionManager;
@@ -531,6 +532,18 @@
assertThat(mLaunchButton.isEnabled()).isFalse();
}
+ @Test
+ public void launchWifiDataUsage_shouldSetWifiNetworkTypeInIntentExtra() {
+ mSummaryPreference.launchWifiDataUsage(mActivity);
+
+ final Intent launchIntent = Shadows.shadowOf(mActivity).getNextStartedActivity();
+ final Bundle args =
+ launchIntent.getBundleExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT_ARGUMENTS);
+
+ assertThat(args.getInt(DataUsageList.EXTRA_NETWORK_TYPE))
+ .isEqualTo(ConnectivityManager.TYPE_WIFI);
+ }
+
private void bindViewHolder() {
mSummaryPreference.onBindViewHolder(mHolder);
mUsageTitle = (TextView) mHolder.findViewById(R.id.usage_title);
diff --git a/tests/robotests/src/com/android/settings/datausage/DataUsageSummaryTest.java b/tests/robotests/src/com/android/settings/datausage/DataUsageSummaryTest.java
index 66f916e..79c3ad1 100644
--- a/tests/robotests/src/com/android/settings/datausage/DataUsageSummaryTest.java
+++ b/tests/robotests/src/com/android/settings/datausage/DataUsageSummaryTest.java
@@ -31,6 +31,7 @@
import android.app.usage.NetworkStatsManager;
import android.content.Context;
import android.net.NetworkPolicyManager;
+import android.telephony.SubscriptionManager;
import androidx.fragment.app.FragmentActivity;
@@ -50,6 +51,7 @@
import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Config;
import org.robolectric.shadows.ShadowApplication;
+import org.robolectric.shadows.ShadowSubscriptionManager;
@Config(shadows = {
ShadowUtils.class,
@@ -114,10 +116,11 @@
}
@Test
+ @Config(shadows = ShadowSubscriptionManager.class)
public void configuration_withSim_shouldShowMobileAndWifi() {
ShadowDataUsageUtils.IS_MOBILE_DATA_SUPPORTED = true;
ShadowDataUsageUtils.IS_WIFI_SUPPORTED = true;
- ShadowDataUsageUtils.DEFAULT_SUBSCRIPTION_ID = 1;
+ ShadowSubscriptionManager.setDefaultDataSubscriptionId(1);
ShadowDataUsageUtils.HAS_SIM = true;
final DataUsageSummary dataUsageSummary = spy(new DataUsageSummary());
@@ -170,4 +173,26 @@
verify(dataUsageSummary).addWifiSection();
verify(dataUsageSummary, never()).addMobileSection(anyInt());
}
+
+ @Test
+ @Config(shadows = ShadowSubscriptionManager.class)
+ public void configuration_invalidDataSusbscription_shouldShowWifiSectionOnly() {
+ ShadowDataUsageUtils.IS_MOBILE_DATA_SUPPORTED = true;
+ ShadowDataUsageUtils.IS_WIFI_SUPPORTED = true;
+ ShadowDataUsageUtils.HAS_SIM = false;
+ ShadowSubscriptionManager.setDefaultDataSubscriptionId(
+ SubscriptionManager.INVALID_SUBSCRIPTION_ID);
+
+ final DataUsageSummary dataUsageSummary = spy(new DataUsageSummary());
+ doReturn(mContext).when(dataUsageSummary).getContext();
+
+ doReturn(true).when(dataUsageSummary).removePreference(anyString());
+ doNothing().when(dataUsageSummary).addWifiSection();
+ doNothing().when(dataUsageSummary).addMobileSection(1);
+
+ dataUsageSummary.onCreate(null);
+
+ verify(dataUsageSummary).addWifiSection();
+ verify(dataUsageSummary, never()).addMobileSection(anyInt());
+ }
}
diff --git a/tests/robotests/src/com/android/settings/development/OverlayCategoryPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/development/OverlayCategoryPreferenceControllerTest.java
index 3938b89..8a90b20 100644
--- a/tests/robotests/src/com/android/settings/development/OverlayCategoryPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/development/OverlayCategoryPreferenceControllerTest.java
@@ -31,6 +31,8 @@
import android.content.pm.PackageManager;
import android.os.RemoteException;
+import com.android.settings.R;
+
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -38,6 +40,8 @@
import org.mockito.MockitoAnnotations;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
+import org.robolectric.shadows.ShadowApplication;
+import org.robolectric.shadows.ShadowToast;
import java.util.ArrayList;
import java.util.Arrays;
@@ -105,22 +109,65 @@
mockCurrentOverlays(ONE_DISABLED, TWO_DISABLED);
mController.onPreferenceChange(null, TWO_DISABLED.packageName);
+ ShadowApplication.runBackgroundTasks();
verify(mOverlayManager)
.setEnabledExclusiveInCategory(eq(TWO_DISABLED.packageName), anyInt());
}
@Test
+ public void onPreferenceChange_enable_fails() throws Exception {
+ mockCurrentOverlays(ONE_DISABLED, TWO_DISABLED);
+ when(mOverlayManager.setEnabledExclusiveInCategory(eq(TWO_DISABLED.packageName), anyInt()))
+ .thenReturn(false);
+
+ mController.onPreferenceChange(null, TWO_DISABLED.packageName);
+ ShadowApplication.runBackgroundTasks();
+
+ assertThat(ShadowToast.getTextOfLatestToast()).isEqualTo(
+ RuntimeEnvironment.application.getString(R.string.overlay_toast_failed_to_apply));
+ }
+
+ @Test
public void onPreferenceChange_disable() throws Exception {
mockCurrentOverlays(ONE_DISABLED, TWO_ENABLED);
mController.onPreferenceChange(
null, OverlayCategoryPreferenceController.PACKAGE_DEVICE_DEFAULT);
+ ShadowApplication.runBackgroundTasks();
verify(mOverlayManager).setEnabled(eq(TWO_ENABLED.packageName), eq(false), anyInt());
}
@Test
+ public void onPreferenceChange_disable_fails() throws Exception {
+ mockCurrentOverlays(ONE_DISABLED, TWO_ENABLED);
+ when(mOverlayManager.setEnabled(eq(TWO_ENABLED.packageName), eq(false), anyInt()))
+ .thenReturn(false);
+
+ mController.onPreferenceChange(
+ null, OverlayCategoryPreferenceController.PACKAGE_DEVICE_DEFAULT);
+ ShadowApplication.runBackgroundTasks();
+
+ assertThat(ShadowToast.getTextOfLatestToast()).isEqualTo(
+ RuntimeEnvironment.application.getString(R.string.overlay_toast_failed_to_apply));
+ }
+
+ @Test
+ public void onPreferenceChange_disable_throws() throws Exception {
+ mockCurrentOverlays(ONE_DISABLED, TWO_ENABLED);
+ when(mOverlayManager.setEnabled(eq(TWO_ENABLED.packageName), eq(false), anyInt()))
+ .thenThrow(new RemoteException());
+
+ mController.onPreferenceChange(
+ null, OverlayCategoryPreferenceController.PACKAGE_DEVICE_DEFAULT);
+ ShadowApplication.runBackgroundTasks();
+
+ assertThat(ShadowToast.getTextOfLatestToast()).isEqualTo(
+ RuntimeEnvironment.application.getString(R.string.overlay_toast_failed_to_apply));
+ }
+
+ @Test
public void updateState_enabled() {
mockCurrentOverlays(ONE_DISABLED, TWO_ENABLED);
diff --git a/tests/robotests/src/com/android/settings/development/gup/GupPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/development/gamedriver/GameDriverAppPreferenceControllerTest.java
similarity index 68%
rename from tests/robotests/src/com/android/settings/development/gup/GupPreferenceControllerTest.java
rename to tests/robotests/src/com/android/settings/development/gamedriver/GameDriverAppPreferenceControllerTest.java
index d5e7a85..f6fa8e0 100644
--- a/tests/robotests/src/com/android/settings/development/gup/GupPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/development/gamedriver/GameDriverAppPreferenceControllerTest.java
@@ -14,14 +14,17 @@
* limitations under the License.
*/
-package com.android.settings.development.gup;
+package com.android.settings.development.gamedriver;
import static com.android.settings.core.BasePreferenceController.AVAILABLE;
-import static com.android.settings.core.BasePreferenceController.DISABLED_DEPENDENT_SETTING;
+import static com.android.settings.core.BasePreferenceController.CONDITIONALLY_UNAVAILABLE;
+import static com.android.settings.development.gamedriver.GameDriverEnableForAllAppsPreferenceController.GAME_DRIVER_DEFAULT;
+import static com.android.settings.development.gamedriver.GameDriverEnableForAllAppsPreferenceController.GAME_DRIVER_OFF;
import static com.android.settings.testutils.ApplicationTestUtils.buildInfo;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.content.ContentResolver;
@@ -49,9 +52,10 @@
import org.robolectric.RuntimeEnvironment;
@RunWith(RobolectricTestRunner.class)
-public class GupPreferenceControllerTest {
+public class GameDriverAppPreferenceControllerTest {
+
private static final int DEFAULT = 0;
- private static final int GUP = 1;
+ private static final int GAME_DRIVER = 1;
private static final int SYSTEM = 2;
private static final String TEST_APP_NAME = "testApp";
private static final String TEST_PKG_NAME = "testPkg";
@@ -65,12 +69,14 @@
private PackageManager mPackageManager;
@Mock
private PreferenceScreen mScreen;
+ @Mock
+ private GameDriverContentObserver mGameDriverContentObserver;
private Context mContext;
private PreferenceGroup mGroup;
private PreferenceManager mPreferenceManager;
private ContentResolver mResolver;
- private GupPreferenceController mController;
+ private GameDriverAppPreferenceController mController;
private CharSequence[] mValueList;
private String mDialogTitle;
@@ -79,24 +85,35 @@
MockitoAnnotations.initMocks(this);
mContext = spy(RuntimeEnvironment.application);
mResolver = mContext.getContentResolver();
- mValueList = mContext.getResources().getStringArray(R.array.gup_app_preference_values);
- mDialogTitle = mContext.getResources().getString(R.string.gup_app_preference_title);
+ mValueList =
+ mContext.getResources().getStringArray(R.array.game_driver_app_preference_values);
+ mDialogTitle = mContext.getResources().getString(R.string.game_driver_app_preference_title);
}
@Test
- public void getAvailability_developmentSettingsEnabled_available() {
+ public void getAvailability_developmentSettingsEnabledAndGameDriverOn_available() {
loadDefaultConfig();
Settings.Global.putInt(mResolver, Settings.Global.DEVELOPMENT_SETTINGS_ENABLED, 1);
+ Settings.Global.putInt(
+ mResolver, Settings.Global.GAME_DRIVER_ALL_APPS, GAME_DRIVER_DEFAULT);
assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE);
}
@Test
- public void getAvailability_developmentSettingsDisabled_disabledDependentSetting() {
+ public void getAvailability_developmentSettingsDisabled_conditionallyUnavailable() {
loadDefaultConfig();
Settings.Global.putInt(mResolver, Settings.Global.DEVELOPMENT_SETTINGS_ENABLED, 0);
- assertThat(mController.getAvailabilityStatus()).isEqualTo(DISABLED_DEPENDENT_SETTING);
+ assertThat(mController.getAvailabilityStatus()).isEqualTo(CONDITIONALLY_UNAVAILABLE);
+ }
+
+ @Test
+ public void getAvailability_gameDriverOff_conditionallyUnavailable() {
+ loadDefaultConfig();
+ Settings.Global.putInt(mResolver, Settings.Global.GAME_DRIVER_ALL_APPS, GAME_DRIVER_OFF);
+
+ assertThat(mController.getAvailabilityStatus()).isEqualTo(CONDITIONALLY_UNAVAILABLE);
}
@Test
@@ -111,10 +128,46 @@
}
@Test
+ public void onStart_shouldRegister() {
+ loadDefaultConfig();
+ mController.mGameDriverContentObserver = mGameDriverContentObserver;
+ mController.onStart();
+
+ verify(mGameDriverContentObserver).register(mResolver);
+ }
+
+ @Test
+ public void onStop_shouldUnregister() {
+ loadDefaultConfig();
+ mController.mGameDriverContentObserver = mGameDriverContentObserver;
+ mController.onStop();
+
+ verify(mGameDriverContentObserver).unregister(mResolver);
+ }
+
+ @Test
+ public void updateState_available_visible() {
+ Settings.Global.putInt(mResolver, Settings.Global.DEVELOPMENT_SETTINGS_ENABLED, 1);
+ Settings.Global.putInt(
+ mResolver, Settings.Global.GAME_DRIVER_ALL_APPS, GAME_DRIVER_DEFAULT);
+ loadDefaultConfig();
+
+ assertThat(mGroup.isVisible()).isTrue();
+ }
+
+ @Test
+ public void updateState_gameDriverOff_notVisible() {
+ Settings.Global.putInt(mResolver, Settings.Global.GAME_DRIVER_ALL_APPS, GAME_DRIVER_OFF);
+ loadDefaultConfig();
+
+ assertThat(mGroup.isVisible()).isFalse();
+ }
+
+ @Test
public void createPreference_configDefault_shouldSetDefaultAttributes() {
loadDefaultConfig();
final ListPreference preference =
- mController.createListPreference(TEST_PKG_NAME, TEST_APP_NAME);
+ mController.createListPreference(mContext, TEST_PKG_NAME, TEST_APP_NAME);
assertThat(preference.getKey()).isEqualTo(TEST_PKG_NAME);
assertThat(preference.getTitle()).isEqualTo(TEST_APP_NAME);
@@ -127,26 +180,26 @@
}
@Test
- public void createPreference_configGup_shouldSetGupAttributes() {
+ public void createPreference_configGAME_DRIVER_shouldSetGameDriverAttributes() {
loadConfig(TEST_PKG_NAME, "");
final ListPreference preference =
- mController.createListPreference(TEST_PKG_NAME, TEST_APP_NAME);
+ mController.createListPreference(mContext, TEST_PKG_NAME, TEST_APP_NAME);
assertThat(preference.getKey()).isEqualTo(TEST_PKG_NAME);
assertThat(preference.getTitle()).isEqualTo(TEST_APP_NAME);
assertThat(preference.getDialogTitle()).isEqualTo(mDialogTitle);
assertThat(preference.getEntries()).isEqualTo(mValueList);
assertThat(preference.getEntryValues()).isEqualTo(mValueList);
- assertThat(preference.getEntry()).isEqualTo(mValueList[GUP]);
- assertThat(preference.getValue()).isEqualTo(mValueList[GUP]);
- assertThat(preference.getSummary()).isEqualTo(mValueList[GUP]);
+ assertThat(preference.getEntry()).isEqualTo(mValueList[GAME_DRIVER]);
+ assertThat(preference.getValue()).isEqualTo(mValueList[GAME_DRIVER]);
+ assertThat(preference.getSummary()).isEqualTo(mValueList[GAME_DRIVER]);
}
@Test
public void createPreference_configSystem_shouldSetSystemAttributes() {
loadConfig("", TEST_PKG_NAME);
final ListPreference preference =
- mController.createListPreference(TEST_PKG_NAME, TEST_APP_NAME);
+ mController.createListPreference(mContext, TEST_PKG_NAME, TEST_APP_NAME);
assertThat(preference.getKey()).isEqualTo(TEST_PKG_NAME);
assertThat(preference.getTitle()).isEqualTo(TEST_APP_NAME);
@@ -162,31 +215,31 @@
public void onPreferenceChange_selectDefault_shouldUpdateAttributesAndSettingsGlobal() {
loadDefaultConfig();
final ListPreference preference =
- mController.createListPreference(TEST_PKG_NAME, TEST_APP_NAME);
+ mController.createListPreference(mContext, TEST_PKG_NAME, TEST_APP_NAME);
mController.onPreferenceChange(preference, mValueList[DEFAULT]);
assertThat(preference.getEntry()).isEqualTo(mValueList[DEFAULT]);
assertThat(preference.getValue()).isEqualTo(mValueList[DEFAULT]);
assertThat(preference.getSummary()).isEqualTo(mValueList[DEFAULT]);
- assertThat(Settings.Global.getString(mResolver, Settings.Global.GUP_DEV_OPT_IN_APPS))
+ assertThat(Settings.Global.getString(mResolver, Settings.Global.GAME_DRIVER_OPT_IN_APPS))
.isEqualTo("");
- assertThat(Settings.Global.getString(mResolver, Settings.Global.GUP_DEV_OPT_OUT_APPS))
+ assertThat(Settings.Global.getString(mResolver, Settings.Global.GAME_DRIVER_OPT_OUT_APPS))
.isEqualTo("");
}
@Test
- public void onPreferenceChange_selectGup_shouldUpdateAttributesAndSettingsGlobal() {
+ public void onPreferenceChange_selectGAME_DRIVER_shouldUpdateAttributesAndSettingsGlobal() {
loadDefaultConfig();
final ListPreference preference =
- mController.createListPreference(TEST_PKG_NAME, TEST_APP_NAME);
- mController.onPreferenceChange(preference, mValueList[GUP]);
+ mController.createListPreference(mContext, TEST_PKG_NAME, TEST_APP_NAME);
+ mController.onPreferenceChange(preference, mValueList[GAME_DRIVER]);
- assertThat(preference.getEntry()).isEqualTo(mValueList[GUP]);
- assertThat(preference.getValue()).isEqualTo(mValueList[GUP]);
- assertThat(preference.getSummary()).isEqualTo(mValueList[GUP]);
- assertThat(Settings.Global.getString(mResolver, Settings.Global.GUP_DEV_OPT_IN_APPS))
+ assertThat(preference.getEntry()).isEqualTo(mValueList[GAME_DRIVER]);
+ assertThat(preference.getValue()).isEqualTo(mValueList[GAME_DRIVER]);
+ assertThat(preference.getSummary()).isEqualTo(mValueList[GAME_DRIVER]);
+ assertThat(Settings.Global.getString(mResolver, Settings.Global.GAME_DRIVER_OPT_IN_APPS))
.isEqualTo(TEST_PKG_NAME);
- assertThat(Settings.Global.getString(mResolver, Settings.Global.GUP_DEV_OPT_OUT_APPS))
+ assertThat(Settings.Global.getString(mResolver, Settings.Global.GAME_DRIVER_OPT_OUT_APPS))
.isEqualTo("");
}
@@ -194,15 +247,15 @@
public void onPreferenceChange_selectSystem_shouldUpdateAttributesAndSettingsGlobal() {
loadDefaultConfig();
final ListPreference preference =
- mController.createListPreference(TEST_PKG_NAME, TEST_APP_NAME);
+ mController.createListPreference(mContext, TEST_PKG_NAME, TEST_APP_NAME);
mController.onPreferenceChange(preference, mValueList[SYSTEM]);
assertThat(preference.getEntry()).isEqualTo(mValueList[SYSTEM]);
assertThat(preference.getValue()).isEqualTo(mValueList[SYSTEM]);
assertThat(preference.getSummary()).isEqualTo(mValueList[SYSTEM]);
- assertThat(Settings.Global.getString(mResolver, Settings.Global.GUP_DEV_OPT_IN_APPS))
+ assertThat(Settings.Global.getString(mResolver, Settings.Global.GAME_DRIVER_OPT_IN_APPS))
.isEqualTo("");
- assertThat(Settings.Global.getString(mResolver, Settings.Global.GUP_DEV_OPT_OUT_APPS))
+ assertThat(Settings.Global.getString(mResolver, Settings.Global.GAME_DRIVER_OPT_OUT_APPS))
.isEqualTo(TEST_PKG_NAME);
}
@@ -224,12 +277,13 @@
private void loadDefaultConfig() { loadConfig("", ""); }
private void loadConfig(String optIn, String optOut) {
- Settings.Global.putString(mResolver, Settings.Global.GUP_DEV_OPT_IN_APPS, optIn);
- Settings.Global.putString(mResolver, Settings.Global.GUP_DEV_OPT_OUT_APPS, optOut);
+ Settings.Global.putString(mResolver, Settings.Global.GAME_DRIVER_OPT_IN_APPS, optIn);
+ Settings.Global.putString(mResolver, Settings.Global.GAME_DRIVER_OPT_OUT_APPS, optOut);
- mController = new GupPreferenceController(mContext, "testKey");
+ mController = new GameDriverAppPreferenceController(mContext, "testKey");
mGroup = spy(new PreferenceCategory(mContext));
final PreferenceManager preferenceManager = new PreferenceManager(mContext);
+ when(mGroup.getContext()).thenReturn(mContext);
when(mGroup.getPreferenceManager()).thenReturn(preferenceManager);
when(mScreen.findPreference(mController.getPreferenceKey())).thenReturn(mGroup);
mController.displayPreference(mScreen);
diff --git a/tests/robotests/src/com/android/settings/development/gamedriver/GameDriverContentObserverTest.java b/tests/robotests/src/com/android/settings/development/gamedriver/GameDriverContentObserverTest.java
new file mode 100644
index 0000000..caaf896
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/development/gamedriver/GameDriverContentObserverTest.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.development.gamedriver;
+
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+
+import android.content.ContentResolver;
+import android.provider.Settings;
+
+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;
+import org.robolectric.RuntimeEnvironment;
+
+@RunWith(RobolectricTestRunner.class)
+public class GameDriverContentObserverTest {
+
+ @Mock
+ private ContentResolver mResolver;
+ @Mock
+ private GameDriverContentObserver.OnGameDriverContentChangedListener mListener;
+
+ private GameDriverContentObserver mGameDriverContentObserver;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ mGameDriverContentObserver = spy(new GameDriverContentObserver(null, null));
+ }
+
+ @Test
+ public void onChange_shouldCallListener() {
+ mGameDriverContentObserver.mListener = mListener;
+ mGameDriverContentObserver.onChange(true);
+
+ verify(mListener).onGameDriverContentChanged();
+ }
+
+ @Test
+ public void register_shouldRegisterContentObserver() {
+ mGameDriverContentObserver.register(mResolver);
+
+ verify(mResolver).registerContentObserver(
+ Settings.Global.getUriFor(Settings.Global.GAME_DRIVER_ALL_APPS), false,
+ mGameDriverContentObserver);
+ }
+
+ @Test
+ public void unregister_shouldUnregisterContentObserver() {
+ mGameDriverContentObserver.unregister(mResolver);
+
+ verify(mResolver).unregisterContentObserver(mGameDriverContentObserver);
+ }
+}
diff --git a/tests/robotests/src/com/android/settings/development/gup/GupDashboardTest.java b/tests/robotests/src/com/android/settings/development/gamedriver/GameDriverDashboardTest.java
similarity index 67%
rename from tests/robotests/src/com/android/settings/development/gup/GupDashboardTest.java
rename to tests/robotests/src/com/android/settings/development/gamedriver/GameDriverDashboardTest.java
index 17278ef..f8f8add 100644
--- a/tests/robotests/src/com/android/settings/development/gup/GupDashboardTest.java
+++ b/tests/robotests/src/com/android/settings/development/gamedriver/GameDriverDashboardTest.java
@@ -14,11 +14,12 @@
* limitations under the License.
*/
-package com.android.settings.development.gup;
+package com.android.settings.development.gamedriver;
import static com.google.common.truth.Truth.assertThat;
-import com.android.internal.logging.nano.MetricsProto;
+import android.app.settings.SettingsEnums;
+
import com.android.settings.R;
import org.junit.Before;
@@ -27,12 +28,13 @@
import org.robolectric.RobolectricTestRunner;
@RunWith(RobolectricTestRunner.class)
-public class GupDashboardTest {
- private GupDashboard mDashboard;
+public class GameDriverDashboardTest {
+
+ private GameDriverDashboard mDashboard;
@Before
public void setUp() {
- mDashboard = new GupDashboard();
+ mDashboard = new GameDriverDashboard();
}
@Test
@@ -41,14 +43,13 @@
}
@Test
- public void getMetricesCategory_shouldReturnGupDashboard() {
+ public void getMetricesCategory_shouldReturnGameDriverDashboard() {
assertThat(mDashboard.getMetricsCategory())
- .isEqualTo(MetricsProto.MetricsEvent.SETTINGS_GUP_DASHBOARD);
+ .isEqualTo(SettingsEnums.SETTINGS_GAME_DRIVER_DASHBOARD);
}
@Test
- public void getPreferenceScreen_shouldReturnGupSettings() {
- assertThat(mDashboard.getPreferenceScreenResId())
- .isEqualTo(R.xml.gup_settings);
+ public void getPreferenceScreen_shouldReturnGameDriverSettings() {
+ assertThat(mDashboard.getPreferenceScreenResId()).isEqualTo(R.xml.game_driver_settings);
}
}
diff --git a/tests/robotests/src/com/android/settings/development/gamedriver/GameDriverEnableForAllAppsPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/development/gamedriver/GameDriverEnableForAllAppsPreferenceControllerTest.java
new file mode 100644
index 0000000..094cd21
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/development/gamedriver/GameDriverEnableForAllAppsPreferenceControllerTest.java
@@ -0,0 +1,168 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.development.gamedriver;
+
+import static com.android.settings.core.BasePreferenceController.AVAILABLE;
+import static com.android.settings.core.BasePreferenceController.CONDITIONALLY_UNAVAILABLE;
+import static com.android.settings.development.gamedriver.GameDriverEnableForAllAppsPreferenceController.GAME_DRIVER_ALL_APPS;
+import static com.android.settings.development.gamedriver.GameDriverEnableForAllAppsPreferenceController.GAME_DRIVER_DEFAULT;
+import static com.android.settings.development.gamedriver.GameDriverEnableForAllAppsPreferenceController.GAME_DRIVER_OFF;
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.atLeastOnce;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.ContentResolver;
+import android.content.Context;
+import android.provider.Settings;
+
+import androidx.preference.PreferenceScreen;
+import androidx.preference.SwitchPreference;
+
+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;
+import org.robolectric.RuntimeEnvironment;
+
+@RunWith(RobolectricTestRunner.class)
+public class GameDriverEnableForAllAppsPreferenceControllerTest {
+
+ @Mock
+ private PreferenceScreen mScreen;
+ @Mock
+ private SwitchPreference mPreference;
+ @Mock
+ private GameDriverContentObserver mGameDriverContentObserver;
+
+ private Context mContext;
+ private ContentResolver mResolver;
+ private GameDriverEnableForAllAppsPreferenceController mController;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ mContext = RuntimeEnvironment.application;
+ mResolver = mContext.getContentResolver();
+ mController = new GameDriverEnableForAllAppsPreferenceController(mContext, "testKey");
+ when(mScreen.findPreference(mController.getPreferenceKey())).thenReturn(mPreference);
+ mController.displayPreference(mScreen);
+
+ Settings.Global.putInt(mResolver, Settings.Global.DEVELOPMENT_SETTINGS_ENABLED, 1);
+ }
+
+ @Test
+ public void getAvailability_developmentSettingsEnabledAndGameDriverSettingsOn_available() {
+ Settings.Global.putInt(
+ mResolver, Settings.Global.GAME_DRIVER_ALL_APPS, GAME_DRIVER_DEFAULT);
+
+ assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE);
+ }
+
+ @Test
+ public void getAvailability_developmentSettingsDisabled_conditionallyUnavailable() {
+ Settings.Global.putInt(mResolver, Settings.Global.DEVELOPMENT_SETTINGS_ENABLED, 0);
+
+ assertThat(mController.getAvailabilityStatus()).isEqualTo(CONDITIONALLY_UNAVAILABLE);
+ }
+
+ @Test
+ public void getAvailability_gameDriverOff_conditionallyUnavailable() {
+ Settings.Global.putInt(mResolver, Settings.Global.GAME_DRIVER_ALL_APPS, GAME_DRIVER_OFF);
+
+ assertThat(mController.getAvailabilityStatus()).isEqualTo(CONDITIONALLY_UNAVAILABLE);
+ }
+
+ @Test
+ public void displayPreference_shouldAddSwitchPreference() {
+ Settings.Global.putInt(
+ mResolver, Settings.Global.GAME_DRIVER_ALL_APPS, GAME_DRIVER_DEFAULT);
+ mController.updateState(mPreference);
+
+ verify(mPreference).setChecked(false);
+ }
+
+ @Test
+ public void onStart_shouldRegister() {
+ mController.mGameDriverContentObserver = mGameDriverContentObserver;
+ mController.onStart();
+
+ verify(mGameDriverContentObserver).register(mResolver);
+ }
+
+ @Test
+ public void onStop_shouldUnregister() {
+ mController.mGameDriverContentObserver = mGameDriverContentObserver;
+ mController.onStop();
+
+ verify(mGameDriverContentObserver).unregister(mResolver);
+ }
+
+ @Test
+ public void updateState_availableAndGameDriverDefault_visibleAndUncheck() {
+ Settings.Global.putInt(
+ mResolver, Settings.Global.GAME_DRIVER_ALL_APPS, GAME_DRIVER_DEFAULT);
+ mController.updateState(mPreference);
+
+ verify(mPreference, atLeastOnce()).setVisible(true);
+ verify(mPreference).setChecked(false);
+ }
+
+ @Test
+ public void updateState_availableAndGameDriverAllApps_visibleAndCheck() {
+ Settings.Global.putInt(
+ mResolver, Settings.Global.GAME_DRIVER_ALL_APPS, GAME_DRIVER_ALL_APPS);
+ mController.updateState(mPreference);
+
+ verify(mPreference, atLeastOnce()).setVisible(true);
+ verify(mPreference).setChecked(true);
+ }
+
+ @Test
+ public void updateState_gameDriverOff_notVisibleAndUncheck() {
+ Settings.Global.putInt(mResolver, Settings.Global.GAME_DRIVER_ALL_APPS, GAME_DRIVER_OFF);
+ mController.updateState(mPreference);
+
+ verify(mPreference).setVisible(false);
+ verify(mPreference).setChecked(false);
+ }
+
+ @Test
+ public void onPreferenceChange_check_shouldUpdateSettingsGlobal() {
+ Settings.Global.putInt(
+ mResolver, Settings.Global.GAME_DRIVER_ALL_APPS, GAME_DRIVER_DEFAULT);
+ mController.onPreferenceChange(mPreference, true);
+
+ assertThat(Settings.Global.getInt(
+ mResolver, Settings.Global.GAME_DRIVER_ALL_APPS, GAME_DRIVER_DEFAULT))
+ .isEqualTo(GAME_DRIVER_ALL_APPS);
+ }
+
+ @Test
+ public void onPreferenceChange_uncheck_shouldUpdateSettingsGlobal() {
+ Settings.Global.putInt(
+ mResolver, Settings.Global.GAME_DRIVER_ALL_APPS, GAME_DRIVER_ALL_APPS);
+ mController.onPreferenceChange(mPreference, false);
+
+ assertThat(Settings.Global.getInt(
+ mResolver, Settings.Global.GAME_DRIVER_ALL_APPS, GAME_DRIVER_DEFAULT))
+ .isEqualTo(GAME_DRIVER_DEFAULT);
+ }
+}
diff --git a/tests/robotests/src/com/android/settings/development/gamedriver/GameDriverFooterPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/development/gamedriver/GameDriverFooterPreferenceControllerTest.java
new file mode 100644
index 0000000..133791e
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/development/gamedriver/GameDriverFooterPreferenceControllerTest.java
@@ -0,0 +1,123 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.development.gamedriver;
+
+import static com.android.settings.core.BasePreferenceController.AVAILABLE_UNSEARCHABLE;
+import static com.android.settings.core.BasePreferenceController.CONDITIONALLY_UNAVAILABLE;
+import static com.android.settings.development.gamedriver.GameDriverEnableForAllAppsPreferenceController.GAME_DRIVER_ALL_APPS;
+import static com.android.settings.development.gamedriver.GameDriverEnableForAllAppsPreferenceController.GAME_DRIVER_DEFAULT;
+import static com.android.settings.development.gamedriver.GameDriverEnableForAllAppsPreferenceController.GAME_DRIVER_OFF;
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.ContentResolver;
+import android.content.Context;
+import android.provider.Settings;
+
+import androidx.preference.PreferenceScreen;
+
+import com.android.settingslib.widget.FooterPreference;
+
+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;
+import org.robolectric.RuntimeEnvironment;
+
+@RunWith(RobolectricTestRunner.class)
+public class GameDriverFooterPreferenceControllerTest {
+
+ @Mock
+ private PreferenceScreen mScreen;
+ @Mock
+ private FooterPreference mPreference;
+ @Mock
+ private GameDriverContentObserver mGameDriverContentObserver;
+
+ private Context mContext;
+ private ContentResolver mResolver;
+ private GameDriverFooterPreferenceController mController;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ mContext = RuntimeEnvironment.application;
+ mResolver = mContext.getContentResolver();
+ mController = spy(new GameDriverFooterPreferenceController(mContext));
+ when(mScreen.findPreference(mController.getPreferenceKey())).thenReturn(mPreference);
+ }
+
+ @Test
+ public void getAvailabilityStatus_gameDriverOff_availableUnsearchable() {
+ Settings.Global.putInt(mResolver, Settings.Global.GAME_DRIVER_ALL_APPS, GAME_DRIVER_OFF);
+
+ assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE_UNSEARCHABLE);
+ }
+
+ @Test
+ public void getAvailabilityStatus_gameDriverDefault_conditionallyUnavailable() {
+ Settings.Global.putInt(
+ mResolver, Settings.Global.GAME_DRIVER_ALL_APPS, GAME_DRIVER_DEFAULT);
+
+ assertThat(mController.getAvailabilityStatus()).isEqualTo(CONDITIONALLY_UNAVAILABLE);
+ }
+
+ @Test
+ public void getAvailabilityStatus_gameDriverAllApps_conditionallyUnavailable() {
+ Settings.Global.putInt(
+ mResolver, Settings.Global.GAME_DRIVER_ALL_APPS, GAME_DRIVER_ALL_APPS);
+
+ assertThat(mController.getAvailabilityStatus()).isEqualTo(CONDITIONALLY_UNAVAILABLE);
+ }
+
+ @Test
+ public void onStart_shouldRegister() {
+ mController.mGameDriverContentObserver = mGameDriverContentObserver;
+ mController.onStart();
+
+ verify(mGameDriverContentObserver).register(mResolver);
+ }
+
+ @Test
+ public void onStop_shouldUnregister() {
+ mController.mGameDriverContentObserver = mGameDriverContentObserver;
+ mController.onStop();
+
+ verify(mGameDriverContentObserver).unregister(mResolver);
+ }
+
+ @Test
+ public void updateState_available_visible() {
+ when(mController.getAvailabilityStatus()).thenReturn(AVAILABLE_UNSEARCHABLE);
+ mController.updateState(mPreference);
+
+ verify(mPreference).setVisible(true);
+ }
+
+ @Test
+ public void updateState_unavailable_invisible() {
+ when(mController.getAvailabilityStatus()).thenReturn(CONDITIONALLY_UNAVAILABLE);
+ mController.updateState(mPreference);
+
+ verify(mPreference).setVisible(false);
+ }
+}
diff --git a/tests/robotests/src/com/android/settings/development/gamedriver/GameDriverGlobalSwitchBarControllerTest.java b/tests/robotests/src/com/android/settings/development/gamedriver/GameDriverGlobalSwitchBarControllerTest.java
new file mode 100644
index 0000000..f546c36
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/development/gamedriver/GameDriverGlobalSwitchBarControllerTest.java
@@ -0,0 +1,147 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.development.gamedriver;
+
+import static com.android.settings.development.gamedriver.GameDriverEnableForAllAppsPreferenceController.GAME_DRIVER_DEFAULT;
+import static com.android.settings.development.gamedriver.GameDriverEnableForAllAppsPreferenceController.GAME_DRIVER_OFF;
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.verify;
+
+import android.content.ContentResolver;
+import android.content.Context;
+import android.provider.Settings;
+
+import com.android.settings.widget.SwitchBar;
+import com.android.settings.widget.SwitchBarController;
+import com.android.settings.widget.SwitchWidgetController;
+
+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;
+import org.robolectric.RuntimeEnvironment;
+
+@RunWith(RobolectricTestRunner.class)
+public class GameDriverGlobalSwitchBarControllerTest {
+
+ @Mock
+ private SwitchBar mSwitchBar;
+ @Mock
+ private SwitchWidgetController mSwitchWidgetController;
+ @Mock
+ private GameDriverContentObserver mGameDriverContentObserver;
+
+ private Context mContext;
+ private ContentResolver mResolver;
+ private GameDriverGlobalSwitchBarController mController;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ mContext = RuntimeEnvironment.application;
+ mResolver = mContext.getContentResolver();
+ }
+
+ @Test
+ public void constructor_gameDriverOn_shouldCheckSwitchBar() {
+ Settings.Global.putInt(
+ mResolver, Settings.Global.GAME_DRIVER_ALL_APPS, GAME_DRIVER_DEFAULT);
+ mController = new GameDriverGlobalSwitchBarController(
+ mContext, new SwitchBarController(mSwitchBar));
+
+ verify(mSwitchBar).setChecked(true);
+ }
+
+ @Test
+ public void constructor_gameDriverOff_shouldUncheckSwitchBar() {
+ Settings.Global.putInt(mResolver, Settings.Global.GAME_DRIVER_ALL_APPS, GAME_DRIVER_OFF);
+ mController = new GameDriverGlobalSwitchBarController(
+ mContext, new SwitchBarController(mSwitchBar));
+
+ verify(mSwitchBar).setChecked(false);
+ }
+
+ @Test
+ public void constructor_developmentSettingsEnabled_shouldEnableSwitchBar() {
+ Settings.Global.putInt(mResolver, Settings.Global.DEVELOPMENT_SETTINGS_ENABLED, 1);
+ mController = new GameDriverGlobalSwitchBarController(
+ mContext, new SwitchBarController(mSwitchBar));
+
+ verify(mSwitchBar).setEnabled(true);
+ }
+
+ @Test
+ public void constructor_developmentSettingsDisabled_shouldDisableSwitchBar() {
+ Settings.Global.putInt(mResolver, Settings.Global.DEVELOPMENT_SETTINGS_ENABLED, 0);
+ mController = new GameDriverGlobalSwitchBarController(
+ mContext, new SwitchBarController(mSwitchBar));
+
+ verify(mSwitchBar).setEnabled(false);
+ }
+
+ @Test
+ public void onStart_shouldStartListeningAndRegister() {
+ mController = new GameDriverGlobalSwitchBarController(
+ mContext, new SwitchBarController(mSwitchBar));
+ mController.mSwitchWidgetController = mSwitchWidgetController;
+ mController.mGameDriverContentObserver = mGameDriverContentObserver;
+ mController.onStart();
+
+ verify(mSwitchWidgetController).startListening();
+ verify(mGameDriverContentObserver).register(mResolver);
+ }
+
+ @Test
+ public void onStop_shouldStopListeningAndUnregister() {
+ mController = new GameDriverGlobalSwitchBarController(
+ mContext, new SwitchBarController(mSwitchBar));
+ mController.mSwitchWidgetController = mSwitchWidgetController;
+ mController.mGameDriverContentObserver = mGameDriverContentObserver;
+ mController.onStop();
+
+ verify(mSwitchWidgetController).stopListening();
+ verify(mGameDriverContentObserver).unregister(mResolver);
+ }
+
+ @Test
+ public void onSwitchToggled_checked_shouldTurnOnGameDriver() {
+ Settings.Global.putInt(mResolver, Settings.Global.GAME_DRIVER_ALL_APPS, GAME_DRIVER_OFF);
+ mController = new GameDriverGlobalSwitchBarController(
+ mContext, new SwitchBarController(mSwitchBar));
+ mController.onSwitchToggled(true);
+
+ assertThat(Settings.Global.getInt(
+ mResolver, Settings.Global.GAME_DRIVER_ALL_APPS, GAME_DRIVER_DEFAULT))
+ .isEqualTo(GAME_DRIVER_DEFAULT);
+ }
+
+ @Test
+ public void onSwitchToggled_unchecked_shouldTurnOffGameDriver() {
+ Settings.Global.putInt(
+ mResolver, Settings.Global.GAME_DRIVER_ALL_APPS, GAME_DRIVER_DEFAULT);
+ mController = new GameDriverGlobalSwitchBarController(
+ mContext, new SwitchBarController(mSwitchBar));
+ mController.onSwitchToggled(false);
+
+ assertThat(Settings.Global.getInt(
+ mResolver, Settings.Global.GAME_DRIVER_ALL_APPS, GAME_DRIVER_DEFAULT))
+ .isEqualTo(GAME_DRIVER_OFF);
+ }
+}
diff --git a/tests/robotests/src/com/android/settings/development/gup/GupEnableForAllAppsPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/development/gup/GupEnableForAllAppsPreferenceControllerTest.java
deleted file mode 100644
index b7aadc3..0000000
--- a/tests/robotests/src/com/android/settings/development/gup/GupEnableForAllAppsPreferenceControllerTest.java
+++ /dev/null
@@ -1,104 +0,0 @@
-/*
- * Copyright 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.settings.development.gup;
-
-import static com.android.settings.core.BasePreferenceController.AVAILABLE;
-import static com.android.settings.core.BasePreferenceController.DISABLED_DEPENDENT_SETTING;
-import static com.android.settings.development.gup.GupEnableForAllAppsPreferenceController.GUP_ALL_APPS;
-import static com.android.settings.development.gup.GupEnableForAllAppsPreferenceController.GUP_DEFAULT;
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import android.content.ContentResolver;
-import android.content.Context;
-import android.provider.Settings;
-
-import androidx.preference.PreferenceScreen;
-import androidx.preference.SwitchPreference;
-
-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;
-import org.robolectric.RuntimeEnvironment;
-
-@RunWith(RobolectricTestRunner.class)
-public class GupEnableForAllAppsPreferenceControllerTest {
- @Mock
- private PreferenceScreen mScreen;
- @Mock
- private SwitchPreference mPreference;
-
- private Context mContext;
- private ContentResolver mResolver;
- private GupEnableForAllAppsPreferenceController mController;
-
- @Before
- public void setUp() {
- MockitoAnnotations.initMocks(this);
- mContext = RuntimeEnvironment.application;
- mResolver = mContext.getContentResolver();
- mController = new GupEnableForAllAppsPreferenceController(mContext, "testKey");
- when(mScreen.findPreference(mController.getPreferenceKey())).thenReturn(mPreference);
- }
-
- @Test
- public void getAvailability_developmentSettingsEnabled_available() {
- Settings.Global.putInt(mResolver, Settings.Global.DEVELOPMENT_SETTINGS_ENABLED, 1);
-
- assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE);
- }
-
- @Test
- public void getAvailability_developmentSettingsDisabled_disabledDependentSetting() {
- Settings.Global.putInt(mResolver, Settings.Global.DEVELOPMENT_SETTINGS_ENABLED, 0);
-
- assertThat(mController.getAvailabilityStatus()).isEqualTo(DISABLED_DEPENDENT_SETTING);
- }
-
- @Test
- public void displayPreference_shouldAddSwitchPreference() {
- Settings.Global.putInt(mResolver, Settings.Global.GUP_DEV_ALL_APPS, GUP_DEFAULT);
- mController.displayPreference(mScreen);
-
- verify(mPreference).setChecked(false);
- }
-
- @Test
- public void onPreferenceChange_check_shouldUpdateSettingsGlobal() {
- Settings.Global.putInt(mResolver, Settings.Global.GUP_DEV_ALL_APPS, GUP_DEFAULT);
- mController.displayPreference(mScreen);
- mController.onPreferenceChange(mPreference, true);
-
- assertThat(Settings.Global.getInt(mResolver, Settings.Global.GUP_DEV_ALL_APPS, GUP_DEFAULT))
- .isEqualTo(GUP_ALL_APPS);
- }
-
- @Test
- public void onPreferenceChange_uncheck_shouldUpdateSettingsGlobal() {
- Settings.Global.putInt(mResolver, Settings.Global.GUP_DEV_ALL_APPS, GUP_ALL_APPS);
- mController.displayPreference(mScreen);
- mController.onPreferenceChange(mPreference, false);
-
- assertThat(Settings.Global.getInt(mResolver, Settings.Global.GUP_DEV_ALL_APPS, GUP_DEFAULT))
- .isEqualTo(GUP_DEFAULT);
- }
-}
diff --git a/tests/robotests/src/com/android/settings/deviceinfo/BrandedAccountPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/deviceinfo/BrandedAccountPreferenceControllerTest.java
index 564acfd..87dcb33 100644
--- a/tests/robotests/src/com/android/settings/deviceinfo/BrandedAccountPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/deviceinfo/BrandedAccountPreferenceControllerTest.java
@@ -29,36 +29,52 @@
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
-import org.mockito.Answers;
-import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.Config;
@RunWith(RobolectricTestRunner.class)
public class BrandedAccountPreferenceControllerTest {
- @Mock(answer = Answers.RETURNS_DEEP_STUBS)
private Context mContext;
- private BrandedAccountPreferenceController mController;
private FakeFeatureFactory fakeFeatureFactory;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
+ mContext = RuntimeEnvironment.application;
fakeFeatureFactory = FakeFeatureFactory.setupForTest();
- mController = new BrandedAccountPreferenceController(mContext);
+
}
@Test
- public void isAvailable_defaultOff() {
- assertThat(mController.isAvailable()).isFalse();
+ public void isAvailable_configOn_noAccount_off() {
+ final BrandedAccountPreferenceController controller =
+ new BrandedAccountPreferenceController(mContext, "test_key");
+ assertThat(controller.isAvailable()).isFalse();
}
@Test
- public void isAvailable_onWhenAccountIsAvailable() {
+ public void isAvailable_accountIsAvailable_on() {
when(fakeFeatureFactory.mAccountFeatureProvider.getAccounts(any(Context.class)))
- .thenReturn(new Account[] {new Account("fake@account.foo", "fake.reallyfake")});
- mController = new BrandedAccountPreferenceController(mContext);
- assertThat(mController.isAvailable()).isTrue();
+ .thenReturn(new Account[]{new Account("fake@account.foo", "fake.reallyfake")});
+
+ final BrandedAccountPreferenceController controller =
+ new BrandedAccountPreferenceController(mContext, "test_key");
+
+ assertThat(controller.isAvailable()).isTrue();
+ }
+
+ @Test
+ @Config(qualifiers = "mcc999")
+ public void isAvailable_configOff_hasAccount_off() {
+ when(fakeFeatureFactory.mAccountFeatureProvider.getAccounts(any(Context.class)))
+ .thenReturn(new Account[]{new Account("fake@account.foo", "fake.reallyfake")});
+
+ final BrandedAccountPreferenceController controller =
+ new BrandedAccountPreferenceController(mContext, "test_key");
+
+ assertThat(controller.isAvailable()).isFalse();
}
}
diff --git a/tests/robotests/src/com/android/settings/deviceinfo/DeviceNamePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/deviceinfo/DeviceNamePreferenceControllerTest.java
index 5eb0114..21c0e74 100644
--- a/tests/robotests/src/com/android/settings/deviceinfo/DeviceNamePreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/deviceinfo/DeviceNamePreferenceControllerTest.java
@@ -75,7 +75,7 @@
configuration.SSID = "test-ap";
when(mWifiManager.getWifiApConfiguration()).thenReturn(configuration);
- mController = new DeviceNamePreferenceController(mContext);
+ mController = new DeviceNamePreferenceController(mContext, "test_key");
mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
}
@@ -99,17 +99,17 @@
public void constructor_deviceNameLoadedIfSet() {
Settings.Global.putString(
mContext.getContentResolver(), Settings.Global.DEVICE_NAME, "Test");
- mController = new DeviceNamePreferenceController(mContext);
+ mController = new DeviceNamePreferenceController(mContext, "test_key");
assertThat(mController.getSummary()).isEqualTo("Test");
}
@Test
- public void isTextValid_nameUnder33CharactersIsValid() {
+ public void isTextValid_nameUnder33Characters_isValid() {
assertThat(mController.isTextValid("12345678901234567890123456789012")).isTrue();
}
@Test
- public void isTextValid_nameTooLongIsInvalid() {
+ public void isTextValid_nameTooLong_isInvalid() {
assertThat(mController.isTextValid("123456789012345678901234567890123")).isFalse();
}
diff --git a/tests/robotests/src/com/android/settings/deviceinfo/firmwareversion/ModuleVersionDialogControllerTest.java b/tests/robotests/src/com/android/settings/deviceinfo/firmwareversion/ModuleVersionDialogControllerTest.java
new file mode 100644
index 0000000..e5958aa
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/deviceinfo/firmwareversion/ModuleVersionDialogControllerTest.java
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.deviceinfo.firmwareversion;
+
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+
+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;
+import org.robolectric.RuntimeEnvironment;
+
+@RunWith(RobolectricTestRunner.class)
+public class ModuleVersionDialogControllerTest {
+
+ @Mock
+ private FirmwareVersionDialogFragment mDialog;
+ @Mock
+ private PackageManager mPackageManager;
+
+ private Context mContext;
+ private ModuleVersionDialogController mController;
+
+ @Before
+ public void setup() {
+ MockitoAnnotations.initMocks(this);
+ mContext = spy(RuntimeEnvironment.application);
+ when(mDialog.getContext()).thenReturn(mContext);
+ when(mContext.getPackageManager()).thenReturn(mPackageManager);
+ mController = new ModuleVersionDialogController(mDialog);
+ }
+
+ @Test
+ public void initialize_noMainlineModuleProvider_shouldRemoveSettingFromDialog() {
+ when(mContext.getString(
+ com.android.internal.R.string.config_defaultModuleMetadataProvider)).thenReturn(null);
+
+ mController.initialize();
+
+ verify(mDialog).removeSettingFromScreen(mController.MODULE_VERSION_LABEL_ID);
+ verify(mDialog).removeSettingFromScreen(mController.MODULE_VERSION_VALUE_ID);
+ }
+
+ @Test
+ public void initialize_noMainlineModulePackageInfo_shouldRemoveSettingFromDialog()
+ throws PackageManager.NameNotFoundException {
+ final String provider = "test.provider";
+ when(mContext.getString(
+ com.android.internal.R.string.config_defaultModuleMetadataProvider))
+ .thenReturn(provider);
+ when(mPackageManager.getPackageInfo(eq(provider), anyInt()))
+ .thenThrow(new PackageManager.NameNotFoundException());
+
+ mController.initialize();
+
+ verify(mDialog).removeSettingFromScreen(mController.MODULE_VERSION_LABEL_ID);
+ verify(mDialog).removeSettingFromScreen(mController.MODULE_VERSION_VALUE_ID);
+ }
+
+ @Test
+ public void initialize_hasMainlineModulePackageInfo_shouldshouldSetDialogTextToMainlineVersion()
+ throws PackageManager.NameNotFoundException {
+ final String provider = "test.provider";
+ final String version = "test version 123";
+ final PackageInfo info = new PackageInfo();
+ info.versionName = version;
+ when(mContext.getString(
+ com.android.internal.R.string.config_defaultModuleMetadataProvider))
+ .thenReturn(provider);
+ when(mPackageManager.getPackageInfo(eq(provider), anyInt())).thenReturn(info);
+
+ mController.initialize();
+
+ verify(mDialog).setText(mController.MODULE_VERSION_VALUE_ID, version);
+ }
+
+}
diff --git a/tests/robotests/src/com/android/settings/display/AdaptiveSleepPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/display/AdaptiveSleepPreferenceControllerTest.java
new file mode 100644
index 0000000..d426e7a
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/display/AdaptiveSleepPreferenceControllerTest.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.display;
+
+import static android.provider.Settings.System.ADAPTIVE_SLEEP;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.content.ContentResolver;
+import android.content.Context;
+import android.provider.Settings;
+
+import com.android.settings.R;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
+
+@RunWith(RobolectricTestRunner.class)
+public class AdaptiveSleepPreferenceControllerTest {
+
+ private static final String PREFERENCE_KEY = "adaptive_sleep";
+
+ private Context mContext;
+ private AdaptiveSleepPreferenceController mController;
+ private ContentResolver mContentResolver;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+
+ mContext = RuntimeEnvironment.application;
+ mContentResolver = mContext.getContentResolver();
+ mController = new AdaptiveSleepPreferenceController(mContext, PREFERENCE_KEY);
+ }
+
+ @Test
+ public void onPreferenceChange_turnOn_returnOn() {
+ mController.onPreferenceChange(null, true);
+
+ final int mode = Settings.System.getInt(mContentResolver, ADAPTIVE_SLEEP, 0);
+ assertThat(mode).isEqualTo(1);
+ }
+
+ @Test
+ public void onPreferenceChange_turnOff_returnOff() {
+ mController.onPreferenceChange(null, false);
+
+ final int mode = Settings.System.getInt(mContentResolver, ADAPTIVE_SLEEP, 1);
+ assertThat(mode).isEqualTo(0);
+ }
+
+ @Test
+ public void setChecked_updatesCorrectly() {
+ mController.setChecked(true);
+
+ assertThat(mController.isChecked()).isTrue();
+
+ mController.setChecked(false);
+
+ assertThat(mController.isChecked()).isFalse();
+ }
+
+ @Test
+ public void isChecked_no() {
+ Settings.System.putInt(mContentResolver, ADAPTIVE_SLEEP, 0);
+
+ assertThat(mController.isChecked()).isFalse();
+ }
+
+ @Test
+ public void isChecked_yes() {
+ Settings.System.putInt(mContentResolver, ADAPTIVE_SLEEP, 1);
+
+ assertThat(mController.isChecked()).isTrue();
+ }
+
+ @Test
+ public void getSummary_settingOn_shouldReturnOnSummary() {
+ mController.setChecked(true);
+
+ assertThat(mController.getSummary())
+ .isEqualTo(mContext.getText(R.string.adaptive_sleep_summary_on));
+ }
+
+ @Test
+ public void getSummary_settingOff_shouldReturnOffSummary() {
+ mController.setChecked(false);
+
+ assertThat(mController.getSummary())
+ .isEqualTo(mContext.getText(R.string.adaptive_sleep_summary_off));
+ }
+
+ @Test
+ public void isSliceable_returnsTrue() {
+ final AdaptiveSleepPreferenceController controller =
+ new AdaptiveSleepPreferenceController(mContext, "any_key");
+ assertThat(controller.isSliceable()).isTrue();
+ }
+}
diff --git a/tests/robotests/src/com/android/settings/display/ColorModePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/display/ColorModePreferenceControllerTest.java
index e7f025f..cf7e34f 100644
--- a/tests/robotests/src/com/android/settings/display/ColorModePreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/display/ColorModePreferenceControllerTest.java
@@ -23,10 +23,10 @@
import static org.mockito.Mockito.when;
import android.content.Context;
+import android.hardware.display.ColorDisplayManager;
import androidx.preference.Preference;
-import com.android.internal.app.ColorDisplayController;
import com.android.settings.R;
import org.junit.Before;
@@ -41,7 +41,7 @@
public class ColorModePreferenceControllerTest {
@Mock
- private ColorDisplayController mColorDisplayController;
+ private ColorDisplayManager mColorDisplayManager;
private Context mContext;
private Preference mPreference;
@@ -53,13 +53,13 @@
mContext = RuntimeEnvironment.application;
mController = spy(new ColorModePreferenceController(mContext, "test"));
mPreference = new Preference(mContext);
- doReturn(mColorDisplayController).when(mController).getColorDisplayController();
+ doReturn(mColorDisplayManager).when(mController).getColorDisplayManager();
}
@Test
public void updateState_colorModeAutomatic_shouldSetSummaryToAutomatic() {
- when(mColorDisplayController.getColorMode())
- .thenReturn(ColorDisplayController.COLOR_MODE_AUTOMATIC);
+ when(mColorDisplayManager.getColorMode())
+ .thenReturn(ColorDisplayManager.COLOR_MODE_AUTOMATIC);
mController.updateState(mPreference);
@@ -69,8 +69,8 @@
@Test
public void updateState_colorModeSaturated_shouldSetSummaryToSaturated() {
- when(mColorDisplayController.getColorMode())
- .thenReturn(ColorDisplayController.COLOR_MODE_SATURATED);
+ when(mColorDisplayManager.getColorMode())
+ .thenReturn(ColorDisplayManager.COLOR_MODE_SATURATED);
mController.updateState(mPreference);
@@ -80,8 +80,8 @@
@Test
public void updateState_colorModeBoosted_shouldSetSummaryToBoosted() {
- when(mColorDisplayController.getColorMode())
- .thenReturn(ColorDisplayController.COLOR_MODE_BOOSTED);
+ when(mColorDisplayManager.getColorMode())
+ .thenReturn(ColorDisplayManager.COLOR_MODE_BOOSTED);
mController.updateState(mPreference);
@@ -91,8 +91,8 @@
@Test
public void updateState_colorModeNatural_shouldSetSummaryToNatural() {
- when(mColorDisplayController.getColorMode())
- .thenReturn(ColorDisplayController.COLOR_MODE_NATURAL);
+ when(mColorDisplayManager.getColorMode())
+ .thenReturn(ColorDisplayManager.COLOR_MODE_NATURAL);
mController.updateState(mPreference);
diff --git a/tests/robotests/src/com/android/settings/display/ColorModePreferenceFragmentTest.java b/tests/robotests/src/com/android/settings/display/ColorModePreferenceFragmentTest.java
index a87dddd..54e8e4d 100644
--- a/tests/robotests/src/com/android/settings/display/ColorModePreferenceFragmentTest.java
+++ b/tests/robotests/src/com/android/settings/display/ColorModePreferenceFragmentTest.java
@@ -25,13 +25,12 @@
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import android.hardware.display.ColorDisplayManager;
import android.os.Bundle;
-import androidx.fragment.app.FragmentActivity;
import androidx.preference.Preference;
import androidx.preference.PreferenceScreen;
-import com.android.internal.app.ColorDisplayController;
import com.android.internal.logging.nano.MetricsProto;
import com.android.settings.R;
import com.android.settings.testutils.shadow.SettingsShadowResources;
@@ -59,17 +58,14 @@
private ColorModePreferenceFragment mFragment;
@Mock
- private ColorDisplayController mController;
-
- @Mock
- private FragmentActivity mActivity;
+ private ColorDisplayManager mManager;
@Before
public void setup() {
MockitoAnnotations.initMocks(this);
mFragment = spy(new ColorModePreferenceFragment());
- ReflectionHelpers.setField(mFragment, "mController", mController);
+ ReflectionHelpers.setField(mFragment, "mColorDisplayManager", mManager);
}
@After
@@ -88,10 +84,10 @@
when(mFragment.getContext()).thenReturn(RuntimeEnvironment.application);
SettingsShadowResources.overrideResource(
com.android.internal.R.array.config_availableColorModes, new int[]{
- ColorDisplayController.COLOR_MODE_NATURAL,
- ColorDisplayController.COLOR_MODE_BOOSTED,
- ColorDisplayController.COLOR_MODE_SATURATED,
- ColorDisplayController.COLOR_MODE_AUTOMATIC
+ ColorDisplayManager.COLOR_MODE_NATURAL,
+ ColorDisplayManager.COLOR_MODE_BOOSTED,
+ ColorDisplayManager.COLOR_MODE_SATURATED,
+ ColorDisplayManager.COLOR_MODE_AUTOMATIC
});
List<? extends CandidateInfo> candidates = mFragment.getCandidates();
@@ -121,8 +117,8 @@
when(mFragment.getContext()).thenReturn(RuntimeEnvironment.application);
SettingsShadowResources.overrideResource(
com.android.internal.R.array.config_availableColorModes, new int[]{
- ColorDisplayController.COLOR_MODE_NATURAL,
- ColorDisplayController.COLOR_MODE_AUTOMATIC
+ ColorDisplayManager.COLOR_MODE_NATURAL,
+ ColorDisplayManager.COLOR_MODE_AUTOMATIC
});
List<? extends CandidateInfo> candidates = mFragment.getCandidates();
@@ -138,9 +134,9 @@
when(mFragment.getContext()).thenReturn(RuntimeEnvironment.application);
SettingsShadowResources.overrideResource(
com.android.internal.R.array.config_availableColorModes, new int[]{
- ColorDisplayController.COLOR_MODE_NATURAL,
- ColorDisplayController.COLOR_MODE_BOOSTED,
- ColorDisplayController.COLOR_MODE_SATURATED,
+ ColorDisplayManager.COLOR_MODE_NATURAL,
+ ColorDisplayManager.COLOR_MODE_BOOSTED,
+ ColorDisplayManager.COLOR_MODE_SATURATED,
});
List<? extends CandidateInfo> candidates = mFragment.getCandidates();
@@ -155,8 +151,8 @@
@Test
public void getKey_natural() {
- when(mController.getColorMode())
- .thenReturn(ColorDisplayController.COLOR_MODE_NATURAL);
+ when(mManager.getColorMode())
+ .thenReturn(ColorDisplayManager.COLOR_MODE_NATURAL);
assertThat(mFragment.getDefaultKey())
.isEqualTo(ColorModePreferenceFragment.KEY_COLOR_MODE_NATURAL);
@@ -164,8 +160,8 @@
@Test
public void getKey_boosted() {
- when(mController.getColorMode())
- .thenReturn(ColorDisplayController.COLOR_MODE_BOOSTED);
+ when(mManager.getColorMode())
+ .thenReturn(ColorDisplayManager.COLOR_MODE_BOOSTED);
assertThat(mFragment.getDefaultKey())
.isEqualTo(ColorModePreferenceFragment.KEY_COLOR_MODE_BOOSTED);
@@ -173,8 +169,8 @@
@Test
public void getKey_saturated() {
- when(mController.getColorMode())
- .thenReturn(ColorDisplayController.COLOR_MODE_SATURATED);
+ when(mManager.getColorMode())
+ .thenReturn(ColorDisplayManager.COLOR_MODE_SATURATED);
assertThat(mFragment.getDefaultKey())
.isEqualTo(ColorModePreferenceFragment.KEY_COLOR_MODE_SATURATED);
@@ -182,8 +178,8 @@
@Test
public void getKey_automatic() {
- when(mController.getColorMode())
- .thenReturn(ColorDisplayController.COLOR_MODE_AUTOMATIC);
+ when(mManager.getColorMode())
+ .thenReturn(ColorDisplayManager.COLOR_MODE_AUTOMATIC);
assertThat(mFragment.getDefaultKey())
.isEqualTo(ColorModePreferenceFragment.KEY_COLOR_MODE_AUTOMATIC);
@@ -192,25 +188,25 @@
@Test
public void setKey_natural() {
mFragment.setDefaultKey(ColorModePreferenceFragment.KEY_COLOR_MODE_NATURAL);
- verify(mController).setColorMode(ColorDisplayController.COLOR_MODE_NATURAL);
+ verify(mManager).setColorMode(ColorDisplayManager.COLOR_MODE_NATURAL);
}
@Test
public void setKey_boosted() {
mFragment.setDefaultKey(ColorModePreferenceFragment.KEY_COLOR_MODE_BOOSTED);
- verify(mController).setColorMode(ColorDisplayController.COLOR_MODE_BOOSTED);
+ verify(mManager).setColorMode(ColorDisplayManager.COLOR_MODE_BOOSTED);
}
@Test
public void setKey_saturated() {
mFragment.setDefaultKey(ColorModePreferenceFragment.KEY_COLOR_MODE_SATURATED);
- verify(mController).setColorMode(ColorDisplayController.COLOR_MODE_SATURATED);
+ verify(mManager).setColorMode(ColorDisplayManager.COLOR_MODE_SATURATED);
}
@Test
public void setKey_automatic() {
mFragment.setDefaultKey(ColorModePreferenceFragment.KEY_COLOR_MODE_AUTOMATIC);
- verify(mController).setColorMode(ColorDisplayController.COLOR_MODE_AUTOMATIC);
+ verify(mManager).setColorMode(ColorDisplayManager.COLOR_MODE_AUTOMATIC);
}
@Test
@@ -237,11 +233,4 @@
assertThat(preferenceCaptor.getValue()).isEqualTo(mockPreview);
}
-
- @Test
- public void onAccessibilityTransformChanged_toggles() {
- when(mFragment.getActivity()).thenReturn(mActivity);
- mFragment.onAccessibilityTransformChanged(true /* state */);
- verify(mActivity).onBackPressed();
- }
}
diff --git a/tests/robotests/src/com/android/settings/display/DisplayWhiteBalancePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/display/DisplayWhiteBalancePreferenceControllerTest.java
index de560373..59820e6 100644
--- a/tests/robotests/src/com/android/settings/display/DisplayWhiteBalancePreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/display/DisplayWhiteBalancePreferenceControllerTest.java
@@ -6,9 +6,9 @@
import static com.google.common.truth.Truth.assertThat;
import android.content.Context;
+import android.hardware.display.ColorDisplayManager;
import android.provider.Settings;
import android.provider.Settings.Secure;
-import com.android.internal.app.ColorDisplayController;
import com.android.settings.testutils.shadow.SettingsShadowResources;
import org.junit.After;
import org.junit.Before;
@@ -30,7 +30,7 @@
private DisplayWhiteBalancePreferenceController mController;
@Mock
- private ColorDisplayController mColorDisplayController;
+ private ColorDisplayManager mColorDisplayManager;
@After
public void tearDown() {
@@ -43,15 +43,15 @@
mContext = RuntimeEnvironment.application;
mController = spy(new DisplayWhiteBalancePreferenceController(mContext,
"display_white_balance"));
- doReturn(mColorDisplayController).when(mController).getColorDisplayController();
+ doReturn(mColorDisplayManager).when(mController).getColorDisplayManager();
}
@Test
public void isAvailable_configuredAvailable() {
SettingsShadowResources.overrideResource(
com.android.internal.R.bool.config_displayWhiteBalanceAvailable, true);
- when(mColorDisplayController.getColorMode())
- .thenReturn(ColorDisplayController.COLOR_MODE_NATURAL);
+ when(mColorDisplayManager.getColorMode())
+ .thenReturn(ColorDisplayManager.COLOR_MODE_NATURAL);
assertThat(mController.isAvailable()).isTrue();
}
@@ -59,20 +59,20 @@
public void isAvailable_configuredUnavailable() {
SettingsShadowResources.overrideResource(
com.android.internal.R.bool.config_displayWhiteBalanceAvailable, false);
- when(mColorDisplayController.getColorMode())
- .thenReturn(ColorDisplayController.COLOR_MODE_SATURATED);
+ when(mColorDisplayManager.getColorMode())
+ .thenReturn(ColorDisplayManager.COLOR_MODE_SATURATED);
assertThat(mController.isAvailable()).isFalse();
SettingsShadowResources.overrideResource(
com.android.internal.R.bool.config_displayWhiteBalanceAvailable, false);
- when(mColorDisplayController.getColorMode())
- .thenReturn(ColorDisplayController.COLOR_MODE_NATURAL);
+ when(mColorDisplayManager.getColorMode())
+ .thenReturn(ColorDisplayManager.COLOR_MODE_NATURAL);
assertThat(mController.isAvailable()).isFalse();
SettingsShadowResources.overrideResource(
com.android.internal.R.bool.config_displayWhiteBalanceAvailable, true);
- when(mColorDisplayController.getColorMode())
- .thenReturn(ColorDisplayController.COLOR_MODE_SATURATED);
+ when(mColorDisplayManager.getColorMode())
+ .thenReturn(ColorDisplayManager.COLOR_MODE_SATURATED);
assertThat(mController.isAvailable()).isFalse();
}
diff --git a/tests/robotests/src/com/android/settings/display/NightDisplayActivationPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/display/NightDisplayActivationPreferenceControllerTest.java
index 6e23e5f..e666d61 100644
--- a/tests/robotests/src/com/android/settings/display/NightDisplayActivationPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/display/NightDisplayActivationPreferenceControllerTest.java
@@ -15,12 +15,11 @@
package com.android.settings.display;
import static com.google.common.truth.Truth.assertThat;
-
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.when;
import android.content.Context;
-import android.provider.Settings.Secure;
+import android.hardware.display.ColorDisplayManager;
import android.view.View;
import androidx.preference.PreferenceScreen;
@@ -47,17 +46,19 @@
private PreferenceScreen mScreen;
private LayoutPreference mPreference;
private Context mContext;
- private NightDisplayActivationPreferenceController mController;
+ private ColorDisplayManager mColorDisplayManager;
+ private NightDisplayActivationPreferenceController mPreferenceController;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mContext = RuntimeEnvironment.application;
+ mColorDisplayManager = mContext.getSystemService(ColorDisplayManager.class);
mPreference = new LayoutPreference(mContext, R.layout.night_display_activation_button);
when(mScreen.findPreference(anyString())).thenReturn(mPreference);
- mController = new NightDisplayActivationPreferenceController(mContext,
+ mPreferenceController = new NightDisplayActivationPreferenceController(mContext,
"night_display_activation");
- mController.displayPreference(mScreen);
+ mPreferenceController.displayPreference(mScreen);
}
@After
@@ -69,14 +70,14 @@
public void isAvailable_configuredAvailable() {
SettingsShadowResources.overrideResource(
com.android.internal.R.bool.config_nightDisplayAvailable, true);
- assertThat(mController.isAvailable()).isTrue();
+ assertThat(mPreferenceController.isAvailable()).isTrue();
}
@Test
public void isAvailable_configuredUnavailable() {
SettingsShadowResources.overrideResource(
com.android.internal.R.bool.config_nightDisplayAvailable, false);
- assertThat(mController.isAvailable()).isFalse();
+ assertThat(mPreferenceController.isAvailable()).isFalse();
}
@Test
@@ -95,25 +96,23 @@
@Test
public void onClick_activates() {
- Secure.putInt(mContext.getContentResolver(), Secure.NIGHT_DISPLAY_ACTIVATED, 0);
+ mColorDisplayManager.setNightDisplayActivated(false);
final View view = mPreference.findViewById(R.id.night_display_turn_on_button);
assertThat(view.getVisibility()).isEqualTo(View.VISIBLE);
view.performClick();
- assertThat(Secure.getInt(mContext.getContentResolver(), Secure.NIGHT_DISPLAY_ACTIVATED, -1))
- .isEqualTo(1);
+ assertThat(mColorDisplayManager.isNightDisplayActivated()).isEqualTo(true);
}
@Test
public void onClick_deactivates() {
- Secure.putInt(mContext.getContentResolver(), Secure.NIGHT_DISPLAY_ACTIVATED, 1);
+ mColorDisplayManager.setNightDisplayActivated(true);
- final View view = mPreference.findViewById(R.id.night_display_turn_on_button);
+ final View view = mPreference.findViewById(R.id.night_display_turn_off_button);
assertThat(view.getVisibility()).isEqualTo(View.VISIBLE);
view.performClick();
- assertThat(Secure.getInt(mContext.getContentResolver(), Secure.NIGHT_DISPLAY_ACTIVATED, -1))
- .isEqualTo(0);
+ assertThat(mColorDisplayManager.isNightDisplayActivated()).isEqualTo(false);
}
}
diff --git a/tests/robotests/src/com/android/settings/display/NightDisplayAutoModePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/display/NightDisplayAutoModePreferenceControllerTest.java
index 85d497a..de5c81e 100644
--- a/tests/robotests/src/com/android/settings/display/NightDisplayAutoModePreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/display/NightDisplayAutoModePreferenceControllerTest.java
@@ -17,9 +17,9 @@
import static com.google.common.truth.Truth.assertThat;
import android.content.Context;
+import android.hardware.display.ColorDisplayManager;
import android.provider.Settings.Secure;
-import com.android.internal.app.ColorDisplayController;
import com.android.settings.testutils.shadow.SettingsShadowResources;
import org.junit.After;
@@ -66,8 +66,8 @@
@Test
public void onPreferenceChange_changesAutoMode() {
mController.onPreferenceChange(null,
- String.valueOf(ColorDisplayController.AUTO_MODE_TWILIGHT));
- assertThat(Secure.getInt(mContext.getContentResolver(), Secure.NIGHT_DISPLAY_AUTO_MODE, -1))
- .isEqualTo(ColorDisplayController.AUTO_MODE_TWILIGHT);
+ String.valueOf(ColorDisplayManager.AUTO_MODE_TWILIGHT));
+ assertThat(mContext.getSystemService(ColorDisplayManager.class).getNightDisplayAutoMode())
+ .isEqualTo(ColorDisplayManager.AUTO_MODE_TWILIGHT);
}
}
diff --git a/tests/robotests/src/com/android/settings/display/NightDisplayIntensityPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/display/NightDisplayIntensityPreferenceControllerTest.java
index 2edec2e..2e2d631 100644
--- a/tests/robotests/src/com/android/settings/display/NightDisplayIntensityPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/display/NightDisplayIntensityPreferenceControllerTest.java
@@ -17,10 +17,9 @@
import static com.google.common.truth.Truth.assertThat;
import android.content.Context;
+import android.hardware.display.ColorDisplayManager;
import android.provider.Settings.Secure;
-
import com.android.settings.testutils.shadow.SettingsShadowResources;
-
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
@@ -33,69 +32,69 @@
@Config(shadows = SettingsShadowResources.class)
public class NightDisplayIntensityPreferenceControllerTest {
- private Context mContext;
- private NightDisplayIntensityPreferenceController mController;
+ private Context mContext;
+ private NightDisplayIntensityPreferenceController mPreferenceController;
- @Before
- public void setUp() {
- mContext = RuntimeEnvironment.application;
- mController = new NightDisplayIntensityPreferenceController(mContext,
- "night_display_temperature");
- }
+ @Before
+ public void setUp() {
+ mContext = RuntimeEnvironment.application;
+ mPreferenceController = new NightDisplayIntensityPreferenceController(mContext,
+ "night_display_temperature");
+ }
- @After
- public void tearDown() {
- SettingsShadowResources.reset();
- }
+ @After
+ public void tearDown() {
+ SettingsShadowResources.reset();
+ }
- @Test
- public void isAvailable_configuredAvailable_isActivated_available() {
- SettingsShadowResources.overrideResource(
- com.android.internal.R.bool.config_nightDisplayAvailable, true);
- Secure.putInt(mContext.getContentResolver(), Secure.NIGHT_DISPLAY_ACTIVATED, 1);
- assertThat(mController.isAvailable()).isTrue();
- }
+ @Test
+ public void isAvailable_configuredAvailable_isActivated_available() {
+ SettingsShadowResources.overrideResource(
+ com.android.internal.R.bool.config_nightDisplayAvailable, true);
+ Secure.putInt(mContext.getContentResolver(), Secure.NIGHT_DISPLAY_ACTIVATED, 1);
+ assertThat(mPreferenceController.isAvailable()).isTrue();
+ }
- @Test
- public void isAvailable_configuredAvailable_isNotActivated_available() {
- SettingsShadowResources.overrideResource(
- com.android.internal.R.bool.config_nightDisplayAvailable, true);
- Secure.putInt(mContext.getContentResolver(), Secure.NIGHT_DISPLAY_ACTIVATED, 0);
- assertThat(mController.isAvailable()).isTrue();
- }
+ @Test
+ public void isAvailable_configuredAvailable_isNotActivated_available() {
+ SettingsShadowResources.overrideResource(
+ com.android.internal.R.bool.config_nightDisplayAvailable, true);
+ Secure.putInt(mContext.getContentResolver(), Secure.NIGHT_DISPLAY_ACTIVATED, 0);
+ assertThat(mPreferenceController.isAvailable()).isTrue();
+ }
- @Test
- public void isAvailable_configuredUnavailable_unavailable() {
- SettingsShadowResources.overrideResource(
- com.android.internal.R.bool.config_nightDisplayAvailable, false);
- assertThat(mController.isAvailable()).isFalse();
- }
+ @Test
+ public void isAvailable_configuredUnavailable_unavailable() {
+ SettingsShadowResources.overrideResource(
+ com.android.internal.R.bool.config_nightDisplayAvailable, false);
+ assertThat(mPreferenceController.isAvailable()).isFalse();
+ }
- @Test
- public void onPreferenceChange_changesTemperature() {
- SettingsShadowResources.overrideResource(
- com.android.internal.R.integer.config_nightDisplayColorTemperatureMin, 2950);
- SettingsShadowResources.overrideResource(
- com.android.internal.R.integer.config_nightDisplayColorTemperatureMax, 3050);
- // A slider-adjusted "20" here would be 1/5 from the left / least-intense, i.e. 3030.
- mController.onPreferenceChange(null, 20);
+ @Test
+ public void onPreferenceChange_changesTemperature() {
+ SettingsShadowResources.overrideResource(
+ com.android.internal.R.integer.config_nightDisplayColorTemperatureMin, 2950);
+ SettingsShadowResources.overrideResource(
+ com.android.internal.R.integer.config_nightDisplayColorTemperatureMax, 3050);
+ // A slider-adjusted "20" here would be 1/5 from the left / least-intense, i.e. 3030.
+ mPreferenceController.onPreferenceChange(null, 20);
- assertThat(Secure.getInt(mContext.getContentResolver(),
- Secure.NIGHT_DISPLAY_COLOR_TEMPERATURE, -1))
- .isEqualTo(3030);
- }
+ assertThat(
+ mContext.getSystemService(ColorDisplayManager.class).getNightDisplayColorTemperature())
+ .isEqualTo(3030);
+ }
- @Test
- public void isSliceableCorrectKey_returnsTrue() {
- final NightDisplayIntensityPreferenceController controller =
- new NightDisplayIntensityPreferenceController(mContext,"night_display_temperature");
- assertThat(controller.isSliceable()).isTrue();
- }
+ @Test
+ public void isSliceableCorrectKey_returnsTrue() {
+ final NightDisplayIntensityPreferenceController controller =
+ new NightDisplayIntensityPreferenceController(mContext, "night_display_temperature");
+ assertThat(controller.isSliceable()).isTrue();
+ }
- @Test
- public void isSliceableIncorrectKey_returnsFalse() {
- final NightDisplayIntensityPreferenceController controller =
- new NightDisplayIntensityPreferenceController(mContext, "bad_key");
- assertThat(controller.isSliceable()).isFalse();
- }
+ @Test
+ public void isSliceableIncorrectKey_returnsFalse() {
+ final NightDisplayIntensityPreferenceController controller =
+ new NightDisplayIntensityPreferenceController(mContext, "bad_key");
+ assertThat(controller.isSliceable()).isFalse();
+ }
}
diff --git a/tests/robotests/src/com/android/settings/display/NightDisplayPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/display/NightDisplayPreferenceControllerTest.java
index c066e6c..eeaae67f 100644
--- a/tests/robotests/src/com/android/settings/display/NightDisplayPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/display/NightDisplayPreferenceControllerTest.java
@@ -3,12 +3,9 @@
import static com.google.common.truth.Truth.assertThat;
import android.app.Application;
-import android.provider.Settings.Secure;
-
-import com.android.internal.app.ColorDisplayController;
+import android.hardware.display.ColorDisplayManager;
import com.android.settings.R;
import com.android.settings.testutils.shadow.SettingsShadowResources;
-
import org.junit.After;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -28,32 +25,32 @@
@Test
public void nightDisplaySuggestion_isNotCompleted_ifAutoModeDisabled() {
final Application context = RuntimeEnvironment.application;
- Secure.putInt(context.getContentResolver(),
- Secure.NIGHT_DISPLAY_AUTO_MODE, ColorDisplayController.AUTO_MODE_DISABLED);
+ context.getSystemService(ColorDisplayManager.class)
+ .setNightDisplayAutoMode(ColorDisplayManager.AUTO_MODE_DISABLED);
assertThat(NightDisplayPreferenceController.isSuggestionComplete(context)).isFalse();
}
@Test
public void nightDisplaySuggestion_isCompleted_ifAutoModeCustom() {
final Application context = RuntimeEnvironment.application;
- Secure.putInt(context.getContentResolver(),
- Secure.NIGHT_DISPLAY_AUTO_MODE, ColorDisplayController.AUTO_MODE_CUSTOM);
+ context.getSystemService(ColorDisplayManager.class)
+ .setNightDisplayAutoMode(ColorDisplayManager.AUTO_MODE_CUSTOM_TIME);
assertThat(NightDisplayPreferenceController.isSuggestionComplete(context)).isTrue();
}
@Test
public void nightDisplaySuggestion_isCompleted_ifAutoModeTwilight() {
final Application context = RuntimeEnvironment.application;
- Secure.putInt(context.getContentResolver(),
- Secure.NIGHT_DISPLAY_AUTO_MODE, ColorDisplayController.AUTO_MODE_TWILIGHT);
+ context.getSystemService(ColorDisplayManager.class)
+ .setNightDisplayAutoMode(ColorDisplayManager.AUTO_MODE_TWILIGHT);
assertThat(NightDisplayPreferenceController.isSuggestionComplete(context)).isTrue();
}
@Test
- public void nightDisplaySuggestion_isCompleted_ifDisabled() {
+ public void nightDisplaySuggestion_isCompleted_ifSuggestionDisabled() {
final Application context = RuntimeEnvironment.application;
- Secure.putInt(context.getContentResolver(),
- Secure.NIGHT_DISPLAY_AUTO_MODE, ColorDisplayController.AUTO_MODE_DISABLED);
+ context.getSystemService(ColorDisplayManager.class)
+ .setNightDisplayAutoMode(ColorDisplayManager.AUTO_MODE_DISABLED);
SettingsShadowResources.overrideResource(R.bool.config_night_light_suggestion_enabled, false);
assertThat(NightDisplayPreferenceController.isSuggestionComplete(context)).isTrue();
}
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/BatteryAppListPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/fuelgauge/BatteryAppListPreferenceControllerTest.java
index e1913a2..3282975 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/BatteryAppListPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/BatteryAppListPreferenceControllerTest.java
@@ -18,11 +18,15 @@
import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.Matchers.anyInt;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;
import android.content.Context;
+import android.content.pm.ModuleInfo;
+import android.content.pm.PackageManager;
+import android.os.UserManager;
import android.text.TextUtils;
import android.text.format.DateUtils;
@@ -34,6 +38,7 @@
import com.android.settings.SettingsActivity;
import com.android.settings.core.InstrumentedPreferenceFragment;
import com.android.settings.testutils.FakeFeatureFactory;
+import com.android.settingslib.applications.ApplicationsState;
import org.junit.Before;
import org.junit.Test;
@@ -42,6 +47,10 @@
import org.mockito.MockitoAnnotations;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
+import org.robolectric.util.ReflectionHelpers;
+
+import java.util.ArrayList;
+import java.util.List;
@RunWith(RobolectricTestRunner.class)
public class BatteryAppListPreferenceControllerTest {
@@ -60,6 +69,10 @@
private InstrumentedPreferenceFragment mFragment;
@Mock
private BatteryUtils mBatteryUtils;
+ @Mock
+ private PackageManager mPackageManager;
+ @Mock
+ private UserManager mUserManager;
private Context mContext;
private PowerGaugePreference mPreference;
@@ -70,6 +83,11 @@
MockitoAnnotations.initMocks(this);
mContext = spy(RuntimeEnvironment.application);
+ when(mContext.getPackageManager()).thenReturn(mPackageManager);
+ when(mContext.getApplicationContext()).thenReturn(mContext);
+ when(mContext.getSystemService(UserManager.class)).thenReturn(mUserManager);
+ when(mUserManager.getProfileIdsWithDisabled(anyInt())).thenReturn(new int[] {});
+
FakeFeatureFactory.setupForTest();
mPreference = new PowerGaugePreference(mContext);
@@ -184,6 +202,21 @@
}
@Test
+ public void testShouldHideSipper_hiddenSystemModule_returnTrue() {
+ ReflectionHelpers.setStaticField(ApplicationsState.class, "sInstance", null);
+ final String packageName = "test.hidden.module";
+ final ModuleInfo moduleInfo = new ModuleInfo();
+ moduleInfo.setPackageName(packageName);
+ moduleInfo.setHidden(true);
+ final List<ModuleInfo> modules = new ArrayList<>();
+ modules.add(moduleInfo);
+ when(mBatteryUtils.getPackageName(anyInt() /* uid */)).thenReturn(packageName);
+ when(mPackageManager.getInstalledModules(anyInt() /* flags */)).thenReturn(modules);
+
+ assertThat(mPreferenceController.shouldHideSipper(mNormalBatterySipper)).isTrue();
+ }
+
+ @Test
public void testNeverUseFakeData() {
assertThat(BatteryAppListPreferenceController.USE_FAKE_DATA).isFalse();
}
diff --git a/tests/robotests/src/com/android/settings/gestures/SilenceGesturePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/gestures/SilenceGesturePreferenceControllerTest.java
deleted file mode 100644
index 2dc880b..0000000
--- a/tests/robotests/src/com/android/settings/gestures/SilenceGesturePreferenceControllerTest.java
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.settings.gestures;
-
-import static android.provider.Settings.Secure.SILENCE_GESTURE;
-
-import static com.android.settings.core.BasePreferenceController.AVAILABLE;
-import static com.android.settings.core.BasePreferenceController.UNSUPPORTED_ON_DEVICE;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.mockito.Mockito.when;
-
-import android.content.Context;
-import android.content.res.Resources;
-import android.provider.Settings;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Answers;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-import org.robolectric.RobolectricTestRunner;
-
-@RunWith(RobolectricTestRunner.class)
-public class SilenceGesturePreferenceControllerTest {
-
- private static final String KEY_SILENCE = "gesture_silence";
-
- @Mock(answer = Answers.RETURNS_DEEP_STUBS)
- private Context mContext;
- @Mock
- private Resources mResources;
-
- private SilenceGesturePreferenceController mController;
-
- @Before
- public void setUp() {
- MockitoAnnotations.initMocks(this);
- when(mContext.getResources()).thenReturn(mResources);
- mController = new SilenceGesturePreferenceController(mContext, KEY_SILENCE);
- }
-
- @Test
- public void getAvailabilityStatus_gestureNotSupported_UNSUPPORTED_ON_DEVICE() {
- when(mResources.getBoolean(
- com.android.internal.R.bool.config_silenceSensorAvailable))
- .thenReturn(false);
- final int availabilityStatus = mController.getAvailabilityStatus();
-
- assertThat(availabilityStatus).isEqualTo(UNSUPPORTED_ON_DEVICE);
- }
-
- @Test
- public void getAvailabilityStatus_gestureSupported_AVAILABLE() {
- when(mResources.getBoolean(
- com.android.internal.R.bool.config_silenceSensorAvailable)).thenReturn(true);
- final int availabilityStatus = mController.getAvailabilityStatus();
-
- assertThat(availabilityStatus).isEqualTo(AVAILABLE);
- }
-
- @Test
- public void isSliceableCorrectKey_returnsTrue() {
- assertThat(mController.isSliceable()).isTrue();
- }
-
- @Test
- public void isChecked_testTrue() {
- Settings.Secure.putInt(mContext.getContentResolver(), SILENCE_GESTURE, 1);
- assertThat(mController.isChecked()).isTrue();
- }
-
- @Test
- public void isChecked_testFalse() {
- Settings.Secure.putInt(mContext.getContentResolver(), SILENCE_GESTURE, 0);
- assertThat(mController.isChecked()).isFalse();
- }
-}
diff --git a/tests/robotests/src/com/android/settings/gestures/SkipGesturePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/gestures/SkipGesturePreferenceControllerTest.java
deleted file mode 100644
index c544786..0000000
--- a/tests/robotests/src/com/android/settings/gestures/SkipGesturePreferenceControllerTest.java
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.settings.gestures;
-
-import static android.provider.Settings.Secure.SKIP_GESTURE;
-
-import static com.android.settings.core.BasePreferenceController.AVAILABLE;
-import static com.android.settings.core.BasePreferenceController.UNSUPPORTED_ON_DEVICE;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.mockito.Mockito.when;
-
-import android.content.Context;
-import android.content.res.Resources;
-import android.provider.Settings;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Answers;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-import org.robolectric.RobolectricTestRunner;
-
-@RunWith(RobolectricTestRunner.class)
-public class SkipGesturePreferenceControllerTest {
-
- private static final String KEY_SKIP = "gesture_skip";
-
- @Mock(answer = Answers.RETURNS_DEEP_STUBS)
- private Context mContext;
- @Mock
- private Resources mResources;
-
- private SkipGesturePreferenceController mController;
-
- @Before
- public void setUp() {
- MockitoAnnotations.initMocks(this);
- when(mContext.getResources()).thenReturn(mResources);
- mController = new SkipGesturePreferenceController(mContext, KEY_SKIP);
- }
-
- @Test
- public void getAvailabilityStatus_gestureNotSupported_UNSUPPORTED_ON_DEVICE() {
- when(mResources.getBoolean(
- com.android.internal.R.bool.config_skipSensorAvailable))
- .thenReturn(false);
- final int availabilityStatus = mController.getAvailabilityStatus();
-
- assertThat(availabilityStatus).isEqualTo(UNSUPPORTED_ON_DEVICE);
- }
-
- @Test
- public void getAvailabilityStatus_gestureSupported_AVAILABLE() {
- when(mResources.getBoolean(
- com.android.internal.R.bool.config_skipSensorAvailable)).thenReturn(true);
- final int availabilityStatus = mController.getAvailabilityStatus();
-
- assertThat(availabilityStatus).isEqualTo(AVAILABLE);
- }
-
- @Test
- public void isSliceableCorrectKey_returnsTrue() {
- assertThat(mController.isSliceable()).isTrue();
- }
-
- @Test
- public void isChecked_testTrue() {
- Settings.Secure.putInt(mContext.getContentResolver(), SKIP_GESTURE, 1);
- assertThat(mController.isChecked()).isTrue();
- }
-
- @Test
- public void isChecked_testFalse() {
- Settings.Secure.putInt(mContext.getContentResolver(), SKIP_GESTURE, 0);
- assertThat(mController.isChecked()).isFalse();
- }
-}
diff --git a/tests/robotests/src/com/android/settings/homepage/contextualcards/ContextualCardManagerTest.java b/tests/robotests/src/com/android/settings/homepage/contextualcards/ContextualCardManagerTest.java
index 3e6ba6c..1a0539c 100644
--- a/tests/robotests/src/com/android/settings/homepage/contextualcards/ContextualCardManagerTest.java
+++ b/tests/robotests/src/com/android/settings/homepage/contextualcards/ContextualCardManagerTest.java
@@ -16,6 +16,7 @@
package com.android.settings.homepage.contextualcards;
+import static com.android.settings.homepage.contextualcards.slices.SliceContextualCardRenderer.VIEW_TYPE_DEFERRED_SETUP;
import static com.android.settings.homepage.contextualcards.slices.SliceContextualCardRenderer.VIEW_TYPE_FULL_WIDTH;
import static com.android.settings.homepage.contextualcards.slices.SliceContextualCardRenderer.VIEW_TYPE_HALF_WIDTH;
@@ -210,7 +211,7 @@
@Test
- public void assignCardWidth_noSuggestionCards_shouldNotHaveHalfCards() {
+ public void getCardsWithViewType_noSuggestionCards_shouldNotHaveHalfCards() {
final List<Integer> categories = Arrays.asList(
ContextualCardProto.ContextualCard.Category.IMPORTANT_VALUE,
ContextualCardProto.ContextualCard.Category.IMPORTANT_VALUE,
@@ -221,7 +222,7 @@
final List<ContextualCard> noSuggestionCards = buildCategoriedCards(getContextualCardList(),
categories);
- final List<ContextualCard> result = mManager.assignCardWidth(noSuggestionCards);
+ final List<ContextualCard> result = mManager.getCardsWithViewType(noSuggestionCards);
assertThat(result).hasSize(5);
for (ContextualCard card : result) {
@@ -230,7 +231,7 @@
}
@Test
- public void assignCardWidth_oneSuggestionCards_shouldNotHaveHalfCards() {
+ public void getCardsWithViewType_oneSuggestionCards_shouldNotHaveHalfCards() {
final List<Integer> categories = Arrays.asList(
ContextualCardProto.ContextualCard.Category.IMPORTANT_VALUE,
ContextualCardProto.ContextualCard.Category.IMPORTANT_VALUE,
@@ -241,7 +242,7 @@
final List<ContextualCard> oneSuggestionCards = buildCategoriedCards(
getContextualCardList(), categories);
- final List<ContextualCard> result = mManager.assignCardWidth(oneSuggestionCards);
+ final List<ContextualCard> result = mManager.getCardsWithViewType(oneSuggestionCards);
assertThat(result).hasSize(5);
for (ContextualCard card : result) {
@@ -250,7 +251,7 @@
}
@Test
- public void assignCardWidth_twoConsecutiveSuggestionCards_shouldHaveTwoHalfCards() {
+ public void getCardsWithViewType_twoConsecutiveSuggestionCards_shouldHaveTwoHalfCards() {
final List<Integer> categories = Arrays.asList(
ContextualCardProto.ContextualCard.Category.IMPORTANT_VALUE,
ContextualCardProto.ContextualCard.Category.IMPORTANT_VALUE,
@@ -264,7 +265,7 @@
VIEW_TYPE_FULL_WIDTH, VIEW_TYPE_HALF_WIDTH, VIEW_TYPE_HALF_WIDTH,
VIEW_TYPE_FULL_WIDTH);
- final List<ContextualCard> result = mManager.assignCardWidth(
+ final List<ContextualCard> result = mManager.getCardsWithViewType(
twoConsecutiveSuggestionCards);
assertThat(result).hasSize(5);
@@ -274,7 +275,7 @@
}
@Test
- public void assignCardWidth_twoNonConsecutiveSuggestionCards_shouldNotHaveHalfCards() {
+ public void getCardsWithViewType_twoNonConsecutiveSuggestionCards_shouldNotHaveHalfCards() {
final List<Integer> categories = Arrays.asList(
ContextualCardProto.ContextualCard.Category.SUGGESTION_VALUE,
ContextualCardProto.ContextualCard.Category.IMPORTANT_VALUE,
@@ -285,7 +286,7 @@
final List<ContextualCard> twoNonConsecutiveSuggestionCards = buildCategoriedCards(
getContextualCardList(), categories);
- final List<ContextualCard> result = mManager.assignCardWidth(
+ final List<ContextualCard> result = mManager.getCardsWithViewType(
twoNonConsecutiveSuggestionCards);
assertThat(result).hasSize(5);
@@ -295,7 +296,7 @@
}
@Test
- public void assignCardWidth_threeConsecutiveSuggestionCards_shouldHaveTwoHalfCards() {
+ public void getCardsWithViewType_threeConsecutiveSuggestionCards_shouldHaveTwoHalfCards() {
final List<Integer> categories = Arrays.asList(
ContextualCardProto.ContextualCard.Category.IMPORTANT_VALUE,
ContextualCardProto.ContextualCard.Category.SUGGESTION_VALUE,
@@ -309,7 +310,7 @@
VIEW_TYPE_HALF_WIDTH, VIEW_TYPE_HALF_WIDTH, VIEW_TYPE_FULL_WIDTH,
VIEW_TYPE_FULL_WIDTH);
- final List<ContextualCard> result = mManager.assignCardWidth(
+ final List<ContextualCard> result = mManager.getCardsWithViewType(
threeConsecutiveSuggestionCards);
assertThat(result).hasSize(5);
@@ -319,7 +320,7 @@
}
@Test
- public void assignCardWidth_fourConsecutiveSuggestionCards_shouldHaveFourHalfCards() {
+ public void getCardsWithViewType_fourConsecutiveSuggestionCards_shouldHaveFourHalfCards() {
final List<Integer> categories = Arrays.asList(
ContextualCardProto.ContextualCard.Category.IMPORTANT_VALUE,
ContextualCardProto.ContextualCard.Category.SUGGESTION_VALUE,
@@ -333,7 +334,7 @@
VIEW_TYPE_HALF_WIDTH, VIEW_TYPE_HALF_WIDTH, VIEW_TYPE_HALF_WIDTH,
VIEW_TYPE_HALF_WIDTH);
- final List<ContextualCard> result = mManager.assignCardWidth(
+ final List<ContextualCard> result = mManager.getCardsWithViewType(
fourConsecutiveSuggestionCards);
assertThat(result).hasSize(5);
@@ -342,6 +343,55 @@
}
}
+ @Test
+ public void getCardsWithViewType_onlyDeferredSetupCard_shouldHaveDeferredSetupCard() {
+ final List<ContextualCard> oneDeferredSetupCards = getDeferredSetupCardList();
+
+ final List<ContextualCard> result = mManager.getCardsWithViewType(oneDeferredSetupCards);
+
+ assertThat(result).hasSize(1);
+ assertThat(result.get(0).getViewType()).isEqualTo(VIEW_TYPE_DEFERRED_SETUP);
+ }
+
+ @Test
+ public void getCardsWithViewType_hasDeferredSetupCard_shouldHaveDeferredSetupCard() {
+ final List<Integer> categories = Arrays.asList(
+ ContextualCardProto.ContextualCard.Category.DEFERRED_SETUP_VALUE,
+ ContextualCardProto.ContextualCard.Category.IMPORTANT_VALUE,
+ ContextualCardProto.ContextualCard.Category.SUGGESTION_VALUE,
+ ContextualCardProto.ContextualCard.Category.SUGGESTION_VALUE,
+ ContextualCardProto.ContextualCard.Category.SUGGESTION_VALUE
+ );
+ final List<ContextualCard> cards = buildCategoriedCards(getContextualCardList(),
+ categories);
+
+ final List<ContextualCard> result = mManager.getCardsWithViewType(cards);
+
+ assertThat(result).hasSize(5);
+ assertThat(result.get(0).getViewType()).isEqualTo(VIEW_TYPE_DEFERRED_SETUP);
+ }
+
+ @Test
+ public void getCardsWithViewType_noDeferredSetupCard_shouldNotHaveDeferredSetupCard() {
+ final List<Integer> categories = Arrays.asList(
+ ContextualCardProto.ContextualCard.Category.IMPORTANT_VALUE,
+ ContextualCardProto.ContextualCard.Category.IMPORTANT_VALUE,
+ ContextualCardProto.ContextualCard.Category.SUGGESTION_VALUE,
+ ContextualCardProto.ContextualCard.Category.SUGGESTION_VALUE,
+ ContextualCardProto.ContextualCard.Category.SUGGESTION_VALUE
+ );
+ final List<ContextualCard> cards = buildCategoriedCards(
+ getContextualCardList(), categories);
+
+ final List<ContextualCard> result = mManager.getCardsWithViewType(cards);
+
+ assertThat(result).hasSize(5);
+ for (int i = 0; i < result.size(); i++) {
+ assertThat(result.get(i).getViewType()).isNotEqualTo(
+ ContextualCardProto.ContextualCard.Category.DEFERRED_SETUP_VALUE);
+ }
+ }
+
private ContextualCard buildContextualCard(String sliceUri) {
return new ContextualCard.Builder()
.setName(TEST_SLICE_NAME)
@@ -396,4 +446,16 @@
.build());
return cards;
}
+
+ private List<ContextualCard> getDeferredSetupCardList() {
+ final List<ContextualCard> cards = new ArrayList<>();
+ cards.add(new ContextualCard.Builder()
+ .setName("deferred_setup")
+ .setCardType(ContextualCard.CardType.SLICE)
+ .setCategory(ContextualCardProto.ContextualCard.Category.DEFERRED_SETUP_VALUE)
+ .setSliceUri(new Uri.Builder().appendPath("test_deferred_setup_path").build())
+ .setViewType(VIEW_TYPE_FULL_WIDTH)
+ .build());
+ return cards;
+ }
}
diff --git a/tests/robotests/src/com/android/settings/homepage/contextualcards/slices/BluetoothDevicesSliceTest.java b/tests/robotests/src/com/android/settings/homepage/contextualcards/slices/BluetoothDevicesSliceTest.java
index bc34fd5..02d7a9d 100644
--- a/tests/robotests/src/com/android/settings/homepage/contextualcards/slices/BluetoothDevicesSliceTest.java
+++ b/tests/robotests/src/com/android/settings/homepage/contextualcards/slices/BluetoothDevicesSliceTest.java
@@ -83,7 +83,8 @@
mBluetoothDevicesSlice = spy(new BluetoothDevicesSlice(mContext));
// Mock the icon and detail intent of Bluetooth.
- mIcon = IconCompat.createWithResource(mContext, R.drawable.ic_settings_bluetooth);
+ mIcon = IconCompat.createWithResource(mContext,
+ com.android.internal.R.drawable.ic_settings_bluetooth);
mDetailIntent = PendingIntent.getActivity(mContext, 0, new Intent("test action"), 0);
doReturn(mIcon).when(mBluetoothDevicesSlice).getBluetoothDeviceIcon(any());
doReturn(mDetailIntent).when(mBluetoothDevicesSlice).getBluetoothDetailIntent(any());
@@ -208,4 +209,4 @@
final CharSequence sliceTitle = metadata.getTitle();
return TextUtils.equals(sliceTitle, title);
}
-}
\ No newline at end of file
+}
diff --git a/tests/robotests/src/com/android/settings/homepage/contextualcards/slices/SliceDeferredSetupCardRendererHelperTest.java b/tests/robotests/src/com/android/settings/homepage/contextualcards/slices/SliceDeferredSetupCardRendererHelperTest.java
new file mode 100644
index 0000000..740a45b
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/homepage/contextualcards/slices/SliceDeferredSetupCardRendererHelperTest.java
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.homepage.contextualcards.slices;
+
+import static com.android.settings.homepage.contextualcards.slices.SliceContextualCardRenderer.VIEW_TYPE_DEFERRED_SETUP;
+import static com.android.settings.homepage.contextualcards.slices.SliceDeferredSetupCardRendererHelper.DeferredSetupCardViewHolder;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.app.Activity;
+import android.app.PendingIntent;
+import android.content.Intent;
+import android.net.Uri;
+import android.view.LayoutInflater;
+import android.view.View;
+
+import androidx.core.graphics.drawable.IconCompat;
+import androidx.recyclerview.widget.LinearLayoutManager;
+import androidx.recyclerview.widget.RecyclerView;
+import androidx.slice.Slice;
+import androidx.slice.SliceProvider;
+import androidx.slice.builders.ListBuilder;
+import androidx.slice.builders.SliceAction;
+import androidx.slice.widget.SliceLiveData;
+
+import com.android.settings.R;
+import com.android.settings.homepage.contextualcards.ContextualCard;
+import com.android.settings.intelligence.ContextualCardProto;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.Robolectric;
+import org.robolectric.RobolectricTestRunner;
+
+@RunWith(RobolectricTestRunner.class)
+public class SliceDeferredSetupCardRendererHelperTest {
+ private static final Uri TEST_SLICE_URI = Uri.parse("content://test/test");
+ private static final CharSequence TITLE = "test_title";
+ private static final CharSequence SUMMARY = "test_summary";
+
+ private Activity mActivity;
+ private SliceDeferredSetupCardRendererHelper mHelper;
+
+ @Before
+ public void setUp() {
+ // Set-up specs for SliceMetadata.
+ SliceProvider.setSpecs(SliceLiveData.SUPPORTED_SPECS);
+ mActivity = Robolectric.buildActivity(Activity.class).create().get();
+ mActivity.setTheme(R.style.Theme_Settings_Home);
+ mHelper = new SliceDeferredSetupCardRendererHelper(mActivity);
+ }
+
+ @Test
+ public void createViewHolder_shouldAlwaysReturnCustomViewHolder() {
+ final RecyclerView.ViewHolder viewHolder = getDeferredSetupCardViewHolder();
+
+ assertThat(viewHolder).isInstanceOf(
+ DeferredSetupCardViewHolder.class);
+ }
+
+ @Test
+ public void bindView_shouldSetTitle() {
+ final RecyclerView.ViewHolder viewHolder = getDeferredSetupCardViewHolder();
+
+ mHelper.bindView(viewHolder, buildContextualCard(), buildSlice());
+
+ assertThat(((DeferredSetupCardViewHolder) viewHolder).title.getText()).isEqualTo(TITLE);
+ }
+
+ @Test
+ public void bindView_shouldSetSummary() {
+ final RecyclerView.ViewHolder viewHolder = getDeferredSetupCardViewHolder();
+
+ mHelper.bindView(viewHolder, buildContextualCard(), buildSlice());
+
+ assertThat(((DeferredSetupCardViewHolder) viewHolder).summary.getText()).isEqualTo(SUMMARY);
+ }
+
+ private RecyclerView.ViewHolder getDeferredSetupCardViewHolder() {
+ final RecyclerView recyclerView = new RecyclerView(mActivity);
+ recyclerView.setLayoutManager(new LinearLayoutManager(mActivity));
+ final View view = LayoutInflater.from(mActivity).inflate(VIEW_TYPE_DEFERRED_SETUP,
+ recyclerView, false);
+
+ return mHelper.createViewHolder(view);
+ }
+
+ private ContextualCard buildContextualCard() {
+ return new ContextualCard.Builder()
+ .setName("test_name")
+ .setCategory(ContextualCardProto.ContextualCard.Category.DEFERRED_SETUP_VALUE)
+ .setCardType(ContextualCard.CardType.SLICE)
+ .setSliceUri(TEST_SLICE_URI)
+ .setViewType(VIEW_TYPE_DEFERRED_SETUP)
+ .build();
+ }
+
+ private Slice buildSlice() {
+ final IconCompat icon = IconCompat.createWithResource(mActivity, R.drawable.empty_icon);
+ final PendingIntent pendingIntent = PendingIntent.getActivity(
+ mActivity,
+ TITLE.hashCode() /* requestCode */,
+ new Intent("test action"),
+ 0 /* flags */);
+ final SliceAction action
+ = SliceAction.createDeeplink(pendingIntent, icon, ListBuilder.SMALL_IMAGE, TITLE);
+ return new ListBuilder(mActivity, TEST_SLICE_URI, ListBuilder.INFINITY)
+ .addRow(new ListBuilder.RowBuilder()
+ .addEndItem(icon, ListBuilder.ICON_IMAGE)
+ .setTitle(TITLE)
+ .setSubtitle(SUMMARY)
+ .setPrimaryAction(action))
+ .build();
+ }
+}
\ No newline at end of file
diff --git a/tests/robotests/src/com/android/settings/location/LocationSliceTest.java b/tests/robotests/src/com/android/settings/location/LocationSliceTest.java
index 0618cd9..a373b1f 100644
--- a/tests/robotests/src/com/android/settings/location/LocationSliceTest.java
+++ b/tests/robotests/src/com/android/settings/location/LocationSliceTest.java
@@ -47,7 +47,7 @@
final SliceAction primaryAction = metadata.getPrimaryAction();
final IconCompat expectedToggleIcon = IconCompat.createWithResource(mContext,
- R.drawable.ic_signal_location);
+ com.android.internal.R.drawable.ic_signal_location);
assertThat(primaryAction.getIcon().toString()).isEqualTo(expectedToggleIcon.toString());
}
}
diff --git a/tests/robotests/src/com/android/settings/location/RecentLocationAccessPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/location/RecentLocationAccessPreferenceControllerTest.java
index 3b33558..8cba1de 100644
--- a/tests/robotests/src/com/android/settings/location/RecentLocationAccessPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/location/RecentLocationAccessPreferenceControllerTest.java
@@ -36,6 +36,7 @@
import com.android.settingslib.widget.LayoutPreference;
import org.junit.Before;
+import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
@@ -77,6 +78,7 @@
/** Verifies the title text, details text are correct, and the click listener is set. */
@Test
+ @Ignore
public void updateState_whenAppListIsEmpty_shouldDisplayTitleTextAndDetailsText() {
doReturn(new ArrayList<>()).when(mRecentLocationApps).getAppListSorted();
mController.displayPreference(mScreen);
diff --git a/tests/robotests/src/com/android/settings/media/MediaDeviceUpdateWorkerTest.java b/tests/robotests/src/com/android/settings/media/MediaDeviceUpdateWorkerTest.java
new file mode 100644
index 0000000..28bf4e9
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/media/MediaDeviceUpdateWorkerTest.java
@@ -0,0 +1,132 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.media;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.ContentResolver;
+import android.content.Context;
+import android.net.Uri;
+
+import com.android.settingslib.media.MediaDevice;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@RunWith(RobolectricTestRunner.class)
+public class MediaDeviceUpdateWorkerTest {
+
+ private static final Uri URI = Uri.parse("content://com.android.settings.slices/test");
+ private static final String TEST_DEVICE_1_ID = "test_device_1_id";
+ private static final String TEST_DEVICE_2_ID = "test_device_2_id";
+ private static final String TEST_DEVICE_3_ID = "test_device_3_id";
+
+ private final List<MediaDevice> mMediaDevices = new ArrayList<>();
+
+ private MediaDeviceUpdateWorker mMediaDeviceUpdateWorker;
+ private ContentResolver mResolver;
+ private Context mContext;
+ private MediaDevice mMediaDevice1;
+ private MediaDevice mMediaDevice2;
+
+ @Before
+ public void setUp() {
+ mContext = spy(RuntimeEnvironment.application);
+ mMediaDeviceUpdateWorker = new MediaDeviceUpdateWorker(mContext, URI);
+ mResolver = mock(ContentResolver.class);
+
+ mMediaDevice1 = mock(MediaDevice.class);
+ when(mMediaDevice1.getId()).thenReturn(TEST_DEVICE_1_ID);
+ mMediaDevice2 = mock(MediaDevice.class);
+ when(mMediaDevice2.getId()).thenReturn(TEST_DEVICE_2_ID);
+ mMediaDevices.add(mMediaDevice1);
+ mMediaDevices.add(mMediaDevice2);
+
+ doReturn(mResolver).when(mContext).getContentResolver();
+ }
+
+ @Test
+ public void onDeviceListUpdate_shouldNotifyChange() {
+ mMediaDeviceUpdateWorker.onDeviceListUpdate(mMediaDevices);
+
+ verify(mResolver).notifyChange(URI, null);
+ }
+
+ @Test
+ public void onSelectedDeviceStateChanged_shouldNotifyChange() {
+ mMediaDeviceUpdateWorker.onSelectedDeviceStateChanged(null, 0);
+
+ verify(mResolver).notifyChange(URI, null);
+ }
+
+ @Test
+ public void onDeviceListUpdate_sameDeviceList_shouldBeEqual() {
+ mMediaDeviceUpdateWorker.onDeviceListUpdate(mMediaDevices);
+
+ final List<MediaDevice> newDevices = new ArrayList<>();
+ newDevices.add(mMediaDevice1);
+ newDevices.add(mMediaDevice2);
+
+ mMediaDeviceUpdateWorker.onDeviceListUpdate(newDevices);
+ final List<MediaDevice> devices = mMediaDeviceUpdateWorker.getMediaDevices();
+
+ assertThat(devices.get(0).getId()).isEqualTo(newDevices.get(0).getId());
+ assertThat(devices.get(1).getId()).isEqualTo(newDevices.get(1).getId());
+ }
+
+ @Test
+ public void onDeviceListUpdate_add1DeviceToDeviceList_shouldBeEqual() {
+ mMediaDeviceUpdateWorker.onDeviceListUpdate(mMediaDevices);
+
+ final List<MediaDevice> newDevices = new ArrayList<>();
+ final MediaDevice device3 = mock(MediaDevice.class);
+ when(mMediaDevice2.getId()).thenReturn(TEST_DEVICE_3_ID);
+ newDevices.add(mMediaDevice1);
+ newDevices.add(mMediaDevice2);
+ newDevices.add(device3);
+
+ mMediaDeviceUpdateWorker.onDeviceListUpdate(newDevices);
+ final List<MediaDevice> devices = mMediaDeviceUpdateWorker.getMediaDevices();
+
+ assertThat(devices.size()).isEqualTo(newDevices.size());
+ }
+
+ @Test
+ public void onDeviceListUpdate_less1DeviceToDeviceList_shouldBeEqual() {
+ mMediaDeviceUpdateWorker.onDeviceListUpdate(mMediaDevices);
+
+ final List<MediaDevice> newDevices = new ArrayList<>();
+ newDevices.add(mMediaDevice1);
+
+ mMediaDeviceUpdateWorker.onDeviceListUpdate(newDevices);
+ final List<MediaDevice> devices = mMediaDeviceUpdateWorker.getMediaDevices();
+
+ assertThat(devices.size()).isEqualTo(newDevices.size());
+ }
+}
diff --git a/tests/robotests/src/com/android/settings/media/MediaOutputSliceTest.java b/tests/robotests/src/com/android/settings/media/MediaOutputSliceTest.java
new file mode 100644
index 0000000..daaba90
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/media/MediaOutputSliceTest.java
@@ -0,0 +1,157 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package com.android.settings.media;
+
+import static com.android.settings.slices.CustomSliceRegistry.MEDIA_OUTPUT_SLICE_URI;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.graphics.drawable.Drawable;
+import android.os.UserHandle;
+import android.util.IconDrawableFactory;
+
+import androidx.slice.Slice;
+import androidx.slice.SliceMetadata;
+import androidx.slice.SliceProvider;
+import androidx.slice.core.SliceAction;
+import androidx.slice.widget.SliceLiveData;
+
+import com.android.settingslib.media.LocalMediaManager;
+import com.android.settingslib.media.MediaDevice;
+
+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;
+import org.robolectric.RuntimeEnvironment;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@RunWith(RobolectricTestRunner.class)
+public class MediaOutputSliceTest {
+
+ private static final String TEST_PACKAGE_NAME = "com.fake.android.music";
+ private static final String TEST_LABEL = "Test app";
+ private static final String TEST_DEVICE_1_ID = "test_device_1_id";
+
+ @Mock
+ private PackageManager mPackageManager;
+ @Mock
+ private ApplicationInfo mApplicationInfo;
+ @Mock
+ private ApplicationInfo mApplicationInfo2;
+ @Mock
+ private LocalMediaManager mLocalMediaManager;
+ @Mock
+ private IconDrawableFactory mIconDrawableFactory;
+ @Mock
+ private Drawable mTestDrawable;
+
+ private final List<MediaDevice> mDevices = new ArrayList<>();
+
+ private Context mContext;
+ private MediaOutputSlice mMediaOutputSlice;
+ private MediaDeviceUpdateWorker mMediaDeviceUpdateWorker;
+
+ @Before
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+ mContext = spy(RuntimeEnvironment.application);
+
+ when(mContext.getPackageManager()).thenReturn(mPackageManager);
+ when(mPackageManager.getApplicationInfo(eq(TEST_PACKAGE_NAME), anyInt()))
+ .thenReturn(mApplicationInfo);
+ when(mPackageManager.getApplicationInfoAsUser(eq(TEST_PACKAGE_NAME), anyInt(), anyInt()))
+ .thenReturn(mApplicationInfo2);
+ when(mApplicationInfo.loadLabel(mPackageManager)).thenReturn(TEST_LABEL);
+ when(mIconDrawableFactory.getBadgedIcon(mApplicationInfo2, UserHandle.myUserId()))
+ .thenReturn(mTestDrawable);
+ when(mTestDrawable.getIntrinsicWidth()).thenReturn(100);
+ when(mTestDrawable.getIntrinsicHeight()).thenReturn(100);
+
+ // Set-up specs for SliceMetadata.
+ SliceProvider.setSpecs(SliceLiveData.SUPPORTED_SPECS);
+
+ mMediaOutputSlice = new MediaOutputSlice(mContext);
+ mMediaDeviceUpdateWorker = new MediaDeviceUpdateWorker(mContext, MEDIA_OUTPUT_SLICE_URI);
+ mMediaDeviceUpdateWorker.setPackageName(TEST_PACKAGE_NAME);
+ mMediaDeviceUpdateWorker.onDeviceListUpdate(mDevices);
+ mMediaDeviceUpdateWorker.mLocalMediaManager = mLocalMediaManager;
+ mMediaOutputSlice.init(TEST_PACKAGE_NAME, mMediaDeviceUpdateWorker, mIconDrawableFactory);
+ }
+
+ @Test
+ public void getSlice_shouldHaveAppTitle() {
+ final Slice mediaSlice = mMediaOutputSlice.getSlice();
+ final SliceMetadata metadata = SliceMetadata.from(mContext, mediaSlice);
+
+ final SliceAction primaryAction = metadata.getPrimaryAction();
+ assertThat(primaryAction.getTitle().toString()).isEqualTo(TEST_LABEL);
+ }
+
+ @Test
+ public void onNotifyChange_foundMediaDevice_connect() {
+ mDevices.clear();
+ final MediaDevice device = mock(MediaDevice.class);
+ when(device.getId()).thenReturn(TEST_DEVICE_1_ID);
+ when(mLocalMediaManager.getMediaDeviceById(mDevices, TEST_DEVICE_1_ID)).thenReturn(device);
+ mDevices.add(device);
+
+ mMediaDeviceUpdateWorker.onDeviceListUpdate(mDevices);
+
+ final Intent intent = new Intent();
+ intent.putExtra("media_device_id", TEST_DEVICE_1_ID);
+
+ mMediaOutputSlice.onNotifyChange(intent);
+
+ verify(mLocalMediaManager).connectDevice(device);
+ }
+
+ @Test
+ public void onNotifyChange_notFoundMediaDevice_doNothing() {
+ mDevices.clear();
+ final MediaDevice device = mock(MediaDevice.class);
+ when(device.getId()).thenReturn(TEST_DEVICE_1_ID);
+ when(mLocalMediaManager.getMediaDeviceById(mDevices, TEST_DEVICE_1_ID)).thenReturn(device);
+ mDevices.add(device);
+
+ mMediaDeviceUpdateWorker.onDeviceListUpdate(mDevices);
+
+ final Intent intent = new Intent();
+ intent.putExtra("media_device_id", "fake_123");
+
+ mMediaOutputSlice.onNotifyChange(intent);
+
+ verify(mLocalMediaManager, never()).connectDevice(device);
+ }
+}
diff --git a/tests/robotests/src/com/android/settings/network/telephony/DefaultSubscriptionControllerTest.java b/tests/robotests/src/com/android/settings/network/telephony/DefaultSubscriptionControllerTest.java
new file mode 100644
index 0000000..f7a2567
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/network/telephony/DefaultSubscriptionControllerTest.java
@@ -0,0 +1,289 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.network.telephony;
+
+import static com.android.settings.core.BasePreferenceController.AVAILABLE;
+import static com.android.settings.core.BasePreferenceController.CONDITIONALLY_UNAVAILABLE;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.telephony.SubscriptionInfo;
+import android.telephony.SubscriptionManager;
+
+import com.android.settings.R;
+import com.android.settings.network.SubscriptionUtil;
+
+import org.junit.After;
+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;
+import org.robolectric.RuntimeEnvironment;
+
+import java.util.Arrays;
+
+import androidx.preference.ListPreference;
+import androidx.preference.PreferenceScreen;
+
+@RunWith(RobolectricTestRunner.class)
+public class DefaultSubscriptionControllerTest {
+ @Mock
+ private SubscriptionManager mManager;
+ @Mock
+ private PreferenceScreen mScreen;
+
+ private ListPreference mListPreference;
+ private Context mContext;
+ private DefaultSubscriptionController mController;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ mContext = spy(RuntimeEnvironment.application);
+ when(mContext.getSystemService(SubscriptionManager.class)).thenReturn(mManager);
+ final String key = "prefkey";
+ mController = spy(new TestDefaultSubscriptionController(mContext, key));
+ mListPreference = spy(new ListPreference(mContext));
+ when(mScreen.findPreference(key)).thenReturn(mListPreference);
+ }
+
+ @After
+ public void tearDown() {
+ SubscriptionUtil.setAvailableSubscriptionsForTesting(null);
+ }
+
+ @Test
+ public void getAvailabilityStatus_onlyOneSubscription_notAvailable() {
+ SubscriptionUtil.setAvailableSubscriptionsForTesting(Arrays.asList(
+ createMockSub(1, "sub1")));
+ assertThat(mController.getAvailabilityStatus()).isEqualTo(CONDITIONALLY_UNAVAILABLE);
+ }
+
+ @Test
+ public void getAvailabilityStatus_twoSubscriptions_isAvailable() {
+ SubscriptionUtil.setAvailableSubscriptionsForTesting(Arrays.asList(
+ createMockSub(1, "sub1"),
+ createMockSub(2, "sub2")));
+ assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE);
+ }
+
+ @Test
+ public void displayPreference_twoSubscriptionsSub1Default_correctListPreferenceValues() {
+ final SubscriptionInfo sub1 = createMockSub(111, "sub1");
+ final SubscriptionInfo sub2 = createMockSub(222, "sub2");
+ SubscriptionUtil.setAvailableSubscriptionsForTesting(Arrays.asList(sub1, sub2));
+ doReturn(sub1.getSubscriptionId()).when(mController).getDefaultSubscriptionId();
+
+ mController.displayPreference(mScreen);
+
+ final CharSequence entry = mListPreference.getEntry();
+ final String value = mListPreference.getValue();
+ assertThat(entry).isEqualTo("sub1");
+ assertThat(value).isEqualTo("111");
+
+ final CharSequence[] entries = mListPreference.getEntries();
+ assertThat(entries.length).isEqualTo(3);
+ assertThat(entries[0]).isEqualTo("sub1");
+ assertThat(entries[1]).isEqualTo("sub2");
+ assertThat(entries[2]).isEqualTo(mContext.getString(R.string.calls_and_sms_ask_every_time));
+
+ final CharSequence[] entryValues = mListPreference.getEntryValues();
+ assertThat(entryValues.length).isEqualTo(3);
+ assertThat(entryValues[0]).isEqualTo("111");
+ assertThat(entryValues[1]).isEqualTo("222");
+ assertThat(entryValues[2]).isEqualTo(
+ Integer.toString(SubscriptionManager.INVALID_SUBSCRIPTION_ID));
+ }
+
+ @Test
+ public void displayPreference_twoSubscriptionsSub2Default_correctListPreferenceValues() {
+ final SubscriptionInfo sub1 = createMockSub(111, "sub1");
+ final SubscriptionInfo sub2 = createMockSub(222, "sub2");
+ SubscriptionUtil.setAvailableSubscriptionsForTesting(Arrays.asList(sub1, sub2));
+ doReturn(sub2.getSubscriptionId()).when(mController).getDefaultSubscriptionId();
+
+ mController.displayPreference(mScreen);
+
+ final CharSequence entry = mListPreference.getEntry();
+ final String value = mListPreference.getValue();
+ assertThat(entry).isEqualTo("sub2");
+ assertThat(value).isEqualTo("222");
+
+ final CharSequence[] entries = mListPreference.getEntries();
+ assertThat(entries.length).isEqualTo(3);
+ assertThat(entries[0]).isEqualTo("sub1");
+ assertThat(entries[1]).isEqualTo("sub2");
+ assertThat(entries[2]).isEqualTo(mContext.getString(R.string.calls_and_sms_ask_every_time));
+
+ final CharSequence[] entryValues = mListPreference.getEntryValues();
+ assertThat(entryValues.length).isEqualTo(3);
+ assertThat(entryValues[0]).isEqualTo("111");
+ assertThat(entryValues[1]).isEqualTo("222");
+ assertThat(entryValues[2]).isEqualTo(
+ Integer.toString(SubscriptionManager.INVALID_SUBSCRIPTION_ID));
+ }
+
+ @Test
+ public void onPreferenceChange_prefChangedToSub2_callbackCalledCorrectly() {
+ final SubscriptionInfo sub1 = createMockSub(111, "sub1");
+ final SubscriptionInfo sub2 = createMockSub(222, "sub2");
+ SubscriptionUtil.setAvailableSubscriptionsForTesting(Arrays.asList(sub1, sub2));
+ doReturn(sub1.getSubscriptionId()).when(mController).getDefaultSubscriptionId();
+
+ mController.displayPreference(mScreen);
+ mListPreference.setValue("222");
+ mController.onPreferenceChange(mListPreference, "222");
+ verify(mController).setDefaultSubscription(eq(222));
+ }
+
+ @Test
+ public void onPreferenceChange_prefChangedToAlwaysAsk_callbackCalledCorrectly() {
+ final SubscriptionInfo sub1 = createMockSub(111, "sub1");
+ final SubscriptionInfo sub2 = createMockSub(222, "sub2");
+ SubscriptionUtil.setAvailableSubscriptionsForTesting(Arrays.asList(sub1, sub2));
+ doReturn(sub1.getSubscriptionId()).when(mController).getDefaultSubscriptionId();
+
+ mController.displayPreference(mScreen);
+ mListPreference.setValue(Integer.toString(SubscriptionManager.INVALID_SUBSCRIPTION_ID));
+ mController.onPreferenceChange(mListPreference,
+ Integer.toString(SubscriptionManager.INVALID_SUBSCRIPTION_ID));
+ verify(mController).setDefaultSubscription(
+ eq(SubscriptionManager.INVALID_SUBSCRIPTION_ID));
+ }
+
+ @Test
+ public void onSubscriptionsChanged_twoSubscriptionsDefaultChanges_selectedEntryGetsUpdated() {
+ final SubscriptionInfo sub1 = createMockSub(111, "sub1");
+ final SubscriptionInfo sub2 = createMockSub(222, "sub2");
+ SubscriptionUtil.setAvailableSubscriptionsForTesting(Arrays.asList(sub1, sub2));
+ doReturn(sub1.getSubscriptionId()).when(mController).getDefaultSubscriptionId();
+
+ mController.displayPreference(mScreen);
+ assertThat( mListPreference.getEntry()).isEqualTo("sub1");
+ assertThat(mListPreference.getValue()).isEqualTo("111");
+
+ doReturn(sub2.getSubscriptionId()).when(mController).getDefaultSubscriptionId();
+ mController.onSubscriptionsChanged();
+ assertThat( mListPreference.getEntry()).isEqualTo("sub2");
+ assertThat(mListPreference.getValue()).isEqualTo("222");
+ }
+
+ @Test
+ public void onSubscriptionsChanged_goFromTwoSubscriptionsToOne_prefDisappears() {
+ final SubscriptionInfo sub1 = createMockSub(111, "sub1");
+ final SubscriptionInfo sub2 = createMockSub(222, "sub2");
+ SubscriptionUtil.setAvailableSubscriptionsForTesting(Arrays.asList(sub1, sub2));
+ doReturn(sub1.getSubscriptionId()).when(mController).getDefaultSubscriptionId();
+
+ mController.displayPreference(mScreen);
+ assertThat(mController.isAvailable()).isTrue();
+ assertThat(mListPreference.isVisible()).isTrue();
+
+ SubscriptionUtil.setAvailableSubscriptionsForTesting(Arrays.asList(sub1));
+ mController.onSubscriptionsChanged();
+
+ assertThat(mController.isAvailable()).isFalse();
+ assertThat(mListPreference.isVisible()).isFalse();
+ }
+
+ @Test
+ public void onSubscriptionsChanged_goFromOneSubscriptionToTwo_prefAppears() {
+ final SubscriptionInfo sub1 = createMockSub(111, "sub1");
+ final SubscriptionInfo sub2 = createMockSub(222, "sub2");
+ SubscriptionUtil.setAvailableSubscriptionsForTesting(Arrays.asList(sub1));
+ doReturn(sub1.getSubscriptionId()).when(mController).getDefaultSubscriptionId();
+
+ mController.displayPreference(mScreen);
+ assertThat(mController.isAvailable()).isFalse();
+ assertThat(mListPreference.isVisible()).isFalse();
+
+ SubscriptionUtil.setAvailableSubscriptionsForTesting(Arrays.asList(sub1, sub2));
+ mController.onSubscriptionsChanged();
+
+ assertThat(mController.isAvailable()).isTrue();
+ assertThat(mListPreference.isVisible()).isTrue();
+ }
+
+ @Test
+ public void onSubscriptionsChanged_goFromTwoToThreeSubscriptions_listGetsUpdated() {
+ final SubscriptionInfo sub1 = createMockSub(111, "sub1");
+ final SubscriptionInfo sub2 = createMockSub(222, "sub2");
+ final SubscriptionInfo sub3 = createMockSub(333, "sub3");
+ SubscriptionUtil.setAvailableSubscriptionsForTesting(Arrays.asList(sub1, sub2));
+ doReturn(sub1.getSubscriptionId()).when(mController).getDefaultSubscriptionId();
+
+ mController.displayPreference(mScreen);
+ assertThat(mListPreference.getEntries().length).isEqualTo(3);
+
+ SubscriptionUtil.setAvailableSubscriptionsForTesting(Arrays.asList(sub1, sub2, sub3));
+ mController.onSubscriptionsChanged();
+
+ assertThat(mController.isAvailable()).isTrue();
+ assertThat(mListPreference.isVisible()).isTrue();
+ final CharSequence[] entries = mListPreference.getEntries();
+ final CharSequence[] entryValues = mListPreference.getEntryValues();
+ assertThat(entries.length).isEqualTo(4);
+ assertThat(entries[0].toString()).isEqualTo("sub1");
+ assertThat(entries[1].toString()).isEqualTo("sub2");
+ assertThat(entries[2].toString()).isEqualTo("sub3");
+ assertThat(entries[3].toString()).isEqualTo(
+ mContext.getString(R.string.calls_and_sms_ask_every_time));
+ assertThat(entryValues[0].toString()).isEqualTo("111");
+ assertThat(entryValues[1].toString()).isEqualTo("222");
+ assertThat(entryValues[2].toString()).isEqualTo("333");
+ assertThat(entryValues[3].toString()).isEqualTo(
+ Integer.toString(SubscriptionManager.INVALID_SUBSCRIPTION_ID));
+ }
+
+ private SubscriptionInfo createMockSub(int id, String displayName) {
+ final SubscriptionInfo sub = mock(SubscriptionInfo.class);
+ when(sub.getSubscriptionId()).thenReturn(id);
+ when(sub.getDisplayName()).thenReturn(displayName);
+ return sub;
+ }
+
+ private class TestDefaultSubscriptionController extends DefaultSubscriptionController {
+
+ public TestDefaultSubscriptionController(Context context, String preferenceKey) {
+ super(context, preferenceKey);
+ }
+
+ @Override
+ protected SubscriptionInfo getDefaultSubscriptionInfo() {
+ return null;
+ }
+
+ @Override
+ protected int getDefaultSubscriptionId() {
+ return 0;
+ }
+
+ @Override
+ protected void setDefaultSubscription(int subscriptionId) {
+ }
+ }
+}
diff --git a/tests/robotests/src/com/android/settings/network/telephony/MobileNetworkSettingsTest.java b/tests/robotests/src/com/android/settings/network/telephony/MobileNetworkSettingsTest.java
index 0240bd8..55a4224 100644
--- a/tests/robotests/src/com/android/settings/network/telephony/MobileNetworkSettingsTest.java
+++ b/tests/robotests/src/com/android/settings/network/telephony/MobileNetworkSettingsTest.java
@@ -85,7 +85,13 @@
}
@Test
- public void onAttach_noCrash() {
+ public void onAttach_noV2Flag_noCrash() {
+ mFragment.onAttach(mContext);
+ }
+
+ @Test
+ public void onAttach_v2Flag_noCrash() {
+ FeatureFlagPersistent.setEnabled(mContext, FeatureFlags.NETWORK_INTERNET_V2, true);
mFragment.onAttach(mContext);
}
diff --git a/tests/robotests/src/com/android/settings/notification/RedactionInterstitialTest.java b/tests/robotests/src/com/android/settings/notification/RedactionInterstitialTest.java
index 61fe025..a2ca62e 100644
--- a/tests/robotests/src/com/android/settings/notification/RedactionInterstitialTest.java
+++ b/tests/robotests/src/com/android/settings/notification/RedactionInterstitialTest.java
@@ -12,6 +12,7 @@
import android.content.ContentResolver;
import android.content.Intent;
import android.os.UserHandle;
+import android.os.UserManager;
import android.provider.Settings;
import android.view.View;
import android.widget.RadioButton;
@@ -20,7 +21,6 @@
import com.android.settings.RestrictedRadioButton;
import com.android.settings.notification.RedactionInterstitial.RedactionInterstitialFragment;
import com.android.settings.testutils.shadow.ShadowRestrictedLockUtilsInternal;
-import com.android.settings.testutils.shadow.ShadowUserManager;
import com.android.settings.testutils.shadow.ShadowUtils;
import org.junit.After;
@@ -30,12 +30,13 @@
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Config;
+import org.robolectric.shadow.api.Shadow;
+import org.robolectric.shadows.ShadowUserManager;
@RunWith(RobolectricTestRunner.class)
@Config(shadows = {
ShadowUtils.class,
ShadowRestrictedLockUtilsInternal.class,
- ShadowUserManager.class,
})
public class RedactionInterstitialTest {
private RedactionInterstitial mActivity;
@@ -103,7 +104,9 @@
@Test
public void managedProfileNoRestrictionsTest() {
setupSettings(1 /* show */, 1 /* showUnredacted */);
- ShadowUserManager.getShadow().addManagedProfile(UserHandle.myUserId());
+ final ShadowUserManager sum =
+ Shadow.extract(RuntimeEnvironment.application.getSystemService(UserManager.class));
+ sum.setManagedProfile(true);
setupActivity();
assertHideAllVisible(false);
@@ -114,7 +117,9 @@
@Test
public void managedProfileUnredactedRestrictionTest() {
setupSettings(1 /* show */, 1 /* showUnredacted */);
- ShadowUserManager.getShadow().addManagedProfile(UserHandle.myUserId());
+ final ShadowUserManager sum =
+ Shadow.extract(RuntimeEnvironment.application.getSystemService(UserManager.class));
+ sum.setManagedProfile(true);
ShadowRestrictedLockUtilsInternal.setKeyguardDisabledFeatures(
KEYGUARD_DISABLE_UNREDACTED_NOTIFICATIONS);
setupActivity();
diff --git a/tests/robotests/src/com/android/settings/panel/MediaOutputPanelTest.java b/tests/robotests/src/com/android/settings/panel/MediaOutputPanelTest.java
new file mode 100644
index 0000000..b411037
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/panel/MediaOutputPanelTest.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package com.android.settings.panel;
+
+import static com.android.settings.media.MediaOutputSlice.MEDIA_PACKAGE_NAME;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.net.Uri;
+
+import com.android.settings.slices.CustomSliceRegistry;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
+
+import java.util.List;
+
+@RunWith(RobolectricTestRunner.class)
+public class MediaOutputPanelTest {
+
+ private static final String TEST_PACKAGENAME = "com.test.packagename";
+
+ private MediaOutputPanel mPanel;
+
+ @Before
+ public void setUp() {
+ mPanel = MediaOutputPanel.create(RuntimeEnvironment.application, TEST_PACKAGENAME);
+ }
+
+ @Test
+ public void getSlices_containsNecessarySlices() {
+ final List<Uri> uris = mPanel.getSlices();
+
+ assertThat(uris).containsExactly(CustomSliceRegistry.MEDIA_OUTPUT_SLICE_URI);
+ }
+
+ @Test
+ public void getSlices_verifyPackageName_isEqual() {
+ final List<Uri> uris = mPanel.getSlices();
+
+ assertThat(uris.get(0).getQueryParameter(MEDIA_PACKAGE_NAME)).isEqualTo(TEST_PACKAGENAME);
+ }
+
+ @Test
+ public void getSeeMoreIntent_isNull() {
+ assertThat(mPanel.getSeeMoreIntent()).isNull();
+ }
+}
diff --git a/tests/robotests/src/com/android/settings/panel/NfcPanelTest.java b/tests/robotests/src/com/android/settings/panel/NfcPanelTest.java
new file mode 100644
index 0000000..bf6662d
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/panel/NfcPanelTest.java
@@ -0,0 +1,40 @@
+package com.android.settings.panel;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.net.Uri;
+
+import com.android.settings.slices.CustomSliceRegistry;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
+
+
+import java.util.List;
+
+@RunWith(RobolectricTestRunner.class)
+public class NfcPanelTest {
+
+ private NfcPanel mPanel;
+
+ @Before
+ public void setUp() {
+ mPanel = NfcPanel.create(RuntimeEnvironment.application);
+ }
+
+ @Test
+ public void getSlices_containsNecessarySlices() {
+ final List<Uri> uris = mPanel.getSlices();
+
+ assertThat(uris).containsExactly(
+ CustomSliceRegistry.NFC_SLICE_URI);
+ }
+
+ @Test
+ public void getSeeMoreIntent_notNull() {
+ assertThat(mPanel.getSeeMoreIntent()).isNotNull();
+ }
+}
diff --git a/tests/robotests/src/com/android/settings/panel/PanelFeatureProviderImplTest.java b/tests/robotests/src/com/android/settings/panel/PanelFeatureProviderImplTest.java
index 99d5d6c..ae57a77 100644
--- a/tests/robotests/src/com/android/settings/panel/PanelFeatureProviderImplTest.java
+++ b/tests/robotests/src/com/android/settings/panel/PanelFeatureProviderImplTest.java
@@ -17,6 +17,8 @@
package com.android.settings.panel;
+import static com.android.settingslib.media.MediaOutputSliceConstants.ACTION_MEDIA_OUTPUT;
+
import static com.google.common.truth.Truth.assertThat;
import android.content.Context;
@@ -32,6 +34,8 @@
@RunWith(RobolectricTestRunner.class)
public class PanelFeatureProviderImplTest {
+ private static final String TEST_PACKAGENAME = "com.test.packagename";
+
private Context mContext;
private PanelFeatureProviderImpl mProvider;
@@ -44,7 +48,7 @@
@Test
public void getPanel_internetConnectivityKey_returnsCorrectPanel() {
final PanelContent panel = mProvider.getPanel(mContext,
- Settings.Panel.ACTION_INTERNET_CONNECTIVITY);
+ Settings.Panel.ACTION_INTERNET_CONNECTIVITY, TEST_PACKAGENAME);
assertThat(panel).isInstanceOf(InternetConnectivityPanel.class);
}
@@ -52,8 +56,16 @@
@Test
public void getPanel_volume_returnsCorrectPanel() {
final PanelContent panel = mProvider.getPanel(mContext,
- Settings.Panel.ACTION_VOLUME);
+ Settings.Panel.ACTION_VOLUME, TEST_PACKAGENAME);
assertThat(panel).isInstanceOf(VolumePanel.class);
}
+
+ @Test
+ public void getPanel_mediaOutputKey_returnsCorrectPanel() {
+ final PanelContent panel = mProvider.getPanel(mContext,
+ ACTION_MEDIA_OUTPUT, TEST_PACKAGENAME);
+
+ assertThat(panel).isInstanceOf(MediaOutputPanel.class);
+ }
}
diff --git a/tests/robotests/src/com/android/settings/panel/PanelFragmentTest.java b/tests/robotests/src/com/android/settings/panel/PanelFragmentTest.java
index 73318f2..389c31e 100644
--- a/tests/robotests/src/com/android/settings/panel/PanelFragmentTest.java
+++ b/tests/robotests/src/com/android/settings/panel/PanelFragmentTest.java
@@ -59,7 +59,7 @@
mFakeFeatureFactory = FakeFeatureFactory.setupForTest();
mFakeFeatureFactory.panelFeatureProvider = mPanelFeatureProvider;
mFakePanelContent = new FakePanelContent();
- doReturn(mFakePanelContent).when(mPanelFeatureProvider).getPanel(any(), any());
+ doReturn(mFakePanelContent).when(mPanelFeatureProvider).getPanel(any(), any(), any());
ActivityController<FakeSettingsPanelActivity> activityController =
Robolectric.buildActivity(FakeSettingsPanelActivity.class);
diff --git a/tests/robotests/src/com/android/settings/panel/PanelSlicesAdapterTest.java b/tests/robotests/src/com/android/settings/panel/PanelSlicesAdapterTest.java
index 7648d23..abefa67 100644
--- a/tests/robotests/src/com/android/settings/panel/PanelSlicesAdapterTest.java
+++ b/tests/robotests/src/com/android/settings/panel/PanelSlicesAdapterTest.java
@@ -58,7 +58,7 @@
mFakeFeatureFactory = FakeFeatureFactory.setupForTest();
mFakeFeatureFactory.panelFeatureProvider = mPanelFeatureProvider;
mFakePanelContent = new FakePanelContent();
- doReturn(mFakePanelContent).when(mPanelFeatureProvider).getPanel(any(), any());
+ doReturn(mFakePanelContent).when(mPanelFeatureProvider).getPanel(any(), any(), any());
ActivityController<FakeSettingsPanelActivity> activityController =
Robolectric.buildActivity(FakeSettingsPanelActivity.class);
diff --git a/tests/robotests/src/com/android/settings/panel/SettingsPanelActivityTest.java b/tests/robotests/src/com/android/settings/panel/SettingsPanelActivityTest.java
new file mode 100644
index 0000000..359cf5d
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/panel/SettingsPanelActivityTest.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.panel;
+
+import static com.android.settings.panel.SettingsPanelActivity.KEY_PANEL_PACKAGE_NAME;
+import static com.android.settings.panel.SettingsPanelActivity.KEY_PANEL_TYPE_ARGUMENT;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.content.Intent;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.Robolectric;
+import org.robolectric.RobolectricTestRunner;
+
+@RunWith(RobolectricTestRunner.class)
+public class SettingsPanelActivityTest {
+
+ @Test
+ public void startMediaOutputSlice_withPackageName_bundleShouldHaveValue() {
+ final Intent intent = new Intent()
+ .setAction("com.android.settings.panel.action.MEDIA_OUTPUT")
+ .putExtra("com.android.settings.panel.extra.PACKAGE_NAME",
+ "com.google.android.music");
+
+ final SettingsPanelActivity activity =
+ Robolectric.buildActivity(SettingsPanelActivity.class, intent).create().get();
+
+ assertThat(activity.mBundle.getString(KEY_PANEL_PACKAGE_NAME))
+ .isEqualTo("com.google.android.music");
+ assertThat(activity.mBundle.getString(KEY_PANEL_TYPE_ARGUMENT))
+ .isEqualTo("com.android.settings.panel.action.MEDIA_OUTPUT");
+ }
+
+ @Test
+ public void startMediaOutputSlice_withoutPackageName_bundleShouldNotHaveValue() {
+ final Intent intent = new Intent()
+ .setAction("com.android.settings.panel.action.MEDIA_OUTPUT");
+
+ final SettingsPanelActivity activity =
+ Robolectric.buildActivity(SettingsPanelActivity.class, intent).create().get();
+
+ assertThat(activity.mBundle.containsKey(KEY_PANEL_PACKAGE_NAME)).isFalse();
+ assertThat(activity.mBundle.containsKey(KEY_PANEL_TYPE_ARGUMENT)).isFalse();
+ }
+}
diff --git a/tests/robotests/src/com/android/settings/password/ChooseLockGenericControllerTest.java b/tests/robotests/src/com/android/settings/password/ChooseLockGenericControllerTest.java
index cbc5765..2b7bdeb 100644
--- a/tests/robotests/src/com/android/settings/password/ChooseLockGenericControllerTest.java
+++ b/tests/robotests/src/com/android/settings/password/ChooseLockGenericControllerTest.java
@@ -16,15 +16,22 @@
package com.android.settings.password;
+import static android.app.admin.DevicePolicyManager.PASSWORD_COMPLEXITY_HIGH;
+import static android.app.admin.DevicePolicyManager.PASSWORD_COMPLEXITY_LOW;
+import static android.app.admin.DevicePolicyManager.PASSWORD_COMPLEXITY_MEDIUM;
+import static android.app.admin.DevicePolicyManager.PASSWORD_COMPLEXITY_NONE;
+
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.nullable;
import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.when;
import static org.robolectric.RuntimeEnvironment.application;
import android.app.admin.DevicePolicyManager;
+import android.app.admin.DevicePolicyManager.PasswordComplexity;
import android.content.ComponentName;
import com.android.settings.R;
@@ -58,11 +65,7 @@
public void setUp() {
MockitoAnnotations.initMocks(this);
- mController = new ChooseLockGenericController(
- application,
- 0 /* userId */,
- mDevicePolicyManager,
- mManagedLockPasswordProvider);
+ mController = createController(PASSWORD_COMPLEXITY_NONE);
SettingsShadowResources.overrideResource(R.bool.config_hide_none_security_option, false);
SettingsShadowResources.overrideResource(R.bool.config_hide_swipe_security_option, false);
}
@@ -225,4 +228,44 @@
assertThat(upgradedQuality).named("upgradedQuality")
.isEqualTo(DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC);
}
+
+ @Test
+ public void upgradeQuality_complexityHigh_minQualityNumericComplex() {
+ when(mDevicePolicyManager.getPasswordQuality(nullable(ComponentName.class), anyInt()))
+ .thenReturn(DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED);
+ ChooseLockGenericController controller = createController(PASSWORD_COMPLEXITY_HIGH);
+
+ assertThat(controller.upgradeQuality(DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED))
+ .isEqualTo(DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX);
+ }
+
+ @Test
+ public void upgradeQuality_complexityMedium_minQualityNumericComplex() {
+ when(mDevicePolicyManager.getPasswordQuality(nullable(ComponentName.class), anyInt()))
+ .thenReturn(DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED);
+ ChooseLockGenericController controller = createController(PASSWORD_COMPLEXITY_MEDIUM);
+
+ assertThat(controller.upgradeQuality(DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED))
+ .isEqualTo(DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX);
+ }
+
+ @Test
+ public void upgradeQuality_complexityLow_minQualitySomething() {
+ when(mDevicePolicyManager.getPasswordQuality(nullable(ComponentName.class), anyInt()))
+ .thenReturn(DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED);
+ ChooseLockGenericController controller = createController(PASSWORD_COMPLEXITY_LOW);
+
+ assertThat(controller.upgradeQuality(DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED))
+ .isEqualTo(DevicePolicyManager.PASSWORD_QUALITY_SOMETHING);
+ }
+
+ private ChooseLockGenericController createController(
+ @PasswordComplexity int minPasswordComplexity) {
+ return new ChooseLockGenericController(
+ application,
+ 0 /* userId */,
+ minPasswordComplexity,
+ mDevicePolicyManager,
+ mManagedLockPasswordProvider);
+ }
}
diff --git a/tests/robotests/src/com/android/settings/password/ChooseLockGenericTest.java b/tests/robotests/src/com/android/settings/password/ChooseLockGenericTest.java
index e324214..a1db12c 100644
--- a/tests/robotests/src/com/android/settings/password/ChooseLockGenericTest.java
+++ b/tests/robotests/src/com/android/settings/password/ChooseLockGenericTest.java
@@ -16,6 +16,15 @@
package com.android.settings.password;
+import static android.app.admin.DevicePolicyManager.ACTION_SET_NEW_PASSWORD;
+import static android.app.admin.DevicePolicyManager.PASSWORD_COMPLEXITY_HIGH;
+import static android.app.admin.DevicePolicyManager.PASSWORD_COMPLEXITY_LOW;
+import static android.app.admin.DevicePolicyManager.PASSWORD_COMPLEXITY_MEDIUM;
+import static android.app.admin.DevicePolicyManager.PASSWORD_COMPLEXITY_NONE;
+
+import static com.android.settings.password.ChooseLockSettingsHelper.EXTRA_KEY_CALLER_APP_NAME;
+import static com.android.settings.password.ChooseLockSettingsHelper.EXTRA_KEY_REQUESTED_MIN_COMPLEXITY;
+
import static com.google.common.truth.Truth.assertThat;
import static org.robolectric.RuntimeEnvironment.application;
@@ -27,8 +36,10 @@
import android.provider.Settings.Global;
import androidx.annotation.Nullable;
+import androidx.preference.Preference;
import com.android.internal.widget.LockPatternUtils;
+import com.android.settings.R;
import com.android.settings.biometrics.BiometricEnrollBase;
import com.android.settings.password.ChooseLockGeneric.ChooseLockGenericFragment;
import com.android.settings.search.SearchFeatureProvider;
@@ -36,6 +47,7 @@
import com.android.settings.testutils.shadow.ShadowStorageManager;
import com.android.settings.testutils.shadow.ShadowUserManager;
import com.android.settings.testutils.shadow.ShadowUtils;
+import com.android.settingslib.widget.FooterPreference;
import org.junit.After;
import org.junit.Before;
@@ -113,6 +125,70 @@
}
@Test
+ public void updatePreferencesOrFinish_footerPreferenceAddedHighComplexityText() {
+ ShadowStorageManager.setIsFileEncryptedNativeOrEmulated(false);
+ Intent intent = new Intent()
+ .putExtra(EXTRA_KEY_CALLER_APP_NAME, "app name")
+ .putExtra(EXTRA_KEY_REQUESTED_MIN_COMPLEXITY, PASSWORD_COMPLEXITY_HIGH);
+ initActivity(intent);
+ CharSequence expectedTitle =
+ mActivity.getString(R.string.unlock_footer_high_complexity_requested, "app name");
+
+ mFragment.updatePreferencesOrFinish(false /* isRecreatingActivity */);
+ FooterPreference footer = mFragment.findPreference(FooterPreference.KEY_FOOTER);
+
+ assertThat(footer.getTitle()).isEqualTo(expectedTitle);
+ }
+
+ @Test
+ public void updatePreferencesOrFinish_footerPreferenceAddedMediumComplexityText() {
+ ShadowStorageManager.setIsFileEncryptedNativeOrEmulated(false);
+ Intent intent = new Intent()
+ .putExtra(EXTRA_KEY_CALLER_APP_NAME, "app name")
+ .putExtra(EXTRA_KEY_REQUESTED_MIN_COMPLEXITY, PASSWORD_COMPLEXITY_MEDIUM);
+ initActivity(intent);
+ CharSequence expectedTitle =
+ mActivity.getString(R.string.unlock_footer_medium_complexity_requested, "app name");
+
+ mFragment.updatePreferencesOrFinish(false /* isRecreatingActivity */);
+ FooterPreference footer = mFragment.findPreference(FooterPreference.KEY_FOOTER);
+
+ assertThat(footer.getTitle()).isEqualTo(expectedTitle);
+ }
+
+ @Test
+ public void updatePreferencesOrFinish_footerPreferenceAddedLowComplexityText() {
+ ShadowStorageManager.setIsFileEncryptedNativeOrEmulated(false);
+ Intent intent = new Intent()
+ .putExtra(EXTRA_KEY_CALLER_APP_NAME, "app name")
+ .putExtra(EXTRA_KEY_REQUESTED_MIN_COMPLEXITY, PASSWORD_COMPLEXITY_LOW);
+ initActivity(intent);
+ CharSequence expectedTitle =
+ mActivity.getString(R.string.unlock_footer_low_complexity_requested, "app name");
+
+ mFragment.updatePreferencesOrFinish(false /* isRecreatingActivity */);
+ FooterPreference footer = mFragment.findPreference(FooterPreference.KEY_FOOTER);
+
+ assertThat(footer.getTitle()).isEqualTo(expectedTitle);
+ }
+
+ @Test
+ public void updatePreferencesOrFinish_footerPreferenceAddedNoneComplexityText() {
+ ShadowStorageManager.setIsFileEncryptedNativeOrEmulated(false);
+ Intent intent = new Intent()
+ .putExtra(EXTRA_KEY_CALLER_APP_NAME, "app name")
+ .putExtra(EXTRA_KEY_REQUESTED_MIN_COMPLEXITY, PASSWORD_COMPLEXITY_NONE);
+ initActivity(intent);
+ CharSequence expectedTitle =
+ mActivity.getString(R.string.unlock_footer_none_complexity_requested, "app name");
+
+ mFragment.updatePreferencesOrFinish(false /* isRecreatingActivity */);
+ FooterPreference footer = mFragment.findPreference(FooterPreference.KEY_FOOTER);
+
+ assertThat(footer.getTitle()).isEqualTo(expectedTitle);
+ }
+
+ @Test
public void onActivityResult_requestcode0_shouldNotFinish() {
initActivity(null);
@@ -165,6 +241,48 @@
assertThat(mActivity.isFinishing()).isTrue();
}
+ @Test
+ public void onPreferenceTreeClick_fingerprintPassesMinComplexityInfoOntoNextActivity() {
+ Intent intent = new Intent(ACTION_SET_NEW_PASSWORD)
+ .putExtra(EXTRA_KEY_REQUESTED_MIN_COMPLEXITY, PASSWORD_COMPLEXITY_HIGH)
+ .putExtra(EXTRA_KEY_CALLER_APP_NAME, "app name");
+ initActivity(intent);
+
+ Preference fingerprintPref = new Preference(application);
+ fingerprintPref.setKey("unlock_skip_fingerprint");
+ boolean result = mFragment.onPreferenceTreeClick(fingerprintPref);
+
+ assertThat(result).isTrue();
+ Intent actualIntent = shadowOf(mActivity).getNextStartedActivityForResult().intent;
+ assertThat(actualIntent.hasExtra(EXTRA_KEY_REQUESTED_MIN_COMPLEXITY)).isTrue();
+ assertThat(actualIntent.getIntExtra(EXTRA_KEY_REQUESTED_MIN_COMPLEXITY, PASSWORD_COMPLEXITY_NONE))
+ .isEqualTo(PASSWORD_COMPLEXITY_HIGH);
+ assertThat(actualIntent.hasExtra(EXTRA_KEY_CALLER_APP_NAME)).isTrue();
+ assertThat(actualIntent.getStringExtra(EXTRA_KEY_CALLER_APP_NAME))
+ .isEqualTo("app name");
+ }
+
+ @Test
+ public void onPreferenceTreeClick_facePassesMinComplexityInfoOntoNextActivity() {
+ Intent intent = new Intent(ACTION_SET_NEW_PASSWORD)
+ .putExtra(EXTRA_KEY_REQUESTED_MIN_COMPLEXITY, PASSWORD_COMPLEXITY_HIGH)
+ .putExtra(EXTRA_KEY_CALLER_APP_NAME, "app name");
+ initActivity(intent);
+
+ Preference facePref = new Preference(application);
+ facePref.setKey("unlock_skip_face");
+ boolean result = mFragment.onPreferenceTreeClick(facePref);
+
+ assertThat(result).isTrue();
+ Intent actualIntent = shadowOf(mActivity).getNextStartedActivityForResult().intent;
+ assertThat(actualIntent.hasExtra(EXTRA_KEY_REQUESTED_MIN_COMPLEXITY)).isTrue();
+ assertThat(actualIntent.getIntExtra(EXTRA_KEY_REQUESTED_MIN_COMPLEXITY, PASSWORD_COMPLEXITY_NONE))
+ .isEqualTo(PASSWORD_COMPLEXITY_HIGH);
+ assertThat(actualIntent.hasExtra(EXTRA_KEY_CALLER_APP_NAME)).isTrue();
+ assertThat(actualIntent.getStringExtra(EXTRA_KEY_CALLER_APP_NAME))
+ .isEqualTo("app name");
+ }
+
private void initActivity(@Nullable Intent intent) {
if (intent == null) {
intent = new Intent();
diff --git a/tests/robotests/src/com/android/settings/password/ChooseLockPasswordTest.java b/tests/robotests/src/com/android/settings/password/ChooseLockPasswordTest.java
index 367cb4c..404d205 100644
--- a/tests/robotests/src/com/android/settings/password/ChooseLockPasswordTest.java
+++ b/tests/robotests/src/com/android/settings/password/ChooseLockPasswordTest.java
@@ -16,19 +16,37 @@
package com.android.settings.password;
+import static android.app.admin.DevicePolicyManager.PASSWORD_COMPLEXITY_HIGH;
+import static android.app.admin.DevicePolicyManager.PASSWORD_COMPLEXITY_LOW;
+import static android.app.admin.DevicePolicyManager.PASSWORD_COMPLEXITY_MEDIUM;
+import static android.app.admin.DevicePolicyManager.PASSWORD_COMPLEXITY_NONE;
+import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC;
+import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC;
+import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_COMPLEX;
+import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_NUMERIC;
+import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX;
+import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_SOMETHING;
+import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
+
+import static com.android.internal.widget.LockPatternUtils.PASSWORD_TYPE_KEY;
+import static com.android.settings.password.ChooseLockGeneric.CONFIRM_CREDENTIALS;
+import static com.android.settings.password.ChooseLockSettingsHelper.EXTRA_KEY_REQUESTED_MIN_COMPLEXITY;
+
import static com.google.common.truth.Truth.assertThat;
import static org.robolectric.RuntimeEnvironment.application;
import android.app.admin.DevicePolicyManager;
+import android.app.admin.DevicePolicyManager.PasswordComplexity;
import android.content.Intent;
import android.os.UserHandle;
-import com.android.internal.widget.LockPatternUtils;
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.ShadowDevicePolicyManager;
+import com.android.settings.testutils.shadow.ShadowLockPatternUtils;
import com.android.settings.testutils.shadow.ShadowUtils;
import com.google.android.setupdesign.GlifLayout;
@@ -44,13 +62,21 @@
import org.robolectric.shadows.ShadowDrawable;
@RunWith(RobolectricTestRunner.class)
-@Config(shadows = {SettingsShadowResources.class, ShadowUtils.class})
+@Config(shadows = {
+ SettingsShadowResources.class,
+ ShadowUtils.class,
+ ShadowDevicePolicyManager.class,
+})
public class ChooseLockPasswordTest {
+ private ShadowDevicePolicyManager mShadowDpm;
+
@Before
public void setUp() {
SettingsShadowResources.overrideResource(
com.android.internal.R.string.config_headlineFontFamily, "");
+ mShadowDpm = ShadowDevicePolicyManager.getShadow();
+ mShadowDpm.setPasswordMaximumLength(16);
}
@After
@@ -72,7 +98,7 @@
assertThat(intent.getStringExtra(ChooseLockSettingsHelper.EXTRA_KEY_PASSWORD))
.named("EXTRA_KEY_PASSWORD")
.isEqualTo("password");
- assertThat(intent.getIntExtra(LockPatternUtils.PASSWORD_TYPE_KEY, 0))
+ assertThat(intent.getIntExtra(PASSWORD_TYPE_KEY, 0))
.named("PASSWORD_TYPE_KEY")
.isEqualTo(DevicePolicyManager.PASSWORD_QUALITY_NUMERIC);
assertThat(intent.getIntExtra(Intent.EXTRA_USER_ID, 0))
@@ -84,7 +110,7 @@
public void intentBuilder_setChallenge_shouldAddExtras() {
Intent intent = new IntentBuilder(application)
.setChallenge(12345L)
- .setPasswordQuality(DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC)
+ .setPasswordQuality(PASSWORD_QUALITY_ALPHANUMERIC)
.setUserId(123)
.build();
@@ -94,15 +120,214 @@
assertThat(intent.getLongExtra(ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE, 0L))
.named("EXTRA_KEY_CHALLENGE")
.isEqualTo(12345L);
- assertThat(intent.getIntExtra(LockPatternUtils.PASSWORD_TYPE_KEY, 0))
+ assertThat(intent.getIntExtra(PASSWORD_TYPE_KEY, 0))
.named("PASSWORD_TYPE_KEY")
- .isEqualTo(DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC);
+ .isEqualTo(PASSWORD_QUALITY_ALPHANUMERIC);
assertThat(intent.getIntExtra(Intent.EXTRA_USER_ID, 0))
.named("EXTRA_USER_ID")
.isEqualTo(123);
}
@Test
+ public void intentBuilder_setMinComplexityMedium_hasMinComplexityExtraMedium() {
+ Intent intent = new IntentBuilder(application)
+ .setRequestedMinComplexity(PASSWORD_COMPLEXITY_MEDIUM)
+ .build();
+
+ assertThat(intent.hasExtra(EXTRA_KEY_REQUESTED_MIN_COMPLEXITY)).isTrue();
+ assertThat(intent.getIntExtra(EXTRA_KEY_REQUESTED_MIN_COMPLEXITY, PASSWORD_COMPLEXITY_NONE))
+ .isEqualTo(PASSWORD_COMPLEXITY_MEDIUM);
+ }
+
+ @Test
+ public void intentBuilder_setMinComplexityNotCalled() {
+ Intent intent = new IntentBuilder(application).build();
+
+ assertThat(intent.hasExtra(EXTRA_KEY_REQUESTED_MIN_COMPLEXITY)).isFalse();
+ }
+
+ @Test
+ public void processAndValidatePasswordRequirements_noMinPasswordComplexity() {
+ mShadowDpm.setPasswordQuality(PASSWORD_QUALITY_ALPHABETIC);
+ mShadowDpm.setPasswordMinimumLength(10);
+
+ assertPasswordValidationResult(
+ /* minComplexity= */ PASSWORD_COMPLEXITY_NONE,
+ /* passwordType= */ PASSWORD_QUALITY_ALPHABETIC,
+ /* userEnteredPassword= */ "",
+ "Must contain at least 1 letter",
+ "Must be at least 10 characters");
+ }
+
+ @Test
+ public void processAndValidatePasswordRequirements_minPasswordComplexityStricter_pin() {
+ mShadowDpm.setPasswordQuality(PASSWORD_QUALITY_SOMETHING);
+
+ assertPasswordValidationResult(
+ /* minComplexity= */ PASSWORD_COMPLEXITY_HIGH,
+ /* passwordType= */ PASSWORD_QUALITY_NUMERIC,
+ /* userEnteredPassword= */ "",
+ "PIN must be at least 8 digits");
+ }
+
+ @Test
+ public void processAndValidatePasswordRequirements_minPasswordComplexityStricter_password() {
+ mShadowDpm.setPasswordQuality(PASSWORD_QUALITY_SOMETHING);
+
+ assertPasswordValidationResult(
+ /* minComplexity= */ PASSWORD_COMPLEXITY_MEDIUM,
+ /* passwordType= */ PASSWORD_QUALITY_ALPHABETIC,
+ /* userEnteredPassword= */ "",
+ "Must contain at least 1 letter",
+ "Must be at least 4 characters");
+ }
+
+ @Test
+ public void processAndValidatePasswordRequirements_dpmRestrictionsStricter_password() {
+ mShadowDpm.setPasswordQuality(PASSWORD_QUALITY_ALPHANUMERIC);
+ mShadowDpm.setPasswordMinimumLength(9);
+
+ assertPasswordValidationResult(
+ /* minComplexity= */ PASSWORD_COMPLEXITY_LOW,
+ /* passwordType= */ PASSWORD_QUALITY_ALPHABETIC,
+ /* userEnteredPassword= */ "",
+ "Must contain at least 1 letter",
+ "Must contain at least 1 numerical digit",
+ "Must be at least 9 characters");
+ }
+
+ @Test
+ public void processAndValidatePasswordRequirements_dpmLengthLonger_pin() {
+ mShadowDpm.setPasswordQuality(PASSWORD_QUALITY_NUMERIC);
+ mShadowDpm.setPasswordMinimumLength(11);
+
+ assertPasswordValidationResult(
+ /* minComplexity= */ PASSWORD_COMPLEXITY_MEDIUM,
+ /* passwordType= */ PASSWORD_QUALITY_NUMERIC,
+ /* userEnteredPassword= */ "",
+ "PIN must be at least 11 digits");
+ }
+
+ @Test
+ public void processAndValidatePasswordRequirements_dpmQualityComplex() {
+ mShadowDpm.setPasswordQuality(PASSWORD_QUALITY_COMPLEX);
+ mShadowDpm.setPasswordMinimumSymbols(2);
+
+ assertPasswordValidationResult(
+ /* minComplexity= */ PASSWORD_COMPLEXITY_HIGH,
+ /* passwordType= */ PASSWORD_QUALITY_ALPHABETIC,
+ /* userEnteredPassword= */ "",
+ "Must contain at least 2 special symbols",
+ "Must be at least 6 characters");
+ }
+
+ @Test
+ @Config(shadows = ShadowLockPatternUtils.class)
+ public void processAndValidatePasswordRequirements_numericComplexNoMinComplexity_pinRequested() {
+ mShadowDpm.setPasswordQuality(PASSWORD_QUALITY_NUMERIC_COMPLEX);
+
+ assertPasswordValidationResult(
+ /* minComplexity= */ PASSWORD_COMPLEXITY_NONE,
+ /* passwordType= */ PASSWORD_QUALITY_NUMERIC,
+ /* userEnteredPassword= */ "12345678",
+ "Ascending, descending, or repeated sequence of digits isn't allowed");
+ }
+
+ @Test
+ @Config(shadows = ShadowLockPatternUtils.class)
+ public void processAndValidatePasswordRequirements_numericComplexNoMinComplexity_passwordRequested() {
+ mShadowDpm.setPasswordQuality(PASSWORD_QUALITY_NUMERIC_COMPLEX);
+
+ assertPasswordValidationResult(
+ /* minComplexity= */ PASSWORD_COMPLEXITY_NONE,
+ /* passwordType= */ PASSWORD_QUALITY_ALPHABETIC,
+ /* userEnteredPassword= */ "12345678",
+ "Ascending, descending, or repeated sequence of digits isn't allowed");
+ }
+
+ @Test
+ @Config(shadows = ShadowLockPatternUtils.class)
+ public void processAndValidatePasswordRequirements_numericComplexHighComplexity_pinRequested() {
+ mShadowDpm.setPasswordQuality(PASSWORD_QUALITY_NUMERIC_COMPLEX);
+
+ assertPasswordValidationResult(
+ /* minComplexity= */ PASSWORD_COMPLEXITY_HIGH,
+ /* passwordType= */ PASSWORD_QUALITY_NUMERIC,
+ /* userEnteredPassword= */ "12345678",
+ "Ascending, descending, or repeated sequence of digits isn't allowed");
+ }
+
+ @Test
+ @Config(shadows = ShadowLockPatternUtils.class)
+ public void processAndValidatePasswordRequirements_numericHighComplexity_pinRequested() {
+ mShadowDpm.setPasswordQuality(PASSWORD_QUALITY_NUMERIC);
+
+ assertPasswordValidationResult(
+ /* minComplexity= */ PASSWORD_COMPLEXITY_HIGH,
+ /* passwordType= */ PASSWORD_QUALITY_NUMERIC,
+ /* userEnteredPassword= */ "12345678",
+ "Ascending, descending, or repeated sequence of digits isn't allowed");
+ }
+
+ @Test
+ @Config(shadows = ShadowLockPatternUtils.class)
+ public void processAndValidatePasswordRequirements_numericComplexLowComplexity_passwordRequested() {
+ mShadowDpm.setPasswordQuality(PASSWORD_QUALITY_NUMERIC_COMPLEX);
+
+ assertPasswordValidationResult(
+ /* minComplexity= */ PASSWORD_COMPLEXITY_LOW,
+ /* passwordType= */ PASSWORD_QUALITY_ALPHABETIC,
+ /* userEnteredPassword= */ "12345678",
+ "Must contain at least 1 letter");
+ }
+
+ @Test
+ public void processAndValidatePasswordRequirements_requirementsUpdateAccordingToMinComplexityAndUserInput_empty() {
+ mShadowDpm.setPasswordQuality(PASSWORD_QUALITY_UNSPECIFIED);
+
+ assertPasswordValidationResult(
+ /* minComplexity= */ PASSWORD_COMPLEXITY_HIGH,
+ /* passwordType= */ PASSWORD_QUALITY_ALPHABETIC,
+ /* userEnteredPassword= */ "",
+ "Must contain at least 1 letter",
+ "Must be at least 6 characters");
+ }
+
+ @Test
+ public void processAndValidatePasswordRequirements_requirementsUpdateAccordingToMinComplexityAndUserInput_numeric() {
+ mShadowDpm.setPasswordQuality(PASSWORD_QUALITY_UNSPECIFIED);
+
+ assertPasswordValidationResult(
+ /* minComplexity= */ PASSWORD_COMPLEXITY_HIGH,
+ /* passwordType= */ PASSWORD_QUALITY_ALPHABETIC,
+ /* userEnteredPassword= */ "1",
+ "Must contain at least 1 letter",
+ "Must be at least 6 characters");
+ }
+
+ @Test
+ public void processAndValidatePasswordRequirements_requirementsUpdateAccordingToMinComplexityAndUserInput_alphabetic() {
+ mShadowDpm.setPasswordQuality(PASSWORD_QUALITY_UNSPECIFIED);
+
+ assertPasswordValidationResult(
+ /* minComplexity= */ PASSWORD_COMPLEXITY_HIGH,
+ /* passwordType= */ PASSWORD_QUALITY_ALPHABETIC,
+ /* userEnteredPassword= */ "b",
+ "Must be at least 6 characters");
+ }
+
+ @Test
+ public void processAndValidatePasswordRequirements_requirementsUpdateAccordingToMinComplexityAndUserInput_alphanumeric() {
+ mShadowDpm.setPasswordQuality(PASSWORD_QUALITY_UNSPECIFIED);
+
+ assertPasswordValidationResult(
+ /* minComplexity= */ PASSWORD_COMPLEXITY_HIGH,
+ /* passwordType= */ PASSWORD_QUALITY_ALPHABETIC,
+ /* userEnteredPassword= */ "b1",
+ "Must be at least 6 characters");
+ }
+
+ @Test
public void assertThat_chooseLockIconChanged_WhenFingerprintExtraSet() {
ShadowDrawable drawable = setActivityAndGetIconDrawable(true);
assertThat(drawable.getCreatedFromResId()).isEqualTo(R.drawable.ic_fingerprint_header);
@@ -132,4 +357,18 @@
ChooseLockPasswordFragment fragment = getChooseLockPasswordFragment(passwordActivity);
return Shadows.shadowOf(((GlifLayout) fragment.getView()).getIcon());
}
+
+ private void assertPasswordValidationResult(@PasswordComplexity int minComplexity,
+ int passwordType, String userEnteredPassword, String... expectedValidationResult) {
+ Intent intent = new Intent();
+ intent.putExtra(CONFIRM_CREDENTIALS, false);
+ intent.putExtra(PASSWORD_TYPE_KEY, passwordType);
+ intent.putExtra(EXTRA_KEY_REQUESTED_MIN_COMPLEXITY, minComplexity);
+ ChooseLockPassword activity = buildChooseLockPasswordActivity(intent);
+ ChooseLockPasswordFragment fragment = getChooseLockPasswordFragment(activity);
+ int validateResult = fragment.validatePassword(userEnteredPassword);
+ String[] messages = fragment.convertErrorCodeToMessages(validateResult);
+
+ assertThat(messages).asList().containsExactly((Object[]) expectedValidationResult);
+ }
}
diff --git a/tests/robotests/src/com/android/settings/password/PasswordUtilsTest.java b/tests/robotests/src/com/android/settings/password/PasswordUtilsTest.java
new file mode 100644
index 0000000..845d346
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/password/PasswordUtilsTest.java
@@ -0,0 +1,140 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.password;
+
+import static android.content.pm.PackageManager.PERMISSION_DENIED;
+import static android.content.pm.PackageManager.PERMISSION_GRANTED;
+
+import static com.android.settings.password.PasswordUtils.getCallingAppLabel;
+import static com.android.settings.password.PasswordUtils.isCallingAppPermitted;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.when;
+
+import android.app.IActivityManager;
+import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.os.IBinder;
+import android.os.RemoteException;
+
+import com.android.settings.testutils.shadow.ShadowActivityManager;
+
+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;
+import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.Config;
+
+@RunWith(RobolectricTestRunner.class)
+@Config(shadows = {ShadowActivityManager.class})
+public class PasswordUtilsTest {
+
+ private static final String PACKAGE_NAME = "com.android.app";
+ private static final String PERMISSION = "com.testing.permission";
+ private static final int UID = 1234;
+
+ @Mock
+ private PackageManager mPackageManager;
+ @Mock
+ private ApplicationInfo mApplicationInfo;
+ @Mock
+ private IActivityManager mActivityService;
+ @Mock
+ private IBinder mActivityToken;
+
+ private Context mContext;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+
+ mContext = spy(RuntimeEnvironment.application);
+ when(mContext.getPackageManager()).thenReturn(mPackageManager);
+ ShadowActivityManager.setService(mActivityService);
+ }
+
+ @Test
+ public void getCallingAppLabel_activityServiceThrowsRemoteException_returnsNull()
+ throws Exception {
+ when(mActivityService.getLaunchedFromPackage(mActivityToken))
+ .thenThrow(new RemoteException());
+
+ assertThat(getCallingAppLabel(mContext, mActivityToken)).isNull();
+ }
+
+ @Test
+ public void getCallingAppLabel_activityServiceReturnsSettingsApp_returnsNull()
+ throws Exception {
+ when(mActivityService.getLaunchedFromPackage(mActivityToken))
+ .thenReturn("com.android.settings");
+
+ assertThat(getCallingAppLabel(mContext, mActivityToken)).isNull();
+ }
+
+ @Test
+ public void getCallingAppLabel_packageManagerThrowsNameNotFound_returnsNull() throws Exception {
+ when(mActivityService.getLaunchedFromPackage(mActivityToken))
+ .thenReturn(PACKAGE_NAME);
+ when(mPackageManager.getApplicationInfo(eq(PACKAGE_NAME), anyInt()))
+ .thenThrow(new NameNotFoundException());
+
+ assertThat(getCallingAppLabel(mContext, mActivityToken)).isNull();
+ }
+
+ @Test
+ public void getCallingAppLabel_returnsLabel() throws Exception {
+ when(mActivityService.getLaunchedFromPackage(mActivityToken))
+ .thenReturn(PACKAGE_NAME);
+ when(mPackageManager.getApplicationInfo(eq(PACKAGE_NAME), anyInt()))
+ .thenReturn(mApplicationInfo);
+ when(mApplicationInfo.loadLabel(mPackageManager)).thenReturn("label");
+
+ assertThat(getCallingAppLabel(mContext, mActivityToken)).isEqualTo("label");
+ }
+
+ @Test
+ public void isCallingAppPermitted_permissionGranted_returnsTrue() throws Exception {
+ when(mActivityService.getLaunchedFromUid(mActivityToken)).thenReturn(UID);
+ when(mContext.checkPermission(PERMISSION, -1, UID)).thenReturn(PERMISSION_GRANTED);
+
+ assertThat(isCallingAppPermitted(mContext, mActivityToken, PERMISSION)).isTrue();
+ }
+
+ @Test
+ public void isCallingAppPermitted_permissionDenied_returnsFalse() throws Exception {
+ when(mActivityService.getLaunchedFromUid(mActivityToken)).thenReturn(UID);
+ when(mContext.checkPermission(PERMISSION, -1, UID)).thenReturn(PERMISSION_DENIED);
+
+ assertThat(isCallingAppPermitted(mContext, mActivityToken, PERMISSION)).isFalse();
+ }
+
+ @Test
+ public void isCallingAppPermitted_throwsRemoteException_returnsFalse() throws Exception {
+ when(mActivityService.getLaunchedFromUid(mActivityToken)).thenThrow(new RemoteException());
+
+ assertThat(isCallingAppPermitted(mContext, mActivityToken, PERMISSION)).isFalse();
+ }
+}
diff --git a/tests/robotests/src/com/android/settings/password/SetNewPasswordActivityTest.java b/tests/robotests/src/com/android/settings/password/SetNewPasswordActivityTest.java
index 99738e7..d1b2b74 100644
--- a/tests/robotests/src/com/android/settings/password/SetNewPasswordActivityTest.java
+++ b/tests/robotests/src/com/android/settings/password/SetNewPasswordActivityTest.java
@@ -16,6 +16,16 @@
package com.android.settings.password;
+import static android.Manifest.permission.GET_AND_REQUEST_SCREEN_LOCK_COMPLEXITY;
+import static android.app.admin.DevicePolicyManager.ACTION_SET_NEW_PARENT_PROFILE_PASSWORD;
+import static android.app.admin.DevicePolicyManager.ACTION_SET_NEW_PASSWORD;
+import static android.app.admin.DevicePolicyManager.EXTRA_PASSWORD_COMPLEXITY;
+import static android.app.admin.DevicePolicyManager.PASSWORD_COMPLEXITY_HIGH;
+import static android.app.admin.DevicePolicyManager.PASSWORD_COMPLEXITY_NONE;
+
+import static com.android.settings.password.ChooseLockSettingsHelper.EXTRA_KEY_CALLER_APP_NAME;
+import static com.android.settings.password.ChooseLockSettingsHelper.EXTRA_KEY_REQUESTED_MIN_COMPLEXITY;
+
import static com.google.common.truth.Truth.assertThat;
import android.content.ComponentName;
@@ -23,6 +33,8 @@
import android.os.Bundle;
import android.provider.Settings;
+import com.android.settings.testutils.shadow.ShadowPasswordUtils;
+
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
@@ -31,11 +43,14 @@
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.Shadows;
+import org.robolectric.annotation.Config;
import org.robolectric.shadows.ShadowActivity;
@RunWith(RobolectricTestRunner.class)
public class SetNewPasswordActivityTest {
+ private static final String APP_LABEL = "label";
+
private int mProvisioned;
@Before
@@ -48,6 +63,7 @@
public void tearDown() {
Settings.Global.putInt(RuntimeEnvironment.application.getContentResolver(),
Settings.Global.DEVICE_PROVISIONED, mProvisioned);
+ ShadowPasswordUtils.reset();
}
@Test
@@ -77,4 +93,106 @@
assertThat(intent.getComponent())
.isEqualTo(new ComponentName(activity, SetupChooseLockGeneric.class));
}
+
+ @Test
+ @Config(shadows = {ShadowPasswordUtils.class})
+ public void testLaunchChooseLock_setNewPasswordExtraWithoutPermission() {
+ ShadowPasswordUtils.setCallingAppLabel(APP_LABEL);
+ Settings.Global.putInt(RuntimeEnvironment.application.getContentResolver(),
+ Settings.Global.DEVICE_PROVISIONED, 1);
+
+ Intent intent = new Intent(ACTION_SET_NEW_PASSWORD);
+ intent.putExtra(EXTRA_PASSWORD_COMPLEXITY, PASSWORD_COMPLEXITY_HIGH);
+ SetNewPasswordActivity activity =
+ Robolectric.buildActivity(SetNewPasswordActivity.class, intent).create().get();
+
+ ShadowActivity shadowActivity = Shadows.shadowOf(activity);
+ assertThat(shadowActivity.getNextStartedActivityForResult()).isNull();
+ }
+
+ @Test
+ @Config(shadows = {ShadowPasswordUtils.class})
+ public void testLaunchChooseLock_setNewPasswordExtraWithPermission() {
+ ShadowPasswordUtils.setCallingAppLabel(APP_LABEL);
+ ShadowPasswordUtils.addGrantedPermission(GET_AND_REQUEST_SCREEN_LOCK_COMPLEXITY);
+ Settings.Global.putInt(RuntimeEnvironment.application.getContentResolver(),
+ Settings.Global.DEVICE_PROVISIONED, 1);
+
+ Intent intent = new Intent(ACTION_SET_NEW_PASSWORD);
+ intent.putExtra(EXTRA_PASSWORD_COMPLEXITY, PASSWORD_COMPLEXITY_HIGH);
+ SetNewPasswordActivity activity =
+ Robolectric.buildActivity(SetNewPasswordActivity.class, intent).create().get();
+
+ ShadowActivity shadowActivity = Shadows.shadowOf(activity);
+ Intent actualIntent = shadowActivity.getNextStartedActivityForResult().intent;
+ assertThat(actualIntent.getAction()).isEqualTo(ACTION_SET_NEW_PASSWORD);
+ assertThat(actualIntent.hasExtra(EXTRA_KEY_REQUESTED_MIN_COMPLEXITY)).isTrue();
+ assertThat(actualIntent.getIntExtra(EXTRA_KEY_REQUESTED_MIN_COMPLEXITY, PASSWORD_COMPLEXITY_NONE))
+ .isEqualTo(PASSWORD_COMPLEXITY_HIGH);
+ assertThat(actualIntent.hasExtra(EXTRA_KEY_CALLER_APP_NAME)).isTrue();
+ assertThat(actualIntent.getStringExtra(EXTRA_KEY_CALLER_APP_NAME)).isEqualTo(APP_LABEL);
+ }
+
+ @Test
+ @Config(shadows = {ShadowPasswordUtils.class})
+ public void testLaunchChooseLock_setNewPasswordExtraInvalidValue() {
+ ShadowPasswordUtils.setCallingAppLabel(APP_LABEL);
+ ShadowPasswordUtils.addGrantedPermission(GET_AND_REQUEST_SCREEN_LOCK_COMPLEXITY);
+ Settings.Global.putInt(RuntimeEnvironment.application.getContentResolver(),
+ Settings.Global.DEVICE_PROVISIONED, 1);
+
+ Intent intent = new Intent(ACTION_SET_NEW_PASSWORD);
+ intent.putExtra(EXTRA_PASSWORD_COMPLEXITY, -1);
+ SetNewPasswordActivity activity =
+ Robolectric.buildActivity(SetNewPasswordActivity.class, intent).create().get();
+
+ ShadowActivity shadowActivity = Shadows.shadowOf(activity);
+ Intent actualIntent = shadowActivity.getNextStartedActivityForResult().intent;
+ assertThat(actualIntent.getAction()).isEqualTo(ACTION_SET_NEW_PASSWORD);
+ assertThat(actualIntent.hasExtra(EXTRA_KEY_REQUESTED_MIN_COMPLEXITY)).isFalse();
+ assertThat(actualIntent.hasExtra(EXTRA_KEY_CALLER_APP_NAME)).isTrue();
+ assertThat(actualIntent.getStringExtra(EXTRA_KEY_CALLER_APP_NAME)).isEqualTo(APP_LABEL);
+ }
+
+ @Test
+ @Config(shadows = {ShadowPasswordUtils.class})
+ public void testLaunchChooseLock_setNewPasswordExtraNoneComplexity() {
+ ShadowPasswordUtils.setCallingAppLabel(APP_LABEL);
+ ShadowPasswordUtils.addGrantedPermission(GET_AND_REQUEST_SCREEN_LOCK_COMPLEXITY);
+ Settings.Global.putInt(RuntimeEnvironment.application.getContentResolver(),
+ Settings.Global.DEVICE_PROVISIONED, 1);
+
+ Intent intent = new Intent(ACTION_SET_NEW_PASSWORD);
+ intent.putExtra(EXTRA_PASSWORD_COMPLEXITY, PASSWORD_COMPLEXITY_NONE);
+ SetNewPasswordActivity activity =
+ Robolectric.buildActivity(SetNewPasswordActivity.class, intent).create().get();
+
+ ShadowActivity shadowActivity = Shadows.shadowOf(activity);
+ Intent actualIntent = shadowActivity.getNextStartedActivityForResult().intent;
+ assertThat(actualIntent.getAction()).isEqualTo(ACTION_SET_NEW_PASSWORD);
+ assertThat(actualIntent.hasExtra(EXTRA_KEY_REQUESTED_MIN_COMPLEXITY)).isFalse();
+ assertThat(actualIntent.hasExtra(EXTRA_KEY_CALLER_APP_NAME)).isTrue();
+ assertThat(actualIntent.getStringExtra(EXTRA_KEY_CALLER_APP_NAME)).isEqualTo(APP_LABEL);
+ }
+
+ @Test
+ @Config(shadows = {ShadowPasswordUtils.class})
+ public void testLaunchChooseLock_setNewParentProfilePasswordExtraWithPermission() {
+ ShadowPasswordUtils.setCallingAppLabel(APP_LABEL);
+ ShadowPasswordUtils.addGrantedPermission(GET_AND_REQUEST_SCREEN_LOCK_COMPLEXITY);
+ Settings.Global.putInt(RuntimeEnvironment.application.getContentResolver(),
+ Settings.Global.DEVICE_PROVISIONED, 1);
+
+ Intent intent = new Intent(ACTION_SET_NEW_PARENT_PROFILE_PASSWORD);
+ intent.putExtra(EXTRA_PASSWORD_COMPLEXITY, PASSWORD_COMPLEXITY_HIGH);
+ SetNewPasswordActivity activity =
+ Robolectric.buildActivity(SetNewPasswordActivity.class, intent).create().get();
+
+ ShadowActivity shadowActivity = Shadows.shadowOf(activity);
+ Intent actualIntent = shadowActivity.getNextStartedActivityForResult().intent;
+ assertThat(actualIntent.getAction()).isEqualTo(ACTION_SET_NEW_PARENT_PROFILE_PASSWORD);
+ assertThat(actualIntent.hasExtra(EXTRA_KEY_REQUESTED_MIN_COMPLEXITY)).isFalse();
+ assertThat(actualIntent.hasExtra(EXTRA_KEY_CALLER_APP_NAME)).isTrue();
+ assertThat(actualIntent.getStringExtra(EXTRA_KEY_CALLER_APP_NAME)).isEqualTo(APP_LABEL);
+ }
}
diff --git a/tests/robotests/src/com/android/settings/password/SetupChooseLockGenericTest.java b/tests/robotests/src/com/android/settings/password/SetupChooseLockGenericTest.java
new file mode 100644
index 0000000..63bdc38
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/password/SetupChooseLockGenericTest.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.settings.password;
+
+import static android.Manifest.permission.GET_AND_REQUEST_SCREEN_LOCK_COMPLEXITY;
+import static android.app.admin.DevicePolicyManager.PASSWORD_COMPLEXITY_HIGH;
+
+import static com.android.settings.password.ChooseLockSettingsHelper.EXTRA_KEY_REQUESTED_MIN_COMPLEXITY;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.robolectric.Shadows.shadowOf;
+
+import android.content.Intent;
+
+import com.android.settings.testutils.shadow.ShadowLockPatternUtils;
+import com.android.settings.testutils.shadow.ShadowPasswordUtils;
+import com.android.settings.testutils.shadow.ShadowUserManager;
+import com.android.settings.testutils.shadow.ShadowUtils;
+
+import org.junit.After;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.Robolectric;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.Shadows;
+import org.robolectric.annotation.Config;
+import org.robolectric.shadows.ShadowActivity;
+
+@RunWith(RobolectricTestRunner.class)
+@Config(shadows = {
+ ShadowUserManager.class,
+ ShadowUtils.class,
+ ShadowLockPatternUtils.class,
+})
+public class SetupChooseLockGenericTest {
+
+ @After
+ public void tearDown() {
+ ShadowPasswordUtils.reset();
+ }
+
+ @Test
+ public void setupChooseLockGenericPasswordComplexityExtraWithoutPermission() {
+ Intent intent = new Intent("com.android.settings.SETUP_LOCK_SCREEN");
+ intent.putExtra(EXTRA_KEY_REQUESTED_MIN_COMPLEXITY, PASSWORD_COMPLEXITY_HIGH);
+ SetupChooseLockGeneric activity =
+ Robolectric.buildActivity(SetupChooseLockGeneric.class, intent).create().get();
+
+ ShadowActivity shadowActivity = Shadows.shadowOf(activity);
+ assertThat(shadowActivity.isFinishing()).isTrue();
+ }
+
+ @Test
+ @Config(shadows = {ShadowPasswordUtils.class})
+ public void setupChooseLockGenericPasswordComplexityExtraWithPermission() {
+ ShadowPasswordUtils.addGrantedPermission(GET_AND_REQUEST_SCREEN_LOCK_COMPLEXITY);
+
+ Intent intent = new Intent("com.android.settings.SETUP_LOCK_SCREEN");
+ intent.putExtra(EXTRA_KEY_REQUESTED_MIN_COMPLEXITY, PASSWORD_COMPLEXITY_HIGH);
+ SetupChooseLockGeneric activity =
+ Robolectric.buildActivity(SetupChooseLockGeneric.class, intent).create().get();
+
+ ShadowActivity shadowActivity = Shadows.shadowOf(activity);
+ assertThat(shadowActivity.isFinishing()).isFalse();
+ }
+}
diff --git a/tests/robotests/src/com/android/settings/password/SetupChooseLockPasswordTest.java b/tests/robotests/src/com/android/settings/password/SetupChooseLockPasswordTest.java
index 946ab69..e0c6ded 100644
--- a/tests/robotests/src/com/android/settings/password/SetupChooseLockPasswordTest.java
+++ b/tests/robotests/src/com/android/settings/password/SetupChooseLockPasswordTest.java
@@ -38,7 +38,7 @@
import com.android.settings.widget.ScrollToParentEditText;
import com.google.android.setupcompat.PartnerCustomizationLayout;
-import com.google.android.setupcompat.template.ButtonFooterMixin;
+import com.google.android.setupcompat.template.FooterBarMixin;
import org.junit.After;
import org.junit.Before;
@@ -142,7 +142,7 @@
final PartnerCustomizationLayout layout = activity.findViewById(R.id.setup_wizard_layout);
final Button skipOrClearButton =
- layout.getMixin(ButtonFooterMixin.class).getSecondaryButtonView();
+ layout.getMixin(FooterBarMixin.class).getSecondaryButtonView();
assertThat(skipOrClearButton).isNotNull();
assertThat(skipOrClearButton.getVisibility()).isEqualTo(View.VISIBLE);
@@ -165,7 +165,7 @@
final PartnerCustomizationLayout layout = activity.findViewById(R.id.setup_wizard_layout);
final Button skipOrClearButton =
- layout.getMixin(ButtonFooterMixin.class).getSecondaryButtonView();
+ layout.getMixin(FooterBarMixin.class).getSecondaryButtonView();
assertThat(skipOrClearButton.isEnabled()).isTrue();
assertThat(skipOrClearButton.getVisibility()).isEqualTo(View.GONE);
diff --git a/tests/robotests/src/com/android/settings/password/SetupChooseLockPatternTest.java b/tests/robotests/src/com/android/settings/password/SetupChooseLockPatternTest.java
index e45869f..430c535 100644
--- a/tests/robotests/src/com/android/settings/password/SetupChooseLockPatternTest.java
+++ b/tests/robotests/src/com/android/settings/password/SetupChooseLockPatternTest.java
@@ -41,7 +41,7 @@
import com.android.settings.testutils.shadow.ShadowUtils;
import com.google.android.setupcompat.PartnerCustomizationLayout;
-import com.google.android.setupcompat.template.ButtonFooterMixin;
+import com.google.android.setupcompat.template.FooterBarMixin;
import org.junit.Before;
import org.junit.Test;
@@ -148,7 +148,7 @@
public void skipButton_shouldBeVisible_duringNonFingerprintFlow() {
PartnerCustomizationLayout layout = mActivity.findViewById(R.id.setup_wizard_layout);
final Button skipOrClearButton =
- layout.getMixin(ButtonFooterMixin.class).getSecondaryButtonView();
+ layout.getMixin(FooterBarMixin.class).getSecondaryButtonView();
assertThat(skipOrClearButton).isNotNull();
assertThat(skipOrClearButton.getVisibility()).isEqualTo(View.VISIBLE);
@@ -163,7 +163,7 @@
PartnerCustomizationLayout layout = mActivity.findViewById(R.id.setup_wizard_layout);
final Button skipOrClearButton =
- layout.getMixin(ButtonFooterMixin.class).getSecondaryButtonView();
+ layout.getMixin(FooterBarMixin.class).getSecondaryButtonView();
assertThat(skipOrClearButton.getVisibility()).isEqualTo(View.VISIBLE);
assertThat(skipOrClearButton.isEnabled()).isTrue();
@@ -177,7 +177,7 @@
PartnerCustomizationLayout layout = mActivity.findViewById(R.id.setup_wizard_layout);
final Button skipOrClearButton =
- layout.getMixin(ButtonFooterMixin.class).getSecondaryButtonView();
+ layout.getMixin(FooterBarMixin.class).getSecondaryButtonView();
assertThat(skipOrClearButton.isEnabled()).isTrue();
assertThat(skipOrClearButton.getVisibility()).isEqualTo(View.VISIBLE);
assertThat(skipOrClearButton.getText())
diff --git a/tests/robotests/src/com/android/settings/security/ConfigureKeyGuardDialogTest.java b/tests/robotests/src/com/android/settings/security/ConfigureKeyGuardDialogTest.java
deleted file mode 100644
index 49a4e92..0000000
--- a/tests/robotests/src/com/android/settings/security/ConfigureKeyGuardDialogTest.java
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.settings.security;
-
-import static org.mockito.Mockito.doNothing;
-import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.verify;
-
-import android.content.DialogInterface;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.robolectric.RobolectricTestRunner;
-import org.robolectric.shadows.androidx.fragment.FragmentController;
-
-@RunWith(RobolectricTestRunner.class)
-public class ConfigureKeyGuardDialogTest {
-
- @Test
- public void displayDialog_clickPositiveButton_launchSetNewPassword() {
- final FragmentController<ConfigureKeyGuardDialog> fragmentController =
- FragmentController.of(new ConfigureKeyGuardDialog());
- final ConfigureKeyGuardDialog fragment = spy(fragmentController.get());
- doNothing().when(fragment).startPasswordSetup();
- fragmentController.create().start().resume();
- fragment.onClick(null /* dialog */, DialogInterface.BUTTON_POSITIVE);
- fragment.onDismiss(null /* dialog */);
-
- verify(fragment).startPasswordSetup();
- }
-}
diff --git a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowActivityManager.java b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowActivityManager.java
index 38d658c..76bdaef 100644
--- a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowActivityManager.java
+++ b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowActivityManager.java
@@ -17,6 +17,7 @@
package com.android.settings.testutils.shadow;
import android.app.ActivityManager;
+import android.app.IActivityManager;
import org.robolectric.annotation.Implementation;
import org.robolectric.annotation.Implements;
@@ -24,6 +25,7 @@
@Implements(ActivityManager.class)
public class ShadowActivityManager {
private static int sCurrentUserId = 0;
+ private static IActivityManager sService = null;
@Implementation
protected static int getCurrentUser() {
@@ -33,4 +35,13 @@
public static void setCurrentUser(int userId) {
sCurrentUserId = userId;
}
+
+ @Implementation
+ public static IActivityManager getService() {
+ return sService;
+ }
+
+ public static void setService(IActivityManager service) {
+ sService = service;
+ }
}
diff --git a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowDevicePolicyManager.java b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowDevicePolicyManager.java
index 6d2dbef..ca75916 100644
--- a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowDevicePolicyManager.java
+++ b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowDevicePolicyManager.java
@@ -1,5 +1,7 @@
package com.android.settings.testutils.shadow;
+import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
+
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
@@ -23,6 +25,10 @@
private boolean mIsAdminActiveAsUser = false;
private ComponentName mDeviceOwnerComponentName;
private int mDeviceOwnerUserId = -1;
+ private int mPasswordMinQuality = PASSWORD_QUALITY_UNSPECIFIED;
+ private int mPasswordMaxLength = 16;
+ private int mPasswordMinLength = 0;
+ private int mPasswordMinSymbols = 0;
public void setShortSupportMessageForUser(ComponentName admin, int userHandle, String message) {
mSupportMessagesMap.put(Objects.hash(admin, userHandle), message);
@@ -70,6 +76,42 @@
mDeviceOwnerComponentName = admin;
}
+ @Implementation
+ public int getPasswordQuality(ComponentName admin, int userHandle) {
+ return mPasswordMinQuality;
+ }
+
+ public void setPasswordQuality(int quality) {
+ mPasswordMinQuality = quality;
+ }
+
+ @Implementation
+ public int getPasswordMinimumLength(ComponentName admin, int userHandle) {
+ return mPasswordMinLength;
+ }
+
+ public void setPasswordMinimumLength(int length) {
+ mPasswordMinLength = length;
+ }
+
+ @Implementation
+ public int getPasswordMinimumSymbols(ComponentName admin, int userHandle) {
+ return mPasswordMinSymbols;
+ }
+
+ public void setPasswordMinimumSymbols(int numOfSymbols) {
+ mPasswordMinSymbols = numOfSymbols;
+ }
+
+ @Implementation
+ public int getPasswordMaximumLength(int quality) {
+ return mPasswordMaxLength;
+ }
+
+ public void setPasswordMaximumLength(int length) {
+ mPasswordMaxLength = length;
+ }
+
public static ShadowDevicePolicyManager getShadow() {
return (ShadowDevicePolicyManager) Shadow.extract(
RuntimeEnvironment.application.getSystemService(DevicePolicyManager.class));
diff --git a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowLockPatternUtils.java b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowLockPatternUtils.java
index 663ab91..7ce098d 100644
--- a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowLockPatternUtils.java
+++ b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowLockPatternUtils.java
@@ -59,4 +59,14 @@
public static void setDeviceEncryptionEnabled(boolean deviceEncryptionEnabled) {
sDeviceEncryptionEnabled = deviceEncryptionEnabled;
}
+
+ @Implementation
+ protected byte[] getPasswordHistoryHashFactor(String currentPassword, int userId) {
+ return null;
+ }
+
+ @Implementation
+ protected boolean checkPasswordHistory(String passwordToCheck, byte[] hashFactor, int userId) {
+ return false;
+ }
}
diff --git a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowPasswordUtils.java b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowPasswordUtils.java
new file mode 100644
index 0000000..6a5c4ae
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowPasswordUtils.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.testutils.shadow;
+
+import android.content.Context;
+import android.os.IBinder;
+
+import com.android.settings.password.PasswordUtils;
+
+import org.robolectric.annotation.Implementation;
+import org.robolectric.annotation.Implements;
+
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Set;
+
+@Implements(PasswordUtils.class)
+public class ShadowPasswordUtils {
+
+ private static String sCallingAppLabel;
+ private static Set<String> sGrantedPermissions;
+
+ public static void reset() {
+ sCallingAppLabel = null;
+ sGrantedPermissions = null;
+ }
+
+ @Implementation
+ protected static boolean isCallingAppPermitted(Context context, IBinder activityToken,
+ String permission) {
+ if (sGrantedPermissions == null) {
+ return false;
+ }
+ return sGrantedPermissions.contains(permission);
+ }
+
+ public static void addGrantedPermission(String... permissions) {
+ if (sGrantedPermissions == null) {
+ sGrantedPermissions = new HashSet<>();
+ }
+ sGrantedPermissions.addAll(Arrays.asList(permissions));
+ }
+
+ @Implementation
+ protected static String getCallingAppLabel(Context context, IBinder activityToken) {
+ return sCallingAppLabel;
+ }
+
+ public static void setCallingAppLabel(String label) {
+ sCallingAppLabel = label;
+ }
+}
diff --git a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowUserManager.java b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowUserManager.java
index d8703be..9a18c1f 100644
--- a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowUserManager.java
+++ b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowUserManager.java
@@ -99,15 +99,6 @@
}
@Implementation
- protected boolean isManagedProfile(@UserIdInt int userId) {
- return mManagedProfiles.contains(userId);
- }
-
- public void addManagedProfile(int userId) {
- mManagedProfiles.add(userId);
- }
-
- @Implementation
protected boolean isQuietModeEnabled(UserHandle userHandle) {
return mIsQuietModeEnabled;
}
diff --git a/tests/robotests/src/com/android/settings/wifi/NetworkRequestDialogFragmentTest.java b/tests/robotests/src/com/android/settings/wifi/NetworkRequestDialogFragmentTest.java
index d84d665..0286d07 100644
--- a/tests/robotests/src/com/android/settings/wifi/NetworkRequestDialogFragmentTest.java
+++ b/tests/robotests/src/com/android/settings/wifi/NetworkRequestDialogFragmentTest.java
@@ -27,16 +27,19 @@
import android.content.Context;
import android.content.DialogInterface;
+import android.content.Intent;
import android.net.wifi.ScanResult;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiManager;
import android.net.wifi.WifiManager.NetworkRequestUserSelectionCallback;
import android.os.Bundle;
import android.widget.Button;
+import android.widget.TextView;
import androidx.appcompat.app.AlertDialog;
import androidx.fragment.app.FragmentActivity;
+import com.android.settings.R;
import com.android.settings.testutils.shadow.ShadowAlertDialogCompat;
import com.android.settings.wifi.NetworkRequestErrorDialogFragment.ERROR_DIALOG_TYPE;
import com.android.settingslib.wifi.AccessPoint;
@@ -63,6 +66,7 @@
private static final String KEY_SSID = "key_ssid";
private static final String KEY_SECURITY = "key_security";
+ private static final String TEST_APP_NAME = "TestAppName";
private FragmentActivity mActivity;
private NetworkRequestDialogFragment networkRequestDialogFragment;
@@ -71,7 +75,9 @@
@Before
public void setUp() {
- mActivity = Robolectric.setupActivity(FragmentActivity.class);
+ mActivity = Robolectric.buildActivity(FragmentActivity.class,
+ new Intent().putExtra(NetworkRequestDialogFragment.EXTRA_APP_NAME,
+ TEST_APP_NAME)).setup().get();
networkRequestDialogFragment = spy(NetworkRequestDialogFragment.newInstance());
mContext = spy(RuntimeEnvironment.application);
@@ -88,6 +94,17 @@
}
@Test
+ public void display_shouldShowTitleWithAppName() {
+ networkRequestDialogFragment.show(mActivity.getSupportFragmentManager(), /* tag */ null);
+ final AlertDialog alertDialog = ShadowAlertDialogCompat.getLatestAlertDialog();
+
+ final String targetTitle = mContext.getString(
+ R.string.network_connection_request_dialog_title, TEST_APP_NAME);
+ final TextView view = alertDialog.findViewById(R.id.network_request_title_text);
+ assertThat(view.getText()).isEqualTo(targetTitle);
+ }
+
+ @Test
public void clickPositiveButton_shouldCloseTheDialog() {
networkRequestDialogFragment.show(mActivity.getSupportFragmentManager(), null);
AlertDialog alertDialog = ShadowAlertDialogCompat.getLatestAlertDialog();
diff --git a/tests/robotests/src/com/android/settings/wifi/WifiConfigControllerTest.java b/tests/robotests/src/com/android/settings/wifi/WifiConfigControllerTest.java
index 7ebb18e..fd25f7d 100644
--- a/tests/robotests/src/com/android/settings/wifi/WifiConfigControllerTest.java
+++ b/tests/robotests/src/com/android/settings/wifi/WifiConfigControllerTest.java
@@ -27,6 +27,7 @@
import static org.mockito.Mockito.when;
import android.content.Context;
+import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiManager;
import android.os.ServiceSpecificException;
import android.security.KeyStore;
@@ -39,6 +40,7 @@
import com.android.settings.R;
import com.android.settings.testutils.shadow.ShadowConnectivityManager;
+import com.android.settings.wifi.details.WifiPrivacyPreferenceController;
import com.android.settingslib.wifi.AccessPoint;
import org.junit.Before;
@@ -386,4 +388,61 @@
@Override
KeyStore getKeyStore() { return mKeyStore; }
}
+
+ @Test
+ public void loadMacRandomizedValue_shouldPersistentAsDefault() {
+ final Spinner privacySetting = mView.findViewById(R.id.privacy_settings);
+ final int prefPersist =
+ WifiPrivacyPreferenceController.translateMacRandomizedValueToPrefValue(
+ WifiConfiguration.RANDOMIZATION_PERSISTENT);
+
+ assertThat(privacySetting.getVisibility()).isEqualTo(View.VISIBLE);
+ assertThat(privacySetting.getSelectedItemPosition()).isEqualTo(prefPersist);
+ }
+
+ @Test
+ public void loadSavedMacRandomizedPersistentValue_shouldCorrectMacValue() {
+ checkSavedMacRandomizedValue(WifiConfiguration.RANDOMIZATION_PERSISTENT);
+ }
+
+ @Test
+ public void loadSavedMacRandomizedNoneValue_shouldCorrectMacValue() {
+ checkSavedMacRandomizedValue(WifiConfiguration.RANDOMIZATION_NONE);
+ }
+
+ private void checkSavedMacRandomizedValue(int macRandomizedValue) {
+ when(mAccessPoint.isSaved()).thenReturn(true);
+ final WifiConfiguration mockWifiConfig = mock(WifiConfiguration.class);
+ when(mAccessPoint.getConfig()).thenReturn(mockWifiConfig);
+ mockWifiConfig.macRandomizationSetting = macRandomizedValue;
+ mController = new TestWifiConfigController(mConfigUiBase, mView, mAccessPoint,
+ WifiConfigUiBase.MODE_CONNECT);
+
+ final Spinner privacySetting = mView.findViewById(R.id.privacy_settings);
+ final int expectedPrefValue =
+ WifiPrivacyPreferenceController.translateMacRandomizedValueToPrefValue(
+ macRandomizedValue);
+
+ assertThat(privacySetting.getVisibility()).isEqualTo(View.VISIBLE);
+ assertThat(privacySetting.getSelectedItemPosition()).isEqualTo(expectedPrefValue);
+ }
+
+ @Test
+ public void saveMacRandomizedValue_noChanged_shouldPersistentAsDefault() {
+ WifiConfiguration config = mController.getConfig();
+ assertThat(config.macRandomizationSetting).isEqualTo(
+ WifiConfiguration.RANDOMIZATION_PERSISTENT);
+ }
+
+ @Test
+ public void saveMacRandomizedValue_ChangedToNone_shouldGetNone() {
+ final Spinner privacySetting = mView.findViewById(R.id.privacy_settings);
+ final int prefMacNone =
+ WifiPrivacyPreferenceController.translateMacRandomizedValueToPrefValue(
+ WifiConfiguration.RANDOMIZATION_NONE);
+ privacySetting.setSelection(prefMacNone);
+
+ WifiConfiguration config = mController.getConfig();
+ assertThat(config.macRandomizationSetting).isEqualTo(WifiConfiguration.RANDOMIZATION_NONE);
+ }
}
diff --git a/tests/robotests/src/com/android/settings/wifi/slice/WifiSliceTest.java b/tests/robotests/src/com/android/settings/wifi/slice/WifiSliceTest.java
index ae352cc..dd99e55 100644
--- a/tests/robotests/src/com/android/settings/wifi/slice/WifiSliceTest.java
+++ b/tests/robotests/src/com/android/settings/wifi/slice/WifiSliceTest.java
@@ -139,4 +139,11 @@
verify(mResolver).notifyChange(WIFI_SLICE_URI, null);
}
+
+ @Test
+ public void onConnectedChanged_shouldNotifyChange() {
+ mWifiScanWorker.onConnectedChanged();
+
+ verify(mResolver).notifyChange(WIFI_SLICE_URI, null);
+ }
}
diff --git a/tests/unit/src/com/android/settings/EncryptionInterstitialTest.java b/tests/unit/src/com/android/settings/EncryptionInterstitialTest.java
index 3b4abfe..503a78c 100644
--- a/tests/unit/src/com/android/settings/EncryptionInterstitialTest.java
+++ b/tests/unit/src/com/android/settings/EncryptionInterstitialTest.java
@@ -36,7 +36,7 @@
import androidx.test.runner.AndroidJUnit4;
import com.google.android.setupcompat.PartnerCustomizationLayout;
-import com.google.android.setupcompat.template.ButtonFooterMixin;
+import com.google.android.setupcompat.template.FooterBarMixin;
import org.junit.After;
import org.junit.Before;
@@ -70,7 +70,7 @@
new Intent(mContext, EncryptionInterstitial.class)
.putExtra("extra_unlock_method_intent", new Intent("test.unlock.intent")));
final PartnerCustomizationLayout layout = activity.findViewById(R.id.setup_wizard_layout);
- layout.getMixin(ButtonFooterMixin.class).getPrimaryButtonView().performClick();
+ layout.getMixin(FooterBarMixin.class).getPrimaryButtonView().performClick();
mActivityMonitor.waitForActivityWithTimeout(1000);
assertEquals(1, mActivityMonitor.getHits());
@@ -85,7 +85,7 @@
new Intent(mContext, EncryptionInterstitial.class)
.putExtra("extra_unlock_method_intent", new Intent("test.unlock.intent")));
final PartnerCustomizationLayout layout = activity.findViewById(R.id.setup_wizard_layout);
- layout.getMixin(ButtonFooterMixin.class).getSecondaryButtonView().performClick();
+ layout.getMixin(FooterBarMixin.class).getSecondaryButtonView().performClick();
mActivityMonitor.waitForActivityWithTimeout(1000);
assertEquals(1, mActivityMonitor.getHits());
diff --git a/tests/unit/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollFinishTest.java b/tests/unit/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollFinishTest.java
index 0a46403..589680d 100644
--- a/tests/unit/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollFinishTest.java
+++ b/tests/unit/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollFinishTest.java
@@ -37,7 +37,7 @@
import com.android.settings.R;
import com.google.android.setupcompat.PartnerCustomizationLayout;
-import com.google.android.setupcompat.template.ButtonFooterMixin;
+import com.google.android.setupcompat.template.FooterBarMixin;
import org.junit.Rule;
import org.junit.Test;
@@ -62,7 +62,7 @@
PartnerCustomizationLayout layout =
mActivityRule.getActivity().findViewById(R.id.setup_wizard_layout);
- layout.getMixin(ButtonFooterMixin.class).getPrimaryButtonView().performClick();
+ layout.getMixin(FooterBarMixin.class).getPrimaryButtonView().performClick();
intended(hasComponent(enrollingComponent));
assertFalse(mActivityRule.getActivity().isFinishing());
@@ -79,7 +79,7 @@
PartnerCustomizationLayout layout =
mActivityRule.getActivity().findViewById(R.id.setup_wizard_layout);
- layout.getMixin(ButtonFooterMixin.class).getPrimaryButtonView().performClick();
+ layout.getMixin(FooterBarMixin.class).getPrimaryButtonView().performClick();
intended(hasComponent(enrollingComponent));
assertTrue(mActivityRule.getActivity().isFinishing());
diff --git a/tests/unit/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollIntroductionTest.java b/tests/unit/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollIntroductionTest.java
index 5078cc2..454de3d 100644
--- a/tests/unit/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollIntroductionTest.java
+++ b/tests/unit/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollIntroductionTest.java
@@ -33,7 +33,7 @@
import com.android.settings.R;
import com.google.android.setupcompat.PartnerCustomizationLayout;
-import com.google.android.setupcompat.template.ButtonFooterMixin;
+import com.google.android.setupcompat.template.FooterBarMixin;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
@@ -84,7 +84,7 @@
assertNotNull(errorTextView.getText().toString());
PartnerCustomizationLayout layout = mActivity.findViewById(R.id.setup_wizard_layout);
- final Button nextButton = layout.getMixin(ButtonFooterMixin.class).getPrimaryButtonView();
+ final Button nextButton = layout.getMixin(FooterBarMixin.class).getPrimaryButtonView();
assertEquals(View.GONE, nextButton.getVisibility());
}
diff --git a/tests/unit/src/com/android/settings/password/ChooseLockPasswordTest.java b/tests/unit/src/com/android/settings/password/ChooseLockPasswordTest.java
index 269be26..e12390c 100644
--- a/tests/unit/src/com/android/settings/password/ChooseLockPasswordTest.java
+++ b/tests/unit/src/com/android/settings/password/ChooseLockPasswordTest.java
@@ -43,7 +43,7 @@
import com.android.settings.R;
import com.google.android.setupcompat.PartnerCustomizationLayout;
-import com.google.android.setupcompat.template.ButtonFooterMixin;
+import com.google.android.setupcompat.template.FooterBarMixin;
import org.junit.Before;
import org.junit.Test;
@@ -67,7 +67,7 @@
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
final PartnerCustomizationLayout layout = activity.findViewById(R.id.setup_wizard_layout);
assertThat(
- layout.getMixin(ButtonFooterMixin.class).getSecondaryButtonView().getVisibility())
+ layout.getMixin(FooterBarMixin.class).getSecondaryButtonView().getVisibility())
.isEqualTo(View.GONE);
}
@@ -79,7 +79,7 @@
onView(withId(R.id.password_entry)).perform(ViewActions.typeText("1234"))
.perform(pressKey(KeyEvent.KEYCODE_ENTER));
assertThat(
- layout.getMixin(ButtonFooterMixin.class).getSecondaryButtonView().getVisibility())
+ layout.getMixin(FooterBarMixin.class).getSecondaryButtonView().getVisibility())
.isEqualTo(View.GONE);
}
@@ -92,10 +92,10 @@
.perform(pressKey(KeyEvent.KEYCODE_ENTER))
.perform(ViewActions.typeText("1"));
// clear should be present if text field contains content
- assertThat(layout.getMixin(ButtonFooterMixin.class).getSecondaryButtonView().getText())
+ assertThat(layout.getMixin(FooterBarMixin.class).getSecondaryButtonView().getText())
.isEqualTo(mContext.getString(R.string.lockpassword_clear_label));
assertThat(
- layout.getMixin(ButtonFooterMixin.class).getSecondaryButtonView().getVisibility())
+ layout.getMixin(FooterBarMixin.class).getSecondaryButtonView().getVisibility())
.isEqualTo(View.VISIBLE);
}
}
diff --git a/tests/unit/src/com/android/settings/password/SetupChooseLockPasswordAppTest.java b/tests/unit/src/com/android/settings/password/SetupChooseLockPasswordAppTest.java
index 67c5cce..cc0253f 100644
--- a/tests/unit/src/com/android/settings/password/SetupChooseLockPasswordAppTest.java
+++ b/tests/unit/src/com/android/settings/password/SetupChooseLockPasswordAppTest.java
@@ -45,7 +45,7 @@
import com.android.settings.R;
import com.google.android.setupcompat.PartnerCustomizationLayout;
-import com.google.android.setupcompat.template.ButtonFooterMixin;
+import com.google.android.setupcompat.template.FooterBarMixin;
import org.junit.Before;
import org.junit.Rule;
@@ -75,7 +75,7 @@
SetupChooseLockPassword activity = mActivityTestRule.launchActivity(null);
PartnerCustomizationLayout layout = activity.findViewById(R.id.setup_wizard_layout);
final Button skipOrClearButton =
- layout.getMixin(ButtonFooterMixin.class).getSecondaryButtonView();
+ layout.getMixin(FooterBarMixin.class).getSecondaryButtonView();
assertThat(skipOrClearButton.getText()).isEqualTo(mContext.getString(R.string.skip_label));
assertThat(skipOrClearButton.getVisibility()).isEqualTo(View.VISIBLE);
@@ -87,7 +87,7 @@
public void clearIsNotShown_when_activityLaunchedInitially() {
SetupChooseLockPassword activity = mActivityTestRule.launchActivity(null);
PartnerCustomizationLayout layout = activity.findViewById(R.id.setup_wizard_layout);
- assertThat(layout.getMixin(ButtonFooterMixin.class).getSecondaryButtonView().getText())
+ assertThat(layout.getMixin(FooterBarMixin.class).getSecondaryButtonView().getText())
.isEqualTo(mContext.getString(R.string.lockpassword_clear_label));
}
@@ -98,7 +98,7 @@
onView(withId(R.id.password_entry)).perform(ViewActions.typeText("1234"))
.perform(pressKey(KeyEvent.KEYCODE_ENTER));
assertThat(
- layout.getMixin(ButtonFooterMixin.class).getSecondaryButtonView().getVisibility())
+ layout.getMixin(FooterBarMixin.class).getSecondaryButtonView().getVisibility())
.isEqualTo(View.GONE);
}
@@ -114,7 +114,7 @@
.perform(ViewActions.typeText("1"));
// clear should be present if text field contains content
assertThat(
- layout.getMixin(ButtonFooterMixin.class).getSecondaryButtonView().getVisibility())
+ layout.getMixin(FooterBarMixin.class).getSecondaryButtonView().getVisibility())
.isEqualTo(View.VISIBLE);
}
}
diff --git a/tests/unit/src/com/android/settings/wifi/dpp/WifiDppChooseSavedWifiNetworkFragmentTest.java b/tests/unit/src/com/android/settings/wifi/dpp/WifiDppChooseSavedWifiNetworkFragmentTest.java
index d2f6e6c..6ad6377 100644
--- a/tests/unit/src/com/android/settings/wifi/dpp/WifiDppChooseSavedWifiNetworkFragmentTest.java
+++ b/tests/unit/src/com/android/settings/wifi/dpp/WifiDppChooseSavedWifiNetworkFragmentTest.java
@@ -29,6 +29,7 @@
import android.content.Context;
import android.content.Intent;
+import android.provider.Settings;
import androidx.fragment.app.FragmentManager;
import androidx.test.InstrumentationRegistry;
import androidx.test.rule.ActivityTestRule;
@@ -88,9 +89,8 @@
@Test
public void clickCancelButton_processWifiDppQrCodeIntent_shouldFinish() {
- final Intent intent =
- new Intent(WifiDppConfiguratorActivity.ACTION_PROCESS_WIFI_DPP_QR_CODE);
- intent.putExtra(WifiDppUtils.EXTRA_QR_CODE, VALID_WIFI_DPP_QR_CODE);
+ final Intent intent = new Intent(Settings.ACTION_PROCESS_WIFI_EASY_CONNECT_QR_CODE);
+ intent.putExtra(Settings.EXTRA_QR_CODE, VALID_WIFI_DPP_QR_CODE);
final WifiDppConfiguratorActivity hostActivity = mActivityRule.launchActivity(intent);
onView(withText(resourceString(CANCEL))).perform(click());
diff --git a/tests/unit/src/com/android/settings/wifi/dpp/WifiDppConfiguratorActivityTest.java b/tests/unit/src/com/android/settings/wifi/dpp/WifiDppConfiguratorActivityTest.java
index 215b7e2..76df764 100644
--- a/tests/unit/src/com/android/settings/wifi/dpp/WifiDppConfiguratorActivityTest.java
+++ b/tests/unit/src/com/android/settings/wifi/dpp/WifiDppConfiguratorActivityTest.java
@@ -18,12 +18,18 @@
import static com.google.common.truth.Truth.assertThat;
+import android.app.Instrumentation;
import android.content.Intent;
import android.content.pm.ActivityInfo;
+import android.os.RemoteException;
+import android.provider.Settings;
+import android.support.test.uiautomator.UiDevice;
+import androidx.test.InstrumentationRegistry;
import androidx.test.rule.ActivityTestRule;
import androidx.test.runner.AndroidJUnit4;
+import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -38,6 +44,13 @@
public final ActivityTestRule<WifiDppConfiguratorActivity> mActivityRule =
new ActivityTestRule<>(WifiDppConfiguratorActivity.class);
+ private UiDevice mDevice;
+
+ @Before
+ public void setUp() {
+ mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
+ }
+
@Test
public void launchActivity_qrCodeScanner_shouldNotAutoFinish() {
Intent intent = new Intent(WifiDppConfiguratorActivity.ACTION_CONFIGURATOR_QR_CODE_SCANNER);
@@ -65,9 +78,8 @@
@Test
public void launchActivity_chooseSavedWifiNetwork_shouldNotAutoFinish() {
- Intent intent = new Intent(
- WifiDppConfiguratorActivity.ACTION_PROCESS_WIFI_DPP_QR_CODE);
- intent.putExtra(WifiDppUtils.EXTRA_QR_CODE, VALID_WIFI_DPP_QR_CODE);
+ Intent intent = new Intent(Settings.ACTION_PROCESS_WIFI_EASY_CONNECT_QR_CODE);
+ intent.putExtra(Settings.EXTRA_QR_CODE, VALID_WIFI_DPP_QR_CODE);
mActivityRule.launchActivity(intent);
@@ -124,12 +136,17 @@
// setWifiDppQrCode and check if getWifiDppQrCode correctly after rotation
mActivityRule.launchActivity(intent);
mActivityRule.getActivity().setWifiDppQrCode(wifiQrCode);
- mActivityRule.getActivity().setRequestedOrientation(
- ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
- mActivityRule.getActivity().setRequestedOrientation(
- ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
- WifiQrCode restoredWifiDppQrCode = mActivityRule.getActivity().getWifiDppQrCode();
+ try {
+ mDevice.setOrientationLeft();
+ mDevice.setOrientationNatural();
+ mDevice.setOrientationRight();
+ mDevice.setOrientationNatural();
+ } catch (RemoteException e) {
+ throw new RuntimeException(e);
+ }
+
+ WifiQrCode restoredWifiDppQrCode = mActivityRule.getActivity().getWifiDppQrCode();
assertThat(restoredWifiDppQrCode).isNotNull();
assertThat(restoredWifiDppQrCode.getQrCode()).isEqualTo(VALID_WIFI_DPP_QR_CODE);
}
@@ -138,17 +155,22 @@
public void rotateScreen_shouldGetCorrectWifiNetworkConfig() {
WifiNetworkConfig wifiNetworkConfig = new WifiNetworkConfig("WPA", "WifiSsid", "password",
/* hiddenSsid */ false, /* networkId */ 0);
- Intent intent = new Intent(
- WifiDppConfiguratorActivity.ACTION_PROCESS_WIFI_DPP_QR_CODE);
- intent.putExtra(WifiDppUtils.EXTRA_QR_CODE, VALID_WIFI_DPP_QR_CODE);
+ Intent intent = new Intent(Settings.ACTION_PROCESS_WIFI_EASY_CONNECT_QR_CODE);
+ intent.putExtra(Settings.EXTRA_QR_CODE, VALID_WIFI_DPP_QR_CODE);
// setWifiNetworkConfig and check if getWifiNetworkConfig correctly after rotation
mActivityRule.launchActivity(intent);
mActivityRule.getActivity().setWifiNetworkConfig(wifiNetworkConfig);
- mActivityRule.getActivity().setRequestedOrientation(
- ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
- mActivityRule.getActivity().setRequestedOrientation(
- ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
+
+ try {
+ mDevice.setOrientationLeft();
+ mDevice.setOrientationNatural();
+ mDevice.setOrientationRight();
+ mDevice.setOrientationNatural();
+ } catch (RemoteException e) {
+ throw new RuntimeException(e);
+ }
+
WifiNetworkConfig restoredWifiNetworkConfig =
mActivityRule.getActivity().getWifiNetworkConfig();
diff --git a/tests/unit/src/com/android/settings/wifi/dpp/WifiNetworkListFragmentTest.java b/tests/unit/src/com/android/settings/wifi/dpp/WifiNetworkListFragmentTest.java
index 8626dee..18d62c2 100644
--- a/tests/unit/src/com/android/settings/wifi/dpp/WifiNetworkListFragmentTest.java
+++ b/tests/unit/src/com/android/settings/wifi/dpp/WifiNetworkListFragmentTest.java
@@ -103,8 +103,7 @@
/** Launch the activity via an Intent with a String extra. */
private void launchActivity(String extraName, String extraValue) {
- final Intent intent = new Intent(
- WifiDppConfiguratorActivity.ACTION_PROCESS_WIFI_DPP_QR_CODE);
+ final Intent intent = new Intent(Settings.ACTION_PROCESS_WIFI_EASY_CONNECT_QR_CODE);
if (extraName != null && extraValue != null) {
intent.putExtra(extraName, extraValue);
}
@@ -168,7 +167,7 @@
setupConnectedAccessPoint();
when(mWifiTracker.isConnected()).thenReturn(true);
- launchActivity(WifiDppUtils.EXTRA_QR_CODE, TEST_DPP_URL);
+ launchActivity(Settings.EXTRA_QR_CODE, TEST_DPP_URL);
callOnWifiStateChanged(WifiManager.WIFI_STATE_ENABLED);
onView(withText(resourceString(WIFI_DISPLAY_STATUS_CONNECTED))).check(