Snap for 5626839 from 5540373d4f to qt-qpr1-release

Change-Id: Id7de678fc0df7858766ebba5d06691bcd8bdb1b2
This commit is contained in:
android-build-team Robot
2019-06-01 23:08:40 +00:00
51 changed files with 1695 additions and 194 deletions

View File

@@ -2507,7 +2507,7 @@
<intent-filter> <intent-filter>
<action android:name="com.android.settings.action.SETTINGS"/> <action android:name="com.android.settings.action.SETTINGS"/>
</intent-filter> </intent-filter>
<meta-data android:name="com.android.settings.order" android:value="-160"/> <meta-data android:name="com.android.settings.order" android:value="-440"/>
<meta-data android:name="com.android.settings.category" <meta-data android:name="com.android.settings.category"
android:value="com.android.settings.category.ia.apps"/> android:value="com.android.settings.category.ia.apps"/>
<meta-data android:name="com.android.settings.summary" <meta-data android:name="com.android.settings.summary"

View File

@@ -0,0 +1,24 @@
<!--
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.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="@android:color/white"
android:pathData="M18 17v-6c0-3.07-1.63-5.64-4.5-6.32V4c0-0.83-0.67-1.5-1.5-1.5s-1.5 0.67 -1.5 1.5v0.68C7.64 5.36 6 7.92 6 11v6H4v2h16v-2h-2zm-2 0H8v-6c0-2.48 1.51-4.5 4-4.5s4 2.02 4 4.5v6zm-6 3h4c0 1.1-0.9 2-2 2s-2-0.9-2-2zm12-9h-2c0-2.74-1.23-5.19-3.16-6.84l1.41-1.41C20.54 4.77 22 7.71 22 11zM5.75 2.75l1.41 1.41C5.23 5.81 4 8.26 4 11H2c0-3.29 1.46-6.23 3.75-8.25z" />
</vector>

View File

@@ -0,0 +1,31 @@
<!--
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
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FFFFFFFF"
android:pathData="M10.67,21H7v-1h3.13c-0.27-0.63-0.46-1.3-0.56-2H7V6h10v3.5c0.69,0,1.36,0.1,2,0.28V3 c0-1.1-0.9-1.99-2-1.99L7,1C5.9,1,5,1.9,5,3v18c0,1.1,0.9,2,2,2h5.52C11.79,22.45,11.16,21.77,10.67,21z M7,3h10v1H7V3z" />
<path
android:fillColor="#FFFFFFFF"
android:pathData="M17,12.5c2.48,0,4.5,2.02,4.5,4.5s-2.02,4.5-4.5,4.5s-4.5-2.02-4.5-4.5S14.52,12.5,17,12.5 M17,11 c-3.31,0-6,2.69-6,6s2.69,6,6,6c3.31,0,6-2.69,6-6S20.31,11,17,11L17,11z" />
<path
android:fillColor="#FFFFFFFF"
android:pathData="M17,14v3l-2.12,2.12C15.42,19.66,16.17,20,17,20c1.66,0,3-1.34,3-3S18.66,14,17,14z" />
</vector>

View File

@@ -87,11 +87,9 @@
<com.android.internal.widget.LockPatternView <com.android.internal.widget.LockPatternView
android:id="@+id/lockPattern" android:id="@+id/lockPattern"
android:layout_width="288dp" android:layout_width="match_parent"
android:layout_height="288dp" android:layout_height="match_parent"
android:layout_marginStart="-42dp" android:layout_gravity="center"/>
android:layout_marginEnd="-42dp"
android:layout_gravity="center_vertical"/>
<TextView <TextView
style="@style/TextAppearance.ErrorText" style="@style/TextAppearance.ErrorText"

View File

@@ -0,0 +1,41 @@
<?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="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:background="?android:attr/selectableItemBackground" >
<ImageView
android:id="@+id/color_icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="@dimen/sim_label_padding"
android:layout_gravity="center_vertical" />
<TextView
android:id="@+id/color_label"
android:gravity="center_vertical"
android:layout_height="wrap_content"
android:layout_width="0dp"
android:layout_weight="1"
android:paddingTop="@dimen/sim_label_padding"
android:paddingBottom="@dimen/sim_label_padding"
android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Subhead"
android:textColor="?android:attr/textColorPrimary"/>
</LinearLayout>

View File

@@ -21,44 +21,89 @@
<LinearLayout <LinearLayout
android:orientation="vertical" android:orientation="vertical"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="wrap_content">
android:padding="@dimen/sim_content_padding">
<EditText <LinearLayout
android:id="@+id/edittext" android:orientation="vertical"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:inputType="text" android:paddingEnd="@dimen/sim_content_padding"
android:maxLength="50" android:paddingStart="@dimen/sim_content_padding">
android:singleLine="true">
<requestFocus/>
</EditText>
<TextView <TextView
style="@style/device_info_dialog_label" android:id="@+id/name_label"
android:id="@+id/operator_name_label" android:layout_width="match_parent"
android:layout_width="match_parent" android:layout_height="wrap_content"
android:layout_height="wrap_content" android:paddingTop="@dimen/sim_label_padding"
android:text="@string/status_operator"/> android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Subhead"
<TextView android:textColor="?android:attr/textColorPrimary"
style="@style/device_info_dialog_value" android:text="@string/mobile_network_sim_name_label"/>
android:id="@+id/operator_name_value"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/device_info_not_available"/>
<TextView <EditText
style="@style/device_info_dialog_label" android:id="@+id/name_edittext"
android:id="@+id/number_label" android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="text"
android:paddingTop="@dimen/sim_label_padding"
android:maxLength="50"
android:singleLine="true"/>
<TextView
android:id="@+id/color_label"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="@dimen/sim_label_padding"
android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Subhead"
android:textColor="?android:attr/textColorPrimary"
android:text="@string/mobile_network_sim_color_label"/>
</LinearLayout>
<Spinner
android:id="@+id/color_spinner"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="@string/status_number_sim_status"/> android:layout_marginStart="@dimen/sim_color_spinner_padding"
<TextView android:layout_marginEnd="@dimen/sim_color_spinner_padding"/>
style="@style/device_info_dialog_value"
android:id="@+id/number_value" <LinearLayout
android:orientation="vertical"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="@string/device_info_not_available"/> android:paddingEnd="@dimen/sim_content_padding"
android:paddingStart="@dimen/sim_content_padding">
<TextView
android:id="@+id/operator_name_label"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="@dimen/sim_label_padding"
android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Subhead"
android:textColor="?android:attr/textColorPrimary"
android:text="@string/status_operator"/>
<TextView
android:id="@+id/operator_name_value"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/device_info_not_available"/>
<TextView
android:id="@+id/number_label"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="@dimen/sim_label_padding"
android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Subhead"
android:textColor="?android:attr/textColorPrimary"
android:text="@string/status_number_sim_status"/>
<TextView
android:id="@+id/number_value"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/device_info_not_available"/>
</LinearLayout>
</LinearLayout> </LinearLayout>
</ScrollView> </ScrollView>

View File

@@ -24,7 +24,7 @@
android:padding="@dimen/notification_importance_toggle_marginTop" android:padding="@dimen/notification_importance_toggle_marginTop"
android:orientation="vertical"> android:orientation="vertical">
<RelativeLayout <com.android.settings.notification.NotificationButtonRelativeLayout
android:id="@+id/alert" android:id="@+id/alert"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
@@ -33,7 +33,7 @@
android:focusable="true"> android:focusable="true">
<ImageView <ImageView
android:id="@+id/alert_icon" android:id="@+id/alert_icon"
android:src="@drawable/ic_notifications" android:src="@drawable/ic_notifications_alert"
android:background="@android:color/transparent" android:background="@android:color/transparent"
android:layout_gravity="center" android:layout_gravity="center"
android:layout_width="wrap_content" android:layout_width="wrap_content"
@@ -65,7 +65,7 @@
android:layout_below="@id/alert_icon" android:layout_below="@id/alert_icon"
android:textAppearance="@style/TextAppearance.NotificationImportanceDetail" android:textAppearance="@style/TextAppearance.NotificationImportanceDetail"
android:visibility="gone" /> android:visibility="gone" />
</RelativeLayout> </com.android.settings.notification.NotificationButtonRelativeLayout>
<RelativeLayout <RelativeLayout
android:id="@+id/silence" android:id="@+id/silence"

View File

@@ -0,0 +1,106 @@
<?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
-->
<!-- This file is copied from preference_radio.xml with modification to
support an extra clickable icon on the opposite side horizontally -->
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:settings="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?android:attr/selectableItemBackground"
android:gravity="center_vertical"
android:minHeight="?android:attr/listPreferredItemHeightSmall"
android:paddingEnd="?android:attr/listPreferredItemPaddingEnd">
<LinearLayout
android:id="@android:id/widget_frame"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:gravity="center"
android:minWidth="56dp"
android:layout_marginEnd="16dp"
android:orientation="vertical" />
<LinearLayout
android:id="@+id/icon_frame"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:minWidth="32dp"
android:orientation="horizontal"
android:layout_marginEnd="16dp"
android:paddingTop="4dp"
android:paddingBottom="4dp">
<androidx.preference.internal.PreferenceImageView
android:id="@android:id/icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
settings:maxWidth="@dimen/secondary_app_icon_size"
settings:maxHeight="@dimen/secondary_app_icon_size" />
</LinearLayout>
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="vertical"
android:paddingTop="16dp"
android:paddingBottom="16dp">
<TextView android:id="@android:id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:singleLine="true"
android:textAppearance="@style/TextAppearance.TileTitle"
android:ellipsize="marquee"
android:fadingEdge="horizontal" />
<TextView android:id="@android:id/summary"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:textAppearance="@style/TextAppearance.Small"
android:textAlignment="viewStart"
android:textColor="?android:attr/textColorSecondary" />
</LinearLayout>
<LinearLayout
android:id="@+id/radio_extra_widget_container"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:orientation="horizontal"
android:gravity="center_vertical">
<View
android:id="@+id/radio_extra_widget_divider"
android:layout_width="@dimen/vertical_divider_width"
android:layout_height="match_parent"
android:layout_marginTop="36dp"
android:layout_marginBottom="36dp"
android:layout_marginStart="8dp"
android:background="?android:attr/dividerVertical" />
<ImageView
android:id="@+id/radio_extra_widget"
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:paddingStart="16dp"
android:paddingEnd="16dp"
android:src="@drawable/ic_settings_about"
android:contentDescription="@string/information_label"
android:layout_gravity="center"
android:background="?android:attr/selectableItemBackground" />
</LinearLayout>
</LinearLayout>

View File

@@ -31,6 +31,10 @@
<style name="Theme.SubSettings" parent="Theme.SubSettings.Base"/> <style name="Theme.SubSettings" parent="Theme.SubSettings.Base"/>
<style name="ThemeOverlay.SwitchBar.Settings" parent="ThemeOverlay.SwitchBar.Settings.Base">
<item name="android:textColorPrimaryInverse">@android:color/black</item>
</style>
<style name="Theme.AlertDialog.Base" parent="@style/Theme.AppCompat.DayNight.Dialog.Alert"> <style name="Theme.AlertDialog.Base" parent="@style/Theme.AppCompat.DayNight.Dialog.Alert">
<item name="colorAccent">@*android:color/accent_device_default_dark</item> <item name="colorAccent">@*android:color/accent_device_default_dark</item>
<item name="android:colorBackground">@color/dialog_background</item> <item name="android:colorBackground">@color/dialog_background</item>

View File

@@ -166,6 +166,7 @@
<dimen name="sim_dialog_margin_bottom">16dip</dimen> <dimen name="sim_dialog_margin_bottom">16dip</dimen>
<!-- SIM Dialog padding --> <!-- SIM Dialog padding -->
<dimen name="sim_dialog_padding">8dip</dimen> <dimen name="sim_dialog_padding">8dip</dimen>
<dimen name="sim_color_spinner_padding">12dip</dimen>
<dimen name="sim_label_padding">16dip</dimen> <dimen name="sim_label_padding">16dip</dimen>
<dimen name="sim_content_padding">24dip</dimen> <dimen name="sim_content_padding">24dip</dimen>
<!-- Sim Card Name length --> <!-- Sim Card Name length -->

View File

@@ -885,7 +885,7 @@
<!-- Message shown in summary field when face unlock is set up. [CHAR LIMIT=40] --> <!-- Message shown in summary field when face unlock is set up. [CHAR LIMIT=40] -->
<string name="security_settings_face_preference_summary">Face added</string> <string name="security_settings_face_preference_summary">Face added</string>
<!-- Message shown in summary field when face unlock is not set up. [CHAR LIMIT=54] --> <!-- Message shown in summary field when face unlock is not set up. [CHAR LIMIT=54] -->
<string name="security_settings_face_preference_summary_none">Tap to set up face unlock</string> <string name="security_settings_face_preference_summary_none">Set up face unlock</string>
<!-- Title shown for menu item that launches face settings or enrollment. [CHAR LIMIT=32] --> <!-- Title shown for menu item that launches face settings or enrollment. [CHAR LIMIT=32] -->
<string name="security_settings_face_preference_title">Face unlock</string> <string name="security_settings_face_preference_title">Face unlock</string>
<!-- Introduction title shown in face enrollment education screen [CHAR LIMIT=40] --> <!-- Introduction title shown in face enrollment education screen [CHAR LIMIT=40] -->
@@ -955,25 +955,25 @@
<!-- Text shown on a toggle which allows or disallows the device to use face unlock for apps. This will be presented to the user together with the context of security_settings_face_settings_use_face_category. [CHAR LIMIT=30] --> <!-- Text shown on a toggle which allows or disallows the device to use face unlock for apps. This will be presented to the user together with the context of security_settings_face_settings_use_face_category. [CHAR LIMIT=30] -->
<string name="security_settings_face_settings_use_face_for_apps">App sign-in \u0026 payments</string> <string name="security_settings_face_settings_use_face_for_apps">App sign-in \u0026 payments</string>
<!-- Title for a category shown for the face settings page, followed by items that the user can toggle on/off to require/disable. --> <!-- Title for a category shown for the face settings page, followed by items that the user can toggle on/off to require/disable. -->
<string name="security_settings_face_settings_require_category">Require for face unlock</string> <string name="security_settings_face_settings_require_category">Requirements for face unlock</string>
<!-- Text shown on a toggle which disables/enables face unlock, depending if the user's eyes are open. [CHAR LIMIT=30] --> <!-- Text shown on a toggle which disables/enables face unlock, depending if the user's eyes are open. [CHAR LIMIT=30] -->
<string name="security_settings_face_settings_require_attention">Open eyes looking at screen</string> <string name="security_settings_face_settings_require_attention">Require eyes to be open</string>
<!-- Text shown on the details of a toggle which disables/enables face unlock, depending if the user's eyes are open. [CHAR LIMIT=70] --> <!-- Text shown on the details of a toggle which disables/enables face unlock, depending if the user's eyes are open. [CHAR LIMIT=70] -->
<string name="security_settings_face_settings_require_attention_details">To unlock the phone, always require looking at the screen with your eyes open</string> <string name="security_settings_face_settings_require_attention_details">To unlock the phone, your eyes must be open</string>
<!-- When authenticating in apps, always require confirmation (e.g. confirm button) after a face is authenticated. [CHAR LIMIT=50] --> <!-- When authenticating in apps, always require confirmation (e.g. confirm button) after a face is authenticated. [CHAR LIMIT=50] -->
<string name="security_settings_face_settings_require_confirmation">Confirm button</string> <string name="security_settings_face_settings_require_confirmation">Always require confirmation</string>
<!-- When authenticating in apps, always require confirmation (e.g. confirm button) after a face is authenticated. [CHAR LIMIT=70] --> <!-- When authenticating in apps, always require confirmation (e.g. confirm button) after a face is authenticated. [CHAR LIMIT=70] -->
<string name="security_settings_face_settings_require_confirmation_details">When authenticating for apps, always require confirmation</string> <string name="security_settings_face_settings_require_confirmation_details">When using face unlock in apps, always require confirmation step</string>
<!-- Button text in face settings which removes the user's faces from the device [CHAR LIMIT=20] --> <!-- Button text in face settings which removes the user's faces from the device [CHAR LIMIT=20] -->
<string name="security_settings_face_settings_remove_face_data">Delete face data</string> <string name="security_settings_face_settings_remove_face_data">Delete face data</string>
<!-- Button text in face settings which lets the user enroll their face [CHAR LIMIT=40] --> <!-- Button text in face settings which lets the user enroll their face [CHAR LIMIT=40] -->
<string name="security_settings_face_settings_enroll">Set up new face unlock</string> <string name="security_settings_face_settings_enroll">Set up face unlock</string>
<!-- Text shown in face settings explaining what your face can be used for. [CHAR LIMIT=NONE] --> <!-- Text shown in face settings explaining what your face can be used for. [CHAR LIMIT=NONE] -->
<string name="security_settings_face_settings_footer">Use face unlock to unlock your device, sign in to apps, and confirm payments.\n\nKeep in mind:\nLooking at the phone can unlock it when you don\u2019t intend to.\n\nYour phone can be unlocked by someone else if it\u2019s held up to your face while your eyes are open.\n\nYour phone can be unlocked by someone who looks a lot like you, say, an identical sibling.</string> <string name="security_settings_face_settings_footer">Use face unlock to unlock your device, sign in to apps, and confirm payments.\n\nKeep in mind:\nLooking at the phone can unlock it when you don\u2019t intend to.\n\nYour phone can be unlocked by someone else if it\u2019s held up to your face while your eyes are open.\n\nYour phone can be unlocked by someone who looks a lot like you, say, an identical sibling.</string>
<!-- Dialog title shown when the user removes an enrollment [CHAR LIMIT=35] --> <!-- Dialog title shown when the user removes an enrollment [CHAR LIMIT=35] -->
<string name="security_settings_face_settings_remove_dialog_title">Delete face data?</string> <string name="security_settings_face_settings_remove_dialog_title">Delete face data?</string>
<!-- Dialog contents shown when the user removes an enrollment [CHAR LIMIT=NONE] --> <!-- Dialog contents shown when the user removes an enrollment [CHAR LIMIT=NONE] -->
<string name="security_settings_face_settings_remove_dialog_details">Data recorded by face unlock will be permanently and securely deleted. After removal, you will need your PIN, pattern, or password to unlock your phone, sign in to apps, and confirm payments.</string> <string name="security_settings_face_settings_remove_dialog_details">The images and biometric data used by face unlock will be permanently and securely deleted. After removal, you will need your PIN, pattern, or password to unlock your phone, sign in to apps, and confirm payments.</string>
<!-- Fingerprint enrollment and settings --><skip /> <!-- Fingerprint enrollment and settings --><skip />
@@ -1075,11 +1075,11 @@
<!-- Dialog text shown when the user tries to skip setting up a screen lock, warning that they can't continue to set fingerprint. (default) [CHAR LIMIT=NONE] --> <!-- Dialog text shown when the user tries to skip setting up a screen lock, warning that they can't continue to set fingerprint. (default) [CHAR LIMIT=NONE] -->
<string name="fingerprint_lock_screen_setup_skip_dialog_text" product="default">Protect your phone with a screen lock option so no one will be able to use it if it is lost or stolen. You also need a screen lock option to set up fingerprint. Tap Cancel, then set a PIN, pattern, or password.</string> <string name="fingerprint_lock_screen_setup_skip_dialog_text" product="default">Protect your phone with a screen lock option so no one will be able to use it if it is lost or stolen. You also need a screen lock option to set up fingerprint. Tap Cancel, then set a PIN, pattern, or password.</string>
<!-- Dialog text shown when the user tries to skip setting up a screen lock, warning that they can't continue to set face unlock. (tablet) [CHAR LIMIT=NONE] --> <!-- Dialog text shown when the user tries to skip setting up a screen lock, warning that they can't continue to set face unlock. (tablet) [CHAR LIMIT=NONE] -->
<string name="face_lock_screen_setup_skip_dialog_text" product="tablet">Protect your tablet with a screen lock option so no one will be able to use it if it is lost or stolen. You also need a screen lock option to set up face unlock. Tap Cancel, then set a PIN, pattern, or password.</string> <string name="face_lock_screen_setup_skip_dialog_text" product="tablet">By protecting your tablet with a screen lock option, no one will be able to use it if it is lost or stolen. You also need a screen lock option to set up face unlock. To go back, tap Cancel. </string>
<!-- Dialog text shown when the user tries to skip setting up a screen lock, warning that they can't continue to set face unlock. (device) [CHAR LIMIT=NONE] --> <!-- Dialog text shown when the user tries to skip setting up a screen lock, warning that they can't continue to set face unlock. (device) [CHAR LIMIT=NONE] -->
<string name="face_lock_screen_setup_skip_dialog_text" product="device">Protect your device with a screen lock option so no one will be able to use it if it is lost or stolen. You also need a screen lock option to set up face unlock. Tap Cancel, then set a PIN, pattern, or password.</string> <string name="face_lock_screen_setup_skip_dialog_text" product="device">By protecting your device with a screen lock option, no one will be able to use it if it is lost or stolen. You also need a screen lock option to set up face unlock. To go back, tap Cancel. </string>
<!-- Dialog text shown when the user tries to skip setting up a screen lock, warning that they can't continue to set face unlock. (default) [CHAR LIMIT=NONE] --> <!-- Dialog text shown when the user tries to skip setting up a screen lock, warning that they can't continue to set face unlock. (default) [CHAR LIMIT=NONE] -->
<string name="face_lock_screen_setup_skip_dialog_text" product="default">Protect your phone with a screen lock option so no one will be able to use it if it is lost or stolen. You also need a screen lock option to set up face unlock. Tap Cancel, then set a PIN, pattern, or password.</string> <string name="face_lock_screen_setup_skip_dialog_text" product="default">By protecting your phone with a screen lock option, no one will be able to use it if it is lost or stolen. You also need a screen lock option to set up face unlock. To go back, tap Cancel.</string>
<!-- Title of dialog shown when the user tries to skip setting up a PIN, warning them of potential consequences of not doing so [CHAR LIMIT=48]--> <!-- Title of dialog shown when the user tries to skip setting up a PIN, warning them of potential consequences of not doing so [CHAR LIMIT=48]-->
<string name="lock_screen_pin_skip_title">Skip PIN setup?</string> <string name="lock_screen_pin_skip_title">Skip PIN setup?</string>
<!-- Title of dialog shown when the user tries to skip setting up a password, warning them of potential consequences of not doing so [CHAR LIMIT=48]--> <!-- Title of dialog shown when the user tries to skip setting up a password, warning them of potential consequences of not doing so [CHAR LIMIT=48]-->
@@ -2833,7 +2833,7 @@
<!-- Setting option summary when adaptive sleep is off [CHAR LIMIT=NONE] --> <!-- Setting option summary when adaptive sleep is off [CHAR LIMIT=NONE] -->
<string name="adaptive_sleep_summary_off">Off</string> <string name="adaptive_sleep_summary_off">Off</string>
<!-- Description about the feature adaptive sleep [CHAR LIMIT=NONE]--> <!-- Description about the feature adaptive sleep [CHAR LIMIT=NONE]-->
<string name="adaptive_sleep_description">Prevents your screen from turning off if youre looking at it.</string> <string name="adaptive_sleep_description">Keep screen on when viewing it</string>
<!-- Description feature's privacy sensitive details to make sure users understand what feature users, what it saves/sends etc [CHAR LIMIT=NONE]--> <!-- Description feature's privacy sensitive details to make sure users understand what feature users, what it saves/sends etc [CHAR LIMIT=NONE]-->
<string name="adaptive_sleep_privacy">Screen attention uses the front camera to see if someone is looking at the screen. It works on device, and images are never stored or sent to Google.</string> <string name="adaptive_sleep_privacy">Screen attention uses the front camera to see if someone is looking at the screen. It works on device, and images are never stored or sent to Google.</string>
@@ -7976,6 +7976,15 @@
<!-- Configure Notifications: Title for the option controlling notifications on the lockscreen. [CHAR LIMIT=30] --> <!-- Configure Notifications: Title for the option controlling notifications on the lockscreen. [CHAR LIMIT=30] -->
<string name="lock_screen_notifications_title">Lock screen</string> <string name="lock_screen_notifications_title">Lock screen</string>
<!-- Configure lock screen: Title for the option of unlocking directly to home. [CHAR LIMIT=30] -->
<string name="lockscreen_bypass_title">Skip lock screen</string>
<!-- Configure lock screen: Summary for the option of unlocking directly to home. [CHAR LIMIT=60] -->
<string name="lockscreen_bypass_summary">After face unlock, go directly to last used screen</string>
<!-- Configure lock screen: Search keywords for the option of unlocking directly to home. [CHAR LIMIT=60] -->
<string name="keywords_lockscreen_bypass">Lock screen, Lockscreen, Skip, Bypass</string>
<!-- Configure Notifications: Title for the option controlling notifications for work profile. [CHAR LIMIT=30] --> <!-- Configure Notifications: Title for the option controlling notifications for work profile. [CHAR LIMIT=30] -->
<string name="locked_work_profile_notification_title">When work profile is locked</string> <string name="locked_work_profile_notification_title">When work profile is locked</string>
@@ -10199,7 +10208,7 @@
<!-- Message for the alert dialog which says that the current default home app does not support gesture navigation. [CHAR LIMIT=NONE] --> <!-- Message for the alert dialog which says that the current default home app does not support gesture navigation. [CHAR LIMIT=NONE] -->
<string name="gesture_not_supported_dialog_message">Not supported by your default home app, <xliff:g id="default_home_app" example="Pixel Launcher">%s</xliff:g></string> <string name="gesture_not_supported_dialog_message">Not supported by your default home app, <xliff:g id="default_home_app" example="Pixel Launcher">%s</xliff:g></string>
<!-- Positive button for the alert dialog when gesture nav not supported by launcher [CHAR LIMIT=40] --> <!-- Positive button for the alert dialog when gesture nav not supported by launcher [CHAR LIMIT=60] -->
<string name="gesture_not_supported_positive_button">Switch default home app</string> <string name="gesture_not_supported_positive_button">Switch default home app</string>
<!-- Content description for the Information icon [CHAR LIMIT=30] --> <!-- Content description for the Information icon [CHAR LIMIT=30] -->
@@ -10952,10 +10961,14 @@
subscription in various places in the Settings app. The default name is typically just the subscription in various places in the Settings app. The default name is typically just the
carrier name, but especially in multi-SIM configurations users may want to use a different carrier name, but especially in multi-SIM configurations users may want to use a different
name. [CHAR LIMIT=40] --> name. [CHAR LIMIT=40] -->
<string name="mobile_network_sim_name">SIM name</string> <string name="mobile_network_sim_name">SIM name &amp; color</string>
<!-- Label on the confirmation button of a dialog that lets a user set the display name of a <!-- Label for an item listing the name of the SIM that the user has specified. [CHAR LIMIT=40] -->
mobile network subscription [CHAR LIMIT=20] --> <string name="mobile_network_sim_name_label">Name</string>
<string name="mobile_network_sim_name_rename">Rename</string> <!-- Label for an item listing the color of the SIM that the user has specified. [CHAR LIMIT=40] -->
<string name="mobile_network_sim_color_label">Color (used by compatible apps)</string>
<!-- Label on the confirmation button of a dialog that lets a user set the display name and
color of a mobile network subscription [CHAR LIMIT=20] -->
<string name="mobile_network_sim_name_rename">Save</string>
<!-- Label for the on position of a switch on the mobile network details page which allows <!-- Label for the on position of a switch on the mobile network details page which allows
disabling/enabling a SIM. The SIM is enabled in this state. [CHAR LIMIT=40] --> disabling/enabling a SIM. The SIM is enabled in this state. [CHAR LIMIT=40] -->
<string name="mobile_network_use_sim_on">Use SIM</string> <string name="mobile_network_use_sim_on">Use SIM</string>

View File

@@ -90,7 +90,7 @@
<item name="android:backgroundDimEnabled">false</item> <item name="android:backgroundDimEnabled">false</item>
</style> </style>
<style name="ThemeOverlay.SwitchBar.Settings" parent="@*android:style/ThemeOverlay.DeviceDefault.ActionBar"> <style name="ThemeOverlay.SwitchBar.Settings.Base" parent="@*android:style/ThemeOverlay.DeviceDefault.ActionBar">
<item name="android:elevation">1dp</item> <item name="android:elevation">1dp</item>
<item name="switchBarMarginStart">@dimen/switchbar_subsettings_margin_start</item> <item name="switchBarMarginStart">@dimen/switchbar_subsettings_margin_start</item>
<item name="switchBarMarginEnd">@dimen/switchbar_subsettings_margin_end</item> <item name="switchBarMarginEnd">@dimen/switchbar_subsettings_margin_end</item>
@@ -99,6 +99,8 @@
<item name="switchBarRestrictionIcon">@*android:drawable/ic_info</item> <item name="switchBarRestrictionIcon">@*android:drawable/ic_info</item>
</style> </style>
<style name="ThemeOverlay.SwitchBar.Settings" parent="ThemeOverlay.SwitchBar.Settings.Base"/>
<style name="Widget.SwitchBar.Switch" parent="@android:style/Widget.Material.CompoundButton.Switch"> <style name="Widget.SwitchBar.Switch" parent="@android:style/Widget.Material.CompoundButton.Switch">
<item name="android:trackTint">@color/switchbar_switch_track_tint</item> <item name="android:trackTint">@color/switchbar_switch_track_tint</item>
<item name="android:thumbTint">@color/switchbar_switch_thumb_tint</item> <item name="android:thumbTint">@color/switchbar_switch_thumb_tint</item>

View File

@@ -62,6 +62,14 @@
android:summary="@string/summary_placeholder" android:summary="@string/summary_placeholder"
settings:searchable="false"/> settings:searchable="false"/>
<!-- Bypass lock screen -->
<SwitchPreference
android:key="privacy_lockscreen_bypass"
android:title="@string/lockscreen_bypass_title"
android:summary="@string/lockscreen_bypass_summary"
settings:keywords="@string/keywords_lockscreen_bypass"
settings:controller="com.android.settings.security.LockscreenBypassPreferenceController" />
<!-- Privacy Service --> <!-- Privacy Service -->
<PreferenceCategory <PreferenceCategory
android:key="privacy_services" android:key="privacy_services"

View File

@@ -30,6 +30,13 @@
android:summary="@string/summary_placeholder" android:summary="@string/summary_placeholder"
settings:keywords="@string/keywords_lock_screen_notif"/> settings:keywords="@string/keywords_lock_screen_notif"/>
<SwitchPreference
android:key="security_lockscreen_bypass"
android:title="@string/lockscreen_bypass_title"
android:summary="@string/lockscreen_bypass_summary"
settings:searchable="false"
settings:controller="com.android.settings.security.LockscreenBypassPreferenceController" />
<com.android.settingslib.RestrictedSwitchPreference <com.android.settingslib.RestrictedSwitchPreference
android:key="security_lockscreen_add_users_when_locked" android:key="security_lockscreen_add_users_when_locked"
android:title="@string/user_add_on_lockscreen_menu" android:title="@string/user_add_on_lockscreen_menu"

View File

@@ -25,6 +25,7 @@ import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.IntentFilter; import android.content.IntentFilter;
import android.content.pm.ResolveInfo; import android.content.pm.ResolveInfo;
import android.os.AsyncTask;
import android.os.Bundle; import android.os.Bundle;
import android.os.Handler; import android.os.Handler;
import android.os.Message; import android.os.Message;
@@ -65,7 +66,7 @@ public class FallbackHome extends Activity {
@Override @Override
public void onColorsChanged(WallpaperColors colors, int which) { public void onColorsChanged(WallpaperColors colors, int which) {
if (colors != null) { if (colors != null) {
View decorView = getWindow().getDecorView(); final View decorView = getWindow().getDecorView();
decorView.setSystemUiVisibility( decorView.setSystemUiVisibility(
updateVisibilityFlagsFromColors(colors, decorView.getSystemUiVisibility())); updateVisibilityFlagsFromColors(colors, decorView.getSystemUiVisibility()));
mWallManager.removeOnColorsChangedListener(this); mWallManager.removeOnColorsChangedListener(this);
@@ -81,7 +82,7 @@ public class FallbackHome extends Activity {
// we don't flash the wallpaper before SUW // we don't flash the wallpaper before SUW
mProvisioned = Settings.Global.getInt(getContentResolver(), mProvisioned = Settings.Global.getInt(getContentResolver(),
Settings.Global.DEVICE_PROVISIONED, 0) != 0; Settings.Global.DEVICE_PROVISIONED, 0) != 0;
int flags; final int flags;
if (!mProvisioned) { if (!mProvisioned) {
setTheme(R.style.FallbackHome_SetupWizard); setTheme(R.style.FallbackHome_SetupWizard);
flags = View.SYSTEM_UI_FLAG_FULLSCREEN | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION flags = View.SYSTEM_UI_FLAG_FULLSCREEN | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
@@ -91,18 +92,11 @@ public class FallbackHome extends Activity {
| View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION; | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION;
} }
// Set the system ui flags to light status bar if the wallpaper supports dark text to match
// current system ui color tints. Use a listener to wait for colors if not ready yet.
mWallManager = getSystemService(WallpaperManager.class); mWallManager = getSystemService(WallpaperManager.class);
if (mWallManager == null) { if (mWallManager == null) {
Log.w(TAG, "Wallpaper manager isn't ready, can't listen to color changes!"); Log.w(TAG, "Wallpaper manager isn't ready, can't listen to color changes!");
} else { } else {
WallpaperColors colors = mWallManager.getWallpaperColors(WallpaperManager.FLAG_SYSTEM); loadWallpaperColors(flags);
if (colors == null) {
mWallManager.addOnColorsChangedListener(mColorsChangedListener, null /* handler */);
} else {
flags = updateVisibilityFlagsFromColors(colors, flags);
}
} }
getWindow().getDecorView().setSystemUiVisibility(flags); getWindow().getDecorView().setSystemUiVisibility(flags);
@@ -139,6 +133,33 @@ public class FallbackHome extends Activity {
} }
}; };
private void loadWallpaperColors(int flags) {
final AsyncTask loadWallpaperColorsTask = new AsyncTask<Object, Void, Integer>() {
@Override
protected Integer doInBackground(Object... params) {
final WallpaperColors colors =
mWallManager.getWallpaperColors(WallpaperManager.FLAG_SYSTEM);
// Use a listener to wait for colors if not ready yet.
if (colors == null) {
mWallManager.addOnColorsChangedListener(mColorsChangedListener,
null /* handler */);
return null;
}
return updateVisibilityFlagsFromColors(colors, flags);
}
@Override
protected void onPostExecute(Integer flagsToUpdate) {
if (flagsToUpdate == null) {
return;
}
getWindow().getDecorView().setSystemUiVisibility(flagsToUpdate);
}
};
loadWallpaperColorsTask.execute();
}
private void maybeFinish() { private void maybeFinish() {
if (getSystemService(UserManager.class).isUserUnlocked()) { if (getSystemService(UserManager.class).isUserUnlocked()) {
final Intent homeIntent = new Intent(Intent.ACTION_MAIN) final Intent homeIntent = new Intent(Intent.ACTION_MAIN)
@@ -162,6 +183,8 @@ public class FallbackHome extends Activity {
} }
} }
// Set the system ui flags to light status bar if the wallpaper supports dark text to match
// current system ui color tints.
private int updateVisibilityFlagsFromColors(WallpaperColors colors, int flags) { private int updateVisibilityFlagsFromColors(WallpaperColors colors, int flags) {
if ((colors.getColorHints() & WallpaperColors.HINT_SUPPORTS_DARK_TEXT) != 0) { if ((colors.getColorHints() & WallpaperColors.HINT_SUPPORTS_DARK_TEXT) != 0) {
return flags | View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR return flags | View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR

View File

@@ -145,7 +145,11 @@ public class FaceSettings extends DashboardFragment {
if (savedInstanceState != null) { if (savedInstanceState != null) {
mToken = savedInstanceState.getByteArray(KEY_TOKEN); mToken = savedInstanceState.getByteArray(KEY_TOKEN);
} }
}
@Override
public void onResume() {
super.onResume();
if (mToken == null) { if (mToken == null) {
final long challenge = mFaceManager.generateChallenge(); final long challenge = mFaceManager.generateChallenge();
ChooseLockSettingsHelper helper = new ChooseLockSettingsHelper(getActivity(), this); ChooseLockSettingsHelper helper = new ChooseLockSettingsHelper(getActivity(), this);
@@ -155,13 +159,7 @@ public class FaceSettings extends DashboardFragment {
Log.e(TAG, "Password not set"); Log.e(TAG, "Password not set");
finish(); finish();
} }
} } else {
}
@Override
public void onResume() {
super.onResume();
if (mToken != null) {
mAttentionController.setToken(mToken); mAttentionController.setToken(mToken);
mEnrollController.setToken(mToken); mEnrollController.setToken(mToken);
} }
@@ -196,13 +194,12 @@ public class FaceSettings extends DashboardFragment {
} }
@Override @Override
public void onDestroy() { public void onStop() {
super.onDestroy(); super.onStop();
if (getActivity().isFinishing()) { mToken = null;
final int result = mFaceManager.revokeChallenge(); final int result = mFaceManager.revokeChallenge();
if (result < 0) { if (result < 0) {
Log.w(TAG, "revokeChallenge failed, result: " + result); Log.w(TAG, "revokeChallenge failed, result: " + result);
}
} }
} }

View File

@@ -64,7 +64,7 @@ public class FaceSettingsRemoveButtonPreferenceController extends BasePreference
builder.setTitle(R.string.security_settings_face_settings_remove_dialog_title) builder.setTitle(R.string.security_settings_face_settings_remove_dialog_title)
.setMessage(R.string.security_settings_face_settings_remove_dialog_details) .setMessage(R.string.security_settings_face_settings_remove_dialog_details)
.setPositiveButton(R.string.okay, mOnClickListener) .setPositiveButton(R.string.delete, mOnClickListener)
.setNegativeButton(R.string.cancel, mOnClickListener); .setNegativeButton(R.string.cancel, mOnClickListener);
AlertDialog dialog = builder.create(); AlertDialog dialog = builder.create();
dialog.setCanceledOnTouchOutside(false); dialog.setCanceledOnTouchOutside(false);

View File

@@ -25,9 +25,9 @@ import com.android.settings.core.TogglePreferenceController;
public class AdaptiveSleepPreferenceController extends TogglePreferenceController { public class AdaptiveSleepPreferenceController extends TogglePreferenceController {
public static final String PREF_NAME = "adaptive_sleep";
private final String SYSTEM_KEY = ADAPTIVE_SLEEP; private static final String SYSTEM_KEY = ADAPTIVE_SLEEP;
private final int DEFAULT_VALUE = 0; private static final int DEFAULT_VALUE = 0;
final boolean hasSufficientPermissions; final boolean hasSufficientPermissions;
@@ -35,9 +35,7 @@ public class AdaptiveSleepPreferenceController extends TogglePreferenceControlle
super(context, key); super(context, key);
final PackageManager packageManager = mContext.getPackageManager(); final PackageManager packageManager = mContext.getPackageManager();
final String attentionPackage = packageManager.getAttentionServicePackageName(); hasSufficientPermissions = hasSufficientPermission(packageManager);
hasSufficientPermissions = attentionPackage != null && packageManager.checkPermission(
Manifest.permission.CAMERA, attentionPackage) == PackageManager.PERMISSION_GRANTED;
} }
@Override @Override
@@ -46,7 +44,6 @@ public class AdaptiveSleepPreferenceController extends TogglePreferenceControlle
SYSTEM_KEY, DEFAULT_VALUE) != DEFAULT_VALUE; SYSTEM_KEY, DEFAULT_VALUE) != DEFAULT_VALUE;
} }
@Override @Override
public boolean setChecked(boolean isChecked) { public boolean setChecked(boolean isChecked) {
Settings.System.putInt(mContext.getContentResolver(), SYSTEM_KEY, Settings.System.putInt(mContext.getContentResolver(), SYSTEM_KEY,
@@ -57,10 +54,7 @@ public class AdaptiveSleepPreferenceController extends TogglePreferenceControlle
@Override @Override
@AvailabilityStatus @AvailabilityStatus
public int getAvailabilityStatus() { public int getAvailabilityStatus() {
return mContext.getResources().getBoolean( return isControllerAvailable(mContext);
com.android.internal.R.bool.config_adaptive_sleep_available)
? AVAILABLE_UNSEARCHABLE
: UNSUPPORTED_ON_DEVICE;
} }
@Override @Override
@@ -69,4 +63,17 @@ public class AdaptiveSleepPreferenceController extends TogglePreferenceControlle
? R.string.adaptive_sleep_summary_on ? R.string.adaptive_sleep_summary_on
: R.string.adaptive_sleep_summary_off); : R.string.adaptive_sleep_summary_off);
} }
public static int isControllerAvailable(Context context) {
return context.getResources().getBoolean(
com.android.internal.R.bool.config_adaptive_sleep_available)
? AVAILABLE_UNSEARCHABLE
: UNSUPPORTED_ON_DEVICE;
}
private static boolean hasSufficientPermission(PackageManager packageManager) {
final String attentionPackage = packageManager.getAttentionServicePackageName();
return attentionPackage != null && packageManager.checkPermission(
Manifest.permission.CAMERA, attentionPackage) == PackageManager.PERMISSION_GRANTED;
}
} }

View File

@@ -16,10 +16,15 @@
package com.android.settings.display; package com.android.settings.display;
import static com.android.settings.homepage.contextualcards.slices.ContextualAdaptiveSleepSlice.PREF;
import static com.android.settings.homepage.contextualcards.slices.ContextualAdaptiveSleepSlice.PREF_KEY_INTERACTED;
import android.app.settings.SettingsEnums; import android.app.settings.SettingsEnums;
import android.content.Context; import android.content.Context;
import android.content.SharedPreferences;
import android.os.Bundle; import android.os.Bundle;
import android.provider.SearchIndexableResource; import android.provider.SearchIndexableResource;
import android.util.Log;
import com.android.settings.R; import com.android.settings.R;
import com.android.settings.dashboard.DashboardFragment; import com.android.settings.dashboard.DashboardFragment;
@@ -40,8 +45,15 @@ public class AdaptiveSleepSettings extends DashboardFragment {
super.onCreate(icicle); super.onCreate(icicle);
final FooterPreference footerPreference = final FooterPreference footerPreference =
mFooterPreferenceMixin.createFooterPreference(); mFooterPreferenceMixin.createFooterPreference();
final Context context = getContext();
footerPreference.setIcon(R.drawable.ic_privacy_shield_24dp); footerPreference.setIcon(R.drawable.ic_privacy_shield_24dp);
footerPreference.setTitle(R.string.adaptive_sleep_privacy); footerPreference.setTitle(R.string.adaptive_sleep_privacy);
context.getSharedPreferences(PREF, Context.MODE_PRIVATE)
.edit()
.putBoolean(PREF_KEY_INTERACTED, true)
.apply();
} }
@Override @Override

View File

@@ -352,15 +352,10 @@ public class BatteryAppListPreferenceController extends AbstractPreferenceContro
@VisibleForTesting @VisibleForTesting
boolean shouldHideSipper(BatterySipper sipper) { boolean shouldHideSipper(BatterySipper sipper) {
// Don't show hidden system module // Don't show over-counted, unaccounted and hidden system module in any condition
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 return sipper.drainType == BatterySipper.DrainType.OVERCOUNTED
|| sipper.drainType == BatterySipper.DrainType.UNACCOUNTED; || sipper.drainType == BatterySipper.DrainType.UNACCOUNTED
|| mBatteryUtils.isHiddenSystemModule(sipper);
} }
@VisibleForTesting @VisibleForTesting

View File

@@ -47,6 +47,7 @@ import com.android.settings.fuelgauge.batterytip.AnomalyInfo;
import com.android.settings.fuelgauge.batterytip.BatteryDatabaseManager; import com.android.settings.fuelgauge.batterytip.BatteryDatabaseManager;
import com.android.settings.fuelgauge.batterytip.StatsManagerConfig; import com.android.settings.fuelgauge.batterytip.StatsManagerConfig;
import com.android.settings.overlay.FeatureFactory; import com.android.settings.overlay.FeatureFactory;
import com.android.settingslib.applications.AppUtils;
import com.android.settingslib.fuelgauge.Estimate; import com.android.settingslib.fuelgauge.Estimate;
import com.android.settingslib.fuelgauge.EstimateKt; import com.android.settingslib.fuelgauge.EstimateKt;
import com.android.settingslib.fuelgauge.PowerWhitelistBackend; import com.android.settingslib.fuelgauge.PowerWhitelistBackend;
@@ -189,8 +190,10 @@ public class BatteryUtils {
&& sipper.drainType != BatterySipper.DrainType.UNACCOUNTED && sipper.drainType != BatterySipper.DrainType.UNACCOUNTED
&& sipper.drainType != BatterySipper.DrainType.BLUETOOTH && sipper.drainType != BatterySipper.DrainType.BLUETOOTH
&& sipper.drainType != BatterySipper.DrainType.WIFI && sipper.drainType != BatterySipper.DrainType.WIFI
&& sipper.drainType != BatterySipper.DrainType.IDLE) { && sipper.drainType != BatterySipper.DrainType.IDLE
// Don't add it if it is overcounted, unaccounted, wifi, bluetooth, or screen && !isHiddenSystemModule(sipper)) {
// Don't add it if it is overcounted, unaccounted, wifi, bluetooth, screen
// or hidden system modules
proportionalSmearPowerMah += sipper.totalPowerMah; proportionalSmearPowerMah += sipper.totalPowerMah;
} }
} }
@@ -253,7 +256,27 @@ public class BatteryUtils {
|| drainType == BatterySipper.DrainType.WIFI || drainType == BatterySipper.DrainType.WIFI
|| (sipper.totalPowerMah * SECONDS_IN_HOUR) < MIN_POWER_THRESHOLD_MILLI_AMP || (sipper.totalPowerMah * SECONDS_IN_HOUR) < MIN_POWER_THRESHOLD_MILLI_AMP
|| mPowerUsageFeatureProvider.isTypeService(sipper) || mPowerUsageFeatureProvider.isTypeService(sipper)
|| mPowerUsageFeatureProvider.isTypeSystem(sipper); || mPowerUsageFeatureProvider.isTypeSystem(sipper)
|| isHiddenSystemModule(sipper);
}
/**
* Return {@code true} if one of packages in {@code sipper} is hidden system modules
*/
public boolean isHiddenSystemModule(BatterySipper sipper) {
if (sipper.uidObj == null) {
return false;
}
sipper.mPackages = mPackageManager.getPackagesForUid(sipper.getUid());
if (sipper.mPackages != null) {
for (int i = 0, length = sipper.mPackages.length; i < length; i++) {
if (AppUtils.isHiddenSystemModule(mContext, sipper.mPackages[i])) {
return true;
}
}
}
return false;
} }
/** /**

View File

@@ -20,7 +20,6 @@ import static com.android.settings.Utils.SETTINGS_PACKAGE_NAME;
import android.content.Context; import android.content.Context;
import android.os.BatteryStats; import android.os.BatteryStats;
import android.text.format.DateUtils;
import androidx.annotation.VisibleForTesting; import androidx.annotation.VisibleForTesting;
@@ -72,22 +71,33 @@ public class HighUsageDetector implements BatteryTipDetector {
if (mPolicy.highUsageEnabled && mDischarging) { if (mPolicy.highUsageEnabled && mDischarging) {
parseBatteryData(); parseBatteryData();
if (mDataParser.isDeviceHeavilyUsed() || mPolicy.testHighUsageTip) { if (mDataParser.isDeviceHeavilyUsed() || mPolicy.testHighUsageTip) {
final List<BatterySipper> batterySippers = mBatteryStatsHelper.getUsageList(); final BatteryStats batteryStats = mBatteryStatsHelper.getStats();
for (int i = 0, size = batterySippers.size(); i < size; i++) { final List<BatterySipper> batterySippers
final BatterySipper batterySipper = batterySippers.get(i); = new ArrayList<>(mBatteryStatsHelper.getUsageList());
if (!mBatteryUtils.shouldHideSipper(batterySipper)) { final double totalPower = mBatteryStatsHelper.getTotalPower();
final long foregroundTimeMs = mBatteryUtils.getProcessTimeMs( final int dischargeAmount = batteryStats != null
BatteryUtils.StatusType.FOREGROUND, batterySipper.uidObj, ? batteryStats.getDischargeAmount(BatteryStats.STATS_SINCE_CHARGED)
BatteryStats.STATS_SINCE_CHARGED); : 0;
if (foregroundTimeMs >= DateUtils.MINUTE_IN_MILLIS) {
mHighUsageAppList.add(new AppInfo.Builder() Collections.sort(batterySippers,
.setUid(batterySipper.getUid()) (sipper1, sipper2) -> Double.compare(sipper2.totalSmearedPowerMah,
.setPackageName( sipper1.totalSmearedPowerMah));
mBatteryUtils.getPackageName(batterySipper.getUid())) for (BatterySipper batterySipper : batterySippers) {
.setScreenOnTimeMs(foregroundTimeMs) final double percent = mBatteryUtils.calculateBatteryPercent(
.build()); batterySipper.totalSmearedPowerMah, totalPower, 0, dischargeAmount);
} if ((percent + 0.5f < 1f) || mBatteryUtils.shouldHideSipper(batterySipper)) {
// Don't show it if we should hide or usage percentage is lower than 1%
continue;
} }
mHighUsageAppList.add(new AppInfo.Builder()
.setUid(batterySipper.getUid())
.setPackageName(
mBatteryUtils.getPackageName(batterySipper.getUid()))
.build());
if (mHighUsageAppList.size() >= mPolicy.highUsageAppCount) {
break;
}
} }
// When in test mode, add an app if necessary // When in test mode, add an app if necessary
@@ -97,10 +107,6 @@ public class HighUsageDetector implements BatteryTipDetector {
.setScreenOnTimeMs(TimeUnit.HOURS.toMillis(3)) .setScreenOnTimeMs(TimeUnit.HOURS.toMillis(3))
.build()); .build());
} }
Collections.sort(mHighUsageAppList, Collections.reverseOrder());
mHighUsageAppList = mHighUsageAppList.subList(0,
Math.min(mPolicy.highUsageAppCount, mHighUsageAppList.size()));
} }
} }

View File

@@ -21,6 +21,10 @@ import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_2BUTTON_OVE
import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON_OVERLAY; import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON_OVERLAY;
import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL_OVERLAY; import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL_OVERLAY;
import static com.android.settings.widget.RadioButtonPreferenceWithExtraWidget.EXTRA_WIDGET_VISIBILITY_GONE;
import static com.android.settings.widget.RadioButtonPreferenceWithExtraWidget.EXTRA_WIDGET_VISIBILITY_INFO;
import android.app.AlertDialog;
import android.app.settings.SettingsEnums; import android.app.settings.SettingsEnums;
import android.content.Context; import android.content.Context;
import android.content.SharedPreferences; import android.content.SharedPreferences;
@@ -29,7 +33,6 @@ import android.graphics.drawable.Drawable;
import android.os.RemoteException; import android.os.RemoteException;
import android.os.ServiceManager; import android.os.ServiceManager;
import android.provider.SearchIndexableResource; import android.provider.SearchIndexableResource;
import android.view.View;
import androidx.annotation.VisibleForTesting; import androidx.annotation.VisibleForTesting;
import androidx.preference.PreferenceScreen; import androidx.preference.PreferenceScreen;
@@ -41,6 +44,7 @@ import com.android.settings.search.BaseSearchIndexProvider;
import com.android.settings.search.Indexable; import com.android.settings.search.Indexable;
import com.android.settings.widget.RadioButtonPickerFragment; import com.android.settings.widget.RadioButtonPickerFragment;
import com.android.settings.widget.RadioButtonPreference; import com.android.settings.widget.RadioButtonPreference;
import com.android.settings.widget.RadioButtonPreferenceWithExtraWidget;
import com.android.settings.widget.VideoPreference; import com.android.settings.widget.VideoPreference;
import com.android.settingslib.search.SearchIndexable; import com.android.settingslib.search.SearchIndexable;
import com.android.settingslib.widget.CandidateInfo; import com.android.settingslib.widget.CandidateInfo;
@@ -94,8 +98,25 @@ public class SystemNavigationGestureSettings extends RadioButtonPickerFragment {
} }
@Override @Override
protected void addStaticPreferences(PreferenceScreen screen) { public void updateCandidates() {
final String defaultKey = getDefaultKey();
final String systemDefaultKey = getSystemDefaultKey();
final PreferenceScreen screen = getPreferenceScreen();
screen.removeAll();
screen.addPreference(mVideoPreference); screen.addPreference(mVideoPreference);
final List<? extends CandidateInfo> candidateList = getCandidates();
if (candidateList == null) {
return;
}
for (CandidateInfo info : candidateList) {
RadioButtonPreferenceWithExtraWidget pref =
new RadioButtonPreferenceWithExtraWidget(getPrefContext());
bindPreference(pref, info.getKey(), info, defaultKey);
bindPreferenceExtra(pref, info.getKey(), info, defaultKey, systemDefaultKey);
screen.addPreference(pref);
}
mayCheckOnlyRadioButton();
} }
@Override @Override
@@ -135,6 +156,13 @@ public class SystemNavigationGestureSettings extends RadioButtonPickerFragment {
@Override @Override
protected boolean setDefaultKey(String key) { protected boolean setDefaultKey(String key) {
final Context c = getContext();
if (key == KEY_SYSTEM_NAV_GESTURAL &&
!SystemNavigationPreferenceController.isGestureNavSupportedByDefaultLauncher(c)) {
// This should not happen since the preference is disabled. Return to be safe.
return false;
}
setCurrentSystemNavigationMode(mOverlayManager, key); setCurrentSystemNavigationMode(mOverlayManager, key);
setIllustrationVideo(mVideoPreference, key); setIllustrationVideo(mVideoPreference, key);
return true; return true;
@@ -196,10 +224,36 @@ public class SystemNavigationGestureSettings extends RadioButtonPickerFragment {
@Override @Override
public void bindPreferenceExtra(RadioButtonPreference pref, public void bindPreferenceExtra(RadioButtonPreference pref,
String key, CandidateInfo info, String defaultKey, String systemDefaultKey) { String key, CandidateInfo info, String defaultKey, String systemDefaultKey) {
if (info instanceof NavModeCandidateInfo) { if (!(info instanceof NavModeCandidateInfo)
pref.setSummary(((NavModeCandidateInfo) info).loadSummary()); || !(pref instanceof RadioButtonPreferenceWithExtraWidget)) {
pref.setAppendixVisibility(View.GONE); return;
} }
pref.setSummary(((NavModeCandidateInfo) info).loadSummary());
RadioButtonPreferenceWithExtraWidget p = (RadioButtonPreferenceWithExtraWidget) pref;
if (info.getKey() == KEY_SYSTEM_NAV_GESTURAL
&& !SystemNavigationPreferenceController.isGestureNavSupportedByDefaultLauncher(
getContext())) {
p.setEnabled(false);
p.setExtraWidgetVisibility(EXTRA_WIDGET_VISIBILITY_INFO);
p.setExtraWidgetOnClickListener((v) -> {
showGestureNavDisabledDialog();
});
} else {
p.setExtraWidgetVisibility(EXTRA_WIDGET_VISIBILITY_GONE);
}
}
private void showGestureNavDisabledDialog() {
final String defaultHomeAppName = SystemNavigationPreferenceController
.getDefaultHomeAppName(getContext());
final String message = getString(R.string.gesture_not_supported_dialog_message,
defaultHomeAppName);
AlertDialog d = new AlertDialog.Builder(getContext())
.setMessage(message)
.setPositiveButton(R.string.okay, null)
.show();
} }
static class NavModeCandidateInfo extends CandidateInfo { static class NavModeCandidateInfo extends CandidateInfo {

View File

@@ -22,11 +22,14 @@ import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL;
import android.content.ComponentName; import android.content.ComponentName;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
import com.android.settings.R; import com.android.settings.R;
import com.android.settings.core.BasePreferenceController; import com.android.settings.core.BasePreferenceController;
import java.util.ArrayList;
public class SystemNavigationPreferenceController extends BasePreferenceController { public class SystemNavigationPreferenceController extends BasePreferenceController {
static final String PREF_KEY_SYSTEM_NAVIGATION = "gesture_system_navigation"; static final String PREF_KEY_SYSTEM_NAVIGATION = "gesture_system_navigation";
@@ -98,4 +101,31 @@ public class SystemNavigationPreferenceController extends BasePreferenceControll
return NAV_BAR_MODE_GESTURAL == context.getResources().getInteger( return NAV_BAR_MODE_GESTURAL == context.getResources().getInteger(
com.android.internal.R.integer.config_navBarInteractionMode); com.android.internal.R.integer.config_navBarInteractionMode);
} }
static boolean isGestureNavSupportedByDefaultLauncher(Context context) {
final ComponentName cn = context.getPackageManager().getHomeActivities(new ArrayList<>());
if (cn == null) {
// There is no default home app set for the current user, don't make any changes yet.
return true;
}
ComponentName recentsComponentName = ComponentName.unflattenFromString(context.getString(
com.android.internal.R.string.config_recentsComponentName));
return recentsComponentName.getPackageName().equals(cn.getPackageName());
}
static String getDefaultHomeAppName(Context context) {
final PackageManager pm = context.getPackageManager();
final ComponentName cn = pm.getHomeActivities(new ArrayList<>());
if (cn != null) {
try {
ApplicationInfo ai = pm.getApplicationInfo(cn.getPackageName(), 0);
if (ai != null) {
return pm.getApplicationLabel(ai).toString();
}
} catch (final PackageManager.NameNotFoundException e) {
// Do nothing
}
}
return "";
}
} }

View File

@@ -64,12 +64,21 @@ public class SettingsContextualCardProvider extends ContextualCardProvider {
.setCardName(contextualNotificationChannelSliceUri) .setCardName(contextualNotificationChannelSliceUri)
.setCardCategory(ContextualCard.Category.POSSIBLE) .setCardCategory(ContextualCard.Category.POSSIBLE)
.build(); .build();
final String contextualAdaptiveSleepSliceUri =
CustomSliceRegistry.CONTEXTUAL_ADAPTIVE_SLEEP_URI.toString();
final ContextualCard contextualAdaptiveSleepCard =
ContextualCard.newBuilder()
.setSliceUri(contextualAdaptiveSleepSliceUri)
.setCardName(contextualAdaptiveSleepSliceUri)
.setCardCategory(ContextualCard.Category.DEFAULT)
.build();
final ContextualCardList cards = ContextualCardList.newBuilder() final ContextualCardList cards = ContextualCardList.newBuilder()
.addCard(wifiCard) .addCard(wifiCard)
.addCard(connectedDeviceCard) .addCard(connectedDeviceCard)
.addCard(lowStorageCard) .addCard(lowStorageCard)
.addCard(batteryFixCard) .addCard(batteryFixCard)
.addCard(notificationChannelCard) .addCard(notificationChannelCard)
.addCard(contextualAdaptiveSleepCard)
.build(); .build();
return cards; return cards;

View File

@@ -0,0 +1,154 @@
/*
* 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.core.BasePreferenceController.AVAILABLE;
import static com.android.settings.display.AdaptiveSleepPreferenceController.PREF_NAME;
import static com.android.settings.display.AdaptiveSleepPreferenceController.isControllerAvailable;
import static com.android.settings.slices.CustomSliceRegistry.CONTEXTUAL_ADAPTIVE_SLEEP_URI;
import android.app.PendingIntent;
import android.app.settings.SettingsEnums;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
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.SubSettings;
import com.android.settings.display.AdaptiveSleepSettings;
import com.android.settings.slices.CustomSliceable;
import com.android.settings.slices.SliceBuilderUtils;
import com.google.common.annotations.VisibleForTesting;
import java.util.concurrent.TimeUnit;
public class ContextualAdaptiveSleepSlice implements CustomSliceable {
private static final String TAG = "ContextualAdaptiveSleepSlice";
private static final long DEFAULT_SETUP_TIME = 0;
private Context mContext;
@VisibleForTesting
static final long DEFERRED_TIME_DAYS = TimeUnit.DAYS.toMillis(14);
@VisibleForTesting
static final String PREF_KEY_SETUP_TIME = "adaptive_sleep_setup_time";
public static final String PREF_KEY_INTERACTED = "adaptive_sleep_interacted";
public static final String PREF = "adaptive_sleep_slice";
public ContextualAdaptiveSleepSlice(Context context) {
mContext = context;
}
@Override
public Slice getSlice() {
final long setupTime = mContext.getSharedPreferences(PREF, Context.MODE_PRIVATE).getLong(
PREF_KEY_SETUP_TIME, DEFAULT_SETUP_TIME);
if (setupTime == DEFAULT_SETUP_TIME) {
// Set the first setup time.
mContext.getSharedPreferences(PREF, Context.MODE_PRIVATE)
.edit()
.putLong(PREF_KEY_SETUP_TIME, System.currentTimeMillis())
.apply();
return null;
}
// Display the contextual card only if all the following 3 conditions hold:
// 1. The Screen Attention is enabled in Settings.
// 2. The device is not recently set up.
// 3. Current user hasn't opened Screen Attention's settings page before.
if (isSettingsAvailable() && !isUserInteracted() && !isRecentlySetup()) {
final IconCompat icon = IconCompat.createWithResource(mContext,
R.drawable.ic_settings_adaptive_sleep);
final CharSequence title = mContext.getText(R.string.adaptive_sleep_title);
final CharSequence subtitle = mContext.getText(R.string.adaptive_sleep_description);
final SliceAction pAction = SliceAction.createDeeplink(getPrimaryAction(),
icon,
ListBuilder.ICON_IMAGE,
title);
final ListBuilder listBuilder = new ListBuilder(mContext,
CONTEXTUAL_ADAPTIVE_SLEEP_URI,
ListBuilder.INFINITY)
.addRow(new ListBuilder.RowBuilder()
.setTitleItem(icon, ListBuilder.ICON_IMAGE)
.setTitle(title)
.setSubtitle(subtitle)
.setPrimaryAction(pAction));
return listBuilder.build();
} else {
return null;
}
}
@Override
public Uri getUri() {
return CONTEXTUAL_ADAPTIVE_SLEEP_URI;
}
@Override
public Intent getIntent() {
final CharSequence screenTitle = mContext.getText(R.string.adaptive_sleep_title);
final Uri contentUri = new Uri.Builder().appendPath(PREF_NAME).build();
return SliceBuilderUtils.buildSearchResultPageIntent(mContext,
AdaptiveSleepSettings.class.getName(), PREF_NAME, screenTitle.toString(),
SettingsEnums.SLICE).setClassName(mContext.getPackageName(),
SubSettings.class.getName()).setData(contentUri);
}
private PendingIntent getPrimaryAction() {
final Intent intent = getIntent();
return PendingIntent.getActivity(mContext, 0 /* requestCode */, intent, 0 /* flags */);
}
/**
* @return {@code true} if the current user has opened the Screen Attention settings page
* before, otherwise {@code false}.
*/
private boolean isUserInteracted() {
return mContext.getSharedPreferences(PREF, Context.MODE_PRIVATE).getBoolean(
PREF_KEY_INTERACTED, false);
}
/**
* The device is recently set up means its first settings-open time is within 2 weeks ago.
*
* @return {@code true} if the device is recently set up, otherwise {@code false}.
*/
private boolean isRecentlySetup() {
final long endTime = System.currentTimeMillis() - DEFERRED_TIME_DAYS;
final long firstSetupTime = mContext.getSharedPreferences(PREF,
Context.MODE_PRIVATE).getLong(PREF_KEY_SETUP_TIME, DEFAULT_SETUP_TIME);
return firstSetupTime > endTime;
}
/**
* Check whether the screen attention settings is enabled. Contextual card will only appear
* when the screen attention settings is available.
*
* @return {@code true} if screen attention settings is enabled, otherwise {@code false}
*/
@VisibleForTesting
boolean isSettingsAvailable() {
return isControllerAvailable(mContext) == AVAILABLE;
}
}

View File

@@ -18,6 +18,7 @@ package com.android.settings.network;
import android.app.settings.SettingsEnums; import android.app.settings.SettingsEnums;
import android.content.Context; import android.content.Context;
import android.os.UserManager;
import android.provider.SearchIndexableResource; import android.provider.SearchIndexableResource;
import com.android.settings.R; import com.android.settings.R;
@@ -66,5 +67,10 @@ public class MobileNetworkListFragment extends DashboardFragment {
result.add(sir); result.add(sir);
return result; return result;
} }
@Override
protected boolean isPageSearchEnabled(Context context) {
return context.getSystemService(UserManager.class).isAdminUser();
}
}; };
} }

View File

@@ -277,5 +277,11 @@ public class MobileNetworkSettings extends RestrictedDashboardFragment {
result.add(sir); result.add(sir);
return result; return result;
} }
/** suppress full page if user is not admin */
@Override
protected boolean isPageSearchEnabled(Context context) {
return context.getSystemService(UserManager.class).isAdminUser();
}
}; };
} }

View File

@@ -19,6 +19,10 @@ package com.android.settings.network.telephony;
import android.app.Dialog; import android.app.Dialog;
import android.app.settings.SettingsEnums; import android.app.settings.SettingsEnums;
import android.content.Context; import android.content.Context;
import android.content.res.Resources;
import android.graphics.Paint;
import android.graphics.drawable.ShapeDrawable;
import android.graphics.drawable.shapes.OvalShape;
import android.os.Bundle; import android.os.Bundle;
import android.telephony.ServiceState; import android.telephony.ServiceState;
import android.telephony.SubscriptionInfo; import android.telephony.SubscriptionInfo;
@@ -30,7 +34,12 @@ import android.text.TextUtils;
import android.util.Log; import android.util.Log;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.EditText; import android.widget.EditText;
import android.widget.ImageView;
import android.widget.Spinner;
import android.widget.TextView; import android.widget.TextView;
import com.android.settings.R; import com.android.settings.R;
@@ -42,9 +51,12 @@ import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting; import androidx.annotation.VisibleForTesting;
import androidx.appcompat.app.AlertDialog; import androidx.appcompat.app.AlertDialog;
/** A dialog allowing the display name of a mobile network subscription to be changed */ /**
* A dialog allowing the display name of a mobile network subscription to be changed
*/
public class RenameMobileNetworkDialogFragment extends InstrumentedDialogFragment { public class RenameMobileNetworkDialogFragment extends InstrumentedDialogFragment {
public static final String TAG ="RenameMobileNetwork";
public static final String TAG = "RenameMobileNetwork";
private static final String KEY_SUBSCRIPTION_ID = "subscription_id"; private static final String KEY_SUBSCRIPTION_ID = "subscription_id";
@@ -52,6 +64,8 @@ public class RenameMobileNetworkDialogFragment extends InstrumentedDialogFragmen
private SubscriptionManager mSubscriptionManager; private SubscriptionManager mSubscriptionManager;
private int mSubId; private int mSubId;
private EditText mNameView; private EditText mNameView;
private Spinner mColorSpinner;
private Color[] mColors;
public static RenameMobileNetworkDialogFragment newInstance(int subscriptionId) { public static RenameMobileNetworkDialogFragment newInstance(int subscriptionId) {
final Bundle args = new Bundle(1); final Bundle args = new Bundle(1);
@@ -76,6 +90,11 @@ public class RenameMobileNetworkDialogFragment extends InstrumentedDialogFragmen
return mNameView; return mNameView;
} }
@VisibleForTesting
protected Spinner getColorSpinnerView() {
return mColorSpinner;
}
@Override @Override
public void onAttach(Context context) { public void onAttach(Context context) {
super.onAttach(context); super.onAttach(context);
@@ -87,6 +106,8 @@ public class RenameMobileNetworkDialogFragment extends InstrumentedDialogFragmen
@NonNull @NonNull
@Override @Override
public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) { public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
mColors = getColors();
final AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); final AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
final LayoutInflater layoutInflater = builder.getContext().getSystemService( final LayoutInflater layoutInflater = builder.getContext().getSystemService(
LayoutInflater.class); LayoutInflater.class);
@@ -95,9 +116,11 @@ public class RenameMobileNetworkDialogFragment extends InstrumentedDialogFragmen
builder.setTitle(R.string.mobile_network_sim_name) builder.setTitle(R.string.mobile_network_sim_name)
.setView(view) .setView(view)
.setPositiveButton(R.string.mobile_network_sim_name_rename, (dialog, which) -> { .setPositiveButton(R.string.mobile_network_sim_name_rename, (dialog, which) -> {
String newName = mNameView.getText().toString(); mSubscriptionManager.setDisplayName(mNameView.getText().toString(), mSubId,
mSubscriptionManager.setDisplayName(newName, mSubId,
SubscriptionManager.NAME_SOURCE_USER_INPUT); SubscriptionManager.NAME_SOURCE_USER_INPUT);
mSubscriptionManager.setIconTint(
mColors[mColorSpinner.getSelectedItemPosition()].getColor(),
mSubId);
}) })
.setNegativeButton(android.R.string.cancel, null); .setNegativeButton(android.R.string.cancel, null);
return builder.create(); return builder.create();
@@ -105,7 +128,7 @@ public class RenameMobileNetworkDialogFragment extends InstrumentedDialogFragmen
@VisibleForTesting @VisibleForTesting
protected void populateView(View view) { protected void populateView(View view) {
mNameView = view.findViewById(R.id.edittext); mNameView = view.findViewById(R.id.name_edittext);
final SubscriptionInfo info = mSubscriptionManager.getActiveSubscriptionInfo(mSubId); final SubscriptionInfo info = mSubscriptionManager.getActiveSubscriptionInfo(mSubId);
if (info == null) { if (info == null) {
Log.w(TAG, "got null SubscriptionInfo for mSubId:" + mSubId); Log.w(TAG, "got null SubscriptionInfo for mSubId:" + mSubId);
@@ -117,6 +140,17 @@ public class RenameMobileNetworkDialogFragment extends InstrumentedDialogFragmen
mNameView.setSelection(displayName.length()); mNameView.setSelection(displayName.length());
} }
mColorSpinner = view.findViewById(R.id.color_spinner);
final ColorAdapter adapter = new ColorAdapter(getContext(),
R.layout.dialog_mobile_network_color_picker_item, mColors);
mColorSpinner.setAdapter(adapter);
for (int i = 0; i < mColors.length; i++) {
if (mColors[i].getColor() == info.getIconTint()) {
mColorSpinner.setSelection(i);
break;
}
}
final TextView operatorName = view.findViewById(R.id.operator_name_value); final TextView operatorName = view.findViewById(R.id.operator_name_value);
final ServiceState serviceState = mTelephonyManager.getServiceStateForSubscriber(mSubId); final ServiceState serviceState = mTelephonyManager.getServiceStateForSubscriber(mSubId);
operatorName.setText(serviceState.getOperatorAlphaLong()); operatorName.setText(serviceState.getOperatorAlphaLong());
@@ -134,4 +168,80 @@ public class RenameMobileNetworkDialogFragment extends InstrumentedDialogFragmen
public int getMetricsCategory() { public int getMetricsCategory() {
return SettingsEnums.MOBILE_NETWORK_RENAME_DIALOG; return SettingsEnums.MOBILE_NETWORK_RENAME_DIALOG;
} }
private class ColorAdapter extends ArrayAdapter<Color> {
private Context mContext;
private int mItemResId;
public ColorAdapter(Context context, int resource, Color[] colors) {
super(context, resource, colors);
mContext = context;
mItemResId = resource;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
final LayoutInflater inflater = (LayoutInflater)
mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
if (convertView == null) {
convertView = inflater.inflate(mItemResId, null);
}
((ImageView) convertView.findViewById(R.id.color_icon))
.setImageDrawable(getItem(position).getDrawable());
((TextView) convertView.findViewById(R.id.color_label))
.setText(getItem(position).getLabel());
return convertView;
}
@Override
public View getDropDownView(int position, View convertView, ViewGroup parent) {
return getView(position, convertView, parent);
}
}
private Color[] getColors() {
final Resources res = getContext().getResources();
final int[] colorInts = res.getIntArray(com.android.internal.R.array.sim_colors);
final String[] colorStrings = res.getStringArray(R.array.color_picker);
final int iconSize = res.getDimensionPixelSize(R.dimen.color_swatch_size);
final int strokeWidth = res.getDimensionPixelSize(R.dimen.color_swatch_stroke_width);
final Color[] colors = new Color[colorInts.length];
for (int i = 0; i < colors.length; i++) {
colors[i] = new Color(colorStrings[i], colorInts[i], iconSize, strokeWidth);
}
return colors;
}
private static class Color {
private String mLabel;
private int mColor;
private ShapeDrawable mDrawable;
private Color(String label, int color, int iconSize, int strokeWidth) {
mLabel = label;
mColor = color;
mDrawable = new ShapeDrawable(new OvalShape());
mDrawable.setIntrinsicHeight(iconSize);
mDrawable.setIntrinsicWidth(iconSize);
mDrawable.getPaint().setStrokeWidth(strokeWidth);
mDrawable.getPaint().setStyle(Paint.Style.FILL_AND_STROKE);
mDrawable.getPaint().setColor(color);
}
private String getLabel() {
return mLabel;
}
private int getColor() {
return mColor;
}
private ShapeDrawable getDrawable() {
return mDrawable;
}
}
} }

View File

@@ -22,6 +22,7 @@ import android.media.AudioManager;
import android.media.AudioSystem; import android.media.AudioSystem;
import android.os.UserHandle; import android.os.UserHandle;
import android.os.UserManager; import android.os.UserManager;
import android.util.Log;
import com.android.settings.Utils; import com.android.settings.Utils;
@@ -30,6 +31,7 @@ import com.android.settings.Utils;
*/ */
public class AudioHelper { public class AudioHelper {
private static final String TAG = "AudioHelper";
private Context mContext; private Context mContext;
private AudioManager mAudioManager; private AudioManager mAudioManager;
@@ -76,6 +78,15 @@ public class AudioHelper {
} }
public int getMinVolume(int stream) { public int getMinVolume(int stream) {
return mAudioManager.getStreamMinVolume(stream); int minVolume;
try {
minVolume = mAudioManager.getStreamMinVolume(stream);
} catch (IllegalArgumentException e) {
Log.w(TAG, "Invalid stream type " + stream);
// Fallback to STREAM_VOICE_CALL because CallVolumePreferenceController.java default
// return STREAM_VOICE_CALL in getAudioStream
minVolume = mAudioManager.getStreamMinVolume(AudioManager.STREAM_VOICE_CALL);
}
return minVolume;
} }
} }

View File

@@ -117,11 +117,13 @@ public class ImportancePreference extends Preference {
case IMPORTANCE_LOW: case IMPORTANCE_LOW:
mAlertButton.setBackground(unselectedBackground); mAlertButton.setBackground(unselectedBackground);
mSilenceButton.setBackground(selectedBackground); mSilenceButton.setBackground(selectedBackground);
mSilenceButton.setSelected(true);
break; break;
case IMPORTANCE_HIGH: case IMPORTANCE_HIGH:
default: default:
mSilenceButton.setBackground(unselectedBackground); mSilenceButton.setBackground(unselectedBackground);
mAlertButton.setBackground(selectedBackground); mAlertButton.setBackground(selectedBackground);
mAlertButton.setSelected(true);
break; break;
} }
setImportanceSummary((ViewGroup) holder.itemView, mImportance, false); setImportanceSummary((ViewGroup) holder.itemView, mImportance, false);

View File

@@ -0,0 +1,33 @@
/*
* 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.notification;
import android.content.Context;
import android.util.AttributeSet;
import android.widget.Button;
import android.widget.RelativeLayout;
public class NotificationButtonRelativeLayout extends RelativeLayout {
public NotificationButtonRelativeLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
public CharSequence getAccessibilityClassName() {
return Button.class.getName();
}
}

View File

@@ -281,7 +281,7 @@ abstract public class NotificationSettingsBase extends DashboardFragment {
} }
private Drawable getAlertingIcon() { private Drawable getAlertingIcon() {
Drawable icon = getContext().getDrawable(R.drawable.ic_notifications); Drawable icon = getContext().getDrawable(R.drawable.ic_notifications_alert);
icon.setTintList(Utils.getColorAccent(getContext())); icon.setTintList(Utils.getColorAccent(getContext()));
return icon; return icon;
} }

View File

@@ -96,18 +96,23 @@ public final class EnableContentCaptureWithServiceSettingsPreferenceController
for (UserInfo info: userInfos) { for (UserInfo info: userInfos) {
userHandles.add(info.getUserHandle()); userHandles.add(info.getUserHandle());
} }
if (userHandles.size() == 1) {
AlertDialog.Builder builder = new AlertDialog.Builder(context); final Intent intent = pref.getIntent().addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
UserAdapter adapter = UserAdapter.createUserAdapter(userManager, context, userHandles); context.startActivityAsUser(intent, userHandles.get(0));
builder.setTitle(com.android.settingslib.R.string.choose_profile) } else {
.setAdapter(adapter, (DialogInterface dialog, int which) -> { AlertDialog.Builder builder = new AlertDialog.Builder(context);
final UserHandle user = userHandles.get(which); UserAdapter adapter = UserAdapter.createUserAdapter(userManager, context,
// Show menu on top level items. userHandles);
final Intent intent = pref.getIntent(); builder.setTitle(com.android.settingslib.R.string.choose_profile)
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK); .setAdapter(adapter, (DialogInterface dialog, int which) -> {
context.startActivityAsUser(intent, user); final UserHandle user = userHandles.get(which);
}) // Show menu on top level items.
.show(); final Intent intent = pref.getIntent()
.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
context.startActivityAsUser(intent, user);
})
.show();
}
} }
} }

View File

@@ -0,0 +1,62 @@
/*
* 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.security;
import android.content.Context;
import android.content.pm.PackageManager;
import android.hardware.face.FaceManager;
import android.provider.Settings;
import com.android.internal.annotations.VisibleForTesting;
import com.android.settings.core.TogglePreferenceController;
public class LockscreenBypassPreferenceController extends TogglePreferenceController {
@VisibleForTesting
protected FaceManager mFaceManager;
public LockscreenBypassPreferenceController(Context context, String preferenceKey) {
super(context, preferenceKey);
if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_FACE)) {
mFaceManager = context.getSystemService(FaceManager.class);
}
}
@Override
public boolean isChecked() {
boolean defaultValue = mContext.getResources().getBoolean(
com.android.internal.R.bool.config_faceAuthDismissesKeyguard);
return Settings.Secure.getInt(mContext.getContentResolver(),
Settings.Secure.FACE_UNLOCK_DISMISSES_KEYGUARD, defaultValue ? 1 : 0) != 0;
}
@Override
public boolean setChecked(boolean isChecked) {
Settings.Secure.putInt(mContext.getContentResolver(),
Settings.Secure.FACE_UNLOCK_DISMISSES_KEYGUARD, isChecked ? 1 : 0);
return true;
}
@Override
public int getAvailabilityStatus() {
if (mFaceManager != null && mFaceManager.isHardwareDetected()) {
return mFaceManager.hasEnrolledTemplates() ? AVAILABLE : DISABLED_DEPENDENT_SETTING;
} else {
return UNSUPPORTED_ON_DEVICE;
}
}
}

View File

@@ -26,6 +26,7 @@ import android.util.ArrayMap;
import androidx.annotation.VisibleForTesting; import androidx.annotation.VisibleForTesting;
import com.android.settings.display.AdaptiveSleepPreferenceController;
import com.android.settings.flashlight.FlashlightSlice; import com.android.settings.flashlight.FlashlightSlice;
import com.android.settings.fuelgauge.batterytip.BatteryTipPreferenceController; import com.android.settings.fuelgauge.batterytip.BatteryTipPreferenceController;
import com.android.settings.homepage.contextualcards.deviceinfo.DataUsageSlice; import com.android.settings.homepage.contextualcards.deviceinfo.DataUsageSlice;
@@ -34,6 +35,7 @@ import com.android.settings.homepage.contextualcards.deviceinfo.EmergencyInfoSli
import com.android.settings.homepage.contextualcards.deviceinfo.StorageSlice; import com.android.settings.homepage.contextualcards.deviceinfo.StorageSlice;
import com.android.settings.homepage.contextualcards.slices.BatteryFixSlice; import com.android.settings.homepage.contextualcards.slices.BatteryFixSlice;
import com.android.settings.homepage.contextualcards.slices.BluetoothDevicesSlice; import com.android.settings.homepage.contextualcards.slices.BluetoothDevicesSlice;
import com.android.settings.homepage.contextualcards.slices.ContextualAdaptiveSleepSlice;
import com.android.settings.homepage.contextualcards.slices.ContextualNotificationChannelSlice; import com.android.settings.homepage.contextualcards.slices.ContextualNotificationChannelSlice;
import com.android.settings.homepage.contextualcards.slices.LowStorageSlice; import com.android.settings.homepage.contextualcards.slices.LowStorageSlice;
import com.android.settings.homepage.contextualcards.slices.NotificationChannelSlice; import com.android.settings.homepage.contextualcards.slices.NotificationChannelSlice;
@@ -64,6 +66,16 @@ public class CustomSliceRegistry {
.appendPath(SettingsSlicesContract.KEY_AIRPLANE_MODE) .appendPath(SettingsSlicesContract.KEY_AIRPLANE_MODE)
.build(); .build();
/**
* Uri for Contextual Adaptive Sleep Slice
*/
public static final Uri CONTEXTUAL_ADAPTIVE_SLEEP_URI = new Uri.Builder()
.scheme(ContentResolver.SCHEME_CONTENT)
.authority(SettingsSliceProvider.SLICE_AUTHORITY)
.appendPath(SettingsSlicesContract.PATH_SETTING_INTENT)
.appendPath(AdaptiveSleepPreferenceController.PREF_NAME)
.build();
/** /**
* Uri for Battery Fix Slice. * Uri for Battery Fix Slice.
*/ */
@@ -328,6 +340,7 @@ public class CustomSliceRegistry {
sUriToSlice.put(BATTERY_FIX_SLICE_URI, BatteryFixSlice.class); sUriToSlice.put(BATTERY_FIX_SLICE_URI, BatteryFixSlice.class);
sUriToSlice.put(BLUETOOTH_DEVICES_SLICE_URI, BluetoothDevicesSlice.class); sUriToSlice.put(BLUETOOTH_DEVICES_SLICE_URI, BluetoothDevicesSlice.class);
sUriToSlice.put(CONTEXTUAL_ADAPTIVE_SLEEP_URI, ContextualAdaptiveSleepSlice.class);
sUriToSlice.put(CONTEXTUAL_NOTIFICATION_CHANNEL_SLICE_URI, sUriToSlice.put(CONTEXTUAL_NOTIFICATION_CHANNEL_SLICE_URI,
ContextualNotificationChannelSlice.class); ContextualNotificationChannelSlice.class);
sUriToSlice.put(CONTEXTUAL_WIFI_SLICE_URI, ContextualWifiSlice.class); sUriToSlice.put(CONTEXTUAL_WIFI_SLICE_URI, ContextualWifiSlice.class);
@@ -337,12 +350,12 @@ public class CustomSliceRegistry {
sUriToSlice.put(FLASHLIGHT_SLICE_URI, FlashlightSlice.class); sUriToSlice.put(FLASHLIGHT_SLICE_URI, FlashlightSlice.class);
sUriToSlice.put(LOCATION_SLICE_URI, LocationSlice.class); sUriToSlice.put(LOCATION_SLICE_URI, LocationSlice.class);
sUriToSlice.put(LOW_STORAGE_SLICE_URI, LowStorageSlice.class); sUriToSlice.put(LOW_STORAGE_SLICE_URI, LowStorageSlice.class);
sUriToSlice.put(MEDIA_OUTPUT_INDICATOR_SLICE_URI, MediaOutputIndicatorSlice.class);
sUriToSlice.put(MEDIA_OUTPUT_SLICE_URI, MediaOutputSlice.class);
sUriToSlice.put(MOBILE_DATA_SLICE_URI, MobileDataSlice.class); sUriToSlice.put(MOBILE_DATA_SLICE_URI, MobileDataSlice.class);
sUriToSlice.put(NOTIFICATION_CHANNEL_SLICE_URI, NotificationChannelSlice.class); sUriToSlice.put(NOTIFICATION_CHANNEL_SLICE_URI, NotificationChannelSlice.class);
sUriToSlice.put(STORAGE_SLICE_URI, StorageSlice.class); sUriToSlice.put(STORAGE_SLICE_URI, StorageSlice.class);
sUriToSlice.put(WIFI_SLICE_URI, WifiSlice.class); sUriToSlice.put(WIFI_SLICE_URI, WifiSlice.class);
sUriToSlice.put(MEDIA_OUTPUT_SLICE_URI, MediaOutputSlice.class);
sUriToSlice.put(MEDIA_OUTPUT_INDICATOR_SLICE_URI, MediaOutputIndicatorSlice.class);
} }
public static Class<? extends CustomSliceable> getSliceClassByUri(Uri uri) { public static Class<? extends CustomSliceable> getSliceClassByUri(Uri uri) {

View File

@@ -40,7 +40,8 @@ public class SlicePreferenceController extends BasePreferenceController implemen
LifecycleObserver, OnStart, OnStop, Observer<Slice> { LifecycleObserver, OnStart, OnStop, Observer<Slice> {
@VisibleForTesting @VisibleForTesting
LiveData<Slice> mLiveData; LiveData<Slice> mLiveData;
private SlicePreference mSlicePreference; @VisibleForTesting
SlicePreference mSlicePreference;
private Uri mUri; private Uri mUri;
public SlicePreferenceController(Context context, String preferenceKey) { public SlicePreferenceController(Context context, String preferenceKey) {
@@ -82,8 +83,6 @@ public class SlicePreferenceController extends BasePreferenceController implemen
@Override @Override
public void onChanged(Slice slice) { public void onChanged(Slice slice) {
if (slice != null) { mSlicePreference.onSliceUpdated(slice);
mSlicePreference.onSliceUpdated(slice);
}
} }
} }

View File

@@ -0,0 +1,79 @@
/*
* 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.widget;
import android.content.Context;
import android.view.View;
import android.widget.ImageView;
import androidx.preference.PreferenceViewHolder;
import com.android.settings.R;
public class RadioButtonPreferenceWithExtraWidget extends RadioButtonPreference {
public static final int EXTRA_WIDGET_VISIBILITY_GONE = 0;
public static final int EXTRA_WIDGET_VISIBILITY_INFO = 1;
private View mExtraWidgetDivider;
private ImageView mExtraWidget;
private int mExtraWidgetVisibility = EXTRA_WIDGET_VISIBILITY_GONE;
private View.OnClickListener mExtraWidgetOnClickListener;
public RadioButtonPreferenceWithExtraWidget(Context context) {
super(context, null);
setLayoutResource(R.layout.preference_radio_with_extra_widget);
}
@Override
public void onBindViewHolder(PreferenceViewHolder view) {
super.onBindViewHolder(view);
mExtraWidget = (ImageView) view.findViewById(R.id.radio_extra_widget);
mExtraWidgetDivider = view.findViewById(R.id.radio_extra_widget_divider);
setExtraWidgetVisibility(mExtraWidgetVisibility);
if (mExtraWidgetOnClickListener != null) {
setExtraWidgetOnClickListener(mExtraWidgetOnClickListener);
}
}
public void setExtraWidgetVisibility(int visibility) {
mExtraWidgetVisibility = visibility;
if (mExtraWidget == null || mExtraWidgetDivider == null) {
return;
}
if (visibility == EXTRA_WIDGET_VISIBILITY_GONE) {
mExtraWidget.setClickable(false);
mExtraWidget.setVisibility(View.GONE);
mExtraWidgetDivider.setVisibility(View.GONE);
} else {
mExtraWidget.setClickable(true);
mExtraWidget.setVisibility(View.VISIBLE);
mExtraWidgetDivider.setVisibility(View.VISIBLE);
}
}
public void setExtraWidgetOnClickListener(View.OnClickListener listener) {
mExtraWidgetOnClickListener = listener;
if (mExtraWidget != null) {
mExtraWidget.setEnabled(true);
mExtraWidget.setOnClickListener(listener);
}
}
}

View File

@@ -20,12 +20,14 @@ import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Matchers.anyInt; import static org.mockito.Matchers.anyInt;
import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy; import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
import android.content.Context; import android.content.Context;
import android.content.pm.ModuleInfo; import android.content.pm.ModuleInfo;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
import android.os.BatteryStats;
import android.os.UserManager; import android.os.UserManager;
import android.text.TextUtils; import android.text.TextUtils;
import android.text.format.DateUtils; import android.text.format.DateUtils;
@@ -94,6 +96,7 @@ public class BatteryAppListPreferenceControllerTest {
when(mNormalBatterySipper.getPackages()).thenReturn(PACKAGE_NAMES); when(mNormalBatterySipper.getPackages()).thenReturn(PACKAGE_NAMES);
when(mNormalBatterySipper.getUid()).thenReturn(UID); when(mNormalBatterySipper.getUid()).thenReturn(UID);
mNormalBatterySipper.drainType = BatterySipper.DrainType.APP; mNormalBatterySipper.drainType = BatterySipper.DrainType.APP;
mNormalBatterySipper.uidObj = mock(BatteryStats.Uid.class);
mPreferenceController = new BatteryAppListPreferenceController(mContext, KEY_APP_LIST, null, mPreferenceController = new BatteryAppListPreferenceController(mContext, KEY_APP_LIST, null,
mSettingsActivity, mFragment); mSettingsActivity, mFragment);
@@ -203,15 +206,7 @@ public class BatteryAppListPreferenceControllerTest {
@Test @Test
public void testShouldHideSipper_hiddenSystemModule_returnTrue() { public void testShouldHideSipper_hiddenSystemModule_returnTrue() {
ReflectionHelpers.setStaticField(ApplicationsState.class, "sInstance", null); when(mBatteryUtils.isHiddenSystemModule(mNormalBatterySipper)).thenReturn(true);
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(); assertThat(mPreferenceController.shouldHideSipper(mNormalBatterySipper)).isTrue();
} }

View File

@@ -368,6 +368,15 @@ public class BatteryUtilsTest {
assertThat(mBatteryUtils.shouldHideSipper(mNormalBatterySipper)).isTrue(); assertThat(mBatteryUtils.shouldHideSipper(mNormalBatterySipper)).isTrue();
} }
@Test
public void testShouldHideSipper_hiddenSystemModule_ReturnTrue() {
mNormalBatterySipper.drainType = BatterySipper.DrainType.APP;
when(mNormalBatterySipper.getUid()).thenReturn(UID);
when(mBatteryUtils.isHiddenSystemModule(mNormalBatterySipper)).thenReturn(true);
assertThat(mBatteryUtils.shouldHideSipper(mNormalBatterySipper)).isTrue();
}
@Test @Test
public void testCalculateBatteryPercent() { public void testCalculateBatteryPercent() {
assertThat(mBatteryUtils.calculateBatteryPercent(BATTERY_SYSTEM_USAGE, TOTAL_BATTERY_USAGE, assertThat(mBatteryUtils.calculateBatteryPercent(BATTERY_SYSTEM_USAGE, TOTAL_BATTERY_USAGE,

View File

@@ -18,6 +18,7 @@ package com.android.settings.fuelgauge.batterytip.detectors;
import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
@@ -40,6 +41,7 @@ import com.android.settings.fuelgauge.batterytip.tips.HighUsageTip;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.mockito.Answers;
import org.mockito.Mock; import org.mockito.Mock;
import org.mockito.MockitoAnnotations; import org.mockito.MockitoAnnotations;
import org.robolectric.RobolectricTestRunner; import org.robolectric.RobolectricTestRunner;
@@ -52,22 +54,25 @@ import java.util.List;
@RunWith(RobolectricTestRunner.class) @RunWith(RobolectricTestRunner.class)
public class HighUsageDetectorTest { public class HighUsageDetectorTest {
private static final int UID_HIGH = 123; private static final int UID_HIGH = 123;
private static final int UID_ZERO = 345; private static final int UID_LOW = 345;
private static final long SCREEN_ON_TIME_MS = DateUtils.HOUR_IN_MILLIS; private static final double POWER_HIGH = 20000;
private static final double POWER_LOW = 10000;
private Context mContext; private Context mContext;
@Mock @Mock(answer = Answers.RETURNS_DEEP_STUBS)
private BatteryStatsHelper mBatteryStatsHelper; private BatteryStatsHelper mBatteryStatsHelper;
@Mock @Mock
private BatteryUtils mBatteryUtils;
@Mock
private BatterySipper mHighBatterySipper; private BatterySipper mHighBatterySipper;
@Mock @Mock
private BatterySipper mZeroBatterySipper; private BatterySipper mLowBatterySipper;
@Mock
private BatterySipper mSystemBatterySipper;
@Mock @Mock
private HighUsageDataParser mDataParser; private HighUsageDataParser mDataParser;
private AppInfo mAppInfo; private AppInfo mHighAppInfo;
private AppInfo mLowAppInfo;
private BatteryTipPolicy mPolicy; private BatteryTipPolicy mPolicy;
private BatteryUtils mBatteryUtils;
private HighUsageDetector mHighUsageDetector; private HighUsageDetector mHighUsageDetector;
private List<BatterySipper> mUsageList; private List<BatterySipper> mUsageList;
@@ -77,28 +82,37 @@ public class HighUsageDetectorTest {
mContext = RuntimeEnvironment.application; mContext = RuntimeEnvironment.application;
mPolicy = spy(new BatteryTipPolicy(mContext)); mPolicy = spy(new BatteryTipPolicy(mContext));
mBatteryUtils = spy(BatteryUtils.getInstance(mContext));
mHighUsageDetector = spy(new HighUsageDetector(mContext, mPolicy, mBatteryStatsHelper, mHighUsageDetector = spy(new HighUsageDetector(mContext, mPolicy, mBatteryStatsHelper,
true /* mDischarging */)); true /* mDischarging */));
mHighUsageDetector.mBatteryUtils = mBatteryUtils; mHighUsageDetector.mBatteryUtils = mBatteryUtils;
mHighUsageDetector.mDataParser = mDataParser; mHighUsageDetector.mDataParser = mDataParser;
doNothing().when(mHighUsageDetector).parseBatteryData(); doNothing().when(mHighUsageDetector).parseBatteryData();
doReturn(UID_HIGH).when(mHighBatterySipper).getUid(); doReturn(UID_HIGH).when(mHighBatterySipper).getUid();
doReturn(UID_LOW).when(mLowBatterySipper).getUid();
mHighBatterySipper.uidObj = mock(BatteryStats.Uid.class); mHighBatterySipper.uidObj = mock(BatteryStats.Uid.class);
mZeroBatterySipper.uidObj = mock(BatteryStats.Uid.class); mHighBatterySipper.drainType = BatterySipper.DrainType.APP;
doReturn(UID_ZERO).when(mZeroBatterySipper).getUid(); mHighBatterySipper.totalSmearedPowerMah = POWER_HIGH;
mAppInfo = new AppInfo.Builder() mLowBatterySipper.uidObj = mock(BatteryStats.Uid.class);
mLowBatterySipper.drainType = BatterySipper.DrainType.APP;
mLowBatterySipper.totalSmearedPowerMah = POWER_LOW;
when(mBatteryUtils.shouldHideSipper(mSystemBatterySipper)).thenReturn(true);
when(mBatteryUtils.shouldHideSipper(mHighBatterySipper)).thenReturn(false);
when(mBatteryUtils.shouldHideSipper(mLowBatterySipper)).thenReturn(false);
when(mBatteryStatsHelper.getStats().getDischargeAmount(anyInt())).thenReturn(100);
when(mBatteryStatsHelper.getTotalPower()).thenReturn(POWER_HIGH + POWER_LOW);
mHighAppInfo = new AppInfo.Builder()
.setUid(UID_HIGH) .setUid(UID_HIGH)
.setScreenOnTimeMs(SCREEN_ON_TIME_MS) .build();
mLowAppInfo = new AppInfo.Builder()
.setUid(UID_LOW)
.build(); .build();
doReturn(SCREEN_ON_TIME_MS).when(mBatteryUtils).getProcessTimeMs(
BatteryUtils.StatusType.FOREGROUND, mHighBatterySipper.uidObj,
BatteryStats.STATS_SINCE_CHARGED);
doReturn(0L).when(mBatteryUtils).getProcessTimeMs(
BatteryUtils.StatusType.FOREGROUND, mZeroBatterySipper.uidObj,
BatteryStats.STATS_SINCE_CHARGED);
mUsageList = new ArrayList<>(); mUsageList = new ArrayList<>();
mUsageList.add(mSystemBatterySipper);
mUsageList.add(mLowBatterySipper);
mUsageList.add(mHighBatterySipper); mUsageList.add(mHighBatterySipper);
when(mBatteryStatsHelper.getUsageList()).thenReturn(mUsageList); when(mBatteryStatsHelper.getUsageList()).thenReturn(mUsageList);
} }
@@ -128,21 +142,15 @@ public class HighUsageDetectorTest {
} }
@Test @Test
public void testDetect_containsHighUsageApp_tipVisible() { public void testDetect_containsHighUsageApp_tipVisibleAndSorted() {
doReturn(true).when(mDataParser).isDeviceHeavilyUsed(); doReturn(true).when(mDataParser).isDeviceHeavilyUsed();
final HighUsageTip highUsageTip = (HighUsageTip) mHighUsageDetector.detect(); final HighUsageTip highUsageTip = (HighUsageTip) mHighUsageDetector.detect();
assertThat(highUsageTip.isVisible()).isTrue(); assertThat(highUsageTip.isVisible()).isTrue();
assertThat(highUsageTip.getHighUsageAppList()).containsExactly(mAppInfo);
}
@Test // Contain two appInfo and large one comes first
public void testDetect_containsHighUsageApp_removeZeroOne() { final List<AppInfo> appInfos = highUsageTip.getHighUsageAppList();
doReturn(true).when(mDataParser).isDeviceHeavilyUsed(); assertThat(appInfos).containsExactly(mLowAppInfo, mHighAppInfo);
mUsageList.add(mZeroBatterySipper); assertThat(appInfos.get(0)).isEqualTo(mHighAppInfo);
final HighUsageTip highUsageTip = (HighUsageTip) mHighUsageDetector.detect();
assertThat(highUsageTip.isVisible()).isTrue();
assertThat(highUsageTip.getHighUsageAppList()).containsExactly(mAppInfo);
} }
} }

View File

@@ -24,10 +24,14 @@ import static com.android.settings.gestures.SystemNavigationPreferenceController
import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.when;
import android.content.ComponentName; import android.content.ComponentName;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.pm.ApplicationInfo; import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo; import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo; import android.content.pm.ServiceInfo;
import android.text.TextUtils; import android.text.TextUtils;
@@ -39,6 +43,7 @@ import org.junit.After;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations; import org.mockito.MockitoAnnotations;
import org.robolectric.RobolectricTestRunner; import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment; import org.robolectric.RuntimeEnvironment;
@@ -53,9 +58,15 @@ public class SystemNavigationPreferenceControllerTest {
private Context mContext; private Context mContext;
private ShadowPackageManager mPackageManager; private ShadowPackageManager mPackageManager;
@Mock
private Context mMockContext;
@Mock
private PackageManager mMockPackageManager;
private SystemNavigationPreferenceController mController; private SystemNavigationPreferenceController mController;
private static final String ACTION_QUICKSTEP = "android.intent.action.QUICKSTEP_SERVICE"; private static final String ACTION_QUICKSTEP = "android.intent.action.QUICKSTEP_SERVICE";
private static final String TEST_RECENTS_COMPONENT_NAME = "test.component.name/.testActivity";
@Before @Before
public void setUp() { public void setUp() {
@@ -69,6 +80,10 @@ public class SystemNavigationPreferenceControllerTest {
mController = new SystemNavigationPreferenceController(mContext, mController = new SystemNavigationPreferenceController(mContext,
PREF_KEY_SYSTEM_NAVIGATION); PREF_KEY_SYSTEM_NAVIGATION);
when(mMockContext.getPackageManager()).thenReturn(mMockPackageManager);
when(mMockContext.getString(com.android.internal.R.string.config_recentsComponentName))
.thenReturn(TEST_RECENTS_COMPONENT_NAME);
} }
@After @After
@@ -166,4 +181,46 @@ public class SystemNavigationPreferenceControllerTest {
assertThat(TextUtils.equals(mController.getSummary(), mContext.getText( assertThat(TextUtils.equals(mController.getSummary(), mContext.getText(
com.android.settings.R.string.swipe_up_to_switch_apps_title))).isTrue(); com.android.settings.R.string.swipe_up_to_switch_apps_title))).isTrue();
} }
@Test
public void testIsGestureNavSupportedByDefaultLauncher_noDefaultLauncher() {
when(mMockPackageManager.getHomeActivities(any())).thenReturn(null);
assertThat(SystemNavigationPreferenceController
.isGestureNavSupportedByDefaultLauncher(mMockContext)).isTrue();
}
@Test
public void testIsGestureNavSupportedByDefaultLauncher_supported() {
when(mMockPackageManager.getHomeActivities(any())).thenReturn(
ComponentName.unflattenFromString(TEST_RECENTS_COMPONENT_NAME));
assertThat(SystemNavigationPreferenceController
.isGestureNavSupportedByDefaultLauncher(mMockContext)).isTrue();
}
@Test
public void testIsGestureNavSupportedByDefaultLauncher_notSupported() {
when(mMockPackageManager.getHomeActivities(any())).thenReturn(
new ComponentName("unsupported", "launcher"));
assertThat(SystemNavigationPreferenceController
.isGestureNavSupportedByDefaultLauncher(mMockContext)).isFalse();
}
@Test
public void testGetDefaultHomeAppName_noDefaultLauncher() {
when(mMockPackageManager.getHomeActivities(any())).thenReturn(null);
assertThat(SystemNavigationPreferenceController
.getDefaultHomeAppName(mMockContext)).isEqualTo("");
}
@Test
public void testGetDefaultHomeAppName_defaultLauncherExists() throws Exception {
when(mMockPackageManager.getHomeActivities(any())).thenReturn(
new ComponentName("supported", "launcher"));
ApplicationInfo info = new ApplicationInfo();
when(mMockPackageManager.getApplicationInfo("supported", 0)).thenReturn(info);
when(mMockPackageManager.getApplicationLabel(info)).thenReturn("Test Home App");
assertThat(SystemNavigationPreferenceController
.getDefaultHomeAppName(mMockContext)).isEqualTo("Test Home App");
}
} }

View File

@@ -0,0 +1,115 @@
/*
* 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.ContextualAdaptiveSleepSlice.DEFERRED_TIME_DAYS;
import static com.android.settings.homepage.contextualcards.slices.ContextualAdaptiveSleepSlice.PREF;
import static com.android.settings.homepage.contextualcards.slices.ContextualAdaptiveSleepSlice.PREF_KEY_SETUP_TIME;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.spy;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.net.Uri;
import androidx.slice.Slice;
import androidx.slice.SliceProvider;
import androidx.slice.widget.SliceLiveData;
import com.android.settings.slices.CustomSliceRegistry;
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 ContextualAdaptiveSleepSliceTest {
private static final String pkgName = "adaptive_sleep";
private Context mContext;
private ContextualAdaptiveSleepSlice mContextualAdaptiveSleepSlice;
@Mock
private PackageManager mPackageManager;
@Mock
private SharedPreferences mSharedPreferences;
@Before
public void setup() {
MockitoAnnotations.initMocks(this);
SliceProvider.setSpecs(SliceLiveData.SUPPORTED_SPECS);
mContext = spy(RuntimeEnvironment.application);
mContextualAdaptiveSleepSlice = spy(new ContextualAdaptiveSleepSlice(mContext));
doReturn(mPackageManager).when(mContext).getPackageManager();
doReturn(mSharedPreferences).when(mContext).getSharedPreferences(eq(PREF), anyInt());
doReturn(true).when(mContextualAdaptiveSleepSlice).isSettingsAvailable();
doReturn(pkgName).when(mPackageManager).getAttentionServicePackageName();
doReturn(-DEFERRED_TIME_DAYS).when(mSharedPreferences).getLong(eq(PREF_KEY_SETUP_TIME),
anyLong());
}
@Test
public void getUri_shouldReturnContextualAdaptiveSleepSliceUri() {
final Uri uri = mContextualAdaptiveSleepSlice.getUri();
assertThat(uri).isEqualTo(CustomSliceRegistry.CONTEXTUAL_ADAPTIVE_SLEEP_URI);
}
@Test
public void getSlice_ShowIfFeatureIsAvailable() {
final Slice slice = mContextualAdaptiveSleepSlice.getSlice();
assertThat(slice).isNotNull();
}
@Test
public void getSlice_DoNotShowIfFeatureIsUnavailable() {
doReturn(false).when(mContextualAdaptiveSleepSlice).isSettingsAvailable();
final Slice slice = mContextualAdaptiveSleepSlice.getSlice();
assertThat(slice).isNull();
}
@Test
public void getSlice_ShowIfNotRecentlySetup() {
final Slice slice = mContextualAdaptiveSleepSlice.getSlice();
assertThat(slice).isNotNull();
}
@Test
public void getSlice_DoNotShowIfRecentlySetup() {
doReturn(System.currentTimeMillis()).when(mSharedPreferences).getLong(
eq(PREF_KEY_SETUP_TIME), anyLong());
final Slice slice = mContextualAdaptiveSleepSlice.getSlice();
assertThat(slice).isNull();
}
}

View File

@@ -0,0 +1,79 @@
/*
* 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;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.when;
import android.content.Context;
import android.os.UserManager;
import com.android.settings.search.BaseSearchIndexProvider;
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.util.ReflectionHelpers;
@RunWith(RobolectricTestRunner.class)
public class MobileNetworkListFragmentTest {
@Mock
private Context mContext;
@Mock
private UserManager mUserManager;
private MobileNetworkListFragment mFragment;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mFragment = new MobileNetworkListFragment();
}
@Test
public void isPageSearchEnabled_adminUser_shouldReturnTrue() {
when(mContext.getSystemService(UserManager.class)).thenReturn(mUserManager);
when(mUserManager.isAdminUser()).thenReturn(true);
final BaseSearchIndexProvider provider =
(BaseSearchIndexProvider) mFragment.SEARCH_INDEX_DATA_PROVIDER;
final Object obj = ReflectionHelpers.callInstanceMethod(provider, "isPageSearchEnabled",
ReflectionHelpers.ClassParameter.from(Context.class, mContext));
final boolean isEnabled = (Boolean) obj;
assertThat(isEnabled).isTrue();
}
@Test
public void isPageSearchEnabled_nonAdminUser_shouldReturnFalse() {
when(mContext.getSystemService(UserManager.class)).thenReturn(mUserManager);
when(mUserManager.isAdminUser()).thenReturn(false);
final BaseSearchIndexProvider provider =
(BaseSearchIndexProvider) mFragment.SEARCH_INDEX_DATA_PROVIDER;
final Object obj = ReflectionHelpers.callInstanceMethod(provider, "isPageSearchEnabled",
ReflectionHelpers.ClassParameter.from(Context.class, mContext));
final boolean isEnabled = (Boolean) obj;
assertThat(isEnabled).isFalse();
}
}

View File

@@ -30,6 +30,7 @@ import android.app.usage.NetworkStatsManager;
import android.content.Context; import android.content.Context;
import android.net.NetworkPolicyManager; import android.net.NetworkPolicyManager;
import android.os.Bundle; import android.os.Bundle;
import android.os.UserManager;
import android.provider.Settings; import android.provider.Settings;
import android.telephony.TelephonyManager; import android.telephony.TelephonyManager;
@@ -38,6 +39,7 @@ import androidx.fragment.app.FragmentActivity;
import com.android.settings.core.FeatureFlags; import com.android.settings.core.FeatureFlags;
import com.android.settings.datausage.DataUsageSummaryPreferenceController; import com.android.settings.datausage.DataUsageSummaryPreferenceController;
import com.android.settings.development.featureflags.FeatureFlagPersistent; import com.android.settings.development.featureflags.FeatureFlagPersistent;
import com.android.settings.search.BaseSearchIndexProvider;
import com.android.settings.testutils.shadow.ShadowEntityHeaderController; import com.android.settings.testutils.shadow.ShadowEntityHeaderController;
import com.android.settings.widget.EntityHeaderController; import com.android.settings.widget.EntityHeaderController;
import com.android.settingslib.core.AbstractPreferenceController; import com.android.settingslib.core.AbstractPreferenceController;
@@ -50,6 +52,7 @@ import org.mockito.MockitoAnnotations;
import org.robolectric.RobolectricTestRunner; import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment; import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Config; import org.robolectric.annotation.Config;
import org.robolectric.util.ReflectionHelpers;
import java.util.List; import java.util.List;
@@ -135,4 +138,34 @@ public class MobileNetworkSettingsTest {
mFragment.onActivityResult(REQUEST_CODE_DELETE_SUBSCRIPTION, 0, null); mFragment.onActivityResult(REQUEST_CODE_DELETE_SUBSCRIPTION, 0, null);
verify(mActivity).finish(); verify(mActivity).finish();
} }
@Test
public void isPageSearchEnabled_adminUser_shouldReturnTrue() {
final UserManager userManager = mock(UserManager.class);
when(mContext.getSystemService(UserManager.class)).thenReturn(userManager);
when(userManager.isAdminUser()).thenReturn(true);
final BaseSearchIndexProvider provider =
(BaseSearchIndexProvider) mFragment.SEARCH_INDEX_DATA_PROVIDER;
final Object obj = ReflectionHelpers.callInstanceMethod(provider, "isPageSearchEnabled",
ReflectionHelpers.ClassParameter.from(Context.class, mContext));
final boolean isEnabled = (Boolean) obj;
assertThat(isEnabled).isTrue();
}
@Test
public void isPageSearchEnabled_nonAdminUser_shouldReturnFalse() {
final UserManager userManager = mock(UserManager.class);
when(mContext.getSystemService(UserManager.class)).thenReturn(userManager);
when(userManager.isAdminUser()).thenReturn(false);
final BaseSearchIndexProvider provider =
(BaseSearchIndexProvider) mFragment.SEARCH_INDEX_DATA_PROVIDER;
final Object obj = ReflectionHelpers.callInstanceMethod(provider, "isPageSearchEnabled",
ReflectionHelpers.ClassParameter.from(Context.class, mContext));
final boolean isEnabled = (Boolean) obj;
assertThat(isEnabled).isFalse();
}
} }

View File

@@ -30,6 +30,7 @@ import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
import android.content.DialogInterface; import android.content.DialogInterface;
import android.graphics.Color;
import android.telephony.ServiceState; import android.telephony.ServiceState;
import android.telephony.SubscriptionInfo; import android.telephony.SubscriptionInfo;
import android.telephony.SubscriptionManager; import android.telephony.SubscriptionManager;
@@ -38,6 +39,7 @@ import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.widget.Button; import android.widget.Button;
import android.widget.EditText; import android.widget.EditText;
import android.widget.Spinner;
import androidx.appcompat.app.AlertDialog; import androidx.appcompat.app.AlertDialog;
import androidx.fragment.app.FragmentActivity; import androidx.fragment.app.FragmentActivity;
@@ -58,6 +60,7 @@ import org.robolectric.annotation.Config;
@RunWith(RobolectricTestRunner.class) @RunWith(RobolectricTestRunner.class)
@Config(shadows = ShadowAlertDialogCompat.class) @Config(shadows = ShadowAlertDialogCompat.class)
public class RenameMobileNetworkDialogFragmentTest { public class RenameMobileNetworkDialogFragmentTest {
@Mock @Mock
private TelephonyManager mTelephonyMgr; private TelephonyManager mTelephonyMgr;
@Mock @Mock
@@ -95,7 +98,7 @@ public class RenameMobileNetworkDialogFragmentTest {
} }
@Test @Test
public void dialog_cancelButtonClicked_setDisplayNameNotCalled() { public void dialog_cancelButtonClicked_setDisplayNameAndIconTintNotCalled() {
when(mSubscriptionMgr.getActiveSubscriptionInfo(mSubscriptionId)).thenReturn( when(mSubscriptionMgr.getActiveSubscriptionInfo(mSubscriptionId)).thenReturn(
mSubscriptionInfo); mSubscriptionInfo);
final AlertDialog dialog = startDialog(); final AlertDialog dialog = startDialog();
@@ -106,10 +109,11 @@ public class RenameMobileNetworkDialogFragmentTest {
negativeButton.performClick(); negativeButton.performClick();
verify(mSubscriptionMgr, never()).setDisplayName(anyString(), anyInt(), anyInt()); verify(mSubscriptionMgr, never()).setDisplayName(anyString(), anyInt(), anyInt());
verify(mSubscriptionMgr, never()).setIconTint(anyInt(), anyInt());
} }
@Test @Test
public void dialog_renameButtonClicked_setDisplayNameCalled() { public void dialog_saveButtonClicked_setDisplayNameAndIconTint() {
when(mSubscriptionMgr.getActiveSubscriptionInfo(mSubscriptionId)).thenReturn( when(mSubscriptionMgr.getActiveSubscriptionInfo(mSubscriptionId)).thenReturn(
mSubscriptionInfo); mSubscriptionInfo);
@@ -117,6 +121,9 @@ public class RenameMobileNetworkDialogFragmentTest {
final EditText nameView = mFragment.getNameView(); final EditText nameView = mFragment.getNameView();
nameView.setText("test2"); nameView.setText("test2");
final Spinner colorSpinnerView = mFragment.getColorSpinnerView();
colorSpinnerView.setSelection(0);
final Button positiveButton = dialog.getButton(DialogInterface.BUTTON_POSITIVE); final Button positiveButton = dialog.getButton(DialogInterface.BUTTON_POSITIVE);
positiveButton.performClick(); positiveButton.performClick();
@@ -124,6 +131,8 @@ public class RenameMobileNetworkDialogFragmentTest {
verify(mSubscriptionMgr).setDisplayName(captor.capture(), eq(mSubscriptionId), verify(mSubscriptionMgr).setDisplayName(captor.capture(), eq(mSubscriptionId),
eq(SubscriptionManager.NAME_SOURCE_USER_INPUT)); eq(SubscriptionManager.NAME_SOURCE_USER_INPUT));
assertThat(captor.getValue()).isEqualTo("test2"); assertThat(captor.getValue()).isEqualTo("test2");
verify(mSubscriptionMgr)
.setIconTint(eq(Color.parseColor("#ff00796b" /* teal */)), eq(mSubscriptionId));
} }
@Test @Test
@@ -140,7 +149,9 @@ public class RenameMobileNetworkDialogFragmentTest {
assertThat(view.findViewById(R.id.number_label).getVisibility()).isEqualTo(View.GONE); assertThat(view.findViewById(R.id.number_label).getVisibility()).isEqualTo(View.GONE);
} }
/** Helper method to start the dialog */ /**
* Helper method to start the dialog
*/
private AlertDialog startDialog() { private AlertDialog startDialog() {
mFragment.show(mActivity.getSupportFragmentManager(), null); mFragment.show(mActivity.getSupportFragmentManager(), null);
return ShadowAlertDialogCompat.getLatestAlertDialog(); return ShadowAlertDialogCompat.getLatestAlertDialog();

View File

@@ -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.notification;
import static com.google.common.truth.Truth.assertThat;
import android.content.Context;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
@RunWith(RobolectricTestRunner.class)
public class AudioHelperTest {
private static final int START = -10;
private static final int END = 10;
private static final int DEFAULT = -100;
private Context mContext;
private AudioHelper mAudioHelper;
@Before
public void setUp() {
mContext = RuntimeEnvironment.application;
mAudioHelper = new AudioHelper(mContext);
}
@Test
public void getMaxVolume_anyStreamType_getValue() {
int volume = DEFAULT;
for (int i = START; i < END; i++) {
volume = mAudioHelper.getMaxVolume(i);
assertThat(volume).isNotEqualTo(DEFAULT);
}
}
@Test
public void getMinVolume_anyStreamType_getValue() {
int volume = DEFAULT;
for (int i = START; i < END; i++) {
volume = mAudioHelper.getMinVolume(i);
assertThat(volume).isNotEqualTo(DEFAULT);
}
}
}

View File

@@ -0,0 +1,77 @@
/*
* 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.security;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.when;
import android.content.Context;
import android.hardware.face.FaceManager;
import android.provider.Settings;
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;
import org.robolectric.util.ReflectionHelpers;
@RunWith(RobolectricTestRunner.class)
public class LockscreenBypassPreferenceControllerTest {
@Mock
private FaceManager mFaceManager;
private SwitchPreference mPreference;
private Context mContext;
private LockscreenBypassPreferenceController mController;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mContext = RuntimeEnvironment.application;
mPreference = new SwitchPreference(mContext);
mController = new LockscreenBypassPreferenceController(mContext, "TestKey");
ReflectionHelpers.setField(mController, "mFaceManager", mFaceManager);
}
@Test
public void isAvailable_whenHardwareDetected() {
assertThat(mController.isAvailable()).isFalse();
when(mFaceManager.isHardwareDetected()).thenReturn(true);
assertThat(mController.isAvailable()).isTrue();
}
@Test
public void onPreferenceChange_settingIsUpdated() {
boolean defaultValue = mContext.getResources().getBoolean(
com.android.internal.R.bool.config_faceAuthDismissesKeyguard);
boolean state = Settings.Secure.getInt(mContext.getContentResolver(),
Settings.Secure.FACE_UNLOCK_DISMISSES_KEYGUARD, defaultValue ? 1 : 0) != 0;
assertThat(mController.onPreferenceChange(mPreference, !state)).isTrue();
boolean newState = Settings.Secure.getInt(mContext.getContentResolver(),
Settings.Secure.FACE_UNLOCK_DISMISSES_KEYGUARD, 0) != 0;
assertThat(newState).isEqualTo(!state);
}
}

View File

@@ -41,6 +41,8 @@ public class SlicePreferenceControllerTest {
@Mock @Mock
private LiveData<Slice> mLiveData; private LiveData<Slice> mLiveData;
@Mock
private SlicePreference mSlicePreference;
private Context mContext; private Context mContext;
private SlicePreferenceController mController; private SlicePreferenceController mController;
private Uri mUri; private Uri mUri;
@@ -53,6 +55,7 @@ public class SlicePreferenceControllerTest {
mContext = spy(RuntimeEnvironment.application); mContext = spy(RuntimeEnvironment.application);
mController = new SlicePreferenceController(mContext, KEY); mController = new SlicePreferenceController(mContext, KEY);
mController.mLiveData = mLiveData; mController.mLiveData = mLiveData;
mController.mSlicePreference = mSlicePreference;
mUri = Uri.EMPTY; mUri = Uri.EMPTY;
} }
@@ -78,4 +81,11 @@ public class SlicePreferenceControllerTest {
mController.onStop(); mController.onStop();
verify(mLiveData).removeObserver(mController); verify(mLiveData).removeObserver(mController);
} }
@Test
public void onChanged_nullSlice_updateSlice() {
mController.onChanged(null);
verify(mController.mSlicePreference).onSliceUpdated(null);
}
} }

View File

@@ -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.widget;
import static com.android.settings.widget.RadioButtonPreferenceWithExtraWidget.EXTRA_WIDGET_VISIBILITY_GONE;
import static com.android.settings.widget.RadioButtonPreferenceWithExtraWidget.EXTRA_WIDGET_VISIBILITY_INFO;
import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.assertEquals;
import android.app.Application;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.preference.PreferenceViewHolder;
import com.android.settings.R;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
@RunWith(RobolectricTestRunner.class)
public class RadioButtonPreferenceWithExtraWidgetTest {
private Application mContext;
private RadioButtonPreferenceWithExtraWidget mPreference;
private TextView mSummary;
private ImageView mExtraWidget;
private View mExtraWidgetDivider;
private boolean mIsClickListenerCalled = false;
private View.OnClickListener mClickListener = new View.OnClickListener() {
@Override
public void onClick(View v) {
mIsClickListenerCalled = true;
}
};
@Before
public void setUp() {
mContext = RuntimeEnvironment.application;
mPreference = new RadioButtonPreferenceWithExtraWidget(mContext);
mPreference.setSummary("test summary");
View view = LayoutInflater.from(mContext)
.inflate(R.layout.preference_radio_with_extra_widget, null);
PreferenceViewHolder preferenceViewHolder =
PreferenceViewHolder.createInstanceForTests(view);
mPreference.onBindViewHolder(preferenceViewHolder);
mSummary = view.findViewById(android.R.id.summary);
mExtraWidget = view.findViewById(R.id.radio_extra_widget);
mExtraWidgetDivider = view.findViewById(R.id.radio_extra_widget_divider);
}
@Test
public void shouldHaveRadioPreferenceWithExtraWidgetLayout() {
assertThat(mPreference.getLayoutResource())
.isEqualTo(R.layout.preference_radio_with_extra_widget);
}
@Test
public void iconSpaceReservedShouldBeFalse() {
assertThat(mPreference.isIconSpaceReserved()).isFalse();
}
@Test
public void summaryShouldBeVisible() {
assertEquals(View.VISIBLE, mSummary.getVisibility());
}
@Test
public void testSetExtraWidgetVisibility_gone() {
mPreference.setExtraWidgetVisibility(EXTRA_WIDGET_VISIBILITY_GONE);
assertEquals(View.GONE, mExtraWidget.getVisibility());
assertEquals(View.GONE, mExtraWidgetDivider.getVisibility());
assertThat(mExtraWidget.isClickable()).isFalse();
}
@Test
public void testSetExtraWidgetVisibility_info() {
mPreference.setExtraWidgetVisibility(EXTRA_WIDGET_VISIBILITY_INFO);
assertEquals(View.VISIBLE, mExtraWidget.getVisibility());
assertEquals(View.VISIBLE, mExtraWidgetDivider.getVisibility());
assertThat(mExtraWidget.isClickable()).isTrue();
}
@Test
public void testSetExtraWidgetOnClickListener() {
mPreference.setExtraWidgetOnClickListener(mClickListener);
assertThat(mIsClickListenerCalled).isFalse();
mExtraWidget.callOnClick();
assertThat(mIsClickListenerCalled).isTrue();
}
@Test
public void extraWidgetStaysEnabledWhenPreferenceIsDisabled() {
mPreference.setEnabled(false);
mExtraWidget.setEnabled(false);
assertThat(mExtraWidget.isEnabled()).isFalse();
mPreference.setExtraWidgetOnClickListener(mClickListener);
assertThat(mExtraWidget.isEnabled()).isTrue();
}
}