Merge "Remove reference to @string/ssl_ca_cert_dialog_title" into nyc-dev
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index fdd9b08..6637d7e 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -1478,8 +1478,7 @@
<activity android:name=".accessibility.AccessibilitySettingsForSetupWizardActivity"
android:label="@string/vision_settings_title"
android:theme="@style/SetupWizardAccessibilityTheme"
- android:taskAffinity="com.android.wizard"
- android:configChanges="orientation|keyboardHidden|screenSize" >
+ android:taskAffinity="com.android.wizard" >
<intent-filter android:priority="1">
<action android:name="android.settings.ACCESSIBILITY_SETTINGS_FOR_SUW" />
<category android:name="android.intent.category.DEFAULT" />
@@ -1558,6 +1557,7 @@
<activity android:name="ConfirmDeviceCredentialActivity$InternalActivity"
android:exported="false"
android:permission="android.permission.MANAGE_USERS"
+ android:resizeableActivity="false"
android:theme="@android:style/Theme.NoDisplay">
<intent-filter android:priority="1">
<action android:name="android.app.action.CONFIRM_DEVICE_CREDENTIAL_WITH_USER" />
diff --git a/res/layout-land/font_size_activity.xml b/res/layout-land/font_size_activity.xml
new file mode 100644
index 0000000..69abac1
--- /dev/null
+++ b/res/layout-land/font_size_activity.xml
@@ -0,0 +1,108 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="horizontal">
+
+ <LinearLayout
+ android:orientation="vertical"
+ android:layout_width="0dp"
+ android:layout_weight="1"
+ android:layout_height="match_parent">
+
+ <include layout="@layout/preview_seek_bar_view_pager" />
+
+ <com.android.settings.widget.DotsPageIndicator
+ android:id="@+id/page_indicator"
+ style="@style/PreviewPagerPageIndicator"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_horizontal"
+ android:padding="6dp" />
+ </LinearLayout>
+
+ <ScrollView
+ android:layout_width="0dp"
+ android:layout_weight="1"
+ android:layout_height="match_parent"
+ android:fillViewport="true">
+
+ <LinearLayout
+ android:orientation="vertical"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingTop="16dp"
+ android:paddingStart="?android:attr/listPreferredItemPaddingStart"
+ android:paddingEnd="?android:attr/listPreferredItemPaddingEnd">
+
+ <TextView
+ android:id="@+id/current_label"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_horizontal"
+ android:padding="6dp"
+ android:textAppearance="@android:style/TextAppearance.Material.Widget.TextView"
+ android:elevation="2dp" />
+
+ <com.android.settings.widget.LabeledSeekBar
+ android:id="@+id/seek_bar"
+ android:layout_width="match_parent"
+ android:layout_height="48dp"
+ style="@android:style/Widget.Material.SeekBar.Discrete" />
+
+ <RelativeLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:gravity="center_vertical">
+
+ <ImageView
+ android:id="@+id/smaller"
+ android:layout_width="48dp"
+ android:layout_height="48dp"
+ android:layout_alignParentStart="true"
+ android:background="?android:attr/selectableItemBackgroundBorderless"
+ android:src="@drawable/ic_font_size_16dp"
+ android:tint="?android:attr/textColorPrimary"
+ android:tintMode="src_in"
+ android:scaleType="center"
+ android:focusable="true"
+ android:contentDescription="@string/font_size_make_smaller_desc" />
+
+ <ImageView
+ android:id="@+id/larger"
+ android:layout_width="48dp"
+ android:layout_height="48dp"
+ android:layout_alignParentEnd="true"
+ android:background="?android:attr/selectableItemBackgroundBorderless"
+ android:src="@drawable/ic_font_size_24dp"
+ android:tint="?android:attr/textColorPrimary"
+ android:tintMode="src_in"
+ android:scaleType="center"
+ android:focusable="true"
+ android:contentDescription="@string/font_size_make_larger_desc" />
+ </RelativeLayout>
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/font_size_summary"
+ android:layout_marginBottom="16dp"
+ android:textAppearance="@android:style/TextAppearance.Material.Subhead" />
+ </LinearLayout>
+ </ScrollView>
+</LinearLayout>
diff --git a/res/layout-land/screen_zoom_activity.xml b/res/layout-land/screen_zoom_activity.xml
new file mode 100644
index 0000000..8d6e735
--- /dev/null
+++ b/res/layout-land/screen_zoom_activity.xml
@@ -0,0 +1,108 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="horizontal">
+
+ <LinearLayout
+ android:orientation="vertical"
+ android:layout_width="0dp"
+ android:layout_weight="1"
+ android:layout_height="match_parent" >
+
+ <include layout="@layout/preview_seek_bar_view_pager" />
+
+ <com.android.settings.widget.DotsPageIndicator
+ android:id="@+id/page_indicator"
+ style="@style/PreviewPagerPageIndicator"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_horizontal"
+ android:padding="6dp" />
+ </LinearLayout>
+
+ <ScrollView
+ android:layout_width="0dp"
+ android:layout_weight="1"
+ android:layout_height="match_parent"
+ android:fillViewport="true">
+
+ <LinearLayout
+ android:orientation="vertical"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingTop="16dp"
+ android:paddingStart="?android:attr/listPreferredItemPaddingStart"
+ android:paddingEnd="?android:attr/listPreferredItemPaddingEnd">
+
+ <TextView
+ android:id="@+id/current_label"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_horizontal"
+ android:padding="6dp"
+ android:textAppearance="@android:style/TextAppearance.Material.Widget.TextView"
+ android:elevation="2dp" />
+
+ <com.android.settings.widget.LabeledSeekBar
+ android:id="@+id/seek_bar"
+ android:layout_width="match_parent"
+ android:layout_height="48dp"
+ style="@android:style/Widget.Material.SeekBar.Discrete"/>
+
+ <RelativeLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:gravity="center_vertical">
+
+ <ImageView
+ android:id="@+id/smaller"
+ android:layout_width="48dp"
+ android:layout_height="48dp"
+ android:layout_alignParentStart="true"
+ android:background="?android:attr/selectableItemBackgroundBorderless"
+ android:src="@drawable/ic_remove_24dp"
+ android:tint="?android:attr/textColorPrimary"
+ android:tintMode="src_in"
+ android:scaleType="center"
+ android:focusable="true"
+ android:contentDescription="@string/screen_zoom_make_smaller_desc" />
+
+ <ImageView
+ android:id="@+id/larger"
+ android:layout_width="48dp"
+ android:layout_height="48dp"
+ android:layout_alignParentEnd="true"
+ android:background="?android:attr/selectableItemBackgroundBorderless"
+ android:src="@drawable/ic_add_24dp"
+ android:tint="?android:attr/textColorPrimary"
+ android:tintMode="src_in"
+ android:scaleType="center"
+ android:focusable="true"
+ android:contentDescription="@string/screen_zoom_make_larger_desc" />
+ </RelativeLayout>
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/screen_zoom_summary"
+ android:layout_marginBottom="16dp"
+ android:textAppearance="@android:style/TextAppearance.Material.Subhead" />
+ </LinearLayout>
+ </ScrollView>
+</LinearLayout>
diff --git a/res/layout/condition_card.xml b/res/layout/condition_card.xml
index 0e480a5..c1224b5 100644
--- a/res/layout/condition_card.xml
+++ b/res/layout/condition_card.xml
@@ -85,11 +85,13 @@
<!-- TODO: Better background -->
<View
+ android:id="@+id/divider"
android:layout_width="match_parent"
android:layout_height=".25dp"
android:background="@android:color/white" />
<com.android.internal.widget.ButtonBarLayout
+ android:id="@+id/buttonBar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="8dp"
diff --git a/res/layout/conversation_message_content.xml b/res/layout/conversation_message_content.xml
index 7bc53e5..bdb0ea7 100644
--- a/res/layout/conversation_message_content.xml
+++ b/res/layout/conversation_message_content.xml
@@ -25,7 +25,6 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
- android:minHeight="@dimen/conversation_message_contact_icon_size"
android:layout_marginTop="0dp" >
<TextView
diff --git a/res/layout/conversation_message_icon.xml b/res/layout/conversation_message_icon.xml
index 4ffd285..9f9f0ac 100644
--- a/res/layout/conversation_message_icon.xml
+++ b/res/layout/conversation_message_icon.xml
@@ -16,8 +16,8 @@
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/conversation_icon"
- android:layout_width="@dimen/conversation_message_contact_icon_size"
- android:layout_height="@dimen/conversation_message_contact_icon_size"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
android:fontFamily="sans-serif"
android:textStyle="bold"
android:textSize="@dimen/conversation_message_contact_icon_text_size"
diff --git a/res/layout/dashboard_category.xml b/res/layout/dashboard_category.xml
index b3500b2..7019a9c 100644
--- a/res/layout/dashboard_category.xml
+++ b/res/layout/dashboard_category.xml
@@ -21,7 +21,8 @@
android:orientation="vertical"
android:paddingBottom="8dip"
android:background="@color/card_background"
- android:importantForAccessibility="noHideDescendants">
+ android:importantForAccessibility="noHideDescendants"
+ android:elevation="@dimen/dashboard_category_elevation" >
<TextView android:id="@android:id/title"
android:layout_width="match_parent"
diff --git a/res/layout/dashboard_tile.xml b/res/layout/dashboard_tile.xml
index 983e6ea..2f87909 100644
--- a/res/layout/dashboard_tile.xml
+++ b/res/layout/dashboard_tile.xml
@@ -21,7 +21,8 @@
android:gravity="center_vertical"
android:minHeight="@dimen/dashboard_tile_minimum_height"
android:clickable="true"
- android:background="@drawable/selectable_card" >
+ android:background="@drawable/selectable_card"
+ android:elevation="@dimen/dashboard_category_elevation" >
<ImageView
android:id="@android:id/icon"
diff --git a/res/layout/edit_user_photo_popup_item.xml b/res/layout/edit_user_photo_popup_item.xml
deleted file mode 100644
index 11fdfbc..0000000
--- a/res/layout/edit_user_photo_popup_item.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2013, 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.
-*/
--->
-
-<TextView xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@android:id/text1"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:minHeight="?android:attr/listPreferredItemHeightSmall"
- android:textAppearance="?android:attr/textAppearanceListItemSmall"
- android:textColor="?android:attr/textColorAlertDialogListItem"
- android:gravity="center_vertical"
- android:paddingStart="16dip"
- android:paddingEnd="16dip"
- android:ellipsize="marquee"
-/>
diff --git a/res/layout/fingerprint_enroll_finish_base.xml b/res/layout/fingerprint_enroll_finish_base.xml
index 03447b3..15ee22a 100644
--- a/res/layout/fingerprint_enroll_finish_base.xml
+++ b/res/layout/fingerprint_enroll_finish_base.xml
@@ -49,20 +49,25 @@
android:visibility="gone" />
<View
- android:layout_height="0dp"
+ android:layout_height="24dp"
android:layout_width="match_parent"
android:layout_weight="1"/>
<ImageView
android:id="@+id/fingerprint_in_app_indicator"
- android:layout_width="@dimen/fingerprint_in_app_indicator_size"
- android:layout_height="@dimen/fingerprint_in_app_indicator_size"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:layout_weight="5"
+ android:minHeight="@dimen/fingerprint_in_app_indicator_min_size"
+ android:minWidth="@dimen/fingerprint_in_app_indicator_min_size"
+ android:maxHeight="@dimen/fingerprint_in_app_indicator_max_size"
+ android:maxWidth="@dimen/fingerprint_in_app_indicator_max_size"
android:layout_gravity="center_horizontal"
android:contentDescription="@android:string/fingerprint_icon_content_description"
android:src="@drawable/fp_app_indicator" />
<View
- android:layout_height="0dp"
+ android:layout_height="24dp"
android:layout_width="match_parent"
android:layout_weight="1"/>
diff --git a/res/layout/font_size_activity.xml b/res/layout/font_size_activity.xml
index 5a4aba6..aa3930c 100644
--- a/res/layout/font_size_activity.xml
+++ b/res/layout/font_size_activity.xml
@@ -63,7 +63,7 @@
android:layout_height="48dp"
android:background="?android:attr/selectableItemBackgroundBorderless"
android:src="@drawable/ic_font_size_16dp"
- android:tint="?android:attr/colorControlNormal"
+ android:tint="?android:attr/textColorPrimary"
android:tintMode="src_in"
android:scaleType="center"
android:focusable="true"
@@ -82,7 +82,7 @@
android:layout_height="48dp"
android:background="?android:attr/selectableItemBackgroundBorderless"
android:src="@drawable/ic_font_size_24dp"
- android:tint="?android:attr/colorControlNormal"
+ android:tint="?android:attr/textColorPrimary"
android:tintMode="src_in"
android:scaleType="center"
android:focusable="true"
diff --git a/res/layout/preference_importance_slider.xml b/res/layout/preference_importance_slider.xml
index 677a32b..dc7c9db 100644
--- a/res/layout/preference_importance_slider.xml
+++ b/res/layout/preference_importance_slider.xml
@@ -15,47 +15,64 @@
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:minHeight="?android:attr/listPreferredItemHeight"
- android:gravity="center_vertical"
- android:paddingStart="?android:attr/listPreferredItemPaddingStart"
- android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
- android:orientation="vertical"
- android:clickable="false"
- android:focusable="false" >
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:minHeight="?android:attr/listPreferredItemHeight"
+ android:gravity="center_vertical"
+ android:paddingStart="?android:attr/listPreferredItemPaddingStart"
+ android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
+ android:paddingTop="8dp"
+ android:paddingBottom="8dp"
+ android:orientation="vertical"
+ android:clickable="false"
+ android:focusable="false" >
- <FrameLayout
+ <TextView
+ android:id="@android:id/title"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:singleLine="true"
+ android:textAppearance="@android:style/TextAppearance.Material.Subhead"
+ android:textColor="?android:attr/textColorPrimary"
+ android:ellipsize="marquee"
+ android:fadingEdge="horizontal" />
+
+ <FrameLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content" >
+
+ <ImageView
+ android:id="@+id/auto_importance"
+ android:src="@drawable/notification_auto_importance"
+ android:layout_gravity="center_vertical|start"
+ android:layout_width="48dp"
+ android:layout_height="48dp" />
+
+ <SeekBar
+ android:id="@*android:id/seekbar"
+ android:layout_marginStart="56dp"
+ android:layout_marginEnd="32dp"
+ android:layout_gravity="center_vertical"
android:layout_width="match_parent"
- android:layout_height="wrap_content" >
+ android:layout_height="48dp"
+ android:focusable="true"
+ android:background="#00ffffff"
+ android:progressBackgroundTint="@color/importance_secondary_slider_color"
+ android:thumbTint="@color/importance_disabled_slider_color"
+ android:progressTint="@color/importance_disabled_slider_color"
+ style="@android:style/Widget.Material.SeekBar.Discrete"
+ android:tickMarkTint="@android:color/black" />
- <ImageView
- android:id="@+id/low_importance"
- android:src="@*android:drawable/ic_notification_block"
- android:layout_gravity="center_vertical|start"
- android:layout_width="24dp"
- android:layout_height="24dp"
- android:tint="@color/importance_icon_tint" />
+ </FrameLayout>
- <SeekBar
- android:id="@*android:id/seekbar"
- android:layout_marginStart="56dp"
- android:layout_marginEnd="56dp"
- android:layout_gravity="center_vertical"
- android:layout_width="match_parent"
- android:layout_height="48dp"
- android:focusable="true"
- android:background="#00ffffff"
- style="@android:style/Widget.Material.SeekBar.Discrete"
- android:tickMarkTint="@android:color/black"/>
-
- <ImageView
- android:id="@+id/max_importance"
- android:src="@*android:drawable/ic_notification_alert"
- android:layout_gravity="center_vertical|end"
- android:layout_width="24dp"
- android:layout_height="24dp"
- android:tint="@color/importance_icon_tint" />
-
- </FrameLayout>
+ <TextView
+ android:id="@android:id/summary"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignStart="@android:id/title"
+ android:textAlignment="viewStart"
+ android:textAppearance="@android:style/TextAppearance.Material.Body1"
+ android:textColor="?android:attr/textColorSecondary"
+ android:maxLines="10"
+ android:minLines="3" />
</LinearLayout>
diff --git a/res/layout/preview_seek_bar_view_pager.xml b/res/layout/preview_seek_bar_view_pager.xml
index e24b674..5524d8a 100644
--- a/res/layout/preview_seek_bar_view_pager.xml
+++ b/res/layout/preview_seek_bar_view_pager.xml
@@ -19,7 +19,6 @@
android:layout_height="0dp"
android:layout_weight="1"
android:orientation="vertical"
- android:minHeight="@dimen/preview_pager_min_height"
android:padding="@dimen/preview_pager_padding"
android:background="@drawable/preview_seek_bar_outline" >
diff --git a/res/layout/restricted_popup_menu_item.xml b/res/layout/restricted_popup_menu_item.xml
new file mode 100644
index 0000000..78a09ef
--- /dev/null
+++ b/res/layout/restricted_popup_menu_item.xml
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2016, 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.
+*/
+-->
+
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:minHeight="?android:attr/listPreferredItemHeightSmall"
+ android:gravity="center_vertical"
+ android:paddingStart="16dip"
+ android:paddingEnd="16dip">
+ <TextView
+ android:id="@+id/text"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textColor="?android:attr/textColorAlertDialogListItem"
+ android:textAppearance="?android:attr/textAppearanceListItemSmall"
+ android:ellipsize="marquee"
+ android:layout_alignParentLeft="true" />
+ <ImageView
+ android:id="@+id/restricted_icon"
+ android:layout_width="@dimen/restricted_icon_size"
+ android:layout_height="@dimen/restricted_icon_size"
+ android:scaleType="centerInside"
+ android:src="@drawable/ic_info"
+ android:layout_alignParentRight="true"
+ android:visibility="gone" />
+</RelativeLayout>
\ No newline at end of file
diff --git a/res/layout/screen_zoom_activity.xml b/res/layout/screen_zoom_activity.xml
index 4d3ab39..0141019 100644
--- a/res/layout/screen_zoom_activity.xml
+++ b/res/layout/screen_zoom_activity.xml
@@ -62,7 +62,7 @@
android:layout_height="48dp"
android:background="?android:attr/selectableItemBackgroundBorderless"
android:src="@drawable/ic_remove_24dp"
- android:tint="?android:attr/colorControlNormal"
+ android:tint="?android:attr/textColorPrimary"
android:tintMode="src_in"
android:scaleType="center"
android:focusable="true"
@@ -81,7 +81,7 @@
android:layout_height="48dp"
android:background="?android:attr/selectableItemBackgroundBorderless"
android:src="@drawable/ic_add_24dp"
- android:tint="?android:attr/colorControlNormal"
+ android:tint="?android:attr/textColorPrimary"
android:tintMode="src_in"
android:scaleType="center"
android:focusable="true"
diff --git a/res/layout/video_preference.xml b/res/layout/video_preference.xml
index a6fde76..5f7116d 100644
--- a/res/layout/video_preference.xml
+++ b/res/layout/video_preference.xml
@@ -15,13 +15,22 @@
-->
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/video_background"
android:layout_width="match_parent"
android:layout_height="wrap_content">
+ <ImageView
+ android:id="@+id/video_background"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:src="@drawable/accessibility_screen_magnification_background"
+ android:scaleType="fitXY"
+ android:adjustViewBounds="true" />
+
<VideoView
android:id="@+id/video"
android:layout_width="wrap_content"
- android:layout_height="wrap_content" />
+ android:layout_height="wrap_content"
+ android:layout_alignTop="@id/video_background"
+ android:layout_centerHorizontal="true" />
</RelativeLayout>
\ No newline at end of file
diff --git a/res/layout/vpn_dialog.xml b/res/layout/vpn_dialog.xml
index 620b43f..6822e95 100644
--- a/res/layout/vpn_dialog.xml
+++ b/res/layout/vpn_dialog.xml
@@ -119,8 +119,7 @@
<LinearLayout android:id="@+id/login"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:orientation="vertical"
- android:visibility="gone">
+ android:orientation="vertical">
<TextView style="@style/vpn_label" android:text="@string/vpn_username"/>
<EditText style="@style/vpn_value" android:id="@+id/username"/>
diff --git a/res/values/colors.xml b/res/values/colors.xml
index 89b2d15..a9756ad 100644
--- a/res/values/colors.xml
+++ b/res/values/colors.xml
@@ -125,6 +125,10 @@
<color name="seek_bar_preference_preview_text">#fff</color>
+ <color name="importance_slider_color">@*android:color/material_deep_teal_500</color>
+ <color name="importance_disabled_slider_color">@*android:color/material_grey_300</color>
+ <color name="importance_secondary_slider_color">#858383</color>
+
<color name="usage_graph_dots">#B0BEC5</color>
</resources>
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index 9d739c0..ef7efa2 100755
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -228,7 +228,9 @@
<dimen name="fingerprint_animation_size">88dp</dimen>
<dimen name="fingerprint_progress_bar_size">192dp</dimen>
<dimen name="fingerprint_enrolling_content_margin_top">36dp</dimen>
- <dimen name="fingerprint_in_app_indicator_size">120dp</dimen>
+ <dimen name="fingerprint_in_app_indicator_size">124dp</dimen>
+ <dimen name="fingerprint_in_app_indicator_min_size">124dp</dimen>
+ <dimen name="fingerprint_in_app_indicator_max_size">264dp</dimen>
<dimen name="setup_fingerprint_ring_radius">80dip</dimen>
<dimen name="setup_fingerprint_progress_bar_size">168dp</dimen>
@@ -261,10 +263,8 @@
<dimen name="unmount_button_padding">8dp</dimen>
<!-- Display, Screen zoom -->
- <dimen name="screen_zoom_preview_height">240dp</dimen>
<dimen name="screen_zoom_preview_app_icon_width">88dp</dimen>
<dimen name="conversation_message_list_padding">10dp</dimen>
- <dimen name="conversation_message_contact_icon_size">42dp</dimen>
<dimen name="conversation_message_contact_icon_text_size">32sp</dimen>
<dimen name="conversation_message_text_size">16sp</dimen>
<dimen name="conversation_status_text_size">12sp</dimen>
@@ -280,9 +280,6 @@
<dimen name="accessibility_layout_margin_start_end">24dp</dimen>
<dimen name="accessibility_button_preference_padding_top_bottom">18dp</dimen>
- <!-- Accessibility, Font size -->
- <dimen name="font_size_preview_height">240dp</dimen>
-
<!-- Accessibility, Screen magnification. These values are meant to be relative values and the actual layout value will be set programmatically. -->
<dimen name="screen_magnification_video_background_width">750dp</dimen>
<dimen name="screen_magnification_video_background_height">383dp</dimen>
@@ -295,7 +292,6 @@
<!-- Display Size and Font Size preview screen -->
<dimen name="preview_pager_padding">8dp</dimen>
- <dimen name="preview_pager_min_height">200dp</dimen>
<!-- Padding between the radio buttons/checkbox and text on the redaction interstitial -->
<dimen name="redaction_padding_start">16dp</dimen>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index c11ea33..3eb6d3d 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -3441,6 +3441,13 @@
If you turn off notifications for this app, you may miss important alerts and updates.
</string>
+ <!-- Manage applications, individual application info screen, section heading for information about the app installer [CHAR_LIMIT=25] -->
+ <string name="app_install_details_group_title">Store</string>
+ <!-- Manage applications, individual application info screen, title for the option which will trigger application info in it's installer [CHAR_LIMIT=25] -->
+ <string name="app_install_details_title">App details</string>
+ <!-- Manage applications, individual application info screen, summary for the option which will trigger application info in it's installer [CHAR_LIMIT=50] -->
+ <string name="app_install_details_summary">App installed from <xliff:g id="app_store">%1$s</xliff:g></string>
+
<!-- App Ops Settings --> <skip />
<!-- [CHAR LIMIT=NONE] App ops settings title, on main settings screen. If clicked, the user is taken to a settings screen for app operations -->
<string name="app_ops_settings">App ops</string>
@@ -5972,22 +5979,25 @@
<string name="notification_importance_none">Not set</string>
<!-- [CHAR LIMIT=100] Notification Importance slider: blocked importance level description -->
- <string name="notification_importance_blocked">Blocked: Never show these notifications</string>
+ <string name="notification_importance_blocked">Never show notifications from this app</string>
<!-- [CHAR LIMIT=100] Notification Importance slider: min importance level description -->
- <string name="notification_importance_min">Min: Silently show at the bottom of the notification list</string>
+ <string name="notification_importance_min">No full screen interruption, peeking, sound, or vibration. Show at the bottom of the notification list. Hide from lock screen and status bar.</string>
<!-- [CHAR LIMIT=100] Notification Importance slider: low importance level description -->
- <string name="notification_importance_low">Low: Silently show these notifications</string>
+ <string name="notification_importance_low">No full screen interruption, peeking, sound, or vibration.</string>
<!-- [CHAR LIMIT=100] Notification Importance slider: normal importance level description -->
- <string name="notification_importance_default">Normal: Allow these notification to make sounds</string>
+ <string name="notification_importance_default">No full screen interruption or peeking.</string>
<!-- [CHAR LIMIT=100] Notification Importance slider: high importance level description -->
- <string name="notification_importance_high">High: Peek onto the screen and allow sound</string>
+ <string name="notification_importance_high">Always peek. No full screen interruption.</string>
<!-- [CHAR LIMIT=100] Notification Importance slider: max importance level description -->
- <string name="notification_importance_max">Urgent: Show at the top of the notifications list, peek onto the screen and allow sound</string>
+ <string name="notification_importance_max">Always peek, and allow full screen interruption. Show at the top of the notification list.</string>
+
+ <!-- [CHAR LIMIT=100] Notification Importance slider: max importance level description -->
+ <string name="notification_importance_unspecified">App determines importance for each notification</string>
<!-- [CHAR LIMIT=60] Notification importance reset button -->
<string name="importance_reset">Reset</string>
@@ -6024,7 +6034,13 @@
<xliff:g id="notification_listener_name">%1$s</xliff:g> will be able to read all notifications,
including personal information such as contact names and the text of messages you receive.
It will also be able to dismiss notifications or trigger action buttons they contain.
+ \n\nThis will also give the app the ability to turn Do Not Disturb on or off and change related settings.
</string>
+ <string name="notification_listener_disable_warning_summary">
+ If you turn off notification access for <xliff:g id="notification_listener_name">%1$s</xliff:g>, Do Not Disturb access may also be turned off.
+ </string>
+ <string name="notification_listener_disable_warning_confirm">Turn off</string>
+ <string name="notification_listener_disable_warning_cancel">Cancel</string>
<!-- Title for managing VR (virtual reality) helper services. [CHAR LIMIT=50] -->
<string name="vr_listeners_title">VR helper services</string>
@@ -6473,6 +6489,8 @@
<string name="notifications_priority">Do Not Disturb overridden</string>
<!-- App notification summary divider [CHAR LIMIT=40] -->
<string name="notifications_summary_divider">\u00A0/\u00A0</string>
+ <!-- App notification summary for advanced controls -->
+ <string name="notification_summary_level">Level %d</string>
<!-- Permissions preference summary [CHAR LIMIT=40] -->
<plurals name="permissions_summary">
@@ -6870,6 +6888,8 @@
<!-- Zen mode access settings - summary for warning dialog when enabling access [CHAR LIMIT=NONE] -->
<string name="zen_access_warning_dialog_summary">The app will be able to turn on/off Do Not Disturb and make changes to related settings.</string>
+ <string name="zen_access_disabled_package_warning">Must stay turned on because notification access is on</string>
+
<!-- Zen mode access settings - title for warning dialog when revoking access [CHAR LIMIT=NONE] -->
<string name="zen_access_revoke_warning_dialog_title">Revoke access to Do Not Disturb for <xliff:g id="app" example="Tasker">%1$s</xliff:g>?</string>
@@ -7187,7 +7207,7 @@
<string name="network_restrictions">Network restrictions</string>
<!-- A summary shown on data usage screens to indicate inaccuracy of data tracking [CHAR LIMIT=NONE] -->
- <string name="operator_warning">Operator data accounting may differ from your device.</string>
+ <string name="operator_warning">Carrier data accounting may differ from device accounting</string>
<!-- Format string describing how much data has been used [CHAR LIMIT=20] -->
<string name="data_used_template"><xliff:g name="amount" example="1 GB">%1$s</xliff:g> used</string>
@@ -7211,22 +7231,25 @@
the code to do that -->
<string name="data_usage_other_apps" translatable="false">Other apps included in usage</string>
- <!-- Description of number of apps allowed to ignore data saver [CHAR LIMIT=NONE] -->
+ <!-- Description of number of apps allowed to ignore Data Saver [CHAR LIMIT=NONE] -->
<plurals name="data_saver_unrestricted_summary">
<item quantity="one">1 app allowed to use unrestricted data when Data Saver is on</item>
<item quantity="other"><xliff:g id="count" example="10">%1$d</xliff:g> apps allowed to use unrestricted data when Data Saver is on</item>
</plurals>
<!-- Name of Data Saver screens [CHAR LIMIT=30] -->
- <string name="data_saver_title">Data Saver</string>
+ <string name="data_saver_title">Data saver</string>
<!-- Button that leads to list of apps with unrestricted data access [CHAR LIMIT=60] -->
<string name="unrestricted_data_saver">Unrestricted data access</string>
- <!-- Summary for the data saver feature being on [CHAR LIMIT=NONE] -->
+ <!-- Description of message shown when app is blacklisted for background data access [CHAR LIMIT=NONE] -->
+ <string name="restrict_background_blacklisted">Background data is turned off</string>
+
+ <!-- Summary for the Data Saver feature being on [CHAR LIMIT=NONE] -->
<string name="data_saver_on">On</string>
- <!-- Summary for the data saver feature being off [CHAR LIMIT=NONE] -->
+ <!-- Summary for the Data Saver feature being off [CHAR LIMIT=NONE] -->
<string name="data_saver_off">Off</string>
<!-- Title for switch to allow app unrestricted data usage [CHAR LIMIT=30] -->
diff --git a/res/xml/app_notification_settings.xml b/res/xml/app_notification_settings.xml
index 8bd0c88..fd2f33e 100644
--- a/res/xml/app_notification_settings.xml
+++ b/res/xml/app_notification_settings.xml
@@ -32,30 +32,22 @@
android:summary="@string/show_silently_summary"
android:order="3" />
<!-- Slider -->
- <com.android.settingslib.RestrictedPreference
- android:key="importance_title"
- android:title="@string/notification_importance_title"
- android:order="4"/>
<com.android.settings.notification.ImportanceSeekBarPreference
android:key="importance"
- android:order="5"/>
-
- <com.android.settings.applications.LayoutPreference
- android:key="importance_reset_button"
- android:layout="@layout/two_buttons_panel"
- android:order="6" />
+ android:title="@string/notification_importance_title"
+ android:order="4"/>
<!-- Visibility Override -->
<DropDownPreference
android:key="visibility_override"
android:title="@string/app_notification_visibility_override_title"
- android:order="7" />
+ android:order="5" />
<!-- Bypass DND -->
<com.android.settingslib.RestrictedSwitchPreference
android:key="bypass_dnd"
android:title="@string/app_notification_override_dnd_title"
android:summary="@string/app_notification_override_dnd_summary"
- android:order="8" />
+ android:order="6" />
</PreferenceScreen>
diff --git a/res/xml/data_saver.xml b/res/xml/data_saver.xml
index 5b69cbb..20ce5c8 100644
--- a/res/xml/data_saver.xml
+++ b/res/xml/data_saver.xml
@@ -15,11 +15,20 @@
-->
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
- android:title="@string/data_saver_title">
+ xmlns:settings="http://schemas.android.com/apk/res-auto"
+ android:title="@string/data_saver_title">
<Preference
android:key="unrestricted_access"
android:title="@string/unrestricted_data_saver"
android:fragment="com.android.settings.datausage.UnrestrictedDataAccess" />
+ <!-- Feature description text -->
+ <com.android.settings.fuelgauge.WallOfTextPreference
+ android:key="description"
+ android:summary="@*android:string/data_saver_description"
+ android:persistent="false"
+ android:selectable="false"
+ settings:allowDividerAbove="true" />
+
</PreferenceScreen>
diff --git a/res/xml/security_settings_misc.xml b/res/xml/security_settings_misc.xml
index 2577b6c..0ba10c0 100644
--- a/res/xml/security_settings_misc.xml
+++ b/res/xml/security_settings_misc.xml
@@ -15,7 +15,8 @@
-->
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
- android:title="@string/security_settings_title">
+ xmlns:settings="http://schemas.android.com/apk/res/com.android.settings"
+ android:title="@string/security_settings_title">
<PreferenceCategory android:key="sim_lock"
android:title="@string/sim_lock_settings_title"
@@ -54,7 +55,8 @@
<com.android.settingslib.RestrictedSwitchPreference android:key="toggle_install_applications"
android:title="@string/install_applications"
android:summaryOff="@string/install_unknown_applications"
- android:summaryOn="@string/install_unknown_applications" />
+ android:summaryOn="@string/install_unknown_applications"
+ settings:useAdditionalSummary="true" />
</PreferenceCategory>
diff --git a/res/xml/tts_settings.xml b/res/xml/tts_settings.xml
index 05ed6e7..ab57649 100644
--- a/res/xml/tts_settings.xml
+++ b/res/xml/tts_settings.xml
@@ -47,6 +47,11 @@
android:title="@string/tts_reset_speech_rate_title"
android:summary="@string/tts_reset_speech_rate_summary" />
+ <Preference android:key="reset_speech_pitch"
+ android:persistent="false"
+ android:title="@string/tts_reset_speech_pitch_title"
+ android:summary="@string/tts_reset_speech_pitch_summary" />
+
<Preference android:key="tts_play_example"
android:persistent="false"
android:title="@string/tts_play_example_title"
diff --git a/res/xml/user_settings.xml b/res/xml/user_settings.xml
index b89f766..cd0103d 100644
--- a/res/xml/user_settings.xml
+++ b/res/xml/user_settings.xml
@@ -34,7 +34,8 @@
<com.android.settingslib.RestrictedSwitchPreference
android:key="add_users_when_locked"
android:title="@string/user_add_on_lockscreen_menu"
- android:summary="@string/user_add_on_lockscreen_menu_summary" />
+ android:summary="@string/user_add_on_lockscreen_menu_summary"
+ settings:useAdditionalSummary="true" />
</PreferenceCategory>
<Preference
android:key="emergency_info"
diff --git a/src/com/android/settings/ConfirmDeviceCredentialActivity.java b/src/com/android/settings/ConfirmDeviceCredentialActivity.java
index 16d0685..d71ba9b 100644
--- a/src/com/android/settings/ConfirmDeviceCredentialActivity.java
+++ b/src/com/android/settings/ConfirmDeviceCredentialActivity.java
@@ -95,6 +95,8 @@
private String getTitleFromOrganizationName(int userId) {
DevicePolicyManager dpm = (DevicePolicyManager) getSystemService(
Context.DEVICE_POLICY_SERVICE);
- return (dpm != null) ? dpm.getOrganizationNameForUser(userId) : null;
+ CharSequence organizationNameForUser = (dpm != null)
+ ? dpm.getOrganizationNameForUser(userId) : null;
+ return organizationNameForUser != null ? organizationNameForUser.toString() : null;
}
}
diff --git a/src/com/android/settings/ConfirmLockPassword.java b/src/com/android/settings/ConfirmLockPassword.java
index ca4be6c..a1bc3dd 100644
--- a/src/com/android/settings/ConfirmLockPassword.java
+++ b/src/com/android/settings/ConfirmLockPassword.java
@@ -267,6 +267,11 @@
handleAttemptLockout(deadline);
} else {
resetState();
+ mErrorTextView.setText("");
+ if (isProfileChallenge()) {
+ updateErrorMessage(mLockPatternUtils.getCurrentFailedPasswordAttempts(
+ mEffectiveUserId));
+ }
}
mCredentialCheckResultTracker.setListener(this);
}
diff --git a/src/com/android/settings/CryptKeeper.java b/src/com/android/settings/CryptKeeper.java
index 1b37066..594cd38 100644
--- a/src/com/android/settings/CryptKeeper.java
+++ b/src/com/android/settings/CryptKeeper.java
@@ -799,6 +799,8 @@
// Asynchronously throw up the IME, since there are issues with requesting it to be shown
// immediately.
if (mLockPatternView == null && !mCooldown) {
+ getWindow().setSoftInputMode(
+ WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE);
mHandler.postDelayed(new Runnable() {
@Override public void run() {
imm.showSoftInputUnchecked(0, null);
diff --git a/src/com/android/settings/DeviceAdminAdd.java b/src/com/android/settings/DeviceAdminAdd.java
index 364700b..9d4d895 100644
--- a/src/com/android/settings/DeviceAdminAdd.java
+++ b/src/com/android/settings/DeviceAdminAdd.java
@@ -82,6 +82,9 @@
public static final String EXTRA_DEVICE_ADMIN_PACKAGE_NAME =
"android.app.extra.DEVICE_ADMIN_PACKAGE_NAME";
+ public static final String EXTRA_CALLED_FROM_SUPPORT_DIALOG =
+ "android.app.extra.CALLED_FROM_SUPPORT_DIALOG";
+
Handler mHandler;
DevicePolicyManager mDPM;
@@ -113,6 +116,8 @@
int mCurSysAppOpMode;
int mCurToastAppOpMode;
+ boolean mIsCalledFromSupportDialog = false;
+
@Override
protected void onCreate(Bundle icicle) {
super.onCreate(icicle);
@@ -129,6 +134,8 @@
return;
}
+ mIsCalledFromSupportDialog = getIntent().getBooleanExtra(
+ EXTRA_CALLED_FROM_SUPPORT_DIALOG, false);
String action = getIntent().getAction();
ComponentName who = (ComponentName)getIntent().getParcelableExtra(
@@ -238,6 +245,12 @@
if (DevicePolicyManager.ACTION_ADD_DEVICE_ADMIN.equals(getIntent().getAction())) {
mRefreshing = false;
if (mDPM.isAdminActive(who)) {
+ if (mDPM.isRemovingAdmin(who, android.os.Process.myUserHandle().getIdentifier())) {
+ Log.w(TAG, "Requested admin is already being removed: " + who);
+ finish();
+ return;
+ }
+
ArrayList<DeviceAdminInfo.PolicyInfo> newPolicies = mDeviceAdmin.getUsedPolicies();
for (int i = 0; i < newPolicies.size(); i++) {
DeviceAdminInfo.PolicyInfo pi = newPolicies.get(i);
@@ -459,6 +472,18 @@
}
@Override
+ protected void onUserLeaveHint() {
+ super.onUserLeaveHint();
+ // In case this is triggered from support dialog, finish this activity once the user leaves
+ // so that this won't appear as a background next time support dialog is triggered. This
+ // is because the support dialog activity and this belong to the same task and we can't
+ // start this in new activity since we need to know the calling package in this activity.
+ if (mIsCalledFromSupportDialog) {
+ finish();
+ }
+ }
+
+ @Override
protected Dialog onCreateDialog(int id, Bundle args) {
switch (id) {
case DIALOG_WARNING: {
@@ -539,7 +564,7 @@
mActionButton.setText(R.string.remove_device_admin);
}
}
- String supportMessage = mDPM.getLongSupportMessageForUser(
+ CharSequence supportMessage = mDPM.getLongSupportMessageForUser(
mDeviceAdmin.getComponent(), UserHandle.myUserId());
if (!TextUtils.isEmpty(supportMessage)) {
mSupportMessage.setText(supportMessage);
diff --git a/src/com/android/settings/PreviewPagerAdapter.java b/src/com/android/settings/PreviewPagerAdapter.java
index 20d1761..7e4ebf3 100644
--- a/src/com/android/settings/PreviewPagerAdapter.java
+++ b/src/com/android/settings/PreviewPagerAdapter.java
@@ -45,19 +45,23 @@
/** Interpolator to use when cross-fading between previews. */
private static final Interpolator FADE_OUT_INTERPOLATOR = new AccelerateInterpolator();
- private final FrameLayout[] mPreviewFrames;
+ private FrameLayout[] mPreviewFrames;
+
+ private boolean mIsLayoutRtl;
private Runnable mAnimationEndAction;
private int mAnimationCounter;
- public PreviewPagerAdapter(Context context, int[] previewSampleResIds,
- Configuration[] configurations) {
+ public PreviewPagerAdapter(Context context, boolean isLayoutRtl,
+ int[] previewSampleResIds, Configuration[] configurations) {
+ mIsLayoutRtl = isLayoutRtl;
mPreviewFrames = new FrameLayout[previewSampleResIds.length];
for (int i = 0; i < previewSampleResIds.length; ++i) {
- mPreviewFrames[i] = new FrameLayout(context);
- mPreviewFrames[i].setLayoutParams(new LinearLayout.LayoutParams(
+ int p = mIsLayoutRtl ? previewSampleResIds.length - 1 - i : i;
+ mPreviewFrames[p] = new FrameLayout(context);
+ mPreviewFrames[p].setLayoutParams(new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.MATCH_PARENT,
LinearLayout.LayoutParams.MATCH_PARENT));
@@ -69,10 +73,10 @@
final LayoutInflater configInflater = LayoutInflater.from(configContext);
final View sampleView = configInflater.inflate(previewSampleResIds[i],
- mPreviewFrames[i], false);
+ mPreviewFrames[p], false);
sampleView.setAlpha(0);
sampleView.setVisibility(View.INVISIBLE);
- mPreviewFrames[i].addView(sampleView);
+ mPreviewFrames[p].addView(sampleView);
}
}
}
diff --git a/src/com/android/settings/PreviewSeekBarPreferenceFragment.java b/src/com/android/settings/PreviewSeekBarPreferenceFragment.java
index aa663cf..9d4a09e 100644
--- a/src/com/android/settings/PreviewSeekBarPreferenceFragment.java
+++ b/src/com/android/settings/PreviewSeekBarPreferenceFragment.java
@@ -21,6 +21,7 @@
import android.os.Bundle;
import android.support.v4.view.ViewPager;
import android.support.v4.view.ViewPager.OnPageChangeListener;
+import android.text.TextUtils;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
@@ -29,9 +30,11 @@
import android.widget.SeekBar;
import android.widget.SeekBar.OnSeekBarChangeListener;
import android.widget.TextView;
+
import com.android.settings.widget.DotsPageIndicator;
import com.android.settings.widget.LabeledSeekBar;
+import java.util.Locale;
/**
* Preference fragment shows a preview and a seek bar to adjust a specific settings.
@@ -146,54 +149,24 @@
final Context context = getPrefContext();
final Configuration origConfig = context.getResources().getConfiguration();
+ final boolean isLayoutRtl = origConfig.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL;
Configuration[] configurations = new Configuration[mEntries.length];
for (int i = 0; i < mEntries.length; ++i) {
configurations[i] = createConfig(origConfig, i);
}
- mPreviewPagerAdapter = new PreviewPagerAdapter(context, mPreviewSampleResIds,
- configurations);
mPreviewPager = (ViewPager) content.findViewById(R.id.preview_pager);
+ mPreviewPagerAdapter = new PreviewPagerAdapter(context, isLayoutRtl,
+ mPreviewSampleResIds, configurations);
mPreviewPager.setAdapter(mPreviewPagerAdapter);
- mPreviewPager.addOnPageChangeListener(new OnPageChangeListener() {
- @Override
- public void onPageScrollStateChanged(int state) {
- // Do nothing.
- }
-
- @Override
- public void onPageScrolled(int position, float positionOffset,
- int positionOffsetPixels) {
- // Do nothing.
- }
-
- @Override
- public void onPageSelected(int position) {
- mPreviewPager.sendAccessibilityEvent(AccessibilityEvent.TYPE_ANNOUNCEMENT);
- }
- });
+ mPreviewPager.setCurrentItem(isLayoutRtl ? mPreviewSampleResIds.length - 1 : 0);
+ mPreviewPager.addOnPageChangeListener(mPreviewPageChangeListener);
mPageIndicator = (DotsPageIndicator) content.findViewById(R.id.page_indicator);
if (mPreviewSampleResIds.length > 1) {
mPageIndicator.setViewPager(mPreviewPager);
mPageIndicator.setVisibility(View.VISIBLE);
- mPageIndicator.setOnPageChangeListener(new OnPageChangeListener() {
- @Override
- public void onPageScrollStateChanged(int state) {
- // Do nothing.
- }
-
- @Override
- public void onPageScrolled(int position, float positionOffset,
- int positionOffsetPixels) {
- // Do nothing.
- }
-
- @Override
- public void onPageSelected(int position) {
- setPagerIndicatorContentDescription(position);
- }
- });
+ mPageIndicator.setOnPageChangeListener(mPageIndicatorPageChangeListener);
} else {
mPageIndicator.setVisibility(View.GONE);
}
@@ -207,15 +180,19 @@
*/
protected abstract Configuration createConfig(Configuration origConfig, int index);
+ /**
+ * Persists the selected value and sends a configuration change.
+ */
+ protected abstract void commit();
+
private void setPreviewLayer(int index, boolean animate) {
mLabel.setText(mEntries[index]);
mSmaller.setEnabled(index > 0);
mLarger.setEnabled(index < mEntries.length - 1);
-
setPagerIndicatorContentDescription(mPreviewPager.getCurrentItem());
+ mPreviewPagerAdapter.setPreviewLayer(index, mCurrentIndex,
+ mPreviewPager.getCurrentItem(), animate);
- mPreviewPagerAdapter.setPreviewLayer(index, mCurrentIndex, mPreviewPager.getCurrentItem(),
- animate);
mCurrentIndex = index;
}
@@ -225,8 +202,39 @@
position + 1, mPreviewSampleResIds.length));
}
- /**
- * Persists the selected value and sends a configuration change.
- */
- protected abstract void commit();
+ private OnPageChangeListener mPreviewPageChangeListener = new OnPageChangeListener() {
+ @Override
+ public void onPageScrollStateChanged(int state) {
+ // Do nothing.
+ }
+
+ @Override
+ public void onPageScrolled(int position, float positionOffset,
+ int positionOffsetPixels) {
+ // Do nothing.
+ }
+
+ @Override
+ public void onPageSelected(int position) {
+ mPreviewPager.sendAccessibilityEvent(AccessibilityEvent.TYPE_ANNOUNCEMENT);
+ }
+ };
+
+ private OnPageChangeListener mPageIndicatorPageChangeListener = new OnPageChangeListener() {
+ @Override
+ public void onPageScrollStateChanged(int state) {
+ // Do nothing.
+ }
+
+ @Override
+ public void onPageScrolled(int position, float positionOffset,
+ int positionOffsetPixels) {
+ // Do nothing.
+ }
+
+ @Override
+ public void onPageSelected(int position) {
+ setPagerIndicatorContentDescription(position);
+ }
+ };
}
diff --git a/src/com/android/settings/SecuritySettings.java b/src/com/android/settings/SecuritySettings.java
index 049660e..b45a988 100644
--- a/src/com/android/settings/SecuritySettings.java
+++ b/src/com/android/settings/SecuritySettings.java
@@ -625,7 +625,7 @@
startFragment(this, "com.android.settings.ChooseLockGeneric$ChooseLockGenericFragment",
R.string.lock_settings_picker_title, SET_OR_CHANGE_LOCK_METHOD_REQUEST, null);
} else if (KEY_UNLOCK_SET_OR_CHANGE_PROFILE.equals(key)) {
- if (Utils.startQuiteModeDialogIfNecessary(this.getActivity(), mUm,
+ if (Utils.startQuietModeDialogIfNecessary(this.getActivity(), mUm,
mProfileChallengeUserId)) {
return false;
}
@@ -750,13 +750,13 @@
final String key = preference.getKey();
final LockPatternUtils lockPatternUtils = mChooseLockSettingsHelper.utils();
if (KEY_VISIBLE_PATTERN_PROFILE.equals(key)) {
- if (Utils.startQuiteModeDialogIfNecessary(this.getActivity(), mUm,
+ if (Utils.startQuietModeDialogIfNecessary(this.getActivity(), mUm,
mProfileChallengeUserId)) {
return false;
}
lockPatternUtils.setVisiblePatternEnabled((Boolean) value, mProfileChallengeUserId);
} else if (KEY_UNIFICATION.equals(key)) {
- if (Utils.startQuiteModeDialogIfNecessary(this.getActivity(), mUm,
+ if (Utils.startQuietModeDialogIfNecessary(this.getActivity(), mUm,
mProfileChallengeUserId)) {
return false;
}
diff --git a/src/com/android/settings/SettingsActivity.java b/src/com/android/settings/SettingsActivity.java
index 6b9bdb3..53c97b5 100644
--- a/src/com/android/settings/SettingsActivity.java
+++ b/src/com/android/settings/SettingsActivity.java
@@ -564,12 +564,7 @@
// Run the Index update only if we have some space
if (!Utils.isLowStorage(this)) {
long indexStartTime = System.currentTimeMillis();
- AsyncTask.execute(new Runnable() {
- @Override
- public void run() {
- Index.getInstance(getApplicationContext()).update();
- }
- });
+ Index.getInstance(getApplicationContext()).update();
if (DEBUG_TIMING) Log.d(LOG_TAG, "Index.update() took "
+ (System.currentTimeMillis() - indexStartTime) + " ms");
} else {
diff --git a/src/com/android/settings/ShowAdminSupportDetailsDialog.java b/src/com/android/settings/ShowAdminSupportDetailsDialog.java
index 2f2379a..fce669c 100644
--- a/src/com/android/settings/ShowAdminSupportDetailsDialog.java
+++ b/src/com/android/settings/ShowAdminSupportDetailsDialog.java
@@ -155,6 +155,7 @@
intent.setClass(activity, DeviceAdminAdd.class);
intent.putExtra(DevicePolicyManager.EXTRA_DEVICE_ADMIN,
enforcedAdmin.component);
+ intent.putExtra(DeviceAdminAdd.EXTRA_CALLED_FROM_SUPPORT_DIALOG, true);
// DeviceAdminAdd class may need to run as managed profile.
activity.startActivityAsUser(intent,
new UserHandle(enforcedAdmin.userId));
diff --git a/src/com/android/settings/Utils.java b/src/com/android/settings/Utils.java
index 4dd203c..e439bed 100644
--- a/src/com/android/settings/Utils.java
+++ b/src/com/android/settings/Utils.java
@@ -336,24 +336,32 @@
}
/* Used by UserSettings as well. Call this on a non-ui thread. */
- public static boolean copyMeProfilePhoto(Context context, UserInfo user) {
+ public static void copyMeProfilePhoto(Context context, UserInfo user) {
Uri contactUri = Profile.CONTENT_URI;
+ int userId = user != null ? user.id : UserHandle.myUserId();
+
InputStream avatarDataStream = Contacts.openContactPhotoInputStream(
context.getContentResolver(),
contactUri, true);
// If there's no profile photo, assign a default avatar
if (avatarDataStream == null) {
- return false;
+ assignDefaultPhoto(context, userId);
+ return;
}
- int userId = user != null ? user.id : UserHandle.myUserId();
+
UserManager um = (UserManager) context.getSystemService(Context.USER_SERVICE);
Bitmap icon = BitmapFactory.decodeStream(avatarDataStream);
um.setUserIcon(userId, icon);
try {
avatarDataStream.close();
} catch (IOException ioe) { }
- return true;
+ }
+
+ public static void assignDefaultPhoto(Context context, int userId) {
+ UserManager um = (UserManager) context.getSystemService(Context.USER_SERVICE);
+ Bitmap bitmap = getDefaultUserIconAsBitmap(userId);
+ um.setUserIcon(userId, bitmap);
}
public static String getMeProfileName(Context context, boolean full) {
@@ -1107,7 +1115,7 @@
Settings.Global.DEVICE_PROVISIONED, 0) != 0;
}
- public static boolean startQuiteModeDialogIfNecessary(Context context, UserManager um,
+ public static boolean startQuietModeDialogIfNecessary(Context context, UserManager um,
int userId) {
if (um.isQuietModeEnabled(UserHandle.of(userId))) {
final Intent intent = UnlaunchableAppActivity.createInQuietModeDialogIntent(userId);
diff --git a/src/com/android/settings/accessibility/ToggleScreenMagnificationPreferenceFragment.java b/src/com/android/settings/accessibility/ToggleScreenMagnificationPreferenceFragment.java
index 748dc15..e6a8c1e 100644
--- a/src/com/android/settings/accessibility/ToggleScreenMagnificationPreferenceFragment.java
+++ b/src/com/android/settings/accessibility/ToggleScreenMagnificationPreferenceFragment.java
@@ -30,20 +30,24 @@
import android.support.v7.preference.PreferenceScreen;
import android.support.v7.preference.PreferenceViewHolder;
import android.view.Display;
-import android.view.Gravity;
+import android.view.ViewTreeObserver;
+import android.view.ViewTreeObserver.OnGlobalLayoutListener;
import android.view.WindowManager;
+import android.widget.ImageView;
import android.widget.MediaController;
-import android.widget.RelativeLayout;
+import android.widget.RelativeLayout.LayoutParams;
import android.widget.VideoView;
import com.android.internal.logging.MetricsProto.MetricsEvent;
import com.android.settings.R;
import com.android.settings.widget.ToggleSwitch;
import com.android.settings.widget.ToggleSwitch.OnBeforeCheckedChangeListener;
-public class ToggleScreenMagnificationPreferenceFragment
- extends ToggleFeaturePreferenceFragment {
+public class ToggleScreenMagnificationPreferenceFragment extends ToggleFeaturePreferenceFragment {
protected class VideoPreference extends Preference {
+ private ImageView mVideoBackgroundView;
+ private OnGlobalLayoutListener mLayoutListener;
+
public VideoPreference(Context context) {
super(context);
}
@@ -51,40 +55,19 @@
@Override
public void onBindViewHolder(PreferenceViewHolder view) {
super.onBindViewHolder(view);
+ Resources res = getPrefContext().getResources();
+ final int backgroundAssetWidth = res.getDimensionPixelSize(
+ R.dimen.screen_magnification_video_background_width);
+ final int videoAssetWidth = res
+ .getDimensionPixelSize(R.dimen.screen_magnification_video_width);
+ final int videoAssetHeight = res
+ .getDimensionPixelSize(R.dimen.screen_magnification_video_height);
+ final int videoAssetMarginTop = res.getDimensionPixelSize(
+ R.dimen.screen_magnification_video_margin_top);
view.setDividerAllowedAbove(false);
view.setDividerAllowedBelow(false);
- final RelativeLayout background =
- (RelativeLayout) view.findViewById(R.id.video_background);
- VideoView videoView = (VideoView) view.findViewById(R.id.video);
-
- // Hacky adjustment for using VideoView in recycle view and positioning
- // it on the background image
- Resources res = getPrefContext().getResources();
- final int backgroundWidth = res.getDimensionPixelSize(
- R.dimen.screen_magnification_video_background_width);
- final int backgroundHeight = res.getDimensionPixelSize(
- R.dimen.screen_magnification_video_background_height);
- final int videoWidth = res.getDimensionPixelSize(
- R.dimen.screen_magnification_video_width);
- final int videoHeight = res.getDimensionPixelSize(
- R.dimen.screen_magnification_video_height);
- final int videoMarginTop = res.getDimensionPixelSize(
- R.dimen.screen_magnification_video_margin_top);
- final int screenWidth = getScreenWidth(getPrefContext());
-
- RelativeLayout.LayoutParams videoLp = new RelativeLayout.LayoutParams(
- screenWidth * videoWidth / backgroundWidth,
- screenWidth * videoHeight / backgroundWidth);
- videoLp.setMargins(0, screenWidth * videoMarginTop / backgroundWidth, 0, 0);
- videoView.setLayoutParams(videoLp);
-
- RelativeLayout.LayoutParams backgroundLp = new RelativeLayout.LayoutParams(
- screenWidth,
- screenWidth * backgroundHeight / backgroundWidth);
- background.setLayoutParams(backgroundLp);
- background.setBackgroundResource(
- R.drawable.accessibility_screen_magnification_background);
- background.setGravity(Gravity.CENTER_HORIZONTAL);
+ mVideoBackgroundView = (ImageView) view.findViewById(R.id.video_background);
+ final VideoView videoView = (VideoView) view.findViewById(R.id.video);
// Loop the video.
videoView.setOnPreparedListener(new OnPreparedListener() {
@@ -100,7 +83,31 @@
R.raw.accessibility_screen_magnification)));
// Make sure video controls (e.g. for pausing) are not displayed.
videoView.setMediaController(null);
- videoView.start();
+
+ // LayoutListener for adjusting the position of the VideoView on the background image.
+ mLayoutListener = new OnGlobalLayoutListener() {
+ @Override
+ public void onGlobalLayout() {
+ final int backgroundViewWidth = mVideoBackgroundView.getWidth();
+
+ LayoutParams videoLp = (LayoutParams) videoView.getLayoutParams();
+ videoLp.width = videoAssetWidth * backgroundViewWidth / backgroundAssetWidth;
+ videoLp.height = videoAssetHeight * backgroundViewWidth / backgroundAssetWidth;
+ videoLp.setMargins(0,
+ videoAssetMarginTop * backgroundViewWidth / backgroundAssetWidth, 0, 0);
+ videoView.setLayoutParams(videoLp);
+ videoView.invalidate();
+ videoView.start();
+ }
+ };
+
+ mVideoBackgroundView.getViewTreeObserver().addOnGlobalLayoutListener(mLayoutListener);
+ }
+
+ @Override
+ protected void onPrepareForRemoval() {
+ mVideoBackgroundView.getViewTreeObserver()
+ .removeOnGlobalLayoutListener(mLayoutListener);
}
}
diff --git a/src/com/android/settings/accounts/AccountSettings.java b/src/com/android/settings/accounts/AccountSettings.java
index 927ad23..3b4c722 100644
--- a/src/com/android/settings/accounts/AccountSettings.java
+++ b/src/com/android/settings/accounts/AccountSettings.java
@@ -191,6 +191,7 @@
@Override
public void onResume() {
super.onResume();
+ cleanUpPreferences();
updateUi();
mManagedProfileBroadcastReceiver.register(getActivity());
listenToAccountUpdates();
@@ -201,7 +202,6 @@
super.onPause();
stopListeningToAccountUpdates();
mManagedProfileBroadcastReceiver.unregister(getActivity());
- cleanUpPreferences();
}
@Override
@@ -251,7 +251,11 @@
ProfileData profileData = mProfiles.valueAt(i);
if (preference == profileData.workModeSwitch) {
final int userId = profileData.userInfo.id;
- mUm.setQuietModeEnabled(userId, !((boolean) newValue));
+ if ((boolean) newValue) {
+ mUm.trySetQuietModeDisabled(userId, null);
+ } else {
+ mUm.setQuietModeEnabled(userId, true);
+ }
return true;
}
}
diff --git a/src/com/android/settings/applications/InstalledAppDetails.java b/src/com/android/settings/applications/InstalledAppDetails.java
index f91f7bf..14277c9 100755
--- a/src/com/android/settings/applications/InstalledAppDetails.java
+++ b/src/com/android/settings/applications/InstalledAppDetails.java
@@ -51,7 +51,8 @@
import android.os.ServiceManager;
import android.os.UserHandle;
import android.os.UserManager;
-import android.service.notification.NotificationListenerService;
+import android.provider.Settings;
+import android.service.notification.NotificationListenerService.Ranking;
import android.support.v7.preference.Preference;
import android.support.v7.preference.Preference.OnPreferenceClickListener;
import android.support.v7.preference.PreferenceCategory;
@@ -71,6 +72,7 @@
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;
+
import com.android.internal.logging.MetricsProto.MetricsEvent;
import com.android.internal.os.BatterySipper;
import com.android.internal.os.BatteryStatsHelper;
@@ -79,6 +81,7 @@
import com.android.settings.DeviceAdminAdd;
import com.android.settings.R;
import com.android.settings.SettingsActivity;
+import com.android.settings.SettingsPreferenceFragment;
import com.android.settings.Utils;
import com.android.settings.applications.PermissionsSummaryHelper.PermissionsResultCallback;
import com.android.settings.datausage.AppDataUsage;
@@ -144,6 +147,8 @@
private static final String KEY_BATTERY = "battery";
private static final String KEY_MEMORY = "memory";
+ private static final String NOTIFICATION_TUNER_SETTING = "show_importance_slider";
+
private final HashSet<String> mHomePackages = new HashSet<String>();
private boolean mInitialized;
@@ -424,7 +429,7 @@
private Intent resolveIntent(Intent i) {
ResolveInfo result = getContext().getPackageManager().resolveActivity(i, 0);
- return result != null ? new Intent(Intent.ACTION_APPLICATION_PREFERENCES)
+ return result != null ? new Intent(i.getAction())
.setClassName(result.activityInfo.packageName, result.activityInfo.name) : null;
}
@@ -737,14 +742,19 @@
}
private void startAppInfoFragment(Class<?> fragment, CharSequence title) {
+ startAppInfoFragment(fragment, title, this, mAppEntry);
+ }
+
+ public static void startAppInfoFragment(Class<?> fragment, CharSequence title,
+ SettingsPreferenceFragment caller, AppEntry appEntry) {
// start new fragment to display extended information
Bundle args = new Bundle();
- args.putString(ARG_PACKAGE_NAME, mAppEntry.info.packageName);
- args.putInt(ARG_PACKAGE_UID, mAppEntry.info.uid);
+ args.putString(ARG_PACKAGE_NAME, appEntry.info.packageName);
+ args.putInt(ARG_PACKAGE_UID, appEntry.info.uid);
args.putBoolean(AppHeader.EXTRA_HIDE_INFO_BUTTON, true);
- SettingsActivity sa = (SettingsActivity) getActivity();
- sa.startPreferencePanel(fragment.getName(), args, -1, title, this, SUB_INFO_FRAGMENT);
+ SettingsActivity sa = (SettingsActivity) caller.getActivity();
+ sa.startPreferencePanel(fragment.getName(), args, -1, title, caller, SUB_INFO_FRAGMENT);
}
/*
@@ -902,10 +912,30 @@
category.addPreference(pref);
}
}
+
+ final String installerPackageName =
+ getContext().getPackageManager().getInstallerPackageName(mPackageName);
+ if (installerPackageName != null) {
+ final Intent intent = new Intent(Intent.ACTION_SHOW_APP_INFO)
+ .setPackage(installerPackageName);
+ final Intent result = resolveIntent(intent);
+ if (result != null) {
+ result.putExtra(Intent.EXTRA_PACKAGE_NAME, mPackageName);
+ PreferenceCategory category = new PreferenceCategory(getPrefContext());
+ category.setTitle(R.string.app_install_details_group_title);
+ screen.addPreference(category);
+ Preference pref = new Preference(getPrefContext());
+ pref.setTitle(R.string.app_install_details_title);
+ pref.setKey("app_info_store");
+ pref.setSummary(getString(R.string.app_install_details_summary, mAppEntry.label));
+ pref.setIntent(result);
+ category.addPreference(pref);
+ }
+ }
}
private boolean hasPermission(String permission) {
- if (mPackageInfo.requestedPermissions == null) {
+ if (mPackageInfo == null || mPackageInfo.requestedPermissions == null) {
return false;
}
for (int i = 0; i < mPackageInfo.requestedPermissions.length; i++) {
@@ -996,13 +1026,22 @@
}
public static CharSequence getNotificationSummary(AppRow appRow, Context context) {
+ boolean showSlider = Settings.Secure.getInt(
+ context.getContentResolver(), NOTIFICATION_TUNER_SETTING, 0) == 1;
List<String> summaryAttributes = new ArrayList<>();
StringBuffer summary = new StringBuffer();
- if (appRow.banned) {
- summaryAttributes.add(context.getString(R.string.notifications_disabled));
- } else if (appRow.appImportance > NotificationListenerService.Ranking.IMPORTANCE_NONE
- && appRow.appImportance < NotificationListenerService.Ranking.IMPORTANCE_DEFAULT) {
- summaryAttributes.add(context.getString(R.string.notifications_silenced));
+ if (showSlider) {
+ if (appRow.appImportance != Ranking.IMPORTANCE_UNSPECIFIED) {
+ summaryAttributes.add(context.getString(
+ R.string.notification_summary_level, appRow.appImportance));
+ }
+ } else {
+ if (appRow.banned) {
+ summaryAttributes.add(context.getString(R.string.notifications_disabled));
+ } else if (appRow.appImportance > Ranking.IMPORTANCE_NONE
+ && appRow.appImportance < Ranking.IMPORTANCE_DEFAULT) {
+ summaryAttributes.add(context.getString(R.string.notifications_silenced));
+ }
}
final boolean lockscreenSecure = new LockPatternUtils(context).isSecure(
UserHandle.myUserId());
diff --git a/src/com/android/settings/dashboard/DashboardDecorator.java b/src/com/android/settings/dashboard/DashboardDecorator.java
index 2e7afaf..9bcf39d 100644
--- a/src/com/android/settings/dashboard/DashboardDecorator.java
+++ b/src/com/android/settings/dashboard/DashboardDecorator.java
@@ -21,7 +21,6 @@
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.RecyclerView.State;
import android.support.v7.widget.RecyclerView.ViewHolder;
-import android.util.Log;
import android.util.TypedValue;
import android.view.View;
import com.android.settings.R;
@@ -41,8 +40,6 @@
@Override
public void onDrawOver(Canvas c, RecyclerView parent, State state) {
final int childCount = parent.getChildCount();
- final int width = parent.getWidth();
- final int bottom = parent.getBottom();
for (int i = 1; i < childCount; i++) {
final View child = parent.getChildAt(i);
final ViewHolder holder = parent.getChildViewHolder(child);
@@ -56,7 +53,8 @@
}
int top = getChildTop(child);
- mDivider.setBounds(0, top, width, top + mDivider.getIntrinsicHeight());
+ mDivider.setBounds(child.getLeft(), top, child.getRight(),
+ top + mDivider.getIntrinsicHeight());
mDivider.draw(c);
}
}
diff --git a/src/com/android/settings/dashboard/conditional/ConditionAdapterUtils.java b/src/com/android/settings/dashboard/conditional/ConditionAdapterUtils.java
index a5d0701..9a45a5a 100644
--- a/src/com/android/settings/dashboard/conditional/ConditionAdapterUtils.java
+++ b/src/com/android/settings/dashboard/conditional/ConditionAdapterUtils.java
@@ -74,13 +74,13 @@
expand.setOnClickListener(onExpandListener);
View detailGroup = view.itemView.findViewById(R.id.detail_group);
+ CharSequence[] actions = condition.getActions();
if (isExpanded != (detailGroup.getVisibility() == View.VISIBLE)) {
animateChange(view.itemView, view.itemView.findViewById(R.id.content),
- detailGroup, isExpanded);
+ detailGroup, isExpanded, actions.length > 0);
}
if (isExpanded) {
view.summary.setText(condition.getSummary());
- CharSequence[] actions = condition.getActions();
for (int i = 0; i < 2; i++) {
Button button = (Button) detailGroup.findViewById(i == 0
? R.id.first_action : R.id.second_action);
@@ -105,7 +105,9 @@
}
private static void animateChange(final View view, final View content,
- final View detailGroup, final boolean visible) {
+ final View detailGroup, final boolean visible, final boolean hasButtons) {
+ setViewVisibility(detailGroup, R.id.divider, hasButtons);
+ setViewVisibility(detailGroup, R.id.buttonBar, hasButtons);
final int beforeBottom = content.getBottom();
setHeight(detailGroup, visible ? LayoutParams.WRAP_CONTENT : 0);
detailGroup.setVisibility(View.VISIBLE);
@@ -138,4 +140,11 @@
params.height = height;
detailGroup.setLayoutParams(params);
}
+
+ private static void setViewVisibility(View containerView, int viewId, boolean visible) {
+ View view = containerView.findViewById(viewId);
+ if (view != null) {
+ view.setVisibility(visible ? View.VISIBLE : View.GONE);
+ }
+ }
}
diff --git a/src/com/android/settings/dashboard/conditional/ConditionManager.java b/src/com/android/settings/dashboard/conditional/ConditionManager.java
index 24d5f09..0d02ae2 100644
--- a/src/com/android/settings/dashboard/conditional/ConditionManager.java
+++ b/src/com/android/settings/dashboard/conditional/ConditionManager.java
@@ -36,7 +36,7 @@
private static final String TAG = "ConditionManager";
- private static final boolean DEBUG = true;
+ private static final boolean DEBUG = false;
private static final String PKG = "com.android.settings.dashboard.conditional.";
diff --git a/src/com/android/settings/dashboard/conditional/HotspotCondition.java b/src/com/android/settings/dashboard/conditional/HotspotCondition.java
index be74c9e..17be591 100644
--- a/src/com/android/settings/dashboard/conditional/HotspotCondition.java
+++ b/src/com/android/settings/dashboard/conditional/HotspotCondition.java
@@ -21,10 +21,15 @@
import android.graphics.drawable.Icon;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiManager;
+import android.os.UserHandle;
+import android.os.UserManager;
+
import com.android.internal.logging.MetricsProto.MetricsEvent;
import com.android.settings.R;
import com.android.settings.TetherSettings;
import com.android.settings.Utils;
+import com.android.settingslib.RestrictedLockUtils;
+import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
import com.android.settingslib.TetherUtil;
public class HotspotCondition extends Condition {
@@ -74,7 +79,12 @@
@Override
public CharSequence[] getActions() {
- return new CharSequence[] { mManager.getContext().getString(R.string.condition_turn_off) };
+ final Context context = mManager.getContext();
+ if (RestrictedLockUtils.hasBaseUserRestriction(context,
+ UserManager.DISALLOW_CONFIG_TETHERING, UserHandle.myUserId())) {
+ return new CharSequence[0];
+ }
+ return new CharSequence[] { context.getString(R.string.condition_turn_off) };
}
@Override
@@ -86,8 +96,15 @@
@Override
public void onActionClick(int index) {
if (index == 0) {
- TetherUtil.setWifiTethering(false, mManager.getContext());
- setActive(false);
+ final Context context = mManager.getContext();
+ final EnforcedAdmin admin = RestrictedLockUtils.checkIfRestrictionEnforced(context,
+ UserManager.DISALLOW_CONFIG_TETHERING, UserHandle.myUserId());
+ if (admin != null) {
+ RestrictedLockUtils.sendShowAdminSupportDetailsIntent(context, admin);
+ } else {
+ TetherUtil.setWifiTethering(false, context);
+ setActive(false);
+ }
} else {
throw new IllegalArgumentException("Unexpected index " + index);
}
diff --git a/src/com/android/settings/dashboard/conditional/WorkModeCondition.java b/src/com/android/settings/dashboard/conditional/WorkModeCondition.java
index f46b495..3d9958b 100644
--- a/src/com/android/settings/dashboard/conditional/WorkModeCondition.java
+++ b/src/com/android/settings/dashboard/conditional/WorkModeCondition.java
@@ -90,7 +90,7 @@
@Override
public void onActionClick(int index) {
if (index == 0) {
- mUm.setQuietModeEnabled(mUserHandle.getIdentifier(), false);
+ mUm.trySetQuietModeDisabled(mUserHandle.getIdentifier(), null);
setActive(false);
} else {
throw new IllegalArgumentException("Unexpected index " + index);
diff --git a/src/com/android/settings/datausage/AppDataUsage.java b/src/com/android/settings/datausage/AppDataUsage.java
index b3c8e03..037614e 100644
--- a/src/com/android/settings/datausage/AppDataUsage.java
+++ b/src/com/android/settings/datausage/AppDataUsage.java
@@ -39,6 +39,8 @@
import android.util.ArraySet;
import android.view.View;
import android.widget.AdapterView;
+
+import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.MetricsProto.MetricsEvent;
import com.android.settings.AppHeader;
import com.android.settings.R;
@@ -78,6 +80,7 @@
private Drawable mIcon;
private CharSequence mLabel;
+ private String mPackageName;
private INetworkStatsSession mStatsSession;
private CycleAdapter mCycleAdapter;
@@ -143,6 +146,7 @@
ApplicationInfo info = pm.getApplicationInfo(mPackages.valueAt(0), 0);
mIcon = info.loadIcon(pm);
mLabel = info.loadLabel(pm);
+ mPackageName = info.packageName;
} catch (PackageManager.NameNotFoundException e) {
}
}
@@ -186,6 +190,7 @@
final PackageManager pm = getPackageManager();
mIcon = Utils.getUserIcon(getActivity(), um, info);
mLabel = Utils.getUserLabel(getActivity(), info);
+ mPackageName = getActivity().getPackageName();
removePreference(KEY_UNRESTRICTED_DATA);
removePreference(KEY_APP_SETTINGS);
removePreference(KEY_RESTRICT_BACKGROUND);
@@ -211,10 +216,11 @@
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
if (preference == mRestrictBackground) {
- setAppRestrictBackground(!(Boolean) newValue);
+ mDataSaverBackend.setIsBlacklisted(mAppItem.key, mPackageName, !(Boolean) newValue);
+ updatePrefs(); // TODO: should have been notified by NPMS instead
return true;
} else if (preference == mUnrestrictedData) {
- mDataSaverBackend.setIsWhitelisted(mAppItem.key, (Boolean) newValue);
+ mDataSaverBackend.setIsWhitelisted(mAppItem.key, mPackageName, (Boolean) newValue);
return true;
}
return false;
@@ -236,7 +242,12 @@
mRestrictBackground.setChecked(!getAppRestrictBackground());
}
if (mUnrestrictedData != null) {
- mUnrestrictedData.setChecked(mDataSaverBackend.isWhitelisted(mAppItem.key));
+ if (getAppRestrictBackground()) {
+ mUnrestrictedData.setVisible(false);
+ } else {
+ mUnrestrictedData.setVisible(true);
+ mUnrestrictedData.setChecked(mDataSaverBackend.isWhitelisted(mAppItem.key));
+ }
}
}
@@ -250,18 +261,21 @@
}
private void bindData() {
+ final long backgroundBytes, foregroundBytes;
if (mChartData == null || mStart == 0) {
- return;
+ backgroundBytes = foregroundBytes = 0;
+ mCycle.setVisible(false);
+ } else {
+ mCycle.setVisible(true);
+ final long now = System.currentTimeMillis();
+ NetworkStatsHistory.Entry entry = null;
+ entry = mChartData.detailDefault.getValues(mStart, mEnd, now, entry);
+ backgroundBytes = entry.rxBytes + entry.txBytes;
+ entry = mChartData.detailForeground.getValues(mStart, mEnd, now, entry);
+ foregroundBytes = entry.rxBytes + entry.txBytes;
}
- final Context context = getContext();
- final long now = System.currentTimeMillis();
-
- NetworkStatsHistory.Entry entry = null;
- entry = mChartData.detailDefault.getValues(mStart, mEnd, now, entry);
- final long backgroundBytes = entry.rxBytes + entry.txBytes;
- entry = mChartData.detailForeground.getValues(mStart, mEnd, now, entry);
- final long foregroundBytes = entry.rxBytes + entry.txBytes;
final long totalBytes = backgroundBytes + foregroundBytes;
+ final Context context = getContext();
mTotalUsage.setSummary(Formatter.formatFileSize(context, totalBytes));
mForegroundUsage.setSummary(Formatter.formatFileSize(context, foregroundBytes));
@@ -274,12 +288,6 @@
return (uidPolicy & POLICY_REJECT_METERED_BACKGROUND) != 0;
}
- private void setAppRestrictBackground(boolean restrictBackground) {
- final int uid = mAppItem.key;
- services.mPolicyManager.setUidPolicy(
- uid, restrictBackground ? POLICY_REJECT_METERED_BACKGROUND : POLICY_NONE);
- }
-
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
diff --git a/src/com/android/settings/datausage/AppStateDataUsageBridge.java b/src/com/android/settings/datausage/AppStateDataUsageBridge.java
index 1aff496..0b535d0 100644
--- a/src/com/android/settings/datausage/AppStateDataUsageBridge.java
+++ b/src/com/android/settings/datausage/AppStateDataUsageBridge.java
@@ -37,20 +37,24 @@
final int N = apps.size();
for (int i = 0; i < N; i++) {
AppEntry app = apps.get(i);
- app.extraInfo = new DataUsageState(mDataSaverBackend.isWhitelisted(app.info.uid));
+ app.extraInfo = new DataUsageState(mDataSaverBackend.isWhitelisted(app.info.uid),
+ mDataSaverBackend.isBlacklisted(app.info.uid));
}
}
@Override
protected void updateExtraInfo(AppEntry app, String pkg, int uid) {
- app.extraInfo = new DataUsageState(mDataSaverBackend.isWhitelisted(uid));
+ app.extraInfo = new DataUsageState(mDataSaverBackend.isWhitelisted(uid),
+ mDataSaverBackend.isBlacklisted(uid));
}
public static class DataUsageState {
public boolean isDataSaverWhitelisted;
+ public boolean isDataSaverBlacklisted;
- public DataUsageState(boolean isDataSaverWhitelisted) {
+ public DataUsageState(boolean isDataSaverWhitelisted, boolean isDataSaverBlacklisted) {
this.isDataSaverWhitelisted = isDataSaverWhitelisted;
+ this.isDataSaverBlacklisted = isDataSaverBlacklisted;
}
}
}
diff --git a/src/com/android/settings/datausage/DataSaverBackend.java b/src/com/android/settings/datausage/DataSaverBackend.java
index c38a05c..55521a8 100644
--- a/src/com/android/settings/datausage/DataSaverBackend.java
+++ b/src/com/android/settings/datausage/DataSaverBackend.java
@@ -24,8 +24,14 @@
import android.util.Log;
import android.util.SparseBooleanArray;
+import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.MetricsProto.MetricsEvent;
+
import java.util.ArrayList;
+import static android.net.NetworkPolicyManager.POLICY_NONE;
+import static android.net.NetworkPolicyManager.POLICY_REJECT_METERED_BACKGROUND;
+
public class DataSaverBackend {
private static final String TAG = "DataSaverBackend";
@@ -37,6 +43,7 @@
private final INetworkPolicyManager mIPolicyManager;
private final ArrayList<Listener> mListeners = new ArrayList<>();
private SparseBooleanArray mWhitelist;
+ private SparseBooleanArray mBlacklist;
// TODO: Staticize into only one.
public DataSaverBackend(Context context) {
@@ -67,13 +74,14 @@
public void setDataSaverEnabled(boolean enabled) {
mPolicyManager.setRestrictBackground(enabled);
+ MetricsLogger.action(mContext, MetricsEvent.ACTION_DATA_SAVER_MODE, enabled ? 1 : 0);
}
public void refreshWhitelist() {
loadWhitelist();
}
- public void setIsWhitelisted(int uid, boolean whitelisted) {
+ public void setIsWhitelisted(int uid, String packageName, boolean whitelisted) {
mWhitelist.put(uid, whitelisted);
try {
if (whitelisted) {
@@ -84,6 +92,7 @@
} catch (RemoteException e) {
Log.w(TAG, "Can't reach policy manager", e);
}
+ MetricsLogger.action(mContext, MetricsEvent.ACTION_DATA_SAVER_WHITELIST, packageName);
}
public boolean isWhitelisted(int uid) {
@@ -116,6 +125,35 @@
}
}
+ public void refreshBlacklist() {
+ loadBlacklist();
+ }
+
+ public void setIsBlacklisted(int uid, String packageName, boolean blacklisted) {
+ mPolicyManager.setUidPolicy(
+ uid, blacklisted ? POLICY_REJECT_METERED_BACKGROUND : POLICY_NONE);
+ if (blacklisted) {
+ MetricsLogger.action(mContext, MetricsEvent.ACTION_DATA_SAVER_BLACKLIST, packageName);
+ }
+ }
+
+ public boolean isBlacklisted(int uid) {
+ if (mBlacklist == null) {
+ loadBlacklist();
+ }
+ return mBlacklist.get(uid);
+ }
+
+ private void loadBlacklist() {
+ mBlacklist = new SparseBooleanArray();
+ try {
+ for (int uid : mIPolicyManager.getUidsWithPolicy(POLICY_REJECT_METERED_BACKGROUND)) {
+ mBlacklist.put(uid, true);
+ }
+ } catch (RemoteException e) {
+ }
+ }
+
private void handleRestrictBackgroundChanged(boolean isDataSaving) {
for (int i = 0; i < mListeners.size(); i++) {
mListeners.get(i).onDataSaverChanged(isDataSaving);
@@ -124,7 +162,8 @@
private final INetworkPolicyListener mPolicyListener = new INetworkPolicyListener.Stub() {
@Override
- public void onUidRulesChanged(int i, int i1) throws RemoteException {
+ public void onUidRulesChanged(int uid, int uidRules) throws RemoteException {
+ // TODO: update UI accordingly
}
@Override
diff --git a/src/com/android/settings/datausage/DataSaverSummary.java b/src/com/android/settings/datausage/DataSaverSummary.java
index e12afbf..591f2c5 100644
--- a/src/com/android/settings/datausage/DataSaverSummary.java
+++ b/src/com/android/settings/datausage/DataSaverSummary.java
@@ -70,6 +70,7 @@
public void onResume() {
super.onResume();
mDataSaverBackend.refreshWhitelist();
+ mDataSaverBackend.refreshBlacklist();
mDataSaverBackend.addListener(this);
mSession.resume();
mDataUsageBridge.resume();
@@ -100,6 +101,9 @@
@Override
public void onExtraInfoUpdated() {
+ if (!isAdded()) {
+ return;
+ }
int count = 0;
final ArrayList<AppEntry> allApps = mSession.getAllApps();
final int N = allApps.size();
diff --git a/src/com/android/settings/datausage/UnrestrictedDataAccess.java b/src/com/android/settings/datausage/UnrestrictedDataAccess.java
index c9014c0..c8df0ba 100644
--- a/src/com/android/settings/datausage/UnrestrictedDataAccess.java
+++ b/src/com/android/settings/datausage/UnrestrictedDataAccess.java
@@ -24,10 +24,15 @@
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
+
import com.android.internal.logging.MetricsProto.MetricsEvent;
+import com.android.settings.AppHeader;
import com.android.settings.R;
+import com.android.settings.SettingsActivity;
import com.android.settings.SettingsPreferenceFragment;
+import com.android.settings.applications.AppInfoBase;
import com.android.settings.applications.AppStateBaseBridge;
+import com.android.settings.applications.InstalledAppDetails;
import com.android.settings.datausage.AppStateDataUsageBridge.DataUsageState;
import com.android.settingslib.applications.ApplicationsState;
import com.android.settingslib.applications.ApplicationsState.AppEntry;
@@ -40,6 +45,7 @@
private static final int MENU_SHOW_SYSTEM = Menu.FIRST + 42;
private static final String EXTRA_SHOW_SYSTEM = "show_system";
+
private ApplicationsState mApplicationsState;
private AppStateDataUsageBridge mDataUsageBridge;
private ApplicationsState.Session mSession;
@@ -144,11 +150,11 @@
}
@Override
- public void onRebuildComplete(ArrayList<ApplicationsState.AppEntry> apps) {
+ public void onRebuildComplete(ArrayList<AppEntry> apps) {
cacheRemoveAllPrefs(getPreferenceScreen());
final int N = apps.size();
for (int i = 0; i < N; i++) {
- ApplicationsState.AppEntry entry = apps.get(i);
+ AppEntry entry = apps.get(i);
String key = entry.info.packageName + "|" + entry.info.uid;
AccessPreference preference = (AccessPreference) getCachedPreference(key);
if (preference == null) {
@@ -200,33 +206,62 @@
if (preference instanceof AccessPreference) {
AccessPreference accessPreference = (AccessPreference) preference;
boolean whitelisted = newValue == Boolean.TRUE;
- mDataSaverBackend.setIsWhitelisted(accessPreference.mEntry.info.uid, whitelisted);
- ((AppStateDataUsageBridge.DataUsageState) accessPreference.mEntry.extraInfo)
- .isDataSaverWhitelisted = whitelisted;
+ mDataSaverBackend.setIsWhitelisted(accessPreference.mEntry.info.uid,
+ accessPreference.mEntry.info.packageName, whitelisted);
+ accessPreference.mState.isDataSaverWhitelisted = whitelisted;
return true;
}
return false;
}
private class AccessPreference extends SwitchPreference {
- private final ApplicationsState.AppEntry mEntry;
+ private final AppEntry mEntry;
+ private final DataUsageState mState;
- public AccessPreference(Context context, ApplicationsState.AppEntry entry) {
+ public AccessPreference(final Context context, AppEntry entry) {
super(context);
mEntry = entry;
+ mState = (DataUsageState) mEntry.extraInfo;
mEntry.ensureLabel(getContext());
- setTitle(entry.label);
- final DataUsageState state = (DataUsageState) entry.extraInfo;
- setChecked(state != null && state.isDataSaverWhitelisted);
+ setState();
if (mEntry.icon != null) {
setIcon(mEntry.icon);
}
+ setOnPreferenceClickListener( new OnPreferenceClickListener() {
+
+ @Override
+ public boolean onPreferenceClick(Preference pref) {
+ if (mState.isDataSaverBlacklisted) {
+ InstalledAppDetails.startAppInfoFragment(AppDataUsage.class,
+ context.getString(R.string.app_data_usage),
+ UnrestrictedDataAccess.this,
+ mEntry);
+ return false;
+ }
+ return true;
+ }});
+ }
+
+ // Sets UI state based on whitelist/blacklist status.
+ private void setState() {
+ setTitle(mEntry.label);
+ // TODO: state is cached, so if blacklist/whitelist changes, it's not updated.
+ // For example, if the initial state is blacklisted, the user taps the preference,
+ // removes the blacklist, and then taps back, the state is not refreshed.
+ // The proper fix for this problem is to implement onUidRulesChanged() on
+ // DataSaverBackend and update the UI accordingly.
+ if (mState != null) {
+ setChecked(mState.isDataSaverWhitelisted);
+ if (mState.isDataSaverBlacklisted) {
+ setSummary(R.string.restrict_background_blacklisted);
+ }
+ // TODO: might need to reset summary once it listens to onUidRulesChanged()
+ }
}
public void reuse() {
- setTitle(mEntry.label);
- final DataUsageState state = (DataUsageState) mEntry.extraInfo;
- setChecked(state != null && state.isDataSaverWhitelisted);
+ setState();
+ notifyChanged();
}
@Override
@@ -243,7 +278,10 @@
}
});
}
+ holder.findViewById(android.R.id.widget_frame)
+ .setVisibility(mState.isDataSaverBlacklisted ? View.INVISIBLE : View.VISIBLE);
super.onBindViewHolder(holder);
}
}
+
}
diff --git a/src/com/android/settings/display/ConversationMessageView.java b/src/com/android/settings/display/ConversationMessageView.java
index a0889c4..06e7b9b 100644
--- a/src/com/android/settings/display/ConversationMessageView.java
+++ b/src/com/android/settings/display/ConversationMessageView.java
@@ -96,13 +96,15 @@
updateViewAppearance();
final int horizontalSpace = MeasureSpec.getSize(widthMeasureSpec);
- final int iconSize = getResources()
- .getDimensionPixelSize(R.dimen.conversation_message_contact_icon_size);
final int unspecifiedMeasureSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
- final int iconMeasureSpec = MeasureSpec.makeMeasureSpec(iconSize, MeasureSpec.EXACTLY);
+ int iconMeasureSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
mContactIconView.measure(iconMeasureSpec, iconMeasureSpec);
+ iconMeasureSpec = MeasureSpec.makeMeasureSpec(
+ Math.max(mContactIconView.getMeasuredWidth(), mContactIconView.getMeasuredHeight()),
+ MeasureSpec.EXACTLY);
+ mContactIconView.measure(iconMeasureSpec, iconMeasureSpec);
final int arrowWidth =
getResources().getDimensionPixelSize(R.dimen.message_bubble_arrow_width);
diff --git a/src/com/android/settings/fingerprint/FingerprintSettings.java b/src/com/android/settings/fingerprint/FingerprintSettings.java
index 3b83e48..6fd2d14 100644
--- a/src/com/android/settings/fingerprint/FingerprintSettings.java
+++ b/src/com/android/settings/fingerprint/FingerprintSettings.java
@@ -837,7 +837,7 @@
public boolean onPreferenceClick(Preference preference) {
final Context context = preference.getContext();
final UserManager userManager = UserManager.get(context);
- if (Utils.startQuiteModeDialogIfNecessary(context, userManager,
+ if (Utils.startQuietModeDialogIfNecessary(context, userManager,
userId)) {
return false;
}
diff --git a/src/com/android/settings/inputmethod/AvailableVirtualKeyboardFragment.java b/src/com/android/settings/inputmethod/AvailableVirtualKeyboardFragment.java
index 1de3fcc..d35f895 100644
--- a/src/com/android/settings/inputmethod/AvailableVirtualKeyboardFragment.java
+++ b/src/com/android/settings/inputmethod/AvailableVirtualKeyboardFragment.java
@@ -16,9 +16,15 @@
package com.android.settings.inputmethod;
+import android.annotation.DrawableRes;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.app.Activity;
import android.app.admin.DevicePolicyManager;
import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.ServiceInfo;
import android.content.res.Configuration;
import android.graphics.Color;
import android.graphics.drawable.ColorDrawable;
@@ -40,8 +46,6 @@
public final class AvailableVirtualKeyboardFragment extends SettingsPreferenceFragment
implements InputMethodPreference.OnSavePreferenceListener {
- private static final Drawable NO_ICON = new ColorDrawable(Color.TRANSPARENT);
-
private final ArrayList<InputMethodPreference> mInputMethodPreferenceList = new ArrayList<>();
private InputMethodSettingValuesWrapper mInputMethodSettingValues;
private InputMethodManager mImm;
@@ -85,27 +89,68 @@
return MetricsEvent.ENABLE_VIRTUAL_KEYBOARDS;
}
+ @Nullable
+ private static Drawable loadDrawable(@NonNull final PackageManager packageManager,
+ @NonNull final String packageName, @DrawableRes final int resId,
+ @NonNull final ApplicationInfo applicationInfo) {
+ if (resId == 0) {
+ return null;
+ }
+ try {
+ return packageManager.getDrawable(packageName, resId, applicationInfo);
+ } catch (Exception e){
+ return null;
+ }
+ }
+
+ @NonNull
+ private static Drawable getInputMethodIcon(@NonNull final PackageManager packageManager,
+ @NonNull final InputMethodInfo imi) {
+ final ServiceInfo si = imi.getServiceInfo();
+ final ApplicationInfo ai = si.applicationInfo;
+ final String packageName = imi.getPackageName();
+ if (si == null || ai == null || packageName == null) {
+ return new ColorDrawable(Color.TRANSPARENT);
+ }
+ // We do not use ServiceInfo#loadLogo() and ServiceInfo#loadIcon here since those methods
+ // internally have some fallback rules, which we want to do manually.
+ Drawable drawable = loadDrawable(packageManager, packageName, si.logo, ai);
+ if (drawable != null) {
+ return drawable;
+ }
+ drawable = loadDrawable(packageManager, packageName, si.icon, ai);
+ if (drawable != null) {
+ return drawable;
+ }
+ // We do not use ApplicationInfo#loadLogo() and ApplicationInfo#loadIcon here since those
+ // methods internally have some fallback rules, which we want to do manually.
+ drawable = loadDrawable(packageManager, packageName, ai.logo, ai);
+ if (drawable != null) {
+ return drawable;
+ }
+ drawable = loadDrawable(packageManager, packageName, ai.icon, ai);
+ if (drawable != null) {
+ return drawable;
+ }
+ return new ColorDrawable(Color.TRANSPARENT);
+ }
+
private void updateInputMethodPreferenceViews() {
mInputMethodSettingValues.refreshAllInputMethodAndSubtypes();
// Clear existing "InputMethodPreference"s
mInputMethodPreferenceList.clear();
List<String> permittedList = mDpm.getPermittedInputMethodsForCurrentUser();
final Context context = getPrefContext();
+ final PackageManager packageManager = getActivity().getPackageManager();
final List<InputMethodInfo> imis = mInputMethodSettingValues.getInputMethodList();
final int N = (imis == null ? 0 : imis.size());
for (int i = 0; i < N; ++i) {
final InputMethodInfo imi = imis.get(i);
final boolean isAllowedByOrganization = permittedList == null
|| permittedList.contains(imi.getPackageName());
- Drawable icon;
- try {
- icon = getActivity().getPackageManager().getApplicationIcon(imi.getPackageName());
- } catch (Exception e) {
- icon = NO_ICON;
- }
final InputMethodPreference pref = new InputMethodPreference(
context, imi, true, isAllowedByOrganization, this);
- pref.setIcon(icon);
+ pref.setIcon(getInputMethodIcon(packageManager, imi));
mInputMethodPreferenceList.add(pref);
}
final Collator collator = Collator.getInstance();
diff --git a/src/com/android/settings/inputmethod/PhysicalKeyboardFragment.java b/src/com/android/settings/inputmethod/PhysicalKeyboardFragment.java
index fb44a3d..cf8db7a 100644
--- a/src/com/android/settings/inputmethod/PhysicalKeyboardFragment.java
+++ b/src/com/android/settings/inputmethod/PhysicalKeyboardFragment.java
@@ -54,6 +54,7 @@
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
+import java.util.List;
public final class PhysicalKeyboardFragment extends SettingsPreferenceFragment
implements InputManager.InputDeviceListener {
@@ -65,7 +66,7 @@
private static final String IM_SUBTYPE_MODE_KEYBOARD = "keyboard";
@NonNull
- private final ArrayList<HardKeyboardDeviceInfo> mLastHardKeyboards = new ArrayList<>();
+ private final List<HardKeyboardDeviceInfo> mLastHardKeyboards = new ArrayList<>();
@NonNull
private final HashSet<Integer> mLoaderIDs = new HashSet<>();
@@ -128,32 +129,42 @@
unregisterShowVirtualKeyboardSettingsObserver();
}
- public void onLoadFinishedInternal(final int loaderId, @NonNull final Keyboards data,
- @NonNull final PreferenceCategory preferenceCategory) {
+ public void onLoadFinishedInternal(
+ final int loaderId, @NonNull final List<Keyboards> keyboardsList) {
if (!mLoaderIDs.remove(loaderId)) {
// Already destroyed loader. Ignore.
return;
}
- final InputDeviceIdentifier deviceId = data.mInputDeviceIdentifier;
- preferenceCategory.removeAll();
- for (Keyboards.KeyboardInfo info : data.mKeyboardInfoList) {
- Preference pref = new Preference(getPrefContext(), null);
- final InputMethodInfo imi = info.mImi;
- final InputMethodSubtype imSubtype = info.mImSubtype;
- if (imi != null && imSubtype != null) {
- pref.setTitle(getDisplayName(getContext(), imi, imSubtype));
- KeyboardLayout layout = info.mLayout;
- if (layout != null) {
- pref.setSummary(layout.getLabel());
+ final PreferenceScreen preferenceScreen = getPreferenceScreen();
+ preferenceScreen.removeAll();
+ for (Keyboards keyboards : keyboardsList) {
+ final PreferenceCategory category = new PreferenceCategory(getPrefContext(), null);
+ category.setTitle(keyboards.mDeviceInfo.mDeviceName);
+ category.setOrder(0);
+ preferenceScreen.addPreference(category);
+ for (Keyboards.KeyboardInfo info : keyboards.mKeyboardInfoList) {
+ Preference pref = new Preference(getPrefContext(), null);
+ final InputMethodInfo imi = info.mImi;
+ final InputMethodSubtype imSubtype = info.mImSubtype;
+ if (imi != null && imSubtype != null) {
+ pref.setTitle(getDisplayName(getContext(), imi, imSubtype));
+ KeyboardLayout layout = info.mLayout;
+ if (layout != null) {
+ pref.setSummary(layout.getLabel());
+ }
+ pref.setOnPreferenceClickListener(preference -> {
+ showKeyboardLayoutScreen(
+ keyboards.mDeviceInfo.mDeviceIdentifier, imi, imSubtype);
+ return true;
+ });
+ category.addPreference(pref);
}
- pref.setOnPreferenceClickListener(preference -> {
- showKeyboardLayoutScreen(deviceId, imi, imSubtype);
- return true;
- });
- preferenceCategory.addPreference(pref);
}
}
+ mKeyboardAssistanceCategory.setOrder(1);
+ preferenceScreen.addPreference(mKeyboardAssistanceCategory);
+ updateShowVirtualKeyboardSwitch();
}
@Override
@@ -193,27 +204,13 @@
final ArrayList<HardKeyboardDeviceInfo> newHardKeyboards = getHardKeyboards();
if (!Objects.equal(newHardKeyboards, mLastHardKeyboards)) {
clearLoader();
- final PreferenceScreen preferenceScreen = getPreferenceScreen();
- preferenceScreen.removeAll();
mLastHardKeyboards.clear();
mLastHardKeyboards.addAll(newHardKeyboards);
- final int N = newHardKeyboards.size();
- for (int i = 0; i < N; ++i) {
- final HardKeyboardDeviceInfo deviceInfo = newHardKeyboards.get(i);
- final PreferenceCategory category = new PreferenceCategory(getPrefContext(), null);
- category.setTitle(deviceInfo.mDeviceName);
- category.setOrder(0);
- getLoaderManager().initLoader(mNextLoaderId, null,
- new Callbacks(getContext(), this, deviceInfo.mDeviceIdentifier, category));
- mLoaderIDs.add(mNextLoaderId);
- ++mNextLoaderId;
- preferenceScreen.addPreference(category);
- }
- mKeyboardAssistanceCategory.setOrder(1);
- preferenceScreen.addPreference(mKeyboardAssistanceCategory);
-
+ getLoaderManager().initLoader(mNextLoaderId, null,
+ new Callbacks(getContext(), this, mLastHardKeyboards));
+ mLoaderIDs.add(mNextLoaderId);
+ ++mNextLoaderId;
}
- updateShowVirtualKeyboardSwitch();
}
private void showKeyboardLayoutScreen(
@@ -285,56 +282,49 @@
context.getString(R.string.physical_device_title), imSubtypeName, imeName);
}
- private static final class Callbacks
- implements LoaderManager.LoaderCallbacks<PhysicalKeyboardFragment.Keyboards> {
+ private static final class Callbacks implements LoaderManager.LoaderCallbacks<List<Keyboards>> {
@NonNull
final Context mContext;
@NonNull
final PhysicalKeyboardFragment mPhysicalKeyboardFragment;
@NonNull
- final InputDeviceIdentifier mInputDeviceIdentifier;
- @NonNull
- final PreferenceCategory mPreferenceCategory;
+ final List<HardKeyboardDeviceInfo> mHardKeyboards;
public Callbacks(
@NonNull Context context,
@NonNull PhysicalKeyboardFragment physicalKeyboardFragment,
- @NonNull InputDeviceIdentifier inputDeviceIdentifier,
- @NonNull PreferenceCategory preferenceCategory) {
+ @NonNull List<HardKeyboardDeviceInfo> hardKeyboards) {
mContext = context;
mPhysicalKeyboardFragment = physicalKeyboardFragment;
- mInputDeviceIdentifier = inputDeviceIdentifier;
- mPreferenceCategory = preferenceCategory;
+ mHardKeyboards = hardKeyboards;
}
@Override
- public Loader<Keyboards> onCreateLoader(int id, Bundle args) {
- return new KeyboardLayoutLoader(mContext, mInputDeviceIdentifier);
+ public Loader<List<Keyboards>> onCreateLoader(int id, Bundle args) {
+ return new KeyboardLayoutLoader(mContext, mHardKeyboards);
}
@Override
- public void onLoadFinished(Loader<Keyboards> loader, Keyboards data) {
- mPhysicalKeyboardFragment.onLoadFinishedInternal(loader.getId(), data,
- mPreferenceCategory);
+ public void onLoadFinished(Loader<List<Keyboards>> loader, List<Keyboards> data) {
+ mPhysicalKeyboardFragment.onLoadFinishedInternal(loader.getId(), data);
}
@Override
- public void onLoaderReset(Loader<Keyboards> loader) {
+ public void onLoaderReset(Loader<List<Keyboards>> loader) {
}
}
- private static final class KeyboardLayoutLoader extends AsyncTaskLoader<Keyboards> {
+ private static final class KeyboardLayoutLoader extends AsyncTaskLoader<List<Keyboards>> {
@NonNull
- private final InputDeviceIdentifier mInputDeviceIdentifier;
+ private final List<HardKeyboardDeviceInfo> mHardKeyboards;
public KeyboardLayoutLoader(
@NonNull Context context,
- @NonNull InputDeviceIdentifier inputDeviceIdentifier) {
+ @NonNull List<HardKeyboardDeviceInfo> hardKeyboards) {
super(context);
- mInputDeviceIdentifier = Preconditions.checkNotNull(inputDeviceIdentifier);
+ mHardKeyboards = Preconditions.checkNotNull(hardKeyboards);
}
- @Override
- public Keyboards loadInBackground() {
+ private Keyboards loadInBackground(HardKeyboardDeviceInfo deviceInfo) {
final ArrayList<Keyboards.KeyboardInfo> keyboardInfoList = new ArrayList<>();
final InputMethodManager imm = getContext().getSystemService(InputMethodManager.class);
final InputManager im = getContext().getSystemService(InputManager.class);
@@ -346,12 +336,21 @@
continue;
}
final KeyboardLayout layout = im.getKeyboardLayoutForInputDevice(
- mInputDeviceIdentifier, imi, subtype);
+ deviceInfo.mDeviceIdentifier, imi, subtype);
keyboardInfoList.add(new Keyboards.KeyboardInfo(imi, subtype, layout));
}
}
}
- return new Keyboards(mInputDeviceIdentifier, keyboardInfoList);
+ return new Keyboards(deviceInfo, keyboardInfoList);
+ }
+
+ @Override
+ public List<Keyboards> loadInBackground() {
+ List<Keyboards> keyboardsList = new ArrayList<>(mHardKeyboards.size());
+ for (HardKeyboardDeviceInfo deviceInfo : mHardKeyboards) {
+ keyboardsList.add(loadInBackground(deviceInfo));
+ }
+ return keyboardsList;
}
@Override
@@ -408,14 +407,14 @@
public static final class Keyboards {
@NonNull
- public final InputDeviceIdentifier mInputDeviceIdentifier;
+ public final HardKeyboardDeviceInfo mDeviceInfo;
@NonNull
public final ArrayList<KeyboardInfo> mKeyboardInfoList;
public Keyboards(
- @NonNull final InputDeviceIdentifier inputDeviceIdentifier,
+ @NonNull final HardKeyboardDeviceInfo deviceInfo,
@NonNull final ArrayList<KeyboardInfo> keyboardInfoList) {
- mInputDeviceIdentifier = inputDeviceIdentifier;
+ mDeviceInfo = deviceInfo;
mKeyboardInfoList = keyboardInfoList;
}
diff --git a/src/com/android/settings/inputmethod/SpellCheckersSettings.java b/src/com/android/settings/inputmethod/SpellCheckersSettings.java
index bc2a5c0..3309af2 100644
--- a/src/com/android/settings/inputmethod/SpellCheckersSettings.java
+++ b/src/com/android/settings/inputmethod/SpellCheckersSettings.java
@@ -113,7 +113,7 @@
mSwitchBar.setChecked(isSpellCheckerEnabled);
final SpellCheckerSubtype currentScs;
- if (mCurrentSci == null) {
+ if (mCurrentSci != null) {
currentScs = mTsm.getCurrentSpellCheckerSubtype(
false /* allowImplicitlySelectedSubtype */);
} else {
diff --git a/src/com/android/settings/inputmethod/VirtualKeyboardFragment.java b/src/com/android/settings/inputmethod/VirtualKeyboardFragment.java
index fe81a81..3b36de6 100644
--- a/src/com/android/settings/inputmethod/VirtualKeyboardFragment.java
+++ b/src/com/android/settings/inputmethod/VirtualKeyboardFragment.java
@@ -113,7 +113,7 @@
InputMethodAndSubtypeUtil.removeUnnecessaryNonPersistentPreference(pref);
pref.updatePreferenceViews();
}
- mAddVirtualKeyboardScreen.setIcon(R.drawable.ic_add);
+ mAddVirtualKeyboardScreen.setIcon(R.drawable.ic_add_24dp);
mAddVirtualKeyboardScreen.setOrder(N);
getPreferenceScreen().addPreference(mAddVirtualKeyboardScreen);
}
diff --git a/src/com/android/settings/localepicker/LocaleDragAndDropAdapter.java b/src/com/android/settings/localepicker/LocaleDragAndDropAdapter.java
index a78c60d..2ce4e72 100644
--- a/src/com/android/settings/localepicker/LocaleDragAndDropAdapter.java
+++ b/src/com/android/settings/localepicker/LocaleDragAndDropAdapter.java
@@ -18,6 +18,7 @@
import android.content.Context;
import android.graphics.Canvas;
+import android.os.Bundle;
import android.support.v4.view.MotionEventCompat;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.helper.ItemTouchHelper;
@@ -36,6 +37,7 @@
import com.android.settings.R;
import java.text.NumberFormat;
+import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
@@ -45,6 +47,7 @@
extends RecyclerView.Adapter<LocaleDragAndDropAdapter.CustomViewHolder> {
private static final String TAG = "LocaleDragAndDropAdapter";
+ private static final String CFGKEY_SELECTED_LOCALES = "selectedLocales";
private final Context mContext;
private final List<LocaleStore.LocaleInfo> mFeedItemList;
private final ItemTouchHelper mItemTouchHelper;
@@ -105,6 +108,7 @@
private static final int SELECTION_LOST = 0;
private static final int SELECTION_UNCHANGED = -1;
private int mSelectionStatus = SELECTION_UNCHANGED;
+
@Override
public void onChildDraw(Canvas c, RecyclerView recyclerView,
RecyclerView.ViewHolder viewHolder, float dX, float dY,
@@ -148,7 +152,6 @@
public void onBindViewHolder(final CustomViewHolder holder, int i) {
final LocaleStore.LocaleInfo feedItem = mFeedItemList.get(i);
final LocaleDragCell dragCell = holder.getLocaleDragCell();
-
String label = feedItem.getFullNameNative();
dragCell.setLabel(label);
dragCell.setLocalized(feedItem.isTranslated());
@@ -156,7 +159,7 @@
dragCell.setShowCheckbox(mRemoveMode);
dragCell.setShowMiniLabel(!mRemoveMode);
dragCell.setShowHandle(!mRemoveMode && mDragEnabled);
- dragCell.setChecked(false);
+ dragCell.setChecked(mRemoveMode ? feedItem.getChecked() : false);
dragCell.setTag(feedItem);
dragCell.getCheckbox()
.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@@ -286,4 +289,40 @@
private void setDragEnabled(boolean enabled) {
mDragEnabled = enabled;
}
+
+ /**
+ * Saves the list of checked locales to preserve status when the list is destroyed.
+ * (for instance when the device is rotated)
+ * @param outInstanceState Bundle in which to place the saved state
+ */
+ public void saveState(Bundle outInstanceState) {
+ if (outInstanceState != null) {
+ final ArrayList<String> selectedLocales = new ArrayList<>();
+ for (LocaleStore.LocaleInfo li : mFeedItemList) {
+ if (li.getChecked()) {
+ selectedLocales.add(li.getId());
+ }
+ }
+ outInstanceState.putStringArrayList(CFGKEY_SELECTED_LOCALES, selectedLocales);
+ }
+ }
+
+ /**
+ * Restores the list of checked locales to preserve status when the list is recreated.
+ * (for instance when the device is rotated)
+ * @param savedInstanceState Bundle with the data saved by {@link #saveState(Bundle)}
+ */
+ public void restoreState(Bundle savedInstanceState) {
+ if (savedInstanceState != null && mRemoveMode) {
+ final ArrayList<String> selectedLocales =
+ savedInstanceState.getStringArrayList(CFGKEY_SELECTED_LOCALES);
+ if (selectedLocales == null || selectedLocales.isEmpty()) {
+ return;
+ }
+ for (LocaleStore.LocaleInfo li : mFeedItemList) {
+ li.setChecked(selectedLocales.contains(li.getId()));
+ }
+ notifyItemRangeChanged(0, mFeedItemList.size());
+ }
+ }
}
diff --git a/src/com/android/settings/localepicker/LocaleListEditor.java b/src/com/android/settings/localepicker/LocaleListEditor.java
index 63649d7..3287d39 100644
--- a/src/com/android/settings/localepicker/LocaleListEditor.java
+++ b/src/com/android/settings/localepicker/LocaleListEditor.java
@@ -31,6 +31,7 @@
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
+
import com.android.internal.app.LocalePicker;
import com.android.internal.app.LocalePickerWithRegion;
import com.android.internal.app.LocaleStore;
@@ -48,12 +49,15 @@
public class LocaleListEditor extends SettingsPreferenceFragment
implements LocalePickerWithRegion.LocaleSelectedListener {
+ private static final String CFGKEY_REMOVE_MODE = "localeRemoveMode";
+ private static final String CFGKEY_REMOVE_DIALOG = "showingLocaleRemoveDialog";
private static final int MENU_ID_REMOVE = Menu.FIRST + 1;
private LocaleDragAndDropAdapter mAdapter;
private Menu mMenu;
- private boolean mRemoveMode;
private View mAddLanguage;
+ private boolean mRemoveMode;
+ private boolean mShowingRemoveDialog;
@Override
protected int getMetricsCategory() {
@@ -83,14 +87,44 @@
}
@Override
+ public void onViewStateRestored(Bundle savedInstanceState) {
+ super.onViewStateRestored(savedInstanceState);
+ if (savedInstanceState != null) {
+ mRemoveMode = savedInstanceState.getBoolean(CFGKEY_REMOVE_MODE, false);
+ mShowingRemoveDialog = savedInstanceState.getBoolean(CFGKEY_REMOVE_DIALOG, false);
+ }
+ setRemoveMode(mRemoveMode);
+ mAdapter.restoreState(savedInstanceState);
+
+ if (mShowingRemoveDialog) {
+ showRemoveLocaleWarningDialog();
+ }
+ }
+
+ @Override
+ public void onSaveInstanceState(Bundle outState) {
+ super.onSaveInstanceState(outState);
+ outState.putBoolean(CFGKEY_REMOVE_MODE, mRemoveMode);
+ outState.putBoolean(CFGKEY_REMOVE_DIALOG, mShowingRemoveDialog);
+ mAdapter.saveState(outState);
+ }
+
+ @Override
public boolean onOptionsItemSelected(MenuItem menuItem) {
- if (menuItem.getItemId() == MENU_ID_REMOVE) {
- if (mRemoveMode) {
- removeLocaleWarningDialog();
- } else {
- setRemoveMode(true);
- }
- return true;
+ switch (menuItem.getItemId()) {
+ case MENU_ID_REMOVE:
+ if (mRemoveMode) {
+ showRemoveLocaleWarningDialog();
+ } else {
+ setRemoveMode(true);
+ }
+ return true;
+ case android.R.id.home:
+ if (mRemoveMode) {
+ setRemoveMode(false);
+ return true;
+ }
+ break;
}
return super.onOptionsItemSelected(menuItem);
}
@@ -98,12 +132,15 @@
private void setRemoveMode(boolean mRemoveMode) {
this.mRemoveMode = mRemoveMode;
mAdapter.setRemoveMode(mRemoveMode);
- mMenu.findItem(MENU_ID_REMOVE).setShowAsAction(
- mRemoveMode ? MenuItem.SHOW_AS_ACTION_ALWAYS : MenuItem.SHOW_AS_ACTION_NEVER);
mAddLanguage.setVisibility(mRemoveMode ? View.INVISIBLE : View.VISIBLE);
+ updateVisibilityOfRemoveMenu();
}
- private void removeLocaleWarningDialog() {
+ // Show the appropriate warning when the user tries to remove locales.
+ // Shows no warning if there is no locale checked, shows a warning
+ // about removing all the locales if all of them are checked, and
+ // a "regular" warning otherwise.
+ private void showRemoveLocaleWarningDialog() {
int checkedCount = mAdapter.getCheckedCount();
// Nothing checked, just exit remove mode without a warning dialog
@@ -114,6 +151,7 @@
// All locales selected, warning dialog, can't remove them all
if (checkedCount == mAdapter.getItemCount()) {
+ mShowingRemoveDialog = true;
new AlertDialog.Builder(getActivity())
.setTitle(R.string.dlg_remove_locales_error_title)
.setMessage(R.string.dlg_remove_locales_error_message)
@@ -122,6 +160,12 @@
public void onClick(DialogInterface dialog, int which) {
}
})
+ .setOnDismissListener(new DialogInterface.OnDismissListener() {
+ @Override
+ public void onDismiss(DialogInterface dialog) {
+ mShowingRemoveDialog = false;
+ }
+ })
.create()
.show();
return;
@@ -129,21 +173,38 @@
final String title = getResources().getQuantityString(R.plurals.dlg_remove_locales_title,
checkedCount);
+ mShowingRemoveDialog = true;
new AlertDialog.Builder(getActivity())
.setTitle(title)
.setMessage(R.string.dlg_remove_locales_message)
.setNegativeButton(android.R.string.no, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
- setRemoveMode(!mRemoveMode);
+ setRemoveMode(false);
}
})
.setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
+ // This is a sensitive area to change.
+ // removeChecked() triggers a system update and "kills" the frame.
+ // This means that saveState + restoreState are called before
+ // setRemoveMode is called.
+ // So we want that mRemoveMode and dialog status have the right values
+ // before that save.
+ // We can't just call setRemoveMode(false) before calling removeCheched
+ // because that unchecks all items and removeChecked would have nothing
+ // to remove.
+ mRemoveMode = false;
+ mShowingRemoveDialog = false;
mAdapter.removeChecked();
- setRemoveMode(!mRemoveMode);
- updateVisibilityOfRemoveMenu();
+ setRemoveMode(false);
+ }
+ })
+ .setOnDismissListener(new DialogInterface.OnDismissListener() {
+ @Override
+ public void onDismiss(DialogInterface dialog) {
+ mShowingRemoveDialog = false;
}
})
.create()
@@ -208,8 +269,14 @@
// Hide the "Remove" menu if there is only one locale in the list, show it otherwise
// This is called when the menu is first created, and then one add / remove locale
private void updateVisibilityOfRemoveMenu() {
+ if (mMenu == null) {
+ return;
+ }
+
final MenuItem menuItemRemove = mMenu.findItem(MENU_ID_REMOVE);
if (menuItemRemove != null) {
+ menuItemRemove.setShowAsAction(
+ mRemoveMode ? MenuItem.SHOW_AS_ACTION_ALWAYS : MenuItem.SHOW_AS_ACTION_NEVER);
menuItemRemove.setVisible(mAdapter.getItemCount() > 1);
}
}
diff --git a/src/com/android/settings/notification/AppNotificationSettings.java b/src/com/android/settings/notification/AppNotificationSettings.java
index 144c841..5113dc6 100644
--- a/src/com/android/settings/notification/AppNotificationSettings.java
+++ b/src/com/android/settings/notification/AppNotificationSettings.java
@@ -72,8 +72,6 @@
addPreferencesFromResource(R.xml.app_notification_settings);
mImportance = (ImportanceSeekBarPreference) findPreference(KEY_IMPORTANCE);
- mImportanceReset = (LayoutPreference) findPreference(KEY_IMPORTANCE_RESET);
- mImportanceTitle = (RestrictedPreference) findPreference(KEY_IMPORTANCE_TITLE);
mPriority =
(RestrictedSwitchPreference) getPreferenceScreen().findPreference(KEY_BYPASS_DND);
mVisibilityOverride =
diff --git a/src/com/android/settings/notification/ConfigureNotificationSettings.java b/src/com/android/settings/notification/ConfigureNotificationSettings.java
index 4d50461..9acac06 100644
--- a/src/com/android/settings/notification/ConfigureNotificationSettings.java
+++ b/src/com/android/settings/notification/ConfigureNotificationSettings.java
@@ -213,7 +213,7 @@
Log.i(TAG, "Preference not found: " + KEY_LOCK_SCREEN_PROFILE_NOTIFICATIONS);
return;
}
-
+ mLockscreenProfile.setUserId(mProfileChallengeUserId);
ArrayList<CharSequence> entries = new ArrayList<>();
ArrayList<CharSequence> values = new ArrayList<>();
entries.add(getString(R.string.lock_screen_notifications_summary_disable_profile));
@@ -241,6 +241,8 @@
mLockscreenProfile.setEntries(entries.toArray(new CharSequence[entries.size()]));
mLockscreenProfile.setEntryValues(values.toArray(new CharSequence[values.size()]));
+ // Work profile does not support this settings as we do not have a policy to enforce it yet
+ mLockscreenProfile.setRemoteInputCheckBoxEnabled(false);
updateLockscreenNotificationsForProfile();
if (mLockscreenProfile.getEntries().length > 1) {
mLockscreenProfile.setOnPreferenceChangeListener(new OnPreferenceChangeListener() {
diff --git a/src/com/android/settings/notification/ImportanceSeekBarPreference.java b/src/com/android/settings/notification/ImportanceSeekBarPreference.java
index aff9688..46f9b3f 100644
--- a/src/com/android/settings/notification/ImportanceSeekBarPreference.java
+++ b/src/com/android/settings/notification/ImportanceSeekBarPreference.java
@@ -20,10 +20,16 @@
import com.android.settings.SeekBarPreference;
import android.content.Context;
+import android.content.res.ColorStateList;
+import android.graphics.drawable.Drawable;
+import android.os.Handler;
+import android.service.notification.NotificationListenerService;
import android.support.v7.preference.PreferenceViewHolder;
import android.util.AttributeSet;
+import android.view.View;
import android.widget.ImageView;
import android.widget.SeekBar;
+import android.widget.TextView;
/**
* A slider preference that controls notification importance.
@@ -34,12 +40,23 @@
private Callback mCallback;
private int mMinProgress;
- private boolean mSystemApp;
+ private TextView mSummaryTextView;
+ private String mSummary;
+ private SeekBar mSeekBar;
+ private ColorStateList mActiveSliderTint;
+ private ColorStateList mInactiveSliderTint;
+ private boolean mAutoOn;
+ private Handler mHandler;
public ImportanceSeekBarPreference(Context context, AttributeSet attrs, int defStyleAttr,
int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
setLayoutResource(R.layout.preference_importance_slider);
+ mActiveSliderTint = ColorStateList.valueOf(
+ context.getColor(R.color.importance_slider_color));
+ mInactiveSliderTint = ColorStateList.valueOf(
+ context.getColor(R.color.importance_disabled_slider_color));
+ mHandler = new Handler();
}
public ImportanceSeekBarPreference(Context context, AttributeSet attrs, int defStyleAttr) {
@@ -63,20 +80,67 @@
notifyChanged();
}
- public void setSystemApp(boolean systemApp) {
- mSystemApp = systemApp;
+ @Override
+ public void setProgress(int progress) {
+ mSummary = getProgressSummary(progress);
+ super.setProgress(progress);
+ }
+
+ public void setAutoOn(boolean autoOn) {
+ mAutoOn = autoOn;
notifyChanged();
}
@Override
public void onBindViewHolder(PreferenceViewHolder view) {
super.onBindViewHolder(view);
- if (mSystemApp) {
- ((ImageView) view.findViewById(R.id.low_importance)).getDrawable().setTint(
- getContext().getColor(R.color.importance_disabled_tint));
+ mSummaryTextView = (TextView) view.findViewById(com.android.internal.R.id.summary);
+ mSeekBar = (SeekBar) view.findViewById(
+ com.android.internal.R.id.seekbar);
+
+ final ImageView autoButton = (ImageView) view.findViewById(R.id.auto_importance);
+ applyAutoUi(autoButton);
+ autoButton.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ applyAuto(autoButton);
+ }
+ });
+ }
+
+ private void applyAuto(ImageView autoButton) {
+ mAutoOn = !mAutoOn;
+ if (!mAutoOn) {
+ setProgress(NotificationListenerService.Ranking.IMPORTANCE_DEFAULT);
+ mCallback.onImportanceChanged(
+ NotificationListenerService.Ranking.IMPORTANCE_DEFAULT, true);
+ } else {
+ mCallback.onImportanceChanged(
+ NotificationListenerService.Ranking.IMPORTANCE_UNSPECIFIED, true);
}
- view.setDividerAllowedAbove(false);
- view.setDividerAllowedBelow(false);
+ applyAutoUi(autoButton);
+ }
+
+ private void applyAutoUi(ImageView autoButton) {
+ mSeekBar.setEnabled(!mAutoOn);
+
+ final ColorStateList tint = mAutoOn ? mInactiveSliderTint : mActiveSliderTint;
+ Drawable icon = autoButton.getDrawable().mutate();
+ icon.setTintList(tint);
+ autoButton.setImageDrawable(icon);
+ mSeekBar.setProgressTintList(tint);
+ mSeekBar.setThumbTintList(tint);
+
+ if (mAutoOn) {
+ mSummary = getProgressSummary(
+ NotificationListenerService.Ranking.IMPORTANCE_UNSPECIFIED);
+ }
+ mSummaryTextView.setText(mSummary);
+ }
+
+ @Override
+ public CharSequence getSummary() {
+ return mSummary;
}
@Override
@@ -86,12 +150,49 @@
seekBar.setProgress(mMinProgress);
progress = mMinProgress;
}
- if (fromTouch) {
- mCallback.onImportanceChanged(progress);
+ if (mSummaryTextView != null) {
+ mSummary = getProgressSummary(progress);
+ mSummaryTextView.setText(mSummary);
+ }
+ mCallback.onImportanceChanged(progress, fromTouch);
+ }
+
+ private String getProgressSummary(int progress) {
+ switch (progress) {
+ case NotificationListenerService.Ranking.IMPORTANCE_NONE:
+ return getContext().getString(R.string.notification_importance_blocked);
+ case NotificationListenerService.Ranking.IMPORTANCE_MIN:
+ return getContext().getString(R.string.notification_importance_min);
+ case NotificationListenerService.Ranking.IMPORTANCE_LOW:
+ return getContext().getString(R.string.notification_importance_low);
+ case NotificationListenerService.Ranking.IMPORTANCE_DEFAULT:
+ return getContext().getString(R.string.notification_importance_default);
+ case NotificationListenerService.Ranking.IMPORTANCE_HIGH:
+ return getContext().getString(R.string.notification_importance_high);
+ case NotificationListenerService.Ranking.IMPORTANCE_MAX:
+ return getContext().getString(R.string.notification_importance_max);
+ default:
+ return getContext().getString(R.string.notification_importance_unspecified);
}
}
+ @Override
+ protected void notifyChanged() {
+ mHandler.post(mNotifyChanged);
+ }
+
+ private void postNotifyChanged() {
+ super.notifyChanged();
+ }
+
+ private final Runnable mNotifyChanged = new Runnable() {
+ @Override
+ public void run() {
+ postNotifyChanged();
+ }
+ };
+
public interface Callback {
- void onImportanceChanged(int progress);
+ void onImportanceChanged(int progress, boolean fromTouch);
}
}
diff --git a/src/com/android/settings/notification/NotificationAccessSettings.java b/src/com/android/settings/notification/NotificationAccessSettings.java
index 0111a38..d81bc0e 100644
--- a/src/com/android/settings/notification/NotificationAccessSettings.java
+++ b/src/com/android/settings/notification/NotificationAccessSettings.java
@@ -16,8 +16,16 @@
package com.android.settings.notification;
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.app.DialogFragment;
+import android.app.NotificationManager;
+import android.content.ComponentName;
import android.content.Context;
+import android.content.DialogInterface;
import android.content.pm.PackageManager;
+import android.os.AsyncTask;
+import android.os.Bundle;
import android.provider.Settings;
import android.service.notification.NotificationListenerService;
@@ -30,6 +38,14 @@
private static final String TAG = NotificationAccessSettings.class.getSimpleName();
private static final Config CONFIG = getNotificationListenerConfig();
+ private NotificationManager mNm;
+
+ @Override
+ public void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+ mNm = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
+ }
+
private static Config getNotificationListenerConfig() {
final Config c = new Config();
c.tag = TAG;
@@ -60,4 +76,74 @@
public static int getEnabledListenersCount(Context context) {
return ServiceListing.getEnabledServicesCount(CONFIG, context);
}
+
+ protected boolean setEnabled(ComponentName service, String title, boolean enable) {
+ if (!enable) {
+ if (!mServiceListing.isEnabled(service)) {
+ return true; // already disabled
+ }
+ // show a friendly dialog
+ new FriendlyWarningDialogFragment()
+ .setServiceInfo(service, title)
+ .show(getFragmentManager(), "friendlydialog");
+ return false;
+ } else {
+ return super.setEnabled(service, title, enable);
+ }
+ }
+
+ private static void deleteRules(final Context context, final String pkg) {
+ AsyncTask.execute(new Runnable() {
+ @Override
+ public void run() {
+ final NotificationManager mgr = context.getSystemService(NotificationManager.class);
+ mgr.removeAutomaticZenRules(pkg);
+ }
+ });
+ }
+
+ public class FriendlyWarningDialogFragment extends DialogFragment {
+ static final String KEY_COMPONENT = "c";
+ static final String KEY_LABEL = "l";
+
+ public FriendlyWarningDialogFragment setServiceInfo(ComponentName cn, String label) {
+ Bundle args = new Bundle();
+ args.putString(KEY_COMPONENT, cn.flattenToString());
+ args.putString(KEY_LABEL, label);
+ setArguments(args);
+ return this;
+ }
+
+ @Override
+ public Dialog onCreateDialog(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ final Bundle args = getArguments();
+ final String label = args.getString(KEY_LABEL);
+ final ComponentName cn = ComponentName.unflattenFromString(args
+ .getString(KEY_COMPONENT));
+
+ final String summary = getResources().getString(
+ R.string.notification_listener_disable_warning_summary, label);
+ return new AlertDialog.Builder(mContext)
+ .setMessage(summary)
+ .setCancelable(true)
+ .setPositiveButton(R.string.notification_listener_disable_warning_confirm,
+ new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int id) {
+ mServiceListing.setEnabled(cn, false);
+ if (!mNm.isNotificationPolicyAccessGrantedForPackage(
+ cn.getPackageName())) {
+ deleteRules(mContext, cn.getPackageName());
+ }
+ }
+ })
+ .setNegativeButton(R.string.notification_listener_disable_warning_cancel,
+ new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int id) {
+ // pass
+ }
+ })
+ .create();
+ }
+ }
}
diff --git a/src/com/android/settings/notification/NotificationLockscreenPreference.java b/src/com/android/settings/notification/NotificationLockscreenPreference.java
index 39b9c5d..8c89968 100644
--- a/src/com/android/settings/notification/NotificationLockscreenPreference.java
+++ b/src/com/android/settings/notification/NotificationLockscreenPreference.java
@@ -18,11 +18,14 @@
import com.android.settings.R;
import com.android.settings.RestrictedListPreference;
+import com.android.settings.Utils;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
+import android.os.UserHandle;
+import android.os.UserManager;
import android.provider.Settings;
import android.util.AttributeSet;
import android.view.View;
@@ -37,11 +40,31 @@
private int mInitialIndex;
private Listener mListener;
private boolean mShowRemoteInput;
+ private boolean mRemoteInputCheckBoxEnabled = true;
+ private int mUserId = UserHandle.myUserId();
public NotificationLockscreenPreference(Context context, AttributeSet attrs) {
super(context, attrs);
}
+ public void setRemoteInputCheckBoxEnabled(boolean enabled) {
+ mRemoteInputCheckBoxEnabled = enabled;
+ }
+
+ @Override
+ protected void onClick() {
+ final Context context = getContext();
+ if (!Utils.startQuietModeDialogIfNecessary(context, UserManager.get(context), mUserId)) {
+ // Call super to create preference dialog only when work mode is on
+ // startQuietModeDialogIfNecessary will return false if mUserId is not a managed user
+ super.onClick();
+ }
+ }
+
+ public void setUserId(int userId) {
+ mUserId = userId;
+ }
+
@Override
protected void onPrepareDialogBuilder(AlertDialog.Builder builder,
DialogInterface.OnClickListener innerListener) {
@@ -85,8 +108,10 @@
return false;
}
- private static int checkboxVisibilityForSelectedIndex(int selected, boolean showRemoteAtAll) {
- return selected == 1 && showRemoteAtAll ? View.VISIBLE : View.GONE;
+ private int checkboxVisibilityForSelectedIndex(int selected,
+ boolean showRemoteAtAll) {
+ return selected == 1 && showRemoteAtAll && mRemoteInputCheckBoxEnabled ? View.VISIBLE
+ : View.GONE;
}
private class Listener implements DialogInterface.OnClickListener,
diff --git a/src/com/android/settings/notification/NotificationSettingsBase.java b/src/com/android/settings/notification/NotificationSettingsBase.java
index 314c2f8..e034965 100644
--- a/src/com/android/settings/notification/NotificationSettingsBase.java
+++ b/src/com/android/settings/notification/NotificationSettingsBase.java
@@ -20,9 +20,7 @@
import com.android.settings.SettingsPreferenceFragment;
import com.android.settings.applications.AppInfoBase;
import com.android.settingslib.RestrictedLockUtils;
-import com.android.settingslib.RestrictedPreference;
import com.android.settingslib.RestrictedSwitchPreference;
-import com.android.settings.applications.LayoutPreference;
import android.app.Notification;
import android.content.Context;
@@ -38,8 +36,6 @@
import android.support.v7.preference.Preference;
import android.text.TextUtils;
import android.util.Log;
-import android.view.View;
-import android.widget.Button;
import android.widget.Toast;
import java.util.ArrayList;
@@ -54,8 +50,6 @@
protected static final String KEY_BYPASS_DND = "bypass_dnd";
protected static final String KEY_VISIBILITY_OVERRIDE = "visibility_override";
protected static final String KEY_IMPORTANCE = "importance";
- protected static final String KEY_IMPORTANCE_TITLE = "importance_title";
- protected static final String KEY_IMPORTANCE_RESET = "importance_reset_button";
protected static final String KEY_BLOCK = "block";
protected static final String KEY_SILENT = "silent";
@@ -68,8 +62,6 @@
protected String mPkg;
protected PackageInfo mPkgInfo;
protected ImportanceSeekBarPreference mImportance;
- protected RestrictedPreference mImportanceTitle;
- protected LayoutPreference mImportanceReset;
protected RestrictedSwitchPreference mPriority;
protected DropDownPreference mVisibilityOverride;
protected RestrictedSwitchPreference mBlock;
@@ -147,9 +139,6 @@
if (mPriority != null) {
mPriority.setDisabledByAdmin(mSuspendedAppsAdmin);
}
- if (mImportanceTitle != null) {
- mImportanceTitle.setDisabledByAdmin(mSuspendedAppsAdmin);
- }
if (mBlock != null) {
mBlock.setDisabledByAdmin(mSuspendedAppsAdmin);
}
@@ -163,54 +152,22 @@
setVisible(mBlock, false);
setVisible(mSilent, false);
mImportance.setDisabledByAdmin(mSuspendedAppsAdmin);
- mImportanceTitle.setDisabledByAdmin(mSuspendedAppsAdmin);
- if (importance == Ranking.IMPORTANCE_UNSPECIFIED) {
- mImportance.setVisible(false);
- mImportanceReset.setVisible(false);
- mImportanceTitle.setOnPreferenceClickListener(showEditableImportance);
- } else {
- mImportanceTitle.setOnPreferenceClickListener(null);
- }
-
- mImportanceTitle.setSummary(getProgressSummary(importance));
- mImportance.setSystemApp(isSystemApp);
mImportance.setMinimumProgress(
isSystemApp ? Ranking.IMPORTANCE_MIN : Ranking.IMPORTANCE_NONE);
mImportance.setMax(Ranking.IMPORTANCE_MAX);
mImportance.setProgress(importance);
+ mImportance.setAutoOn(importance == Ranking.IMPORTANCE_UNSPECIFIED);
mImportance.setCallback(new ImportanceSeekBarPreference.Callback() {
@Override
- public void onImportanceChanged(int progress) {
- mBackend.setImportance(mPkg, mUid, progress);
- mImportanceTitle.setSummary(getProgressSummary(progress));
+ public void onImportanceChanged(int progress, boolean fromUser) {
+ if (fromUser) {
+ mBackend.setImportance(mPkg, mUid, progress);
+ }
updateDependents(progress);
}
});
-
- Button button = (Button) mImportanceReset.findViewById(R.id.left_button);
- button.setText(R.string.importance_reset);
- button.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- if (mSuspendedAppsAdmin != null) {
- RestrictedLockUtils.sendShowAdminSupportDetailsIntent(
- getActivity(), mSuspendedAppsAdmin);
- return;
- }
-
- mBackend.setImportance(mPkg, mUid, Ranking.IMPORTANCE_UNSPECIFIED);
- mImportanceReset.setVisible(false);
- mImportance.setVisible(false);
- mImportanceTitle.setOnPreferenceClickListener(showEditableImportance);
- mImportanceTitle.setSummary(getProgressSummary(Ranking.IMPORTANCE_UNSPECIFIED));
- updateDependents(Ranking.IMPORTANCE_UNSPECIFIED);
- }
- });
- mImportanceReset.findViewById(R.id.right_button).setVisibility(View.INVISIBLE);
} else {
setVisible(mImportance, false);
- setVisible(mImportanceReset, false);
- setVisible(mImportanceTitle, false);
boolean blocked = importance == Ranking.IMPORTANCE_NONE || banned;
mBlock.setChecked(blocked);
mBlock.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
@@ -240,27 +197,6 @@
}
}
- private String getProgressSummary(int progress) {
- switch (progress) {
- case Ranking.IMPORTANCE_NONE:
- return mContext.getString(R.string.notification_importance_blocked);
- case Ranking.IMPORTANCE_MIN:
- return mContext.getString(R.string.notification_importance_min);
- case Ranking.IMPORTANCE_LOW:
- return mContext.getString(R.string.notification_importance_low);
- case Ranking.IMPORTANCE_DEFAULT:
- return mContext.getString(R.string.notification_importance_default);
- case Ranking.IMPORTANCE_HIGH:
- return mContext.getString(R.string.notification_importance_high);
- case Ranking.IMPORTANCE_MAX:
- return mContext.getString(R.string.notification_importance_max);
- case Ranking.IMPORTANCE_UNSPECIFIED:
- return mContext.getString(R.string.notification_importance_none);
- default:
- return "";
- }
- }
-
protected void setupPriorityPref(boolean priority) {
mPriority.setDisabledByAdmin(mSuspendedAppsAdmin);
mPriority.setChecked(priority);
@@ -363,18 +299,4 @@
}
return null;
}
-
- private Preference.OnPreferenceClickListener showEditableImportance =
- new Preference.OnPreferenceClickListener() {
- @Override
- public boolean onPreferenceClick(Preference preference) {
- mBackend.setImportance(mPkg, mUid, Ranking.IMPORTANCE_DEFAULT);
- mImportance.setProgress(Ranking.IMPORTANCE_DEFAULT);
- mImportanceTitle.setSummary(getProgressSummary(Ranking.IMPORTANCE_DEFAULT));
- mImportance.setVisible(true);
- mImportanceReset.setVisible(true);
- mImportanceTitle.setOnPreferenceClickListener(null);
- return true;
- }
- };
}
diff --git a/src/com/android/settings/notification/RedactionInterstitial.java b/src/com/android/settings/notification/RedactionInterstitial.java
index abadb8b..35e4036 100644
--- a/src/com/android/settings/notification/RedactionInterstitial.java
+++ b/src/com/android/settings/notification/RedactionInterstitial.java
@@ -186,7 +186,10 @@
private void updateRemoteInputCheckboxVisibility() {
boolean visible = mRadioGroup.getCheckedRadioButtonId() == R.id.show_all;
- mRemoteInputCheckbox.setVisibility(visible ? View.VISIBLE : View.INVISIBLE);
+ boolean isManagedProfile = Utils.isManagedProfile(UserManager.get(getPrefContext()),
+ mUserId);
+ mRemoteInputCheckbox
+ .setVisibility((visible && !isManagedProfile) ? View.VISIBLE : View.INVISIBLE);
}
}
}
diff --git a/src/com/android/settings/notification/ZenAccessSettings.java b/src/com/android/settings/notification/ZenAccessSettings.java
index 9ff2fed..638972e 100644
--- a/src/com/android/settings/notification/ZenAccessSettings.java
+++ b/src/com/android/settings/notification/ZenAccessSettings.java
@@ -21,6 +21,7 @@
import android.app.Dialog;
import android.app.DialogFragment;
import android.app.NotificationManager;
+import android.content.ComponentName;
import android.content.Context;
import android.content.DialogInterface;
import android.content.pm.ApplicationInfo;
@@ -32,6 +33,7 @@
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
+import android.provider.Settings;
import android.provider.Settings.Secure;
import android.support.v14.preference.SwitchPreference;
import android.support.v7.preference.Preference;
@@ -40,6 +42,8 @@
import android.text.TextUtils;
import android.util.ArraySet;
import android.view.View;
+import android.widget.Toast;
+
import com.android.internal.logging.MetricsProto.MetricsEvent;
import com.android.settings.R;
@@ -50,6 +54,7 @@
public class ZenAccessSettings extends EmptyTextSettings {
private final SettingObserver mObserver = new SettingObserver();
+ private static final String ENABLED_SERVICES_SEPARATOR = ":";
private Context mContext;
private PackageManager mPkgMan;
@@ -83,6 +88,9 @@
getContentResolver().registerContentObserver(
Secure.getUriFor(Secure.ENABLED_NOTIFICATION_POLICY_ACCESS_PACKAGES), false,
mObserver);
+ getContentResolver().registerContentObserver(
+ Secure.getUriFor(Secure.ENABLED_NOTIFICATION_LISTENERS), false,
+ mObserver);
}
@Override
@@ -96,7 +104,7 @@
screen.removeAll();
final ArrayList<ApplicationInfo> apps = new ArrayList<>();
final ArraySet<String> requesting = mNoMan.getPackagesRequestingNotificationPolicyAccess();
- if (requesting != null && !requesting.isEmpty()) {
+ if (!requesting.isEmpty()) {
final List<ApplicationInfo> installed = mPkgMan.getInstalledApplications(0);
if (installed != null) {
for (ApplicationInfo app : installed) {
@@ -106,6 +114,8 @@
}
}
}
+ ArraySet<String> autoApproved = getEnabledNotificationListeners();
+ requesting.addAll(autoApproved);
Collections.sort(apps, new PackageItemInfo.DisplayNameComparator(mPkgMan));
for (ApplicationInfo app : apps) {
final String pkg = app.packageName;
@@ -115,6 +125,10 @@
pref.setIcon(app.loadIcon(mPkgMan));
pref.setTitle(label);
pref.setChecked(hasAccess(pkg));
+ if (autoApproved.contains(pkg)) {
+ pref.setEnabled(false);
+ pref.setSummary(getString(R.string.zen_access_disabled_package_warning));
+ }
pref.setOnPreferenceChangeListener(new OnPreferenceChangeListener() {
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
@@ -135,6 +149,22 @@
}
}
+ private ArraySet<String> getEnabledNotificationListeners() {
+ ArraySet<String> packages = new ArraySet<>();
+ String settingValue = Settings.Secure.getString(getContext().getContentResolver(),
+ Settings.Secure.ENABLED_NOTIFICATION_LISTENERS);
+ if (!TextUtils.isEmpty(settingValue)) {
+ String[] restored = settingValue.split(ENABLED_SERVICES_SEPARATOR);
+ for (int i = 0; i < restored.length; i++) {
+ ComponentName value = ComponentName.unflattenFromString(restored[i]);
+ if (null != value) {
+ packages.add(value.getPackageName());
+ }
+ }
+ }
+ return packages;
+ }
+
private boolean hasAccess(String pkg) {
return mNoMan.isNotificationPolicyAccessGrantedForPackage(pkg);
}
diff --git a/src/com/android/settings/notification/ZenModeAutomationSettings.java b/src/com/android/settings/notification/ZenModeAutomationSettings.java
index 3cf28e1..1fdba61 100644
--- a/src/com/android/settings/notification/ZenModeAutomationSettings.java
+++ b/src/com/android/settings/notification/ZenModeAutomationSettings.java
@@ -43,11 +43,10 @@
import com.android.internal.logging.MetricsProto.MetricsEvent;
import com.android.settings.R;
import com.android.settings.utils.ManagedServiceSettings.Config;
-import com.android.settings.utils.ServiceListing;
+import com.android.settings.utils.ZenServiceListing;
import java.lang.ref.WeakReference;
import java.util.Arrays;
-import java.util.Collections;
import java.util.Comparator;
import java.util.Map;
@@ -56,14 +55,14 @@
static final Config CONFIG = getConditionProviderConfig();
private PackageManager mPm;
- private ServiceListing mServiceListing;
+ private ZenServiceListing mServiceListing;
@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
addPreferencesFromResource(R.xml.zen_mode_automation_settings);
mPm = mContext.getPackageManager();
- mServiceListing = new ServiceListing(mContext, CONFIG);
+ mServiceListing = new ZenServiceListing(mContext, CONFIG);
mServiceListing.reloadApprovedServices();
}
@@ -203,6 +202,7 @@
final Config c = new Config();
c.tag = TAG;
c.setting = Settings.Secure.ENABLED_NOTIFICATION_POLICY_ACCESS_PACKAGES;
+ c.secondarySetting = Settings.Secure.ENABLED_NOTIFICATION_LISTENERS;
c.intentAction = ConditionProviderService.SERVICE_INTERFACE;
c.permission = android.Manifest.permission.BIND_CONDITION_PROVIDER_SERVICE;
c.noun = "condition provider";
@@ -308,7 +308,7 @@
final String action = isSchedule ? ZenModeScheduleRuleSettings.ACTION
: isEvent ? ZenModeEventRuleSettings.ACTION : "";
- ServiceInfo si = mServiceListing.findService(mContext, CONFIG, rule.getOwner());
+ ServiceInfo si = mServiceListing.findService(rule.getOwner());
ComponentName settingsActivity = getSettingsActivity(si);
setIntent(getRuleIntent(action, settingsActivity, mId));
setSelectable(settingsActivity != null || isSystemRule);
diff --git a/src/com/android/settings/notification/ZenRuleInfo.java b/src/com/android/settings/notification/ZenRuleInfo.java
index 2a06a08..2d7abf8 100644
--- a/src/com/android/settings/notification/ZenRuleInfo.java
+++ b/src/com/android/settings/notification/ZenRuleInfo.java
@@ -4,6 +4,31 @@
import android.net.Uri;
public class ZenRuleInfo {
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ ZenRuleInfo that = (ZenRuleInfo) o;
+
+ if (isSystem != that.isSystem) return false;
+ if (ruleInstanceLimit != that.ruleInstanceLimit) return false;
+ if (packageName != null ? !packageName.equals(that.packageName) : that.packageName != null)
+ return false;
+ if (title != null ? !title.equals(that.title) : that.title != null) return false;
+ if (settingsAction != null ? !settingsAction.equals(
+ that.settingsAction) : that.settingsAction != null) return false;
+ if (configurationActivity != null ? !configurationActivity.equals(
+ that.configurationActivity) : that.configurationActivity != null) return false;
+ if (defaultConditionId != null ? !defaultConditionId.equals(
+ that.defaultConditionId) : that.defaultConditionId != null) return false;
+ if (serviceComponent != null ? !serviceComponent.equals(
+ that.serviceComponent) : that.serviceComponent != null) return false;
+ return packageLabel != null ? packageLabel.equals(
+ that.packageLabel) : that.packageLabel == null;
+
+ }
+
public String packageName;
public String title;
public String settingsAction;
diff --git a/src/com/android/settings/notification/ZenRuleSelectionDialog.java b/src/com/android/settings/notification/ZenRuleSelectionDialog.java
index 05f42d8..9de9a60 100644
--- a/src/com/android/settings/notification/ZenRuleSelectionDialog.java
+++ b/src/com/android/settings/notification/ZenRuleSelectionDialog.java
@@ -27,6 +27,7 @@
import android.graphics.drawable.Drawable;
import android.os.AsyncTask;
import android.service.notification.ZenModeConfig;
+import android.util.ArraySet;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
@@ -36,6 +37,7 @@
import com.android.settings.R;
import com.android.settings.utils.ServiceListing;
+import com.android.settings.utils.ZenServiceListing;
import java.lang.ref.WeakReference;
import java.text.Collator;
@@ -43,6 +45,8 @@
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
+import java.util.Set;
+import java.util.TreeSet;
public abstract class ZenRuleSelectionDialog {
private static final String TAG = "ZenRuleSelectionDialog";
@@ -53,9 +57,9 @@
private NotificationManager mNm;
private final AlertDialog mDialog;
private final LinearLayout mRuleContainer;
- private final ServiceListing mServiceListing;
+ private final ZenServiceListing mServiceListing;
- public ZenRuleSelectionDialog(Context context, ServiceListing serviceListing) {
+ public ZenRuleSelectionDialog(Context context, ZenServiceListing serviceListing) {
mContext = context;
mPm = context.getPackageManager();
mNm = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
@@ -67,7 +71,7 @@
if (mServiceListing != null) {
bindType(defaultNewEvent());
bindType(defaultNewSchedule());
- mServiceListing.addCallback(mServiceListingCallback);
+ mServiceListing.addZenCallback(mServiceListingCallback);
mServiceListing.reloadApprovedServices();
}
mDialog = new AlertDialog.Builder(context)
@@ -77,7 +81,7 @@
@Override
public void onDismiss(DialogInterface dialog) {
if (mServiceListing != null) {
- mServiceListing.removeCallback(mServiceListingCallback);
+ mServiceListing.removeZenCallback(mServiceListingCallback);
}
}
})
@@ -152,24 +156,24 @@
return rt;
}
- private void bindExternalRules(List<ZenRuleInfo> externalRuleTypes) {
- Collections.sort(externalRuleTypes, RULE_TYPE_COMPARATOR);
+ private void bindExternalRules(Set<ZenRuleInfo> externalRuleTypes) {
for (ZenRuleInfo ri : externalRuleTypes) {
bindType(ri);
}
}
- private final ServiceListing.Callback mServiceListingCallback = new ServiceListing.Callback() {
+ private final ZenServiceListing.Callback mServiceListingCallback = new
+ ZenServiceListing.Callback() {
@Override
- public void onServicesReloaded(List<ServiceInfo> services) {
+ public void onServicesReloaded(Set<ServiceInfo> services) {
if (DEBUG) Log.d(TAG, "Services reloaded: count=" + services.size());
- List<ZenRuleInfo> externalRuleTypes = new ArrayList<>();
- for (int i = 0; i < services.size(); i++) {
- final ZenRuleInfo ri = ZenModeAutomationSettings.getRuleInfo(mPm, services.get(i));
+ Set<ZenRuleInfo> externalRuleTypes = new TreeSet<>(RULE_TYPE_COMPARATOR);
+ for (ServiceInfo serviceInfo : services) {
+ final ZenRuleInfo ri = ZenModeAutomationSettings.getRuleInfo(mPm, serviceInfo);
if (ri != null && ri.configurationActivity != null
&& mNm.isNotificationPolicyAccessGrantedForPackage(ri.packageName)
&& (ri.ruleInstanceLimit <= 0 || ri.ruleInstanceLimit
- >= (mNm.getRuleInstanceCount(services.get(i).getComponentName()) + 1))) {
+ >= (mNm.getRuleInstanceCount(serviceInfo.getComponentName()) + 1))) {
externalRuleTypes.add(ri);
}
}
diff --git a/src/com/android/settings/search/Index.java b/src/com/android/settings/search/Index.java
index 3fd06a2..40d34bc 100644
--- a/src/com/android/settings/search/Index.java
+++ b/src/com/android/settings/search/Index.java
@@ -140,6 +140,7 @@
IndexColumns.DATA_SUMMARY_OFF_NORMALIZED,
IndexColumns.DATA_ENTRIES
};
+ private static final String INDEX = "index";
// Max number of saved search queries (who will be used for proposing suggestions)
private static long MAX_SAVED_SEARCH_QUERY = 64;
@@ -177,6 +178,7 @@
public Map<String, List<String>> nonIndexableKeys;
public boolean forceUpdate = false;
+ public boolean fullIndex = true;
public UpdateData() {
dataToUpdate = new ArrayList<SearchIndexableData>();
@@ -189,6 +191,7 @@
dataToDelete = new ArrayList<SearchIndexableData>(other.dataToDelete);
nonIndexableKeys = new HashMap<String, List<String>>(other.nonIndexableKeys);
forceUpdate = other.forceUpdate;
+ fullIndex = other.fullIndex;
}
public UpdateData copy() {
@@ -200,6 +203,7 @@
dataToDelete.clear();
nonIndexableKeys.clear();
forceUpdate = false;
+ fullIndex = false;
}
}
@@ -213,9 +217,7 @@
*/
public static Index getInstance(Context context) {
if (sInstance == null) {
- sInstance = new Index(context, BASE_AUTHORITY);
- } else {
- sInstance.setContext(context);
+ sInstance = new Index(context.getApplicationContext(), BASE_AUTHORITY);
}
return sInstance;
}
@@ -301,24 +303,30 @@
}
public void update() {
- final Intent intent = new Intent(SearchIndexablesContract.PROVIDER_INTERFACE);
- List<ResolveInfo> list =
- mContext.getPackageManager().queryIntentContentProviders(intent, 0);
+ AsyncTask.execute(new Runnable() {
+ @Override
+ public void run() {
+ final Intent intent = new Intent(SearchIndexablesContract.PROVIDER_INTERFACE);
+ List<ResolveInfo> list =
+ mContext.getPackageManager().queryIntentContentProviders(intent, 0);
- final int size = list.size();
- for (int n = 0; n < size; n++) {
- final ResolveInfo info = list.get(n);
- if (!isWellKnownProvider(info)) {
- continue;
+ final int size = list.size();
+ for (int n = 0; n < size; n++) {
+ final ResolveInfo info = list.get(n);
+ if (!isWellKnownProvider(info)) {
+ continue;
+ }
+ final String authority = info.providerInfo.authority;
+ final String packageName = info.providerInfo.packageName;
+
+ addIndexablesFromRemoteProvider(packageName, authority);
+ addNonIndexablesKeysFromRemoteProvider(packageName, authority);
+ }
+
+ mDataToProcess.fullIndex = true;
+ updateInternal();
}
- final String authority = info.providerInfo.authority;
- final String packageName = info.providerInfo.packageName;
-
- addIndexablesFromRemoteProvider(packageName, authority);
- addNonIndexablesKeysFromRemoteProvider(packageName, authority);
- }
-
- updateInternal();
+ });
}
private boolean addIndexablesFromRemoteProvider(String packageName, String authority) {
@@ -472,7 +480,7 @@
* @param includeInSearchResults true means that you want the bit "enabled" set so that the
* data will be seen included into the search results
*/
- public void updateFromClassNameResource(String className, boolean rebuild,
+ public void updateFromClassNameResource(String className, final boolean rebuild,
boolean includeInSearchResults) {
if (className == null) {
throw new IllegalArgumentException("class name cannot be null!");
@@ -484,19 +492,29 @@
}
res.context = mContext;
res.enabled = includeInSearchResults;
- if (rebuild) {
- deleteIndexableData(res);
- }
- addIndexableData(res);
- mDataToProcess.forceUpdate = true;
- updateInternal();
- res.enabled = false;
+ AsyncTask.execute(new Runnable() {
+ @Override
+ public void run() {
+ if (rebuild) {
+ deleteIndexableData(res);
+ }
+ addIndexableData(res);
+ mDataToProcess.forceUpdate = true;
+ updateInternal();
+ res.enabled = false;
+ }
+ });
}
public void updateFromSearchIndexableData(SearchIndexableData data) {
- addIndexableData(data);
- mDataToProcess.forceUpdate = true;
- updateInternal();
+ AsyncTask.execute(new Runnable() {
+ @Override
+ public void run() {
+ addIndexableData(data);
+ mDataToProcess.forceUpdate = true;
+ updateInternal();
+ }
+ });
}
private SQLiteDatabase getReadableDatabase() {
@@ -1182,6 +1200,7 @@
final Map<String, List<String>> nonIndexableKeys = params[0].nonIndexableKeys;
final boolean forceUpdate = params[0].forceUpdate;
+ final boolean fullIndex = params[0].fullIndex;
final SQLiteDatabase database = getWritableDatabase();
if (database == null) {
@@ -1203,6 +1222,9 @@
} finally {
database.endTransaction();
}
+ if (fullIndex) {
+ setLocaleIndexed(localeStr);
+ }
return null;
}
@@ -1225,8 +1247,8 @@
try {
indexOneSearchIndexableData(database, localeStr, data, nonIndexableKeys);
} catch (Exception e) {
- Log.e(LOG_TAG,
- "Cannot index: " + data.className + " for locale: " + localeStr, e);
+ Log.e(LOG_TAG, "Cannot index: " + (data != null ? data.className : data)
+ + " for locale: " + localeStr, e);
}
}
@@ -1273,24 +1295,12 @@
return database.delete(Tables.TABLE_PREFS_INDEX, whereClause, whereArgs);
}
+ private void setLocaleIndexed(String locale) {
+ mContext.getSharedPreferences(INDEX, 0).edit().putBoolean(locale, true).commit();
+ }
+
private boolean isLocaleAlreadyIndexed(SQLiteDatabase database, String locale) {
- Cursor cursor = null;
- boolean result = false;
- final StringBuilder sb = new StringBuilder(IndexColumns.LOCALE);
- sb.append(" = ");
- DatabaseUtils.appendEscapedSQLString(sb, locale);
- try {
- // We care only for 1 row
- cursor = database.query(Tables.TABLE_PREFS_INDEX, null,
- sb.toString(), null, null, null, null, "1");
- final int count = cursor.getCount();
- result = (count >= 1);
- } finally {
- if (cursor != null) {
- cursor.close();
- }
- }
- return result;
+ return mContext.getSharedPreferences(INDEX, 0).getBoolean(locale, false);
}
}
diff --git a/src/com/android/settings/tts/TextToSpeechSettings.java b/src/com/android/settings/tts/TextToSpeechSettings.java
index c8f7b88..8c34518 100644
--- a/src/com/android/settings/tts/TextToSpeechSettings.java
+++ b/src/com/android/settings/tts/TextToSpeechSettings.java
@@ -71,6 +71,9 @@
/** Preference key for the TTS reset speech rate preference. */
private static final String KEY_RESET_SPEECH_RATE = "reset_speech_rate";
+ /** Preference key for the TTS reset speech pitch preference. */
+ private static final String KEY_RESET_SPEECH_PITCH = "reset_speech_pitch";
+
/** Preference key for the TTS status field. */
private static final String KEY_STATUS = "tts_status";
@@ -87,25 +90,28 @@
private static final int VOICE_DATA_INTEGRITY_CHECK = 1977;
/**
- * Maximum speech rate value.
+ * Speech rate value.
* This value should be kept in sync with the max value set in tts_settings xml.
*/
private static final int MAX_SPEECH_RATE = 600;
+ private static final int MIN_SPEECH_RATE = 10;
/**
- * Maximum speech pitch value. Pitch value varies from 50 to 500, where 100
- * is the value for normal pitch. The max pitch value is set to 500, based on
- * feedback from a few accessibility users. The range for pitch is not set in stone,
+ * Speech pitch value.
+ * TTS pitch value varies from 25 to 400, where 100 is the value
+ * for normal pitch. The max pitch value is set to 400, based on feedback from users
+ * and the GoogleTTS pitch variation range. The range for pitch is not set in stone
* and should be readjusted based on user need.
- *
* This value should be kept in sync with the max value set in tts_settings xml.
*/
- private static final int MAX_SPEECH_PITCH = 500;
+ private static final int MAX_SPEECH_PITCH = 400;
+ private static final int MIN_SPEECH_PITCH = 25;
private PreferenceCategory mEnginePreferenceCategory;
private SeekBarPreference mDefaultPitchPref;
private SeekBarPreference mDefaultRatePref;
private Preference mResetSpeechRate;
+ private Preference mResetSpeechPitch;
private Preference mPlayExample;
private Preference mEngineStatus;
@@ -188,6 +194,8 @@
mResetSpeechRate = findPreference(KEY_RESET_SPEECH_RATE);
mResetSpeechRate.setOnPreferenceClickListener(this);
+ mResetSpeechPitch = findPreference(KEY_RESET_SPEECH_PITCH);
+ mResetSpeechPitch.setOnPreferenceClickListener(this);
mEnginePreferenceCategory = (PreferenceCategory) findPreference(
KEY_ENGINE_PREFERENCE_SECTION);
@@ -251,24 +259,27 @@
private void initSettings() {
final ContentResolver resolver = getContentResolver();
- // Set up the default rate and pitch.
- try {
- mDefaultPitch = android.provider.Settings.Secure.getInt(resolver, TTS_DEFAULT_PITCH);
- mDefaultRate = android.provider.Settings.Secure.getInt(resolver, TTS_DEFAULT_RATE);
- } catch (SettingNotFoundException e) {
- // Default rate and pitch setting not found, initialize it.
- mDefaultPitch = TextToSpeech.Engine.DEFAULT_PITCH;
- mDefaultRate = TextToSpeech.Engine.DEFAULT_RATE;
- }
- mDefaultRatePref.setProgress(mDefaultRate);
+ // Set up the default rate and pitch.
+ mDefaultRate = android.provider.Settings.Secure.getInt(
+ resolver, TTS_DEFAULT_RATE, TextToSpeech.Engine.DEFAULT_RATE);
+ mDefaultPitch = android.provider.Settings.Secure.getInt(
+ resolver, TTS_DEFAULT_PITCH, TextToSpeech.Engine.DEFAULT_PITCH);
+
+ mDefaultRatePref.setProgress(getSeekBarProgressFromValue(KEY_DEFAULT_RATE, mDefaultRate));
mDefaultRatePref.setOnPreferenceChangeListener(this);
- mDefaultRatePref.setMax(MAX_SPEECH_RATE);
+ mDefaultRatePref.setMax(getSeekBarProgressFromValue(KEY_DEFAULT_RATE, MAX_SPEECH_RATE));
- mDefaultPitchPref.setProgress(mDefaultPitch);
+ mDefaultPitchPref.setProgress(getSeekBarProgressFromValue(KEY_DEFAULT_PITCH,
+ mDefaultPitch));
mDefaultPitchPref.setOnPreferenceChangeListener(this);
- mDefaultPitchPref.setMax(MAX_SPEECH_PITCH);
+ mDefaultPitchPref.setMax(getSeekBarProgressFromValue(KEY_DEFAULT_PITCH,
+ MAX_SPEECH_PITCH));
- mCurrentEngine = mTts.getCurrentEngine();
+ if (mTts != null) {
+ mCurrentEngine = mTts.getCurrentEngine();
+ mTts.setSpeechRate(mDefaultRate/100.0f);
+ mTts.setPitch(mDefaultPitch/100.0f);
+ }
SettingsActivity activity = null;
if (getActivity() instanceof SettingsActivity) {
@@ -291,6 +302,34 @@
}
/**
+ * The minimum speech pitch/rate value should be > 0 but the minimum value of a seekbar in
+ * android is fixed at 0. Therefore, we increment the seekbar progress with MIN_SPEECH_VALUE
+ * so that the minimum seekbar progress value is MIN_SPEECH_PITCH/RATE.
+ * SPEECH_VALUE = MIN_SPEECH_VALUE + SEEKBAR_PROGRESS
+ */
+ private int getValueFromSeekBarProgress(String preferenceKey, int progress) {
+ if (preferenceKey.equals(KEY_DEFAULT_RATE)) {
+ return MIN_SPEECH_RATE + progress;
+ } else if (preferenceKey.equals(KEY_DEFAULT_PITCH)) {
+ return MIN_SPEECH_PITCH + progress;
+ }
+ return progress;
+ }
+
+ /**
+ * Since we are appending the MIN_SPEECH value to the speech seekbar progress, the
+ * speech seekbar progress should be set to (speechValue - MIN_SPEECH value).
+ */
+ private int getSeekBarProgressFromValue(String preferenceKey, int value) {
+ if (preferenceKey.equals(KEY_DEFAULT_RATE)) {
+ return value - MIN_SPEECH_RATE;
+ } else if (preferenceKey.equals(KEY_DEFAULT_PITCH)) {
+ return value - MIN_SPEECH_PITCH;
+ }
+ return value;
+ }
+
+ /**
* Called when the TTS engine is initialized.
*/
public void onInitEngine(int status) {
@@ -484,25 +523,16 @@
@Override
public boolean onPreferenceChange(Preference preference, Object objValue) {
if (KEY_DEFAULT_RATE.equals(preference.getKey())) {
- updateSpeechRate(((Integer) objValue).intValue());
+ updateSpeechRate((Integer) objValue);
} else if (KEY_DEFAULT_PITCH.equals(preference.getKey())) {
- mDefaultPitch = ((Integer) objValue).intValue();
- try {
- android.provider.Settings.Secure.putInt(getContentResolver(),
- TTS_DEFAULT_PITCH, mDefaultPitch);
- if (mTts != null) {
- mTts.setPitch(mDefaultPitch / 100.0f);
- }
- if (DBG) Log.d(TAG, "TTS default pitch changed, now" + mDefaultPitch);
- } catch (NumberFormatException e) {
- Log.e(TAG, "could not persist default TTS pitch setting", e);
- }
+ updateSpeechPitchValue((Integer) objValue);
}
return true;
}
/**
- * Called when mPlayExample or mResetSpeechRate is clicked.
+ * Called when mPlayExample, mResetSpeechRate or mResetSpeechPitch is
+ * clicked.
*/
@Override
public boolean onPreferenceClick(Preference preference) {
@@ -512,15 +542,24 @@
speakSampleText();
return true;
} else if (preference == mResetSpeechRate) {
- mDefaultRatePref.setProgress(TextToSpeech.Engine.DEFAULT_RATE);
- updateSpeechRate(TextToSpeech.Engine.DEFAULT_RATE);
+ int speechRateSeekbarProgress = getSeekBarProgressFromValue(
+ KEY_DEFAULT_RATE, TextToSpeech.Engine.DEFAULT_RATE);
+ mDefaultRatePref.setProgress(speechRateSeekbarProgress);
+ updateSpeechRate(speechRateSeekbarProgress);
+ return true;
+ } else if (preference == mResetSpeechPitch) {
+ int pitchSeekbarProgress = getSeekBarProgressFromValue(
+ KEY_DEFAULT_PITCH, TextToSpeech.Engine.DEFAULT_PITCH);
+ mDefaultPitchPref.setProgress(pitchSeekbarProgress);
+ updateSpeechPitchValue(pitchSeekbarProgress);
return true;
}
return false;
}
- private void updateSpeechRate(int speechRate) {
- mDefaultRate = speechRate;
+ private void updateSpeechRate(int speechRateSeekBarProgress) {
+ mDefaultRate = getValueFromSeekBarProgress(KEY_DEFAULT_RATE,
+ speechRateSeekBarProgress);
try {
android.provider.Settings.Secure.putInt(getContentResolver(),
TTS_DEFAULT_RATE, mDefaultRate);
@@ -534,6 +573,22 @@
return;
}
+ private void updateSpeechPitchValue(int speechPitchSeekBarProgress) {
+ mDefaultPitch = getValueFromSeekBarProgress(KEY_DEFAULT_PITCH,
+ speechPitchSeekBarProgress);
+ try {
+ android.provider.Settings.Secure.putInt(getContentResolver(),
+ TTS_DEFAULT_PITCH, mDefaultPitch);
+ if (mTts != null) {
+ mTts.setPitch(mDefaultPitch / 100.0f);
+ }
+ if (DBG) Log.d(TAG, "TTS default pitch changed, now" + mDefaultPitch);
+ } catch (NumberFormatException e) {
+ Log.e(TAG, "could not persist default TTS pitch setting", e);
+ }
+ return;
+ }
+
private void updateWidgetState(boolean enable) {
mPlayExample.setEnabled(enable);
mDefaultRatePref.setEnabled(enable);
diff --git a/src/com/android/settings/users/EditUserPhotoController.java b/src/com/android/settings/users/EditUserPhotoController.java
index 97a9937..5229da0 100644
--- a/src/com/android/settings/users/EditUserPhotoController.java
+++ b/src/com/android/settings/users/EditUserPhotoController.java
@@ -32,6 +32,7 @@
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.AsyncTask;
+import android.os.UserHandle;
import android.os.UserManager;
import android.provider.ContactsContract.DisplayPhoto;
import android.provider.MediaStore;
@@ -40,13 +41,15 @@
import android.view.Gravity;
import android.view.View;
import android.view.View.OnClickListener;
+import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.ImageView;
-import android.widget.ListAdapter;
import android.widget.ListPopupWindow;
+import android.widget.TextView;
import com.android.settings.R;
+import com.android.settingslib.RestrictedLockUtils;
import com.android.settingslib.drawable.CircleFramedDrawable;
import java.io.File;
@@ -61,9 +64,6 @@
public class EditUserPhotoController {
private static final String TAG = "EditUserPhotoController";
- private static final int POPUP_LIST_ITEM_ID_CHOOSE_PHOTO = 1;
- private static final int POPUP_LIST_ITEM_ID_TAKE_PHOTO = 2;
-
// It seems that this class generates custom request codes and they may
// collide with ours, these values are very unlikely to have a conflict.
private static final int REQUEST_CODE_CHOOSE_PHOTO = 1001;
@@ -100,10 +100,6 @@
showUpdatePhotoPopup();
}
});
- final UserManager um = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
- if (um.hasUserRestriction(UserManager.DISALLOW_SET_USER_ICON)) {
- mImageView.setEnabled(false);
- }
mNewUserPhotoBitmap = bitmap;
mNewUserPhotoDrawable = drawable;
}
@@ -142,19 +138,31 @@
return;
}
- Context context = mImageView.getContext();
- final List<EditUserPhotoController.AdapterItem> items = new ArrayList<EditUserPhotoController.AdapterItem>();
+ final Context context = mImageView.getContext();
+ final List<EditUserPhotoController.RestrictedMenuItem> items = new ArrayList<>();
- if (canTakePhoto()) {
- String title = mImageView.getContext().getString( R.string.user_image_take_photo);
- EditUserPhotoController.AdapterItem item = new AdapterItem(title, POPUP_LIST_ITEM_ID_TAKE_PHOTO);
- items.add(item);
+ if (canTakePhoto) {
+ final String title = context.getString(R.string.user_image_take_photo);
+ final Runnable action = new Runnable() {
+ @Override
+ public void run() {
+ takePhoto();
+ }
+ };
+ items.add(new RestrictedMenuItem(context, title, UserManager.DISALLOW_SET_USER_ICON,
+ action));
}
if (canChoosePhoto) {
- String title = context.getString(R.string.user_image_choose_photo);
- EditUserPhotoController.AdapterItem item = new AdapterItem(title, POPUP_LIST_ITEM_ID_CHOOSE_PHOTO);
- items.add(item);
+ final String title = context.getString(R.string.user_image_choose_photo);
+ final Runnable action = new Runnable() {
+ @Override
+ public void run() {
+ choosePhoto();
+ }
+ };
+ items.add(new RestrictedMenuItem(context, title, UserManager.DISALLOW_SET_USER_ICON,
+ action));
}
final ListPopupWindow listPopupWindow = new ListPopupWindow(context);
@@ -162,10 +170,7 @@
listPopupWindow.setAnchorView(mImageView);
listPopupWindow.setModal(true);
listPopupWindow.setInputMethodMode(ListPopupWindow.INPUT_METHOD_NOT_NEEDED);
-
- ListAdapter adapter = new ArrayAdapter<EditUserPhotoController.AdapterItem>(context,
- R.layout.edit_user_photo_popup_item, items);
- listPopupWindow.setAdapter(adapter);
+ listPopupWindow.setAdapter(new RestrictedPopupMenuAdapter(context, items));
final int width = Math.max(mImageView.getWidth(), context.getResources()
.getDimensionPixelSize(R.dimen.update_user_photo_popup_min_width));
@@ -175,17 +180,10 @@
listPopupWindow.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
- EditUserPhotoController.AdapterItem item = items.get(position);
- switch (item.id) {
- case POPUP_LIST_ITEM_ID_CHOOSE_PHOTO: {
- choosePhoto();
- listPopupWindow.dismiss();
- } break;
- case POPUP_LIST_ITEM_ID_TAKE_PHOTO: {
- takePhoto();
- listPopupWindow.dismiss();
- } break;
- }
+ listPopupWindow.dismiss();
+ final RestrictedMenuItem item =
+ (RestrictedMenuItem) parent.getAdapter().getItem(position);
+ item.doAction();
}
});
@@ -363,18 +361,82 @@
new File(mContext.getCacheDir(), NEW_USER_PHOTO_FILE_NAME).delete();
}
- private static final class AdapterItem {
- final String title;
- final int id;
+ private static final class RestrictedMenuItem {
+ private final Context mContext;
+ private final String mTitle;
+ private final Runnable mAction;
+ private final RestrictedLockUtils.EnforcedAdmin mAdmin;
+ // Restriction may be set by system or something else via UserManager.setUserRestriction().
+ private final boolean mIsRestrictedByBase;
- public AdapterItem(String title, int id) {
- this.title = title;
- this.id = id;
+ /**
+ * The menu item, used for popup menu. Any element of such a menu can be disabled by admin.
+ * @param context A context.
+ * @param title The title of the menu item.
+ * @param restriction The restriction, that if is set, blocks the menu item.
+ * @param action The action on menu item click.
+ */
+ public RestrictedMenuItem(Context context, String title, String restriction,
+ Runnable action) {
+ mContext = context;
+ mTitle = title;
+ mAction = action;
+
+ final int myUserId = UserHandle.myUserId();
+ mAdmin = RestrictedLockUtils.checkIfRestrictionEnforced(context,
+ restriction, myUserId);
+ mIsRestrictedByBase = RestrictedLockUtils.hasBaseUserRestriction(mContext,
+ restriction, myUserId);
}
@Override
public String toString() {
- return title;
+ return mTitle;
+ }
+
+ final void doAction() {
+ if (isRestrictedByBase()) {
+ return;
+ }
+
+ if (isRestrictedByAdmin()) {
+ RestrictedLockUtils.sendShowAdminSupportDetailsIntent(mContext, mAdmin);
+ return;
+ }
+
+ mAction.run();
+ }
+
+ final boolean isRestrictedByAdmin() {
+ return mAdmin != null;
+ }
+
+ final boolean isRestrictedByBase() {
+ return mIsRestrictedByBase;
+ }
+ }
+
+ /**
+ * Provide this adapter to ListPopupWindow.setAdapter() to have a popup window menu, where
+ * any element can be restricted by admin (profile owner or device owner).
+ */
+ private static final class RestrictedPopupMenuAdapter extends ArrayAdapter<RestrictedMenuItem> {
+ public RestrictedPopupMenuAdapter(Context context, List<RestrictedMenuItem> items) {
+ super(context, R.layout.restricted_popup_menu_item, R.id.text, items);
+ }
+
+ @Override
+ public View getView(int position, View convertView, ViewGroup parent) {
+ final View view = super.getView(position, convertView, parent);
+ final RestrictedMenuItem item = getItem(position);
+ final TextView text = (TextView) view.findViewById(R.id.text);
+ final ImageView image = (ImageView) view.findViewById(R.id.restricted_icon);
+
+ text.setEnabled(!item.isRestrictedByAdmin() && !item.isRestrictedByBase());
+ image.setVisibility(item.isRestrictedByAdmin() && !item.isRestrictedByBase() ?
+ ImageView.VISIBLE : ImageView.GONE);
+
+ return view;
}
}
}
diff --git a/src/com/android/settings/users/UserSettings.java b/src/com/android/settings/users/UserSettings.java
index eb74c4b..bf93cd3 100644
--- a/src/com/android/settings/users/UserSettings.java
+++ b/src/com/android/settings/users/UserSettings.java
@@ -331,7 +331,8 @@
protected String doInBackground(Void... values) {
UserInfo user = mUserManager.getUserInfo(UserHandle.myUserId());
if (user.iconPath == null || user.iconPath.equals("")) {
- assignProfilePhoto(user);
+ // Assign profile photo.
+ Utils.copyMeProfilePhoto(getActivity(), user);
}
return user.name;
}
@@ -404,14 +405,14 @@
private UserInfo createRestrictedProfile() {
UserInfo newUserInfo = mUserManager.createRestrictedProfile(mAddingUserName);
- assignDefaultPhoto(newUserInfo);
+ Utils.assignDefaultPhoto(getActivity(), newUserInfo.id);
return newUserInfo;
}
private UserInfo createTrustedUser() {
UserInfo newUserInfo = mUserManager.createUser(mAddingUserName, 0);
if (newUserInfo != null) {
- assignDefaultPhoto(newUserInfo);
+ Utils.assignDefaultPhoto(getActivity(), newUserInfo.id);
}
return newUserInfo;
}
@@ -898,17 +899,6 @@
}.execute(missingIcons);
}
- private void assignProfilePhoto(final UserInfo user) {
- if (!Utils.copyMeProfilePhoto(getActivity(), user)) {
- assignDefaultPhoto(user);
- }
- }
-
- private void assignDefaultPhoto(UserInfo user) {
- Bitmap bitmap = Utils.getDefaultUserIconAsBitmap(user.id);
- mUserManager.setUserIcon(user.id, bitmap);
- }
-
private Drawable getEncircledDefaultIcon() {
if (mDefaultIconDrawable == null) {
mDefaultIconDrawable = encircle(Utils.getDefaultUserIconAsBitmap(UserHandle.USER_NULL));
diff --git a/src/com/android/settings/utils/ManagedServiceSettings.java b/src/com/android/settings/utils/ManagedServiceSettings.java
index e198955..da4798e 100644
--- a/src/com/android/settings/utils/ManagedServiceSettings.java
+++ b/src/com/android/settings/utils/ManagedServiceSettings.java
@@ -42,9 +42,9 @@
public abstract class ManagedServiceSettings extends EmptyTextSettings {
private final Config mConfig;
- private Context mContext;
+ protected Context mContext;
private PackageManager mPM;
- private ServiceListing mServiceListing;
+ protected ServiceListing mServiceListing;
private TextView mEmpty;
abstract protected Config getConfig();
@@ -111,7 +111,7 @@
}
}
- private boolean setEnabled(ComponentName service, String title, boolean enable) {
+ protected boolean setEnabled(ComponentName service, String title, boolean enable) {
if (!enable) {
// the simple version: disabling
mServiceListing.setEnabled(service, false);
@@ -173,6 +173,7 @@
public static class Config {
public String tag;
public String setting;
+ public String secondarySetting;
public String intentAction;
public String permission;
public String noun;
diff --git a/src/com/android/settings/utils/ServiceListing.java b/src/com/android/settings/utils/ServiceListing.java
index dfca5a3..6a5fa10 100644
--- a/src/com/android/settings/utils/ServiceListing.java
+++ b/src/com/android/settings/utils/ServiceListing.java
@@ -30,6 +30,7 @@
import android.net.Uri;
import android.os.Handler;
import android.provider.Settings;
+import android.text.TextUtils;
import android.util.Slog;
import com.android.settings.utils.ManagedServiceSettings.Config;
@@ -46,7 +47,6 @@
private final HashSet<ComponentName> mEnabledServices = new HashSet<ComponentName>();
private final List<ServiceInfo> mServices = new ArrayList<ServiceInfo>();
private final List<Callback> mCallbacks = new ArrayList<Callback>();
- private final List<ServiceInfo> mApprovedServices = new ArrayList<ServiceInfo>();
private boolean mListening;
@@ -95,18 +95,7 @@
return getServices(c, null, pm);
}
- public ServiceInfo findService(Context context, Config config, final ComponentName cn) {
- final ServiceListing listing = new ServiceListing(context, config);
- for (ServiceInfo service : mApprovedServices) {
- final ComponentName serviceCN = new ComponentName(service.packageName, service.name);
- if (serviceCN.equals(cn)) {
- return service;
- }
- }
- return null;
- }
-
- private static int getServices(Config c, List<ServiceInfo> list, PackageManager pm) {
+ protected static int getServices(Config c, List<ServiceInfo> list, PackageManager pm) {
int services = 0;
if (list != null) {
list.clear();
@@ -174,26 +163,6 @@
return mServices;
}
- public void reloadApprovedServices() {
- mApprovedServices.clear();
- final String flat = Settings.Secure.getString(mContentResolver, mConfig.setting);
- if (flat != null && !"".equals(flat)) {
- final List<String> names = Arrays.asList(flat.split(":"));
- List<ServiceInfo> services = new ArrayList<>();
- getServices(mConfig, services, mContext.getPackageManager());
- for (ServiceInfo service : services) {
- final ComponentName componentName = service.getComponentName();
- String flatCn = service.getComponentName().flattenToString();
- if (names.contains(flatCn) || names.contains(componentName.getPackageName())) {
- mApprovedServices.add(service);
- }
- }
- for (Callback callback : mCallbacks) {
- callback.onServicesReloaded(mApprovedServices);
- }
- }
- }
-
public boolean isEnabled(ComponentName cn) {
return mEnabledServices.contains(cn);
}
diff --git a/src/com/android/settings/utils/ZenServiceListing.java b/src/com/android/settings/utils/ZenServiceListing.java
new file mode 100644
index 0000000..167b066
--- /dev/null
+++ b/src/com/android/settings/utils/ZenServiceListing.java
@@ -0,0 +1,148 @@
+/*
+ * Copyright (C) 2016 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.utils;
+
+import android.app.ActivityManager;
+import android.content.ComponentName;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.content.pm.ServiceInfo;
+import android.provider.Settings;
+import android.text.TextUtils;
+import android.util.ArraySet;
+import android.util.Slog;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Set;
+
+public class ZenServiceListing {
+
+ private final ContentResolver mContentResolver;
+ private final Context mContext;
+ private final ManagedServiceSettings.Config mConfig;
+ private final Set<ServiceInfo> mApprovedServices = new ArraySet<ServiceInfo>();
+ private final List<Callback> mZenCallbacks = new ArrayList<>();
+
+ public ZenServiceListing(Context context, ManagedServiceSettings.Config config) {
+ mContext = context;
+ mConfig = config;
+ mContentResolver = context.getContentResolver();
+ }
+
+ public ServiceInfo findService(final ComponentName cn) {
+ for (ServiceInfo service : mApprovedServices) {
+ final ComponentName serviceCN = new ComponentName(service.packageName, service.name);
+ if (serviceCN.equals(cn)) {
+ return service;
+ }
+ }
+ return null;
+ }
+
+ public void addZenCallback(Callback callback) {
+ mZenCallbacks.add(callback);
+ }
+
+ public void removeZenCallback(Callback callback) {
+ mZenCallbacks.remove(callback);
+ }
+
+ public void reloadApprovedServices() {
+ mApprovedServices.clear();
+ String[] settings = {mConfig.setting, mConfig.secondarySetting};
+
+ for (String setting : settings) {
+ if (!TextUtils.isEmpty(setting)) {
+ final String flat = Settings.Secure.getString(mContentResolver, setting);
+ if (!TextUtils.isEmpty(flat)) {
+ final List<String> names = Arrays.asList(flat.split(":"));
+ List<ServiceInfo> services = new ArrayList<>();
+ getServices(mConfig, services, mContext.getPackageManager());
+ for (ServiceInfo service : services) {
+ if (matchesApprovedPackage(names, service.getComponentName())) {
+ mApprovedServices.add(service);
+ }
+ }
+ }
+ }
+ }
+ if (!mApprovedServices.isEmpty()) {
+ for (Callback callback : mZenCallbacks) {
+ callback.onServicesReloaded(mApprovedServices);
+ }
+ }
+ }
+
+ // Setting could contain: the component name of the condition provider, the package name of
+ // the condition provider, the component name of the notification listener.
+ private boolean matchesApprovedPackage(List<String> approved, ComponentName serviceOwner) {
+ String flatCn = serviceOwner.flattenToString();
+ if (approved.contains(flatCn) || approved.contains(serviceOwner.getPackageName())) {
+ return true;
+ }
+ for (String entry : approved) {
+ if (!TextUtils.isEmpty(entry)) {
+ ComponentName approvedComponent = ComponentName.unflattenFromString(entry);
+ if (approvedComponent != null && approvedComponent.getPackageName().equals(
+ serviceOwner.getPackageName())) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ private static int getServices(ManagedServiceSettings.Config c, List<ServiceInfo> list,
+ PackageManager pm) {
+ int services = 0;
+ if (list != null) {
+ list.clear();
+ }
+ final int user = ActivityManager.getCurrentUser();
+
+ List<ResolveInfo> installedServices = pm.queryIntentServicesAsUser(
+ new Intent(c.intentAction),
+ PackageManager.GET_SERVICES | PackageManager.GET_META_DATA,
+ user);
+
+ for (int i = 0, count = installedServices.size(); i < count; i++) {
+ ResolveInfo resolveInfo = installedServices.get(i);
+ ServiceInfo info = resolveInfo.serviceInfo;
+
+ if (!c.permission.equals(info.permission)) {
+ Slog.w(c.tag, "Skipping " + c.noun + " service "
+ + info.packageName + "/" + info.name
+ + ": it does not require the permission "
+ + c.permission);
+ continue;
+ }
+ if (list != null) {
+ list.add(info);
+ }
+ services++;
+ }
+ return services;
+ }
+
+ public interface Callback {
+ void onServicesReloaded(Set<ServiceInfo> services);
+ }
+}
diff --git a/src/com/android/settings/vpn2/AppDialogFragment.java b/src/com/android/settings/vpn2/AppDialogFragment.java
index e70b412..004ad80 100644
--- a/src/com/android/settings/vpn2/AppDialogFragment.java
+++ b/src/com/android/settings/vpn2/AppDialogFragment.java
@@ -137,11 +137,8 @@
private void onDisconnect(final DialogInterface dialog) {
final int userId = UserHandle.getUserId(mPackageInfo.applicationInfo.uid);
try {
- final VpnConfig vpnConfig = mService.getVpnConfig(userId);
- if (vpnConfig == null || vpnConfig.legacy) {
- return;
- }
- if (mPackageInfo.packageName.equals(vpnConfig.user)) {
+ if (mPackageInfo.packageName.equals(getConnectedPackage(mService, userId))) {
+ mService.setAlwaysOnVpnPackage(userId, null);
mService.prepareVpn(mPackageInfo.packageName, VpnConfig.LEGACY_VPN, userId);
}
} catch (RemoteException e) {
@@ -149,4 +146,10 @@
" for user " + userId, e);
}
}
+
+ private static String getConnectedPackage(IConnectivityManager service, final int userId)
+ throws RemoteException {
+ final VpnConfig config = service.getVpnConfig(userId);
+ return config != null ? config.user : null;
+ }
}
diff --git a/src/com/android/settings/vpn2/ConfigDialog.java b/src/com/android/settings/vpn2/ConfigDialog.java
index a13e29d..92050e9 100644
--- a/src/com/android/settings/vpn2/ConfigDialog.java
+++ b/src/com/android/settings/vpn2/ConfigDialog.java
@@ -170,6 +170,9 @@
// Show type-specific fields.
changeType(mProfile.type);
+ // Hide 'save login' when we are editing.
+ mSaveLogin.setVisibility(View.GONE);
+
// Switch to advanced view immediately if any advanced options are on
if (!mProfile.searchDomains.isEmpty() || !mProfile.dnsServers.isEmpty() ||
!mProfile.routes.isEmpty()) {
@@ -188,9 +191,6 @@
} else {
setTitle(context.getString(R.string.vpn_connect_to, mProfile.name));
- // Not editing, just show username and password.
- mView.findViewById(R.id.login).setVisibility(View.VISIBLE);
-
// Create a button to connect the network.
setButton(DialogInterface.BUTTON_POSITIVE,
context.getString(R.string.vpn_connect), mListener);
@@ -259,6 +259,7 @@
public void onCheckedChanged(CompoundButton compoundButton, boolean b) {
if (compoundButton == mAlwaysOnVpn) {
updateSaveLoginStatus();
+ getButton(DialogInterface.BUTTON_POSITIVE).setEnabled(validate(mEditing));
}
}
@@ -318,6 +319,9 @@
if (!editing) {
return mUsername.getText().length() != 0 && mPassword.getText().length() != 0;
}
+ if (mAlwaysOnVpn.isChecked() && !getProfile().isValidLockdownProfile()) {
+ return false;
+ }
if (mName.getText().length() == 0 || mServer.getText().length() == 0 ||
!validateAddresses(mDnsServers.getText().toString(), false) ||
!validateAddresses(mRoutes.getText().toString(), true)) {
@@ -441,7 +445,8 @@
break;
}
- profile.saveLogin = mSaveLogin.isChecked();
+ final boolean hasLogin = !profile.username.isEmpty() || !profile.password.isEmpty();
+ profile.saveLogin = mSaveLogin.isChecked() || (mEditing && hasLogin);
return profile;
}
}
diff --git a/src/com/android/settings/vpn2/ConfigDialogFragment.java b/src/com/android/settings/vpn2/ConfigDialogFragment.java
index fc49fd8..5e4a7d9 100644
--- a/src/com/android/settings/vpn2/ConfigDialogFragment.java
+++ b/src/com/android/settings/vpn2/ConfigDialogFragment.java
@@ -152,12 +152,9 @@
return;
}
- // Update only if lockdown vpn has been changed
- if (!VpnUtils.isVpnLockdown(profile.key)) {
- final ConnectivityManager conn = ConnectivityManager.from(getActivity());
- conn.setAlwaysOnVpnPackageForUser(UserHandle.myUserId(), null);
- VpnUtils.setLockdownVpn(getContext(), profile.key);
- }
+ final ConnectivityManager conn = ConnectivityManager.from(getActivity());
+ conn.setAlwaysOnVpnPackageForUser(UserHandle.myUserId(), null);
+ VpnUtils.setLockdownVpn(getContext(), profile.key);
} else {
// update only if lockdown vpn has been changed
if (VpnUtils.isVpnLockdown(profile.key)) {
diff --git a/src/com/android/settings/vpn2/VpnSettings.java b/src/com/android/settings/vpn2/VpnSettings.java
index f605896..6c47b43 100644
--- a/src/com/android/settings/vpn2/VpnSettings.java
+++ b/src/com/android/settings/vpn2/VpnSettings.java
@@ -299,11 +299,6 @@
return true;
} else if (preference instanceof AppPreference) {
AppPreference pref = (AppPreference) preference;
- if (pref.isAlwaysOn()) {
- // User can't disconnect vpn when always-on is enabled
- return true;
- }
-
boolean connected = (pref.getState() == AppPreference.STATE_CONNECTED);
if (!connected) {
diff --git a/src/com/android/settings/widget/LabeledSeekBar.java b/src/com/android/settings/widget/LabeledSeekBar.java
index bf6983e..f1a6788 100644
--- a/src/com/android/settings/widget/LabeledSeekBar.java
+++ b/src/com/android/settings/widget/LabeledSeekBar.java
@@ -17,6 +17,7 @@
package com.android.settings.widget;
import android.content.Context;
+import android.content.res.Configuration;
import android.graphics.Rect;
import android.os.Bundle;
import android.support.v4.view.ViewCompat;
@@ -24,6 +25,7 @@
import android.support.v4.widget.ExploreByTouchHelper;
import android.util.AttributeSet;
import android.view.MotionEvent;
+import android.view.View;
import android.view.accessibility.AccessibilityEvent;
import android.widget.RadioButton;
import android.widget.RadioGroup;
@@ -121,8 +123,12 @@
private class LabeledSeekBarExploreByTouchHelper extends ExploreByTouchHelper {
+ private boolean mIsLayoutRtl;
+
public LabeledSeekBarExploreByTouchHelper(LabeledSeekBar forView) {
super(forView);
+ mIsLayoutRtl = forView.getResources().getConfiguration()
+ .getLayoutDirection() == View.LAYOUT_DIRECTION_RTL;
}
@Override
@@ -192,20 +198,23 @@
}
private int getVirtualViewIdIndexFromX(float x) {
- final int posBase = Math.max(0,
+ int posBase = Math.max(0,
((int) x - LabeledSeekBar.this.getPaddingStart()) / getHalfVirtualViewWidth());
- return (posBase + 1) / 2;
+ posBase = (posBase + 1) / 2;
+ return mIsLayoutRtl ? LabeledSeekBar.this.getMax() - posBase : posBase;
}
private Rect getBoundsInParentFromVirtualViewId(int virtualViewId) {
- int left = (virtualViewId * 2 - 1) * getHalfVirtualViewWidth()
+ final int updatedVirtualViewId = mIsLayoutRtl
+ ? LabeledSeekBar.this.getMax() - virtualViewId : virtualViewId;
+ int left = (updatedVirtualViewId * 2 - 1) * getHalfVirtualViewWidth()
+ LabeledSeekBar.this.getPaddingStart();
- int right = (virtualViewId * 2 + 1) * getHalfVirtualViewWidth()
+ int right = (updatedVirtualViewId * 2 + 1) * getHalfVirtualViewWidth()
+ LabeledSeekBar.this.getPaddingStart();
// Edge case
- left = virtualViewId == 0 ? 0 : left;
- right = virtualViewId == LabeledSeekBar.this.getMax()
+ left = updatedVirtualViewId == 0 ? 0 : left;
+ right = updatedVirtualViewId == LabeledSeekBar.this.getMax()
? LabeledSeekBar.this.getWidth() : right;
final Rect r = new Rect();
diff --git a/src/com/android/settings/wifi/WifiEnabler.java b/src/com/android/settings/wifi/WifiEnabler.java
index 2ff404d..f064050 100644
--- a/src/com/android/settings/wifi/WifiEnabler.java
+++ b/src/com/android/settings/wifi/WifiEnabler.java
@@ -26,6 +26,8 @@
import android.net.wifi.WifiManager;
import android.os.Handler;
import android.os.Message;
+import android.os.UserHandle;
+import android.os.UserManager;
import android.provider.Settings;
import android.widget.Switch;
import android.widget.Toast;
@@ -35,6 +37,8 @@
import com.android.settings.R;
import com.android.settings.search.Index;
import com.android.settings.widget.SwitchBar;
+import com.android.settingslib.RestrictedLockUtils;
+import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
import com.android.settingslib.WirelessUtils;
import java.util.concurrent.atomic.AtomicBoolean;
@@ -136,6 +140,9 @@
}
private void handleWifiStateChanged(int state) {
+ // Clear any previous state
+ mSwitchBar.setDisabledByAdmin(null);
+
switch (state) {
case WifiManager.WIFI_STATE_ENABLING:
mSwitchBar.setEnabled(false);
@@ -158,6 +165,16 @@
mSwitchBar.setEnabled(true);
updateSearchIndex(false);
}
+ if (mayDisableTethering(!mSwitchBar.isChecked())) {
+ if (RestrictedLockUtils.hasBaseUserRestriction(mContext,
+ UserManager.DISALLOW_CONFIG_TETHERING, UserHandle.myUserId())) {
+ mSwitchBar.setEnabled(false);
+ } else {
+ final EnforcedAdmin admin = RestrictedLockUtils.checkIfRestrictionEnforced(mContext,
+ UserManager.DISALLOW_CONFIG_TETHERING, UserHandle.myUserId());
+ mSwitchBar.setDisabledByAdmin(admin);
+ }
+ }
}
private void updateSearchIndex(boolean isWiFiOn) {
@@ -206,9 +223,7 @@
}
// Disable tethering if enabling Wifi
- int wifiApState = mWifiManager.getWifiApState();
- if (isChecked && ((wifiApState == WifiManager.WIFI_AP_STATE_ENABLING) ||
- (wifiApState == WifiManager.WIFI_AP_STATE_ENABLED))) {
+ if (mayDisableTethering(isChecked)) {
mWifiManager.setWifiApEnabled(null, false);
}
MetricsLogger.action(mContext,
@@ -219,4 +234,10 @@
Toast.makeText(mContext, R.string.wifi_error, Toast.LENGTH_SHORT).show();
}
}
+
+ private boolean mayDisableTethering(boolean isChecked) {
+ final int wifiApState = mWifiManager.getWifiApState();
+ return isChecked && ((wifiApState == WifiManager.WIFI_AP_STATE_ENABLING) ||
+ (wifiApState == WifiManager.WIFI_AP_STATE_ENABLED));
+ }
}