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>
<action android:name="com.android.settings.action.SETTINGS"/>
</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"
android:value="com.android.settings.category.ia.apps"/>
<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
android:id="@+id/lockPattern"
android:layout_width="288dp"
android:layout_height="288dp"
android:layout_marginStart="-42dp"
android:layout_marginEnd="-42dp"
android:layout_gravity="center_vertical"/>
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center"/>
<TextView
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
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="@dimen/sim_content_padding">
android:layout_height="wrap_content">
<EditText
android:id="@+id/edittext"
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="text"
android:maxLength="50"
android:singleLine="true">
<requestFocus/>
</EditText>
android:paddingEnd="@dimen/sim_content_padding"
android:paddingStart="@dimen/sim_content_padding">
<TextView
style="@style/device_info_dialog_label"
android:id="@+id/operator_name_label"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/status_operator"/>
<TextView
style="@style/device_info_dialog_value"
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/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/mobile_network_sim_name_label"/>
<TextView
style="@style/device_info_dialog_label"
android:id="@+id/number_label"
<EditText
android:id="@+id/name_edittext"
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_height="wrap_content"
android:text="@string/status_number_sim_status"/>
<TextView
style="@style/device_info_dialog_value"
android:id="@+id/number_value"
android:layout_marginStart="@dimen/sim_color_spinner_padding"
android:layout_marginEnd="@dimen/sim_color_spinner_padding"/>
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
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>
</ScrollView>

View File

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

View File

@@ -166,6 +166,7 @@
<dimen name="sim_dialog_margin_bottom">16dip</dimen>
<!-- SIM Dialog padding -->
<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_content_padding">24dip</dimen>
<!-- Sim Card Name length -->

View File

@@ -885,7 +885,7 @@
<!-- Message shown in summary field when face unlock is set up. [CHAR LIMIT=40] -->
<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] -->
<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] -->
<string name="security_settings_face_preference_title">Face unlock</string>
<!-- 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] -->
<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. -->
<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] -->
<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] -->
<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] -->
<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] -->
<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] -->
<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] -->
<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] -->
<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] -->
<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] -->
<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 />
@@ -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] -->
<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] -->
<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] -->
<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] -->
<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]-->
<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]-->
@@ -2833,7 +2833,7 @@
<!-- Setting option summary when adaptive sleep is off [CHAR LIMIT=NONE] -->
<string name="adaptive_sleep_summary_off">Off</string>
<!-- Description about the feature adaptive sleep [CHAR LIMIT=NONE]-->
<string name="adaptive_sleep_description">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]-->
<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] -->
<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] -->
<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] -->
<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>
<!-- 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
carrier name, but especially in multi-SIM configurations users may want to use a different
name. [CHAR LIMIT=40] -->
<string name="mobile_network_sim_name">SIM name</string>
<!-- Label on the confirmation button of a dialog that lets a user set the display name of a
mobile network subscription [CHAR LIMIT=20] -->
<string name="mobile_network_sim_name_rename">Rename</string>
<string name="mobile_network_sim_name">SIM name &amp; color</string>
<!-- Label for an item listing the name of the SIM that the user has specified. [CHAR LIMIT=40] -->
<string name="mobile_network_sim_name_label">Name</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
disabling/enabling a SIM. The SIM is enabled in this state. [CHAR LIMIT=40] -->
<string name="mobile_network_use_sim_on">Use SIM</string>

View File

@@ -90,7 +90,7 @@
<item name="android:backgroundDimEnabled">false</item>
</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="switchBarMarginStart">@dimen/switchbar_subsettings_margin_start</item>
<item name="switchBarMarginEnd">@dimen/switchbar_subsettings_margin_end</item>
@@ -99,6 +99,8 @@
<item name="switchBarRestrictionIcon">@*android:drawable/ic_info</item>
</style>
<style name="ThemeOverlay.SwitchBar.Settings" parent="ThemeOverlay.SwitchBar.Settings.Base"/>
<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:thumbTint">@color/switchbar_switch_thumb_tint</item>

View File

@@ -62,6 +62,14 @@
android:summary="@string/summary_placeholder"
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 -->
<PreferenceCategory
android:key="privacy_services"

View File

@@ -30,6 +30,13 @@
android:summary="@string/summary_placeholder"
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
android:key="security_lockscreen_add_users_when_locked"
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.IntentFilter;
import android.content.pm.ResolveInfo;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
@@ -65,7 +66,7 @@ public class FallbackHome extends Activity {
@Override
public void onColorsChanged(WallpaperColors colors, int which) {
if (colors != null) {
View decorView = getWindow().getDecorView();
final View decorView = getWindow().getDecorView();
decorView.setSystemUiVisibility(
updateVisibilityFlagsFromColors(colors, decorView.getSystemUiVisibility()));
mWallManager.removeOnColorsChangedListener(this);
@@ -81,7 +82,7 @@ public class FallbackHome extends Activity {
// we don't flash the wallpaper before SUW
mProvisioned = Settings.Global.getInt(getContentResolver(),
Settings.Global.DEVICE_PROVISIONED, 0) != 0;
int flags;
final int flags;
if (!mProvisioned) {
setTheme(R.style.FallbackHome_SetupWizard);
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;
}
// 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);
if (mWallManager == null) {
Log.w(TAG, "Wallpaper manager isn't ready, can't listen to color changes!");
} else {
WallpaperColors colors = mWallManager.getWallpaperColors(WallpaperManager.FLAG_SYSTEM);
if (colors == null) {
mWallManager.addOnColorsChangedListener(mColorsChangedListener, null /* handler */);
} else {
flags = updateVisibilityFlagsFromColors(colors, flags);
}
loadWallpaperColors(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() {
if (getSystemService(UserManager.class).isUserUnlocked()) {
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) {
if ((colors.getColorHints() & WallpaperColors.HINT_SUPPORTS_DARK_TEXT) != 0) {
return flags | View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR

View File

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

View File

@@ -25,9 +25,9 @@ import com.android.settings.core.TogglePreferenceController;
public class AdaptiveSleepPreferenceController extends TogglePreferenceController {
private final String SYSTEM_KEY = ADAPTIVE_SLEEP;
private final int DEFAULT_VALUE = 0;
public static final String PREF_NAME = "adaptive_sleep";
private static final String SYSTEM_KEY = ADAPTIVE_SLEEP;
private static final int DEFAULT_VALUE = 0;
final boolean hasSufficientPermissions;
@@ -35,9 +35,7 @@ public class AdaptiveSleepPreferenceController extends TogglePreferenceControlle
super(context, key);
final PackageManager packageManager = mContext.getPackageManager();
final String attentionPackage = packageManager.getAttentionServicePackageName();
hasSufficientPermissions = attentionPackage != null && packageManager.checkPermission(
Manifest.permission.CAMERA, attentionPackage) == PackageManager.PERMISSION_GRANTED;
hasSufficientPermissions = hasSufficientPermission(packageManager);
}
@Override
@@ -46,7 +44,6 @@ public class AdaptiveSleepPreferenceController extends TogglePreferenceControlle
SYSTEM_KEY, DEFAULT_VALUE) != DEFAULT_VALUE;
}
@Override
public boolean setChecked(boolean isChecked) {
Settings.System.putInt(mContext.getContentResolver(), SYSTEM_KEY,
@@ -57,10 +54,7 @@ public class AdaptiveSleepPreferenceController extends TogglePreferenceControlle
@Override
@AvailabilityStatus
public int getAvailabilityStatus() {
return mContext.getResources().getBoolean(
com.android.internal.R.bool.config_adaptive_sleep_available)
? AVAILABLE_UNSEARCHABLE
: UNSUPPORTED_ON_DEVICE;
return isControllerAvailable(mContext);
}
@Override
@@ -69,4 +63,17 @@ public class AdaptiveSleepPreferenceController extends TogglePreferenceControlle
? R.string.adaptive_sleep_summary_on
: 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;
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.content.Context;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.provider.SearchIndexableResource;
import android.util.Log;
import com.android.settings.R;
import com.android.settings.dashboard.DashboardFragment;
@@ -40,8 +45,15 @@ public class AdaptiveSleepSettings extends DashboardFragment {
super.onCreate(icicle);
final FooterPreference footerPreference =
mFooterPreferenceMixin.createFooterPreference();
final Context context = getContext();
footerPreference.setIcon(R.drawable.ic_privacy_shield_24dp);
footerPreference.setTitle(R.string.adaptive_sleep_privacy);
context.getSharedPreferences(PREF, Context.MODE_PRIVATE)
.edit()
.putBoolean(PREF_KEY_INTERACTED, true)
.apply();
}
@Override

View File

@@ -352,15 +352,10 @@ public class BatteryAppListPreferenceController extends AbstractPreferenceContro
@VisibleForTesting
boolean shouldHideSipper(BatterySipper sipper) {
// Don't show hidden system module
final String packageName = mBatteryUtils.getPackageName(sipper.getUid());
if (!TextUtils.isEmpty(packageName)
&& AppUtils.isHiddenSystemModule(mContext, packageName)) {
return true;
}
// Don't show over-counted and unaccounted in any condition
// Don't show over-counted, unaccounted and hidden system module in any condition
return sipper.drainType == BatterySipper.DrainType.OVERCOUNTED
|| sipper.drainType == BatterySipper.DrainType.UNACCOUNTED;
|| sipper.drainType == BatterySipper.DrainType.UNACCOUNTED
|| mBatteryUtils.isHiddenSystemModule(sipper);
}
@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.StatsManagerConfig;
import com.android.settings.overlay.FeatureFactory;
import com.android.settingslib.applications.AppUtils;
import com.android.settingslib.fuelgauge.Estimate;
import com.android.settingslib.fuelgauge.EstimateKt;
import com.android.settingslib.fuelgauge.PowerWhitelistBackend;
@@ -189,8 +190,10 @@ public class BatteryUtils {
&& sipper.drainType != BatterySipper.DrainType.UNACCOUNTED
&& sipper.drainType != BatterySipper.DrainType.BLUETOOTH
&& sipper.drainType != BatterySipper.DrainType.WIFI
&& sipper.drainType != BatterySipper.DrainType.IDLE) {
// Don't add it if it is overcounted, unaccounted, wifi, bluetooth, or screen
&& sipper.drainType != BatterySipper.DrainType.IDLE
&& !isHiddenSystemModule(sipper)) {
// Don't add it if it is overcounted, unaccounted, wifi, bluetooth, screen
// or hidden system modules
proportionalSmearPowerMah += sipper.totalPowerMah;
}
}
@@ -253,7 +256,27 @@ public class BatteryUtils {
|| drainType == BatterySipper.DrainType.WIFI
|| (sipper.totalPowerMah * SECONDS_IN_HOUR) < MIN_POWER_THRESHOLD_MILLI_AMP
|| 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.os.BatteryStats;
import android.text.format.DateUtils;
import androidx.annotation.VisibleForTesting;
@@ -72,22 +71,33 @@ public class HighUsageDetector implements BatteryTipDetector {
if (mPolicy.highUsageEnabled && mDischarging) {
parseBatteryData();
if (mDataParser.isDeviceHeavilyUsed() || mPolicy.testHighUsageTip) {
final List<BatterySipper> batterySippers = mBatteryStatsHelper.getUsageList();
for (int i = 0, size = batterySippers.size(); i < size; i++) {
final BatterySipper batterySipper = batterySippers.get(i);
if (!mBatteryUtils.shouldHideSipper(batterySipper)) {
final long foregroundTimeMs = mBatteryUtils.getProcessTimeMs(
BatteryUtils.StatusType.FOREGROUND, batterySipper.uidObj,
BatteryStats.STATS_SINCE_CHARGED);
if (foregroundTimeMs >= DateUtils.MINUTE_IN_MILLIS) {
mHighUsageAppList.add(new AppInfo.Builder()
.setUid(batterySipper.getUid())
.setPackageName(
mBatteryUtils.getPackageName(batterySipper.getUid()))
.setScreenOnTimeMs(foregroundTimeMs)
.build());
}
final BatteryStats batteryStats = mBatteryStatsHelper.getStats();
final List<BatterySipper> batterySippers
= new ArrayList<>(mBatteryStatsHelper.getUsageList());
final double totalPower = mBatteryStatsHelper.getTotalPower();
final int dischargeAmount = batteryStats != null
? batteryStats.getDischargeAmount(BatteryStats.STATS_SINCE_CHARGED)
: 0;
Collections.sort(batterySippers,
(sipper1, sipper2) -> Double.compare(sipper2.totalSmearedPowerMah,
sipper1.totalSmearedPowerMah));
for (BatterySipper batterySipper : batterySippers) {
final double percent = mBatteryUtils.calculateBatteryPercent(
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
@@ -97,10 +107,6 @@ public class HighUsageDetector implements BatteryTipDetector {
.setScreenOnTimeMs(TimeUnit.HOURS.toMillis(3))
.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_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.content.Context;
import android.content.SharedPreferences;
@@ -29,7 +33,6 @@ import android.graphics.drawable.Drawable;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.provider.SearchIndexableResource;
import android.view.View;
import androidx.annotation.VisibleForTesting;
import androidx.preference.PreferenceScreen;
@@ -41,6 +44,7 @@ import com.android.settings.search.BaseSearchIndexProvider;
import com.android.settings.search.Indexable;
import com.android.settings.widget.RadioButtonPickerFragment;
import com.android.settings.widget.RadioButtonPreference;
import com.android.settings.widget.RadioButtonPreferenceWithExtraWidget;
import com.android.settings.widget.VideoPreference;
import com.android.settingslib.search.SearchIndexable;
import com.android.settingslib.widget.CandidateInfo;
@@ -94,8 +98,25 @@ public class SystemNavigationGestureSettings extends RadioButtonPickerFragment {
}
@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);
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
@@ -135,6 +156,13 @@ public class SystemNavigationGestureSettings extends RadioButtonPickerFragment {
@Override
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);
setIllustrationVideo(mVideoPreference, key);
return true;
@@ -196,10 +224,36 @@ public class SystemNavigationGestureSettings extends RadioButtonPickerFragment {
@Override
public void bindPreferenceExtra(RadioButtonPreference pref,
String key, CandidateInfo info, String defaultKey, String systemDefaultKey) {
if (info instanceof NavModeCandidateInfo) {
pref.setSummary(((NavModeCandidateInfo) info).loadSummary());
pref.setAppendixVisibility(View.GONE);
if (!(info instanceof NavModeCandidateInfo)
|| !(pref instanceof RadioButtonPreferenceWithExtraWidget)) {
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 {

View File

@@ -22,11 +22,14 @@ import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import com.android.settings.R;
import com.android.settings.core.BasePreferenceController;
import java.util.ArrayList;
public class SystemNavigationPreferenceController extends BasePreferenceController {
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(
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)
.setCardCategory(ContextualCard.Category.POSSIBLE)
.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()
.addCard(wifiCard)
.addCard(connectedDeviceCard)
.addCard(lowStorageCard)
.addCard(batteryFixCard)
.addCard(notificationChannelCard)
.addCard(contextualAdaptiveSleepCard)
.build();
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.content.Context;
import android.os.UserManager;
import android.provider.SearchIndexableResource;
import com.android.settings.R;
@@ -66,5 +67,10 @@ public class MobileNetworkListFragment extends DashboardFragment {
result.add(sir);
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);
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.settings.SettingsEnums;
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.telephony.ServiceState;
import android.telephony.SubscriptionInfo;
@@ -30,7 +34,12 @@ import android.text.TextUtils;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.Spinner;
import android.widget.TextView;
import com.android.settings.R;
@@ -42,9 +51,12 @@ import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
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 static final String TAG ="RenameMobileNetwork";
public static final String TAG = "RenameMobileNetwork";
private static final String KEY_SUBSCRIPTION_ID = "subscription_id";
@@ -52,6 +64,8 @@ public class RenameMobileNetworkDialogFragment extends InstrumentedDialogFragmen
private SubscriptionManager mSubscriptionManager;
private int mSubId;
private EditText mNameView;
private Spinner mColorSpinner;
private Color[] mColors;
public static RenameMobileNetworkDialogFragment newInstance(int subscriptionId) {
final Bundle args = new Bundle(1);
@@ -76,6 +90,11 @@ public class RenameMobileNetworkDialogFragment extends InstrumentedDialogFragmen
return mNameView;
}
@VisibleForTesting
protected Spinner getColorSpinnerView() {
return mColorSpinner;
}
@Override
public void onAttach(Context context) {
super.onAttach(context);
@@ -87,6 +106,8 @@ public class RenameMobileNetworkDialogFragment extends InstrumentedDialogFragmen
@NonNull
@Override
public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
mColors = getColors();
final AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
final LayoutInflater layoutInflater = builder.getContext().getSystemService(
LayoutInflater.class);
@@ -95,9 +116,11 @@ public class RenameMobileNetworkDialogFragment extends InstrumentedDialogFragmen
builder.setTitle(R.string.mobile_network_sim_name)
.setView(view)
.setPositiveButton(R.string.mobile_network_sim_name_rename, (dialog, which) -> {
String newName = mNameView.getText().toString();
mSubscriptionManager.setDisplayName(newName, mSubId,
mSubscriptionManager.setDisplayName(mNameView.getText().toString(), mSubId,
SubscriptionManager.NAME_SOURCE_USER_INPUT);
mSubscriptionManager.setIconTint(
mColors[mColorSpinner.getSelectedItemPosition()].getColor(),
mSubId);
})
.setNegativeButton(android.R.string.cancel, null);
return builder.create();
@@ -105,7 +128,7 @@ public class RenameMobileNetworkDialogFragment extends InstrumentedDialogFragmen
@VisibleForTesting
protected void populateView(View view) {
mNameView = view.findViewById(R.id.edittext);
mNameView = view.findViewById(R.id.name_edittext);
final SubscriptionInfo info = mSubscriptionManager.getActiveSubscriptionInfo(mSubId);
if (info == null) {
Log.w(TAG, "got null SubscriptionInfo for mSubId:" + mSubId);
@@ -117,6 +140,17 @@ public class RenameMobileNetworkDialogFragment extends InstrumentedDialogFragmen
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 ServiceState serviceState = mTelephonyManager.getServiceStateForSubscriber(mSubId);
operatorName.setText(serviceState.getOperatorAlphaLong());
@@ -134,4 +168,80 @@ public class RenameMobileNetworkDialogFragment extends InstrumentedDialogFragmen
public int getMetricsCategory() {
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.os.UserHandle;
import android.os.UserManager;
import android.util.Log;
import com.android.settings.Utils;
@@ -30,6 +31,7 @@ import com.android.settings.Utils;
*/
public class AudioHelper {
private static final String TAG = "AudioHelper";
private Context mContext;
private AudioManager mAudioManager;
@@ -76,6 +78,15 @@ public class AudioHelper {
}
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:
mAlertButton.setBackground(unselectedBackground);
mSilenceButton.setBackground(selectedBackground);
mSilenceButton.setSelected(true);
break;
case IMPORTANCE_HIGH:
default:
mSilenceButton.setBackground(unselectedBackground);
mAlertButton.setBackground(selectedBackground);
mAlertButton.setSelected(true);
break;
}
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() {
Drawable icon = getContext().getDrawable(R.drawable.ic_notifications);
Drawable icon = getContext().getDrawable(R.drawable.ic_notifications_alert);
icon.setTintList(Utils.getColorAccent(getContext()));
return icon;
}

View File

@@ -96,18 +96,23 @@ public final class EnableContentCaptureWithServiceSettingsPreferenceController
for (UserInfo info: userInfos) {
userHandles.add(info.getUserHandle());
}
AlertDialog.Builder builder = new AlertDialog.Builder(context);
UserAdapter adapter = UserAdapter.createUserAdapter(userManager, context, userHandles);
builder.setTitle(com.android.settingslib.R.string.choose_profile)
.setAdapter(adapter, (DialogInterface dialog, int which) -> {
final UserHandle user = userHandles.get(which);
// Show menu on top level items.
final Intent intent = pref.getIntent();
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
context.startActivityAsUser(intent, user);
})
.show();
if (userHandles.size() == 1) {
final Intent intent = pref.getIntent().addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
context.startActivityAsUser(intent, userHandles.get(0));
} else {
AlertDialog.Builder builder = new AlertDialog.Builder(context);
UserAdapter adapter = UserAdapter.createUserAdapter(userManager, context,
userHandles);
builder.setTitle(com.android.settingslib.R.string.choose_profile)
.setAdapter(adapter, (DialogInterface dialog, int which) -> {
final UserHandle user = userHandles.get(which);
// Show menu on top level items.
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 com.android.settings.display.AdaptiveSleepPreferenceController;
import com.android.settings.flashlight.FlashlightSlice;
import com.android.settings.fuelgauge.batterytip.BatteryTipPreferenceController;
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.slices.BatteryFixSlice;
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.LowStorageSlice;
import com.android.settings.homepage.contextualcards.slices.NotificationChannelSlice;
@@ -64,6 +66,16 @@ public class CustomSliceRegistry {
.appendPath(SettingsSlicesContract.KEY_AIRPLANE_MODE)
.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.
*/
@@ -328,6 +340,7 @@ public class CustomSliceRegistry {
sUriToSlice.put(BATTERY_FIX_SLICE_URI, BatteryFixSlice.class);
sUriToSlice.put(BLUETOOTH_DEVICES_SLICE_URI, BluetoothDevicesSlice.class);
sUriToSlice.put(CONTEXTUAL_ADAPTIVE_SLEEP_URI, ContextualAdaptiveSleepSlice.class);
sUriToSlice.put(CONTEXTUAL_NOTIFICATION_CHANNEL_SLICE_URI,
ContextualNotificationChannelSlice.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(LOCATION_SLICE_URI, LocationSlice.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(NOTIFICATION_CHANNEL_SLICE_URI, NotificationChannelSlice.class);
sUriToSlice.put(STORAGE_SLICE_URI, StorageSlice.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) {

View File

@@ -40,7 +40,8 @@ public class SlicePreferenceController extends BasePreferenceController implemen
LifecycleObserver, OnStart, OnStop, Observer<Slice> {
@VisibleForTesting
LiveData<Slice> mLiveData;
private SlicePreference mSlicePreference;
@VisibleForTesting
SlicePreference mSlicePreference;
private Uri mUri;
public SlicePreferenceController(Context context, String preferenceKey) {
@@ -82,8 +83,6 @@ public class SlicePreferenceController extends BasePreferenceController implemen
@Override
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.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;
import android.content.Context;
import android.content.pm.ModuleInfo;
import android.content.pm.PackageManager;
import android.os.BatteryStats;
import android.os.UserManager;
import android.text.TextUtils;
import android.text.format.DateUtils;
@@ -94,6 +96,7 @@ public class BatteryAppListPreferenceControllerTest {
when(mNormalBatterySipper.getPackages()).thenReturn(PACKAGE_NAMES);
when(mNormalBatterySipper.getUid()).thenReturn(UID);
mNormalBatterySipper.drainType = BatterySipper.DrainType.APP;
mNormalBatterySipper.uidObj = mock(BatteryStats.Uid.class);
mPreferenceController = new BatteryAppListPreferenceController(mContext, KEY_APP_LIST, null,
mSettingsActivity, mFragment);
@@ -203,15 +206,7 @@ public class BatteryAppListPreferenceControllerTest {
@Test
public void testShouldHideSipper_hiddenSystemModule_returnTrue() {
ReflectionHelpers.setStaticField(ApplicationsState.class, "sInstance", null);
final String packageName = "test.hidden.module";
final ModuleInfo moduleInfo = new ModuleInfo();
moduleInfo.setPackageName(packageName);
moduleInfo.setHidden(true);
final List<ModuleInfo> modules = new ArrayList<>();
modules.add(moduleInfo);
when(mBatteryUtils.getPackageName(anyInt() /* uid */)).thenReturn(packageName);
when(mPackageManager.getInstalledModules(anyInt() /* flags */)).thenReturn(modules);
when(mBatteryUtils.isHiddenSystemModule(mNormalBatterySipper)).thenReturn(true);
assertThat(mPreferenceController.shouldHideSipper(mNormalBatterySipper)).isTrue();
}

View File

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

View File

@@ -24,10 +24,14 @@ import static com.android.settings.gestures.SystemNavigationPreferenceController
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.Context;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
import android.text.TextUtils;
@@ -39,6 +43,7 @@ import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
@@ -53,9 +58,15 @@ public class SystemNavigationPreferenceControllerTest {
private Context mContext;
private ShadowPackageManager mPackageManager;
@Mock
private Context mMockContext;
@Mock
private PackageManager mMockPackageManager;
private SystemNavigationPreferenceController mController;
private static final String ACTION_QUICKSTEP = "android.intent.action.QUICKSTEP_SERVICE";
private static final String TEST_RECENTS_COMPONENT_NAME = "test.component.name/.testActivity";
@Before
public void setUp() {
@@ -69,6 +80,10 @@ public class SystemNavigationPreferenceControllerTest {
mController = new SystemNavigationPreferenceController(mContext,
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
@@ -166,4 +181,46 @@ public class SystemNavigationPreferenceControllerTest {
assertThat(TextUtils.equals(mController.getSummary(), mContext.getText(
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.net.NetworkPolicyManager;
import android.os.Bundle;
import android.os.UserManager;
import android.provider.Settings;
import android.telephony.TelephonyManager;
@@ -38,6 +39,7 @@ import androidx.fragment.app.FragmentActivity;
import com.android.settings.core.FeatureFlags;
import com.android.settings.datausage.DataUsageSummaryPreferenceController;
import com.android.settings.development.featureflags.FeatureFlagPersistent;
import com.android.settings.search.BaseSearchIndexProvider;
import com.android.settings.testutils.shadow.ShadowEntityHeaderController;
import com.android.settings.widget.EntityHeaderController;
import com.android.settingslib.core.AbstractPreferenceController;
@@ -50,6 +52,7 @@ import org.mockito.MockitoAnnotations;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Config;
import org.robolectric.util.ReflectionHelpers;
import java.util.List;
@@ -135,4 +138,34 @@ public class MobileNetworkSettingsTest {
mFragment.onActivityResult(REQUEST_CODE_DELETE_SUBSCRIPTION, 0, null);
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 android.content.DialogInterface;
import android.graphics.Color;
import android.telephony.ServiceState;
import android.telephony.SubscriptionInfo;
import android.telephony.SubscriptionManager;
@@ -38,6 +39,7 @@ import android.view.LayoutInflater;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Spinner;
import androidx.appcompat.app.AlertDialog;
import androidx.fragment.app.FragmentActivity;
@@ -58,6 +60,7 @@ import org.robolectric.annotation.Config;
@RunWith(RobolectricTestRunner.class)
@Config(shadows = ShadowAlertDialogCompat.class)
public class RenameMobileNetworkDialogFragmentTest {
@Mock
private TelephonyManager mTelephonyMgr;
@Mock
@@ -95,7 +98,7 @@ public class RenameMobileNetworkDialogFragmentTest {
}
@Test
public void dialog_cancelButtonClicked_setDisplayNameNotCalled() {
public void dialog_cancelButtonClicked_setDisplayNameAndIconTintNotCalled() {
when(mSubscriptionMgr.getActiveSubscriptionInfo(mSubscriptionId)).thenReturn(
mSubscriptionInfo);
final AlertDialog dialog = startDialog();
@@ -106,10 +109,11 @@ public class RenameMobileNetworkDialogFragmentTest {
negativeButton.performClick();
verify(mSubscriptionMgr, never()).setDisplayName(anyString(), anyInt(), anyInt());
verify(mSubscriptionMgr, never()).setIconTint(anyInt(), anyInt());
}
@Test
public void dialog_renameButtonClicked_setDisplayNameCalled() {
public void dialog_saveButtonClicked_setDisplayNameAndIconTint() {
when(mSubscriptionMgr.getActiveSubscriptionInfo(mSubscriptionId)).thenReturn(
mSubscriptionInfo);
@@ -117,6 +121,9 @@ public class RenameMobileNetworkDialogFragmentTest {
final EditText nameView = mFragment.getNameView();
nameView.setText("test2");
final Spinner colorSpinnerView = mFragment.getColorSpinnerView();
colorSpinnerView.setSelection(0);
final Button positiveButton = dialog.getButton(DialogInterface.BUTTON_POSITIVE);
positiveButton.performClick();
@@ -124,6 +131,8 @@ public class RenameMobileNetworkDialogFragmentTest {
verify(mSubscriptionMgr).setDisplayName(captor.capture(), eq(mSubscriptionId),
eq(SubscriptionManager.NAME_SOURCE_USER_INPUT));
assertThat(captor.getValue()).isEqualTo("test2");
verify(mSubscriptionMgr)
.setIconTint(eq(Color.parseColor("#ff00796b" /* teal */)), eq(mSubscriptionId));
}
@Test
@@ -140,7 +149,9 @@ public class RenameMobileNetworkDialogFragmentTest {
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() {
mFragment.show(mActivity.getSupportFragmentManager(), null);
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
private LiveData<Slice> mLiveData;
@Mock
private SlicePreference mSlicePreference;
private Context mContext;
private SlicePreferenceController mController;
private Uri mUri;
@@ -53,6 +55,7 @@ public class SlicePreferenceControllerTest {
mContext = spy(RuntimeEnvironment.application);
mController = new SlicePreferenceController(mContext, KEY);
mController.mLiveData = mLiveData;
mController.mSlicePreference = mSlicePreference;
mUri = Uri.EMPTY;
}
@@ -78,4 +81,11 @@ public class SlicePreferenceControllerTest {
mController.onStop();
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();
}
}