Merge "Changed "Take Bug Report" action to call 'bugreportplus'."
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 37edca7..43fe796 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -1161,6 +1161,18 @@
</activity>
-->
+ <activity android:name="Settings$BackgroundCheckSummaryActivity"
+ android:label="@string/background_check_title"
+ android:taskAffinity=""
+ android:enabled="false">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.DEFAULT" />
+ </intent-filter>
+ <meta-data android:name="com.android.settings.FRAGMENT_CLASS"
+ android:value="com.android.settings.applications.BackgroundCheckSummary" />
+ </activity>
+
<activity android:name="Settings$LocationSettingsActivity"
android:label="@string/location_settings_title"
android:icon="@drawable/ic_settings_location"
diff --git a/res/drawable/ic_add_24dp.xml b/res/drawable/ic_add_24dp.xml
index 6535107..97178b2 100644
--- a/res/drawable/ic_add_24dp.xml
+++ b/res/drawable/ic_add_24dp.xml
@@ -14,11 +14,12 @@
~ limitations under the License
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="24.0dp"
- android:height="24.0dp"
- android:viewportWidth="48.0"
- android:viewportHeight="48.0">
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="48"
+ android:viewportHeight="48"
+ android:tint="?android:attr/colorAccent">
<path
- android:fillColor="?android:attr/colorAccent"
- android:pathData="M38.0,26.0L26.0,26.0l0.0,12.0l-4.0,0.0L22.0,26.0L10.0,26.0l0.0,-4.0l12.0,0.0L22.0,10.0l4.0,0.0l0.0,12.0l12.0,0.0l0.0,4.0z"/>
+ android:fillColor="@android:color/white"
+ android:pathData="M38,26L26,26l0,12l-4,0L22,26L10,26l0,-4l12,0L22,10l4,0l0,12l12,0l0,4.0z"/>
</vector>
diff --git a/res/drawable/ic_info.xml b/res/drawable/ic_info.xml
index 13d00a4..6e19d26 100644
--- a/res/drawable/ic_info.xml
+++ b/res/drawable/ic_info.xml
@@ -14,11 +14,11 @@
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="24.0dp"
- android:height="24.0dp"
- android:viewportWidth="24.0"
- android:viewportHeight="24.0">
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24">
<path
- android:fillColor="#FFFFFFFF"
- android:pathData="M11.0,17.0l2.0,0.0l0.0,-6.0l-2.0,0.0l0.0,6.0zm1.0,-15.0C6.48,2.0 2.0,6.48 2.0,12.0s4.48,10.0 10.0,10.0 10.0,-4.48 10.0,-10.0S17.52,2.0 12.0,2.0zm0.0,18.0c-4.41,0.0 -8.0,-3.59 -8.0,-8.0s3.59,-8.0 8.0,-8.0 8.0,3.59 8.0,8.0 -3.59,8.0 -8.0,8.0zM11.0,9.0l2.0,0.0L13.0,7.0l-2.0,0.0l0.0,2.0z"/>
+ android:fillColor="@android:color/white"
+ android:pathData="M11,17l2,0l0,-6l-2,0l0,6.0zm1,-15.0C6.48,2 2,6.48 2,12.0s4.48,10 10,10 10,-4.48 10,-10.0S17.52,2 12,2.0zm0,18.0c-4.41,0 -8,-3.59 -8,-8.0s3.59,-8 8,-8 8,3.59 8,8 -3.59,8 -8,8.0zM11,9l2,0L13,7l-2,0l0,2.0z"/>
</vector>
diff --git a/res/drawable/ic_remove_24dp.xml b/res/drawable/ic_remove_24dp.xml
new file mode 100644
index 0000000..9233623
--- /dev/null
+++ b/res/drawable/ic_remove_24dp.xml
@@ -0,0 +1,25 @@
+<!--
+ ~ Copyright (C) 2015 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License
+ -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="48"
+ android:viewportHeight="48"
+ android:tint="?android:attr/colorAccent">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M38 26H10v-4h28v4z"/>
+</vector>
diff --git a/res/drawable/screen_zoom_preview_action_background.xml b/res/drawable/screen_zoom_preview_action_background.xml
new file mode 100644
index 0000000..32fbb02
--- /dev/null
+++ b/res/drawable/screen_zoom_preview_action_background.xml
@@ -0,0 +1,22 @@
+<?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.
+-->
+
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shape="oval">
+ <size android:width="24dp"
+ android:height="24dp" />
+ <solid android:color="@android:color/white" />
+</shape>
diff --git a/res/layout/app_ops_item.xml b/res/layout/app_ops_item.xml
index 8d21456..adba9da 100644
--- a/res/layout/app_ops_item.xml
+++ b/res/layout/app_ops_item.xml
@@ -25,7 +25,7 @@
android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
android:paddingTop="8dip"
android:paddingBottom="8dip"
- android:columnCount="3">
+ android:columnCount="4">
<ImageView
android:id="@+id/app_icon"
@@ -47,6 +47,14 @@
android:textAppearance="?android:attr/textAppearanceMedium"
android:textAlignment="viewStart" />
+ <Switch
+ android:id="@+id/op_switch"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_rowSpan="2"
+ android:focusable="false"
+ android:clickable="false" />
+
<TextView
android:id="@+id/op_name"
android:layout_width="0dip"
diff --git a/res/layout/background_check_summary.xml b/res/layout/background_check_summary.xml
new file mode 100644
index 0000000..ee47194
--- /dev/null
+++ b/res/layout/background_check_summary.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 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:id="@+id/appops_content"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical">
+</LinearLayout>
diff --git a/res/layout/screen_zoom_activity.xml b/res/layout/screen_zoom_activity.xml
new file mode 100644
index 0000000..81ce102
--- /dev/null
+++ b/res/layout/screen_zoom_activity.xml
@@ -0,0 +1,96 @@
+<?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.
+-->
+
+<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <LinearLayout
+ android:orientation="vertical"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingTop="16dp"
+ android:paddingLeft="?android:attr/listPreferredItemPaddingStart"
+ android:paddingEnd="?android:attr/listPreferredItemPaddingEnd">
+
+ <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" />
+
+ <FrameLayout
+ android:layout_width="match_parent"
+ android:layout_height="@dimen/screen_zoom_preview_height"
+ android:background="?android:attr/colorBackgroundFloating"
+ android:elevation="2dp">
+
+ <com.android.settings.display.TouchBlockingFrameLayout
+ android:id="@+id/preview_frame"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent" />
+
+ <TextView
+ android:id="@+id/current_density"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_horizontal|bottom"
+ android:padding="8dp"
+ android:theme="@android:style/Theme.Material"
+ android:background="?android:attr/colorBackgroundFloating"
+ android:textAppearance="@android:style/TextAppearance.Material.Caption"
+ android:textAllCaps="true"
+ android:elevation="2dp" />
+ </FrameLayout>
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingTop="8dp">
+
+ <ImageView
+ android:id="@+id/smaller"
+ android:layout_width="48dp"
+ android:layout_height="48dp"
+ android:background="?android:attr/selectableItemBackgroundBorderless"
+ android:src="@drawable/ic_remove_24dp"
+ android:tint="?android:attr/colorControlNormal"
+ android:tintMode="src_in"
+ android:scaleType="center"
+ android:focusable="true"
+ android:contentDescription="@string/screen_zoom_make_smaller_desc" />
+
+ <SeekBar
+ android:id="@+id/seek_bar"
+ android:layout_width="0dp"
+ android:layout_height="48dp"
+ android:layout_weight="1" />
+
+ <ImageView
+ android:id="@+id/larger"
+ android:layout_width="48dp"
+ android:layout_height="48dp"
+ android:background="?android:attr/selectableItemBackgroundBorderless"
+ android:src="@drawable/ic_add_24dp"
+ android:tint="?android:attr/colorControlNormal"
+ android:tintMode="src_in"
+ android:scaleType="center"
+ android:focusable="true"
+ android:contentDescription="@string/screen_zoom_make_larger_desc" />
+ </LinearLayout>
+ </LinearLayout>
+</ScrollView>
diff --git a/res/layout/screen_zoom_preview.xml b/res/layout/screen_zoom_preview.xml
new file mode 100644
index 0000000..7cdb663
--- /dev/null
+++ b/res/layout/screen_zoom_preview.xml
@@ -0,0 +1,85 @@
+<?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="vertical">
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="?android:attr/actionBarSize"
+ android:orientation="horizontal"
+ android:theme="?android:attr/actionBarTheme"
+ style="?android:attr/actionBarStyle">
+
+ <TextView
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:layout_marginLeft="16dp"
+ android:text="@string/screen_zoom_preview_title"
+ android:textAppearance="@android:style/TextAppearance.Material.Widget.ActionBar.Title" />
+
+ <ImageView
+ android:layout_width="36dp"
+ android:layout_height="48dp"
+ style="?android:attr/actionOverflowButtonStyle" />
+ </LinearLayout>
+
+ <ScrollView
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:scrollbars="none"
+ android:background="?android:attr/colorBackgroundFloating">
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical">
+
+ <TextView
+ style="@android:style/TextAppearance.Material.Subhead"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="16dp"
+ android:layout_marginTop="16dp"
+ android:text="@string/permissions_label" />
+
+ <include layout="@layout/screen_zoom_preview_item" />
+
+ <View
+ android:layout_width="match_parent"
+ android:layout_height="1dp"
+ android:layout_marginLeft="62dp"
+ android:layout_marginRight="8dp"
+ android:background="#36000000" />
+
+ <include layout="@layout/screen_zoom_preview_item" />
+
+ <View
+ android:layout_width="match_parent"
+ android:layout_height="1dp"
+ android:layout_marginLeft="62dp"
+ android:layout_marginRight="8dp"
+ android:background="#36000000" />
+
+ <include layout="@layout/screen_zoom_preview_item" />
+
+ </LinearLayout>
+
+ </ScrollView>
+</LinearLayout>
diff --git a/res/layout/screen_zoom_preview_item.xml b/res/layout/screen_zoom_preview_item.xml
new file mode 100644
index 0000000..68076f0
--- /dev/null
+++ b/res/layout/screen_zoom_preview_item.xml
@@ -0,0 +1,65 @@
+<?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"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:gravity="center_vertical"
+ android:padding="16dp"
+ tools:showIn="@layout/screen_zoom_preview">
+
+ <ImageView
+ android:id="@+id/icon"
+ android:layout_width="48dp"
+ android:layout_height="48dp"
+ android:background="@drawable/screen_zoom_preview_action_background"
+ android:backgroundTint="?android:attr/colorAccent"
+ android:src="@drawable/ic_settings_32dp"
+ android:scaleType="center" />
+
+ <LinearLayout
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:orientation="vertical"
+ android:paddingStart="16dp">
+
+ <TextView
+ android:id="@+id/title"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/usage_access"
+ style="@android:style/TextAppearance.Material.Body1" />
+
+ <TextView
+ android:id="@+id/summary"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/usage_access_description"
+ style="@android:style/TextAppearance.Material.Caption" />
+ </LinearLayout>
+
+ <ImageView
+ android:id="@+id/action"
+ android:layout_width="24dp"
+ android:layout_height="24dp"
+ android:layout_marginLeft="24dp"
+ android:src="@drawable/ic_info"
+ android:tint="?android:attr/colorControlNormal"
+ android:tintMode="src_in"
+ android:scaleType="center" />
+</LinearLayout>
diff --git a/res/values-land/dimens.xml b/res/values-land/dimens.xml
index d15c254..7612c97 100755
--- a/res/values-land/dimens.xml
+++ b/res/values-land/dimens.xml
@@ -48,4 +48,7 @@
<!-- Fingerprint -->
<item name="fingerprint_illustration_aspect_ratio" format="float" type="dimen">0.0</item>
<dimen name="fingerprint_decor_padding_top">24dp</dimen>
+
+ <!-- Display, Screen zoom -->
+ <dimen name="screen_zoom_preview_height">160dp</dimen>
</resources>
diff --git a/res/values/arrays.xml b/res/values/arrays.xml
index f04892e..12a0172 100644
--- a/res/values/arrays.xml
+++ b/res/values/arrays.xml
@@ -620,11 +620,25 @@
<item>monitor high power location</item>
<item>get usage stats</item>
<item>mute/unmute microphone</item>
+ <item>show toast</item>
<item>project media</item>
<item>activate VPN</item>
<item>write wallpaper</item>
<item>assist structure</item>
<item>assist screenshot</item>
+ <item>read phone state</item>
+ <item>add voicemail</item>
+ <item>use sip</item>
+ <item>process outgoing call</item>
+ <item>fingerprint</item>
+ <item>body sensors</item>
+ <item>read cell broadcasts</item>
+ <item>mock location</item>
+ <item>read storage</item>
+ <item>write storage</item>
+ <item>turn on screen</item>
+ <item>get accounts</item>
+ <item>run in background</item>
</string-array>
<!-- User display names for app ops codes -->
@@ -674,11 +688,25 @@
<item>Location</item>
<item>Get usage stats</item>
<item>Mute/unmute microphone</item>
+ <item>Show toast</item>
<item>Project media</item>
<item>Activate VPN</item>
<item>Write wallpaper</item>
<item>Assist structure</item>
<item>Assist screenshot</item>
+ <item>Read phone state</item>
+ <item>Add voicemail</item>
+ <item>Use sip</item>
+ <item>Process outgoing call</item>
+ <item>Fingerprint</item>
+ <item>Body sensors</item>
+ <item>Read cell broadcasts</item>
+ <item>Mock location</item>
+ <item>Read storage</item>
+ <item>Write storage</item>
+ <item>Turn on screen</item>
+ <item>Get accounts</item>
+ <item>Run in background</item>
</string-array>
<!-- Titles for the list of long press timeout options. -->
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index dc0b186..481cc73 100755
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -252,4 +252,7 @@
<!-- Button bar padding for unmount button. -->
<dimen name="unmount_button_padding">8dp</dimen>
+
+ <!-- Display, Screen zoom -->
+ <dimen name="screen_zoom_preview_height">240dp</dimen>
</resources>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index cc5cf8f..a1a1901 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -2783,8 +2783,6 @@
<!-- Security & location settings screen, section header for settings relating to location -->
<string name="location_title">My Location</string>
- <!-- Title for managed profile preference category [CHAR_LIMIT=25] -->
- <string name="managed_profile_location_category">Work profile</string>
<!-- [CHAR LIMIT=30] Title for managed profile location switch -->
<string name="managed_profile_location_switch_title">Location for work profile</string>
<!-- [CHAR LIMIT=30] Text to show on managed profile location switch if MDM has locked down location access for managed profile-->
@@ -3661,6 +3659,8 @@
<string name="accessibility_power_button_ends_call_prerefence_title">Power button ends call</string>
<!-- Title for the accessibility preference to speak passwords. [CHAR LIMIT=35] -->
<string name="accessibility_toggle_speak_password_preference_title">Speak passwords</string>
+ <!-- Title for the accessibility preference for enabling/disabling large icons for mouse/trackpad pointers. [CHAR LIMIT=35] -->
+ <string name="accessibility_toggle_large_pointer_icon_title">Large mouse/trackpad pointer icons</string>
<!-- Title for accessibility preference to choose long-press delay i.e. timeout before it is detected. [CHAR LIMIT=35] -->
<string name="accessibility_long_press_timeout_preference_title">Touch & hold delay</string>
<!-- Title for the accessibility preference to configure display color inversion. [CHAR LIMIT=NONE] -->
@@ -6427,6 +6427,12 @@
usb_use_file_transfer, use_use_photo_transfer, and usb_use_MIDI -->
<string name="usb_use">Use USB for</string>
+ <!-- Settings item title for background check prefs [CHAR LIMIT=35] -->
+ <string name="background_check_pref">Background check</string>
+
+ <!-- Settings screen title for background check prefs [CHAR LIMIT=35] -->
+ <string name="background_check_title">Full background access</string>
+
<!-- Title for the "context" preference to determine whether assist can access the data currently displayed on-screen [CHAR LIMIT=40] -->
<string name="assist_access_context_title">Use text from screen</string>
@@ -6607,23 +6613,33 @@
<!-- Description of setting that controls gesture to open camera by double tapping the power button [CHAR LIMIT=NONE] -->
<string name="camera_double_tap_power_gesture_desc">Quickly open camera without unlocking your screen</string>
- <!-- Title of setting that controls display scale (e.g. density). [CHAR LIMIT=40] -->
- <string name="force_density_preference_title">Display scale</string>
- <!-- Keywords for setting that controls display scale (e.g. density). [CHAR LIMIT=NONE] -->
- <string name="force_density_keywords">display density zoom scale scaling</string>
- <!-- Description for the display scale that makes interface elements small. [CHAR LIMIT=24] -->
- <string name="force_density_summary_small">Small</string>
- <!-- Description for the device's default display scale. [CHAR LIMIT=24] -->
- <string name="force_density_summary_normal">Normal</string>
- <!-- Description for the display scale that makes interface elements large. [CHAR LIMIT=24] -->
- <string name="force_density_summary_large">Large</string>
- <!-- Description for the display scale that makes interface elements larger. [CHAR LIMIT=24] -->
- <string name="force_density_summary_very_large">Larger</string>
- <!-- Description for the display scale that makes interface elements largest. [CHAR LIMIT=24] -->
- <string name="force_density_summary_extremely_large">Largest</string>
- <!-- Description for a custom display scale. This shows the requested display
- density in raw pixels per inch rather than computing a scale amount. [CHAR LIMIT=24] -->
- <string name="force_density_summary_custom">Custom (<xliff:g id="densityDpi" example="160">%d</xliff:g>)</string>
+ <!-- Title of setting that controls screen zoom (e.g. how large interface elements appear). [CHAR LIMIT=40] -->
+ <string name="screen_zoom_title">Screen zoom</string>
+ <!-- Keywords for setting that controls screen zoom (e.g. how large interface elements appear). [CHAR LIMIT=NONE] -->
+ <string name="screen_zoom_keywords">display density screen zoom scale scaling</string>
+
+ <string name="screen_zoom_summary">Choose how zoomed you want the screen using the slider below the preview image.</string>
+
+ <!-- Title of the screen zoom preview activity. -->
+ <string name="screen_zoom_preview_title">Preview</string>
+ <!-- Description for the button that makes interface elements smaller. [CHAR_LIMIT=NONE] -->
+ <string name="screen_zoom_make_smaller_desc">Make smaller</string>
+ <!-- Description for the button that makes interface elements larger. [CHAR_LIMIT=NONE] -->
+ <string name="screen_zoom_make_larger_desc">Make larger</string>
+
+ <!-- Description for the screen zoom level that makes interface elements small. [CHAR LIMIT=24] -->
+ <string name="screen_zoom_summary_small">Small</string>
+ <!-- Description for the device's default screen zoom level. [CHAR LIMIT=24] -->
+ <string name="screen_zoom_summary_normal">Normal</string>
+ <!-- Description for the screen zoom level that makes interface elements large. [CHAR LIMIT=24] -->
+ <string name="screen_zoom_summary_large">Large</string>
+ <!-- Description for the screen zoom level that makes interface elements larger. [CHAR LIMIT=24] -->
+ <string name="screen_zoom_summary_very_large">Larger</string>
+ <!-- Description for the screen zoom level that makes interface elements largest. [CHAR LIMIT=24] -->
+ <string name="screen_zoom_summary_extremely_large">Largest</string>
+ <!-- Description for a custom screen zoom level. This shows the requested display
+ density in raw pixels per inch rather than using a relative description. [CHAR LIMIT=24] -->
+ <string name="screen_zoom_summary_custom">Custom (<xliff:g id="densityDpi" example="160">%d</xliff:g>)</string>
<!-- Button to show all top-level settings items [CHAR LIMIT=20] -->
<string name="see_all">See all</string>
diff --git a/res/xml/accessibility_settings.xml b/res/xml/accessibility_settings.xml
index 881037d..791f1b8 100644
--- a/res/xml/accessibility_settings.xml
+++ b/res/xml/accessibility_settings.xml
@@ -68,6 +68,10 @@
android:title="@string/accessibility_toggle_speak_password_preference_title"
android:persistent="false"/>
+ <SwitchPreference
+ android:key="toggle_large_pointer_icon"
+ android:title="@string/accessibility_toggle_large_pointer_icon_title" />
+
<PreferenceScreen
android:fragment="com.android.settings.accessibility.ToggleGlobalGesturePreferenceFragment"
android:key="enable_global_gesture_preference_screen"
diff --git a/res/xml/development_prefs.xml b/res/xml/development_prefs.xml
index 84c3cbf..d3c8852 100644
--- a/res/xml/development_prefs.xml
+++ b/res/xml/development_prefs.xml
@@ -340,6 +340,10 @@
android:entries="@array/app_process_limit_entries"
android:entryValues="@array/app_process_limit_values" />
+ <Preference
+ android:key="background_check"
+ android:title="@string/background_check_pref" />
+
<SwitchPreference
android:key="show_all_anrs"
android:title="@string/show_all_anrs"
diff --git a/res/xml/display_settings.xml b/res/xml/display_settings.xml
index 60730a9..1016c2a 100644
--- a/res/xml/display_settings.xml
+++ b/res/xml/display_settings.xml
@@ -99,12 +99,10 @@
android:entries="@array/entries_font_size"
android:entryValues="@array/entryvalues_font_size" />
- <com.android.settings.DisplayDensityPreference
- android:key="display_density"
- android:title="@string/force_density_preference_title"
- android:summary="%s"
- settings:keywords="@string/force_density_keywords"
- android:persistent="false" />
+ <com.android.settings.display.ScreenZoomPreference
+ android:key="screen_zoom"
+ android:title="@string/screen_zoom_title"
+ settings:keywords="@string/screen_zoom_keywords" />
<com.android.settings.DropDownPreference
android:key="auto_rotate"
diff --git a/res/xml/location_settings.xml b/res/xml/location_settings.xml
index 2cd86f5..4ccc14a 100644
--- a/res/xml/location_settings.xml
+++ b/res/xml/location_settings.xml
@@ -27,19 +27,13 @@
android:summary="@string/location_mode_location_off_title" />
<!-- This preference category gets removed if there is no managed profile -->
- <PreferenceCategory
- android:key="managed_profile_location_category"
- android:title="@string/managed_profile_location_category">
-
- <Preference
- android:key="managed_profile_location_switch"
- android:title="@string/managed_profile_location_switch_title"
- android:summary="@string/managed_profile_location_switch_lockdown"
- android:persistent="false"
- android:enabled="false"
- android:selectable="false" />
-
- </PreferenceCategory>
+ <SwitchPreference
+ android:key="managed_profile_location_switch"
+ android:title="@string/managed_profile_location_switch_title"
+ android:summary="@string/managed_profile_location_switch_lockdown"
+ android:persistent="false"
+ android:enabled="false"
+ android:selectable="true" />
<PreferenceCategory
android:key="recent_location_requests"
diff --git a/src/com/android/settings/ApnEditor.java b/src/com/android/settings/ApnEditor.java
index e785abb..20fb9ea 100644
--- a/src/com/android/settings/ApnEditor.java
+++ b/src/com/android/settings/ApnEditor.java
@@ -203,10 +203,22 @@
mFirstTime = icicle == null;
if (action.equals(Intent.ACTION_EDIT)) {
- mUri = intent.getData();
+ Uri uri = intent.getData();
+ if (!uri.isPathPrefixMatch(Telephony.Carriers.CONTENT_URI)) {
+ Log.e(TAG, "Edit request not for carrier table. Uri: " + uri);
+ finish();
+ return;
+ }
+ mUri = uri;
} else if (action.equals(Intent.ACTION_INSERT)) {
if (mFirstTime || icicle.getInt(SAVED_POS) == 0) {
- mUri = getContentResolver().insert(intent.getData(), new ContentValues());
+ Uri uri = intent.getData();
+ if (!uri.isPathPrefixMatch(Telephony.Carriers.CONTENT_URI)) {
+ Log.e(TAG, "Insert request not for carrier table. Uri: " + uri);
+ finish();
+ return;
+ }
+ mUri = getContentResolver().insert(uri, new ContentValues());
} else {
mUri = ContentUris.withAppendedId(Telephony.Carriers.CONTENT_URI,
icicle.getInt(SAVED_POS));
diff --git a/src/com/android/settings/ChooseLockGeneric.java b/src/com/android/settings/ChooseLockGeneric.java
index 65f0ba6..114637c 100644
--- a/src/com/android/settings/ChooseLockGeneric.java
+++ b/src/com/android/settings/ChooseLockGeneric.java
@@ -220,13 +220,17 @@
&& !dpm.getDoNotAskCredentialsOnBoot()) {
mEncryptionRequestQuality = quality;
mEncryptionRequestDisabled = disabled;
+ // Get the intent that the encryption interstitial should start for creating
+ // the new unlock method.
+ Intent unlockMethodIntent = getIntentForUnlockMethod(quality, disabled);
final Context context = getActivity();
// If accessibility is enabled and the user hasn't seen this dialog before, set the
// default state to agree with that which is compatible with accessibility
// (password not required).
final boolean accEn = AccessibilityManager.getInstance(context).isEnabled();
final boolean required = mLockPatternUtils.isCredentialRequiredToDecrypt(!accEn);
- Intent intent = getEncryptionInterstitialIntent(context, quality, required);
+ Intent intent = getEncryptionInterstitialIntent(context, quality, required,
+ unlockMethodIntent);
intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_FOR_FINGERPRINT,
mForFingerprint);
startActivityForResult(intent, ENABLE_ENCRYPTION_REQUEST);
@@ -246,9 +250,8 @@
updatePreferencesOrFinish();
} else if (requestCode == ENABLE_ENCRYPTION_REQUEST
&& resultCode == Activity.RESULT_OK) {
- mRequirePassword = data.getBooleanExtra(
- EncryptionInterstitial.EXTRA_REQUIRE_PASSWORD, true);
- updateUnlockMethodAndFinish(mEncryptionRequestQuality, mEncryptionRequestDisabled);
+ getActivity().setResult(resultCode, data);
+ finish();
} else if (requestCode == CHOOSE_LOCK_REQUEST) {
getActivity().setResult(resultCode, data);
finish();
@@ -451,8 +454,9 @@
}
protected Intent getEncryptionInterstitialIntent(Context context, int quality,
- boolean required) {
- return EncryptionInterstitial.createStartIntent(context, quality, required);
+ boolean required, Intent unlockMethodIntent) {
+ return EncryptionInterstitial.createStartIntent(context, quality, required,
+ unlockMethodIntent);
}
/**
@@ -471,34 +475,13 @@
}
quality = upgradeQuality(quality);
+ Intent intent = getIntentForUnlockMethod(quality, disabled);
+ if (intent != null) {
+ startActivityForResult(intent, CHOOSE_LOCK_REQUEST);
+ return;
+ }
- final Context context = getActivity();
- if (quality >= DevicePolicyManager.PASSWORD_QUALITY_NUMERIC) {
- int minLength = mDPM.getPasswordMinimumLength(null);
- if (minLength < MIN_PASSWORD_LENGTH) {
- minLength = MIN_PASSWORD_LENGTH;
- }
- final int maxLength = mDPM.getPasswordMaximumLength(quality);
- Intent intent;
- if (mHasChallenge) {
- intent = getLockPasswordIntent(context, quality, minLength,
- maxLength, mRequirePassword, mChallenge, mUserId);
- } else {
- intent = getLockPasswordIntent(context, quality, minLength,
- maxLength, mRequirePassword, mUserPassword, mUserId);
- }
- startActivityForResult(intent, CHOOSE_LOCK_REQUEST);
- } else if (quality == DevicePolicyManager.PASSWORD_QUALITY_SOMETHING) {
- Intent intent;
- if (mHasChallenge) {
- intent = getLockPatternIntent(context, mRequirePassword,
- mChallenge, mUserId);
- } else {
- intent = getLockPatternIntent(context, mRequirePassword,
- mUserPassword, mUserId);
- }
- startActivityForResult(intent, CHOOSE_LOCK_REQUEST);
- } else if (quality == DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) {
+ if (quality == DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) {
mChooseLockSettingsHelper.utils().clearLock(mUserId);
mChooseLockSettingsHelper.utils().setLockScreenDisabled(disabled, mUserId);
removeAllFingerprintTemplatesAndFinish();
@@ -508,6 +491,34 @@
}
}
+ private Intent getIntentForUnlockMethod(int quality, boolean disabled) {
+ Intent intent = null;
+ final Context context = getActivity();
+ if (quality >= DevicePolicyManager.PASSWORD_QUALITY_NUMERIC) {
+ int minLength = mDPM.getPasswordMinimumLength(null);
+ if (minLength < MIN_PASSWORD_LENGTH) {
+ minLength = MIN_PASSWORD_LENGTH;
+ }
+ final int maxLength = mDPM.getPasswordMaximumLength(quality);
+ if (mHasChallenge) {
+ intent = getLockPasswordIntent(context, quality, minLength,
+ maxLength, mRequirePassword, mChallenge, mUserId);
+ } else {
+ intent = getLockPasswordIntent(context, quality, minLength,
+ maxLength, mRequirePassword, mUserPassword, mUserId);
+ }
+ } else if (quality == DevicePolicyManager.PASSWORD_QUALITY_SOMETHING) {
+ if (mHasChallenge) {
+ intent = getLockPatternIntent(context, mRequirePassword,
+ mChallenge, mUserId);
+ } else {
+ intent = getLockPatternIntent(context, mRequirePassword,
+ mUserPassword, mUserId);
+ }
+ }
+ return intent;
+ }
+
private void removeAllFingerprintTemplatesAndFinish() {
if (mFingerprintManager != null && mFingerprintManager.isHardwareDetected()
&& mFingerprintManager.getEnrolledFingerprints().size() > 0) {
diff --git a/src/com/android/settings/DevelopmentSettings.java b/src/com/android/settings/DevelopmentSettings.java
index 9bccbcf..950af3c 100644
--- a/src/com/android/settings/DevelopmentSettings.java
+++ b/src/com/android/settings/DevelopmentSettings.java
@@ -76,6 +76,7 @@
import android.widget.TextView;
import com.android.internal.logging.MetricsLogger;
+import com.android.settings.applications.BackgroundCheckSummary;
import com.android.settings.fuelgauge.InactiveApps;
import com.android.settings.search.BaseSearchIndexProvider;
import com.android.settings.search.Indexable;
@@ -170,6 +171,8 @@
= "immediately_destroy_activities";
private static final String APP_PROCESS_LIMIT_KEY = "app_process_limit";
+ private static final String BACKGROUND_CHECK_KEY = "background_check";
+
private static final String SHOW_ALL_ANRS_KEY = "show_all_anrs";
private static final String PACKAGE_MIME_TYPE = "application/vnd.android.package-archive";
@@ -1718,6 +1721,8 @@
writeForceResizableOptions();
} else if (INACTIVE_APPS_KEY.equals(preference.getKey())) {
startInactiveAppsFragment();
+ } else if (BACKGROUND_CHECK_KEY.equals(preference.getKey())) {
+ startBackgroundCheckFragment();
} else {
return super.onPreferenceTreeClick(preference);
}
@@ -1731,6 +1736,12 @@
null, R.string.inactive_apps_title, null, null, 0);
}
+ private void startBackgroundCheckFragment() {
+ ((SettingsActivity) getActivity()).startPreferencePanel(
+ BackgroundCheckSummary.class.getName(),
+ null, R.string.background_check_title, null, null, 0);
+ }
+
private boolean showKeyguardConfirmation(Resources resources, int requestCode) {
return new ChooseLockSettingsHelper(getActivity(), this).launchConfirmationActivity(
requestCode, resources.getString(R.string.oem_unlock_enable));
diff --git a/src/com/android/settings/DisplayDensityPreference.java b/src/com/android/settings/DisplayDensityPreference.java
deleted file mode 100644
index 85f2fb2..0000000
--- a/src/com/android/settings/DisplayDensityPreference.java
+++ /dev/null
@@ -1,247 +0,0 @@
-/*
- * 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
- */
-
-package com.android.settings;
-
-import android.content.Context;
-import android.content.res.Resources;
-import android.os.AsyncTask;
-import android.os.RemoteException;
-import android.support.annotation.ArrayRes;
-import android.support.v7.preference.ListPreference;
-import android.util.AttributeSet;
-import android.util.DisplayMetrics;
-import android.util.Log;
-import android.util.MathUtils;
-import android.view.Display;
-import android.view.IWindowManager;
-import android.view.WindowManagerGlobal;
-
-import com.android.settings.R;
-
-import java.util.Arrays;
-
-/**
- * Preference for changing the density of the display on which the preference
- * is visible.
- */
-public class DisplayDensityPreference extends ListPreference {
- private static final String LOG_TAG = "DisplayDensityPreference";
-
- /** Minimum increment between density scales. */
- private static final float MIN_SCALE_INTERVAL = 0.09f;
-
- /** Minimum density scale. This is available on all devices. */
- private static final float MIN_SCALE = 0.85f;
-
- /** Maximum density scale. The actual scale used depends on the device. */
- private static final float MAX_SCALE = 1.50f;
-
- /** Sentinel value for "normal" scaling (effectively disabled). */
- private static final int DENSITY_VALUE_NORMAL = -1;
-
- /** Summary used for "normal" scale. */
- private static final int DENSITY_SUMMARY_NORMAL = R.string.force_density_summary_normal;
-
- /**
- * Summaries for scales smaller than "normal" in order of smallest to
- * largest.
- */
- private static final int[] SMALLER_SUMMARIES = new int[] {
- R.string.force_density_summary_small
- };
-
- /**
- * Summaries for scales larger than "normal" in order of smallest to
- * largest.
- */
- private static final int[] LARGER_SUMMARIES = new int[] {
- R.string.force_density_summary_large,
- R.string.force_density_summary_very_large,
- R.string.force_density_summary_extremely_large,
- };
-
- /**
- * Minimum allowed screen dimension, corresponds to resource qualifiers
- * "small" or "sw320dp". This value must be at least the minimum screen
- * size required by the CDD so that we meet developer expectations.
- */
- private static final int MIN_DIMENSION_DP = 320;
-
- /** The ID of the display affected by this preference. */
- private int mDisplayId = Display.DEFAULT_DISPLAY;
-
- public DisplayDensityPreference(Context context, AttributeSet attrs) {
- super(context, attrs);
-
- if (!prepareList()) {
- setEnabled(false);
- }
- }
-
- private boolean prepareList() {
- final int initialDensity = getInitialDisplayDensity(mDisplayId);
- if (initialDensity <= 0) {
- return false;
- }
-
- final Resources res = getContext().getResources();
- final DisplayMetrics metrics = res.getDisplayMetrics();
- final int currentDensity = metrics.densityDpi;
- int currentDensityIndex = -1;
-
- // Compute number of "larger" and "smaller" scales for this display.
- final int minDimensionPx = Math.min(metrics.widthPixels, metrics.heightPixels);
- final int maxDensity = DisplayMetrics.DENSITY_MEDIUM * minDimensionPx / MIN_DIMENSION_DP;
- final float maxScale = Math.min(MAX_SCALE, maxDensity / (float) initialDensity);
- final float minScale = MIN_SCALE;
- final int numLarger = (int) MathUtils.constrain((maxScale - 1) / MIN_SCALE_INTERVAL,
- 0, LARGER_SUMMARIES.length);
- final int numSmaller = (int) MathUtils.constrain((1 - minScale) / MIN_SCALE_INTERVAL,
- 0, SMALLER_SUMMARIES.length);
-
- CharSequence[] values = new CharSequence[1 + numSmaller + numLarger];
- CharSequence[] entries = new CharSequence[values.length];
- int curIndex = 0;
-
- if (numSmaller > 0) {
- final float interval = (1 - minScale) / numSmaller;
- for (int i = numSmaller - 1; i >= 0; i--) {
- final int density = (int) (initialDensity * (1 - (i + 1) * interval));
- if (currentDensity == density) {
- currentDensityIndex = curIndex;
- }
- values[curIndex] = Integer.toString(density);
- entries[curIndex] = res.getText(SMALLER_SUMMARIES[i]);
- curIndex++;
- }
- }
-
- if (currentDensity == initialDensity) {
- currentDensityIndex = curIndex;
- }
- values[curIndex] = Integer.toString(DENSITY_VALUE_NORMAL);
- entries[curIndex] = res.getText(DENSITY_SUMMARY_NORMAL);
- curIndex++;
-
- if (numLarger > 0) {
- final float interval = (maxScale - 1) / numLarger;
- for (int i = 0; i < numLarger; i++) {
- final int density = (int) (initialDensity * (1 + (i + 1) * interval));
- if (currentDensity == density) {
- currentDensityIndex = curIndex;
- }
- values[curIndex] = Integer.toString(density);
- entries[curIndex] = res.getText(LARGER_SUMMARIES[i]);
- curIndex++;
- }
- }
-
- final int displayIndex;
- if (currentDensityIndex >= 0) {
- displayIndex = currentDensityIndex;
- } else {
- // We don't understand the current density. Must have been set by
- // someone else. Make room for another entry...
- values = Arrays.copyOf(values, values.length + 1);
- values[curIndex] = res.getString(R.string.force_density_summary_custom, currentDensity);
-
- entries = Arrays.copyOf(entries, values.length + 1);
- entries[curIndex] = Integer.toString(currentDensity);
-
- displayIndex = curIndex;
- }
-
- super.setEntryValues(values);
- super.setEntries(entries);
-
- setValueIndex(displayIndex);
-
- return true;
- }
-
- @Override
- public boolean callChangeListener(Object newValue) {
- final boolean allowed = super.callChangeListener(newValue);
- if (allowed) {
- final int density = Integer.parseInt((String) newValue);
- setForcedDisplayDensity(mDisplayId, density);
- }
-
- return allowed;
- }
-
- @Override
- public void setEntries(CharSequence[] entries) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void setEntries(@ArrayRes int entriesResId) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void setEntryValues(CharSequence[] entryValues) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void setEntryValues(@ArrayRes int entryValuesResId) {
- throw new UnsupportedOperationException();
- }
-
- /**
- * Returns the initial density for the specified display.
- *
- * @param displayId the identifier of the display
- * @return the initial density of the specified display, or {@code -1} if
- * the display does not exist or the density could not be obtained
- */
- private static int getInitialDisplayDensity(int displayId) {
- try {
- IWindowManager wm = WindowManagerGlobal.getWindowManagerService();
- return wm.getInitialDisplayDensity(displayId);
- } catch (RemoteException exc) {
- return -1;
- }
- }
-
- /**
- * Asynchronously applies display density changes to the specified display.
- *
- * @param displayId the identifier of the display to modify
- * @param density the density to force for the specified display, or <= 0
- * to clear any previously forced density
- */
- private static void setForcedDisplayDensity(final int displayId, final int density) {
- AsyncTask.execute(new Runnable() {
- @Override
- public void run() {
- try {
- IWindowManager wm = WindowManagerGlobal.getWindowManagerService();
- if (density <= 0) {
- wm.clearForcedDisplayDensity(displayId);
- } else {
- wm.setForcedDisplayDensity(displayId, density);
- }
- } catch (RemoteException exc) {
- Log.w(LOG_TAG, "Unable to save forced display density setting");
- }
- }
- });
- }
-}
diff --git a/src/com/android/settings/DisplaySettings.java b/src/com/android/settings/DisplaySettings.java
index 0d52aa7..e9ab1f7 100644
--- a/src/com/android/settings/DisplaySettings.java
+++ b/src/com/android/settings/DisplaySettings.java
@@ -76,7 +76,6 @@
private static final String KEY_CAMERA_GESTURE = "camera_gesture";
private static final String KEY_CAMERA_DOUBLE_TAP_POWER_GESTURE
= "camera_double_tap_power_gesture";
- private static final String KEY_DISPLAY_DENSITY = "display_density";
private DropDownPreference mFontSizePref;
@@ -214,9 +213,6 @@
mNightModePreference.setValue(String.valueOf(currentNightMode));
mNightModePreference.setOnPreferenceChangeListener(this);
}
-
- final Preference displayDensity = findPreference(KEY_DISPLAY_DENSITY);
- displayDensity.setOnPreferenceChangeListener(this);
}
private static boolean allowAllRotations(Context context) {
diff --git a/src/com/android/settings/DropDownPreference.java b/src/com/android/settings/DropDownPreference.java
index 3088497..70bd663 100644
--- a/src/com/android/settings/DropDownPreference.java
+++ b/src/com/android/settings/DropDownPreference.java
@@ -64,6 +64,7 @@
}
});
setPersistent(false);
+ setSummary("%s");
updateEntries();
}
@@ -95,7 +96,6 @@
public void setValue(String value) {
super.setValue(value);
mSpinner.setSelection(findIndexOfValue(getValue()));
- setSummary(getEntry());
}
public void setValueIndex(int index) {
diff --git a/src/com/android/settings/EncryptionInterstitial.java b/src/com/android/settings/EncryptionInterstitial.java
index 3aec03e..5cd0508 100644
--- a/src/com/android/settings/EncryptionInterstitial.java
+++ b/src/com/android/settings/EncryptionInterstitial.java
@@ -26,10 +26,12 @@
import android.content.Intent;
import android.os.Bundle;
import android.os.UserHandle;
+import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.accessibility.AccessibilityManager;
+import android.widget.Button;
import android.widget.RadioButton;
import android.widget.TextView;
@@ -39,9 +41,12 @@
import java.util.List;
public class EncryptionInterstitial extends SettingsActivity {
+ private final static String TAG = EncryptionInterstitial.class.getSimpleName();
protected static final String EXTRA_PASSWORD_QUALITY = "extra_password_quality";
+ protected static final String EXTRA_UNLOCK_METHOD_INTENT = "extra_unlock_method_intent";
public static final String EXTRA_REQUIRE_PASSWORD = "extra_require_password";
+ private static final int CHOOSE_LOCK_REQUEST = 100;
@Override
public Intent getIntent() {
@@ -56,7 +61,7 @@
}
public static Intent createStartIntent(Context ctx, int quality,
- boolean requirePasswordDefault) {
+ boolean requirePasswordDefault, Intent unlockMethodIntent) {
return new Intent(ctx, EncryptionInterstitial.class)
.putExtra(EXTRA_PREFS_SHOW_BUTTON_BAR, true)
.putExtra(EXTRA_PREFS_SET_BACK_TEXT, (String) null)
@@ -64,7 +69,8 @@
R.string.encryption_continue_button))
.putExtra(EXTRA_PASSWORD_QUALITY, quality)
.putExtra(EXTRA_SHOW_FRAGMENT_TITLE_RESID, R.string.encryption_interstitial_header)
- .putExtra(EXTRA_REQUIRE_PASSWORD, requirePasswordDefault);
+ .putExtra(EXTRA_REQUIRE_PASSWORD, requirePasswordDefault)
+ .putExtra(EXTRA_UNLOCK_METHOD_INTENT, unlockMethodIntent);
}
public static class EncryptionInterstitialFragment extends SettingsPreferenceFragment
@@ -75,6 +81,7 @@
private RadioButton mDontRequirePasswordToDecryptButton;
private TextView mEncryptionMessage;
private boolean mPasswordRequired;
+ private Intent mUnlockMethodIntent;
@Override
protected int getMetricsCategory() {
@@ -98,7 +105,9 @@
(TextView) view.findViewById(R.id.encryption_message);
boolean forFingerprint = getActivity().getIntent().getBooleanExtra(
ChooseLockSettingsHelper.EXTRA_KEY_FOR_FINGERPRINT, false);
- int quality = getActivity().getIntent().getIntExtra(EXTRA_PASSWORD_QUALITY, 0);
+ Intent intent = getActivity().getIntent();
+ final int quality = intent.getIntExtra(EXTRA_PASSWORD_QUALITY, 0);
+ mUnlockMethodIntent = (Intent) intent.getParcelableExtra(EXTRA_UNLOCK_METHOD_INTENT);
final int msgId;
final int enableId;
final int disableId;
@@ -136,6 +145,36 @@
setRequirePasswordState(getActivity().getIntent().getBooleanExtra(
EXTRA_REQUIRE_PASSWORD, true));
+
+ Button nextButton = getNextButton();
+ if (nextButton != null) {
+ nextButton.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ startLockIntent();
+ }
+ });
+ }
+ }
+
+ protected void startLockIntent() {
+ if (mUnlockMethodIntent != null) {
+ mUnlockMethodIntent.putExtra(EXTRA_REQUIRE_PASSWORD, mPasswordRequired);
+ startActivityForResult(mUnlockMethodIntent, CHOOSE_LOCK_REQUEST);
+ } else {
+ Log.wtf(TAG, "no unlock intent to start");
+ finish();
+ }
+ }
+
+ @Override
+ public void onActivityResult(int requestCode, int resultCode, Intent data) {
+ super.onActivityResult(requestCode, resultCode, data);
+ if (requestCode == CHOOSE_LOCK_REQUEST &&
+ resultCode == RESULT_FIRST_USER) {
+ getActivity().setResult(RESULT_OK, data);
+ finish();
+ }
}
@Override
@@ -206,15 +245,6 @@
mPasswordRequired = required;
mRequirePasswordToDecryptButton.setChecked(required);
mDontRequirePasswordToDecryptButton.setChecked(!required);
-
- // Updates value returned by SettingsActivity.onActivityResult().
- SettingsActivity sa = (SettingsActivity)getActivity();
- Intent resultIntentData = sa.getResultIntentData();
- if (resultIntentData == null) {
- resultIntentData = new Intent();
- sa.setResultIntentData(resultIntentData);
- }
- resultIntentData.putExtra(EXTRA_REQUIRE_PASSWORD, mPasswordRequired);
}
@Override
diff --git a/src/com/android/settings/InstrumentedFragment.java b/src/com/android/settings/InstrumentedFragment.java
index 44fd110..cc0014d 100644
--- a/src/com/android/settings/InstrumentedFragment.java
+++ b/src/com/android/settings/InstrumentedFragment.java
@@ -32,6 +32,7 @@
public static final int SOUND = UNDECLARED + 2;
public static final int CONFIGURE_NOTIFICATION = UNDECLARED + 3;
public static final int CONFIGURE_WIFI = UNDECLARED + 4;
+ public static final int DISPLAY_SCREEN_ZOOM = UNDECLARED + 5;
/**
* Declare the view of this category.
diff --git a/src/com/android/settings/ResetNetworkConfirm.java b/src/com/android/settings/ResetNetworkConfirm.java
index 9050448..4615a99 100644
--- a/src/com/android/settings/ResetNetworkConfirm.java
+++ b/src/com/android/settings/ResetNetworkConfirm.java
@@ -31,6 +31,7 @@
import android.widget.Button;
import android.widget.Toast;
+import com.android.ims.ImsManager;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.telephony.PhoneConstants;
@@ -94,6 +95,8 @@
btManager.getAdapter().factoryReset();
}
+ ImsManager.factoryReset(context);
+
Toast.makeText(context, R.string.reset_network_complete_toast, Toast.LENGTH_SHORT)
.show();
}
diff --git a/src/com/android/settings/Settings.java b/src/com/android/settings/Settings.java
index 4380d1e..149ef45 100644
--- a/src/com/android/settings/Settings.java
+++ b/src/com/android/settings/Settings.java
@@ -61,6 +61,7 @@
return super.isValidFragment(className);
}
}
+ public static class BackgroundCheckSummaryActivity extends SettingsActivity { /* empty */ }
public static class StorageUseActivity extends SettingsActivity { /* empty */ }
public static class DevelopmentSettingsActivity extends SettingsActivity { /* empty */ }
public static class AccessibilitySettingsActivity extends SettingsActivity { /* empty */ }
diff --git a/src/com/android/settings/SetupChooseLockGeneric.java b/src/com/android/settings/SetupChooseLockGeneric.java
index 0b0333b..9559f8d 100644
--- a/src/com/android/settings/SetupChooseLockGeneric.java
+++ b/src/com/android/settings/SetupChooseLockGeneric.java
@@ -170,9 +170,9 @@
@Override
protected Intent getEncryptionInterstitialIntent(Context context, int quality,
- boolean required) {
+ boolean required, Intent unlockMethodIntent) {
Intent intent = SetupEncryptionInterstitial.createStartIntent(context, quality,
- required);
+ required, unlockMethodIntent);
SetupWizardUtils.copySetupExtras(getActivity().getIntent(), intent);
return intent;
}
diff --git a/src/com/android/settings/SetupEncryptionInterstitial.java b/src/com/android/settings/SetupEncryptionInterstitial.java
index cd943af..8d061ec 100644
--- a/src/com/android/settings/SetupEncryptionInterstitial.java
+++ b/src/com/android/settings/SetupEncryptionInterstitial.java
@@ -38,9 +38,9 @@
public class SetupEncryptionInterstitial extends EncryptionInterstitial {
public static Intent createStartIntent(Context ctx, int quality,
- boolean requirePasswordDefault) {
+ boolean requirePasswordDefault, Intent unlockMethodIntent) {
Intent startIntent = EncryptionInterstitial.createStartIntent(ctx, quality,
- requirePasswordDefault);
+ requirePasswordDefault, unlockMethodIntent);
startIntent.setClass(ctx, SetupEncryptionInterstitial.class);
startIntent.putExtra(EXTRA_PREFS_SHOW_BUTTON_BAR, false)
.putExtra(EXTRA_SHOW_FRAGMENT_TITLE_RESID, -1);
@@ -102,12 +102,7 @@
@Override
public void onNavigateNext() {
- final SetupEncryptionInterstitial activity =
- (SetupEncryptionInterstitial) getActivity();
- if (activity != null) {
- activity.setResult(RESULT_OK, activity.getResultIntentData());
- finish();
- }
+ startLockIntent();
}
}
}
diff --git a/src/com/android/settings/accessibility/AccessibilitySettings.java b/src/com/android/settings/accessibility/AccessibilitySettings.java
index b2ccdd1..672582d 100644
--- a/src/com/android/settings/accessibility/AccessibilitySettings.java
+++ b/src/com/android/settings/accessibility/AccessibilitySettings.java
@@ -85,6 +85,8 @@
"toggle_lock_screen_rotation_preference";
private static final String TOGGLE_SPEAK_PASSWORD_PREFERENCE =
"toggle_speak_password_preference";
+ private static final String TOGGLE_LARGE_POINTER_ICON =
+ "toggle_large_pointer_icon";
private static final String SELECT_LONG_PRESS_TIMEOUT_PREFERENCE =
"select_long_press_timeout_preference";
private static final String ENABLE_ACCESSIBILITY_GESTURE_PREFERENCE_SCREEN =
@@ -181,6 +183,7 @@
private SwitchPreference mTogglePowerButtonEndsCallPreference;
private SwitchPreference mToggleLockScreenRotationPreference;
private SwitchPreference mToggleSpeakPasswordPreference;
+ private SwitchPreference mToggleLargePointerIconPreference;
private ListPreference mSelectLongPressTimeoutPreference;
private Preference mNoServicesMessagePreference;
private PreferenceScreen mCaptioningPreferenceScreen;
@@ -278,6 +281,9 @@
} else if (mToggleSpeakPasswordPreference == preference) {
handleToggleSpeakPasswordPreferenceClick();
return true;
+ } else if (mToggleLargePointerIconPreference == preference) {
+ handleToggleLargePointerIconPreferenceClick();
+ return true;
} else if (mGlobalGesturePreferenceScreen == preference) {
handleToggleEnableAccessibilityGesturePreferenceClick();
return true;
@@ -322,6 +328,12 @@
mToggleSpeakPasswordPreference.isChecked() ? 1 : 0);
}
+ private void handleToggleLargePointerIconPreferenceClick() {
+ Settings.Secure.putInt(getContentResolver(),
+ Settings.Secure.ACCESSIBILITY_LARGE_POINTER_ICON,
+ mToggleLargePointerIconPreference.isChecked() ? 1 : 0);
+ }
+
private void handleToggleEnableAccessibilityGesturePreferenceClick() {
Bundle extras = mGlobalGesturePreferenceScreen.getExtras();
extras.putString(EXTRA_TITLE, getString(
@@ -379,6 +391,10 @@
mToggleSpeakPasswordPreference =
(SwitchPreference) findPreference(TOGGLE_SPEAK_PASSWORD_PREFERENCE);
+ // Large pointer icon.
+ mToggleLargePointerIconPreference =
+ (SwitchPreference) findPreference(TOGGLE_LARGE_POINTER_ICON);
+
// Long press timeout.
mSelectLongPressTimeoutPreference =
(ListPreference) findPreference(SELECT_LONG_PRESS_TIMEOUT_PREFERENCE);
@@ -565,6 +581,10 @@
Settings.Secure.ACCESSIBILITY_SPEAK_PASSWORD, 0) != 0;
mToggleSpeakPasswordPreference.setChecked(speakPasswordEnabled);
+ // Large pointer icon.
+ mToggleLargePointerIconPreference.setChecked(Settings.Secure.getInt(getContentResolver(),
+ Settings.Secure.ACCESSIBILITY_LARGE_POINTER_ICON, 0) != 0);
+
// Long press timeout.
final int longPressTimeout = Settings.Secure.getInt(getContentResolver(),
Settings.Secure.LONG_PRESS_TIMEOUT, mLongPressTimeoutDefault);
diff --git a/src/com/android/settings/applications/AppOpsCategory.java b/src/com/android/settings/applications/AppOpsCategory.java
index 3ccd6bb..4b54891 100644
--- a/src/com/android/settings/applications/AppOpsCategory.java
+++ b/src/com/android/settings/applications/AppOpsCategory.java
@@ -16,6 +16,7 @@
package com.android.settings.applications;
+import android.app.AppOpsManager;
import android.app.ListFragment;
import android.app.LoaderManager;
import android.content.AsyncTaskLoader;
@@ -34,6 +35,7 @@
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.ListView;
+import android.widget.Switch;
import android.widget.TextView;
import com.android.settings.R;
@@ -48,6 +50,7 @@
private static final int RESULT_APP_DETAILS = 1;
AppOpsState mState;
+ boolean mUserControlled;
// This is the Adapter being used to display the list's data.
AppListAdapter mAdapter;
@@ -58,8 +61,13 @@
}
public AppOpsCategory(AppOpsState.OpsTemplate template) {
+ this(template, false);
+ }
+
+ public AppOpsCategory(AppOpsState.OpsTemplate template, boolean userControlled) {
Bundle args = new Bundle();
args.putParcelable("template", template);
+ args.putBoolean("userControlled", userControlled);
setArguments(args);
}
@@ -117,18 +125,22 @@
final InterestingConfigChanges mLastConfig = new InterestingConfigChanges();
final AppOpsState mState;
final AppOpsState.OpsTemplate mTemplate;
+ final boolean mUserControlled;
List<AppOpEntry> mApps;
PackageIntentReceiver mPackageObserver;
- public AppListLoader(Context context, AppOpsState state, AppOpsState.OpsTemplate template) {
+ public AppListLoader(Context context, AppOpsState state, AppOpsState.OpsTemplate template,
+ boolean userControlled) {
super(context);
mState = state;
mTemplate = template;
+ mUserControlled = userControlled;
}
@Override public List<AppOpEntry> loadInBackground() {
- return mState.buildState(mTemplate);
+ return mState.buildState(mTemplate, 0, null,
+ mUserControlled ? AppOpsState.LABEL_COMPARATOR : AppOpsState.RECENCY_COMPARATOR);
}
/**
@@ -247,13 +259,15 @@
private final Resources mResources;
private final LayoutInflater mInflater;
private final AppOpsState mState;
+ private final boolean mUserControlled;
List<AppOpEntry> mList;
- public AppListAdapter(Context context, AppOpsState state) {
+ public AppListAdapter(Context context, AppOpsState state, boolean userControlled) {
mResources = context.getResources();
mInflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
mState = state;
+ mUserControlled = userControlled;
}
public void setData(List<AppOpEntry> data) {
@@ -292,9 +306,18 @@
((ImageView)view.findViewById(R.id.app_icon)).setImageDrawable(
item.getAppEntry().getIcon());
((TextView)view.findViewById(R.id.app_name)).setText(item.getAppEntry().getLabel());
- ((TextView)view.findViewById(R.id.op_name)).setText(item.getSummaryText(mState));
- ((TextView)view.findViewById(R.id.op_time)).setText(
- item.getTimeText(mResources, false));
+ if (mUserControlled) {
+ ((TextView) view.findViewById(R.id.op_name)).setText(
+ item.getTimeText(mResources, false));
+ view.findViewById(R.id.op_time).setVisibility(View.GONE);
+ ((Switch) view.findViewById(R.id.op_switch)).setChecked(
+ item.getPrimaryOpMode() == AppOpsManager.MODE_ALLOWED);
+ } else {
+ ((TextView) view.findViewById(R.id.op_name)).setText(item.getSummaryText(mState));
+ ((TextView) view.findViewById(R.id.op_time)).setText(
+ item.getTimeText(mResources, false));
+ view.findViewById(R.id.op_switch).setVisibility(View.GONE);
+ }
return view;
}
@@ -304,6 +327,7 @@
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mState = new AppOpsState(getActivity());
+ mUserControlled = getArguments().getBoolean("userControlled");
}
@Override public void onActivityCreated(Bundle savedInstanceState) {
@@ -317,7 +341,7 @@
setHasOptionsMenu(true);
// Create an empty adapter we will use to display the loaded data.
- mAdapter = new AppListAdapter(getActivity(), mState);
+ mAdapter = new AppListAdapter(getActivity(), mState, mUserControlled);
setListAdapter(mAdapter);
// Start out with a progress indicator.
@@ -341,8 +365,22 @@
@Override public void onListItemClick(ListView l, View v, int position, long id) {
AppOpEntry entry = mAdapter.getItem(position);
if (entry != null) {
- mCurrentPkgName = entry.getAppEntry().getApplicationInfo().packageName;
- startApplicationDetailsActivity();
+ if (mUserControlled) {
+ // We treat this as tapping on the check box, toggling the app op state.
+ Switch sw = ((Switch) v.findViewById(R.id.op_switch));
+ boolean checked = !sw.isChecked();
+ sw.setChecked(checked);
+ AppOpsManager.OpEntry op = entry.getOpEntry(0);
+ int mode = checked ? AppOpsManager.MODE_ALLOWED : AppOpsManager.MODE_IGNORED;
+ mState.getAppOpsManager().setMode(op.getOp(),
+ entry.getAppEntry().getApplicationInfo().uid,
+ entry.getAppEntry().getApplicationInfo().packageName,
+ mode);
+ entry.overridePrimaryOpMode(mode);
+ } else {
+ mCurrentPkgName = entry.getAppEntry().getApplicationInfo().packageName;
+ startApplicationDetailsActivity();
+ }
}
}
@@ -352,7 +390,7 @@
if (fargs != null) {
template = (AppOpsState.OpsTemplate)fargs.getParcelable("template");
}
- return new AppListLoader(getActivity(), mState, template);
+ return new AppListLoader(getActivity(), mState, template, mUserControlled);
}
@Override public void onLoadFinished(Loader<List<AppOpEntry>> loader, List<AppOpEntry> data) {
diff --git a/src/com/android/settings/applications/AppOpsState.java b/src/com/android/settings/applications/AppOpsState.java
index c3189d6..237eac6 100644
--- a/src/com/android/settings/applications/AppOpsState.java
+++ b/src/com/android/settings/applications/AppOpsState.java
@@ -180,6 +180,7 @@
false,
false,
false,
+ false,
false }
);
@@ -206,9 +207,14 @@
false }
);
+ public static final OpsTemplate RUN_IN_BACKGROUND_TEMPLATE = new OpsTemplate(
+ new int[] { AppOpsManager.OP_RUN_IN_BACKGROUND },
+ new boolean[] { false }
+ );
+
public static final OpsTemplate[] ALL_TEMPLATES = new OpsTemplate[] {
LOCATION_TEMPLATE, PERSONAL_TEMPLATE, MESSAGING_TEMPLATE,
- MEDIA_TEMPLATE, DEVICE_TEMPLATE
+ MEDIA_TEMPLATE, DEVICE_TEMPLATE, RUN_IN_BACKGROUND_TEMPLATE
};
/**
@@ -306,6 +312,7 @@
= new ArrayList<AppOpsManager.OpEntry>();
private final AppEntry mApp;
private final int mSwitchOrder;
+ private int mOverriddenPrimaryMode = -1;
public AppOpEntry(AppOpsManager.PackageOps pkg, AppOpsManager.OpEntry op, AppEntry app,
int switchOrder) {
@@ -363,6 +370,14 @@
return mOps.get(pos);
}
+ public int getPrimaryOpMode() {
+ return mOverriddenPrimaryMode >= 0 ? mOverriddenPrimaryMode : mOps.get(0).getMode();
+ }
+
+ public void overridePrimaryOpMode(int mode) {
+ mOverriddenPrimaryMode = mode;
+ }
+
private CharSequence getCombinedText(ArrayList<AppOpsManager.OpEntry> ops,
CharSequence[] items) {
if (ops.size() == 1) {
@@ -418,9 +433,9 @@
}
/**
- * Perform alphabetical comparison of application entry objects.
+ * Perform app op state comparison of application entry objects.
*/
- public static final Comparator<AppOpEntry> APP_OP_COMPARATOR = new Comparator<AppOpEntry>() {
+ public static final Comparator<AppOpEntry> RECENCY_COMPARATOR = new Comparator<AppOpEntry>() {
private final Collator sCollator = Collator.getInstance();
@Override
public int compare(AppOpEntry object1, AppOpEntry object2) {
@@ -440,6 +455,18 @@
}
};
+ /**
+ * Perform alphabetical comparison of application entry objects.
+ */
+ public static final Comparator<AppOpEntry> LABEL_COMPARATOR = new Comparator<AppOpEntry>() {
+ private final Collator sCollator = Collator.getInstance();
+ @Override
+ public int compare(AppOpEntry object1, AppOpEntry object2) {
+ return sCollator.compare(object1.getAppEntry().getLabel(),
+ object2.getAppEntry().getLabel());
+ }
+ };
+
private void addOp(List<AppOpEntry> entries, AppOpsManager.PackageOps pkgOps,
AppEntry appEntry, AppOpsManager.OpEntry opEntry, boolean allowMerge, int switchOrder) {
if (allowMerge && entries.size() > 0) {
@@ -466,8 +493,12 @@
entries.add(entry);
}
+ public AppOpsManager getAppOpsManager() {
+ return mAppOps;
+ }
+
public List<AppOpEntry> buildState(OpsTemplate tpl) {
- return buildState(tpl, 0, null);
+ return buildState(tpl, 0, null, RECENCY_COMPARATOR);
}
private AppEntry getAppEntry(final Context context, final HashMap<String, AppEntry> appEntries,
@@ -492,6 +523,11 @@
}
public List<AppOpEntry> buildState(OpsTemplate tpl, int uid, String packageName) {
+ return buildState(tpl, uid, packageName, RECENCY_COMPARATOR);
+ }
+
+ public List<AppOpEntry> buildState(OpsTemplate tpl, int uid, String packageName,
+ Comparator<AppOpEntry> comparator) {
final Context context = mContext;
final HashMap<String, AppEntry> appEntries = new HashMap<String, AppEntry>();
@@ -593,7 +629,7 @@
}
// Sort the list.
- Collections.sort(entries, APP_OP_COMPARATOR);
+ Collections.sort(entries, comparator);
// Done!
return entries;
diff --git a/src/com/android/settings/applications/BackgroundCheckSummary.java b/src/com/android/settings/applications/BackgroundCheckSummary.java
new file mode 100644
index 0000000..dfd4c49
--- /dev/null
+++ b/src/com/android/settings/applications/BackgroundCheckSummary.java
@@ -0,0 +1,66 @@
+/**
+ * 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.
+ */
+
+package com.android.settings.applications;
+
+import android.app.Fragment;
+import android.app.FragmentManager;
+import android.app.FragmentTransaction;
+import android.content.res.TypedArray;
+import android.os.Bundle;
+import android.preference.PreferenceFrameLayout;
+import android.support.v13.app.FragmentPagerAdapter;
+import android.support.v4.view.PagerTabStrip;
+import android.support.v4.view.ViewPager;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+import com.android.internal.logging.MetricsLogger;
+import com.android.settings.InstrumentedFragment;
+import com.android.settings.R;
+
+public class BackgroundCheckSummary extends InstrumentedFragment {
+ // layout inflater object used to inflate views
+ private LayoutInflater mInflater;
+
+ @Override
+ protected int getMetricsCategory() {
+ return MetricsLogger.BACKGROUND_CHECK_SUMMARY;
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
+ // initialize the inflater
+ mInflater = inflater;
+
+ View rootView = mInflater.inflate(R.layout.background_check_summary,
+ container, false);
+
+ // We have to do this now because PreferenceFrameLayout looks at it
+ // only when the view is added.
+ if (container instanceof PreferenceFrameLayout) {
+ ((PreferenceFrameLayout.LayoutParams) rootView.getLayoutParams()).removeBorders = true;
+ }
+
+ FragmentTransaction ft = getChildFragmentManager().beginTransaction();
+ ft.add(R.id.appops_content, new AppOpsCategory(AppOpsState.RUN_IN_BACKGROUND_TEMPLATE,
+ true), "appops");
+ ft.commitAllowingStateLoss();
+
+ return rootView;
+ }
+}
diff --git a/src/com/android/settings/display/DisplayDensityUtils.java b/src/com/android/settings/display/DisplayDensityUtils.java
new file mode 100644
index 0000000..cef5418
--- /dev/null
+++ b/src/com/android/settings/display/DisplayDensityUtils.java
@@ -0,0 +1,240 @@
+/*
+ * 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.
+ */
+
+package com.android.settings.display;
+
+import com.android.settings.R;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.os.AsyncTask;
+import android.os.RemoteException;
+import android.util.DisplayMetrics;
+import android.util.Log;
+import android.util.MathUtils;
+import android.view.Display;
+import android.view.IWindowManager;
+import android.view.WindowManagerGlobal;
+
+import java.util.Arrays;
+
+/**
+ * Utility methods for working with display density.
+ */
+class DisplayDensityUtils {
+ private static final String LOG_TAG = "DisplayDensityUtils";
+
+ /** Minimum increment between density scales. */
+ private static final float MIN_SCALE_INTERVAL = 0.09f;
+
+ /** Minimum density scale. This is available on all devices. */
+ private static final float MIN_SCALE = 0.85f;
+
+ /** Maximum density scale. The actual scale used depends on the device. */
+ private static final float MAX_SCALE = 1.50f;
+
+ /** Summary used for "normal" scale. */
+ private static final int SUMMARY_NORMAL = R.string.screen_zoom_summary_normal;
+
+ /** Summary used for "custom" scale. */
+ private static final int SUMMARY_CUSTOM = R.string.screen_zoom_summary_custom;
+
+ /**
+ * Summaries for scales smaller than "normal" in order of smallest to
+ * largest.
+ */
+ private static final int[] SUMMARIES_SMALLER = new int[] {
+ R.string.screen_zoom_summary_small
+ };
+
+ /**
+ * Summaries for scales larger than "normal" in order of smallest to
+ * largest.
+ */
+ private static final int[] SUMMARIES_LARGER = new int[] {
+ R.string.screen_zoom_summary_large,
+ R.string.screen_zoom_summary_very_large,
+ R.string.screen_zoom_summary_extremely_large,
+ };
+
+ /**
+ * Minimum allowed screen dimension, corresponds to resource qualifiers
+ * "small" or "sw320dp". This value must be at least the minimum screen
+ * size required by the CDD so that we meet developer expectations.
+ */
+ private static final int MIN_DIMENSION_DP = 320;
+
+ private final String[] mEntries;
+ private final int[] mValues;
+
+ private final int mNormalDensity;
+ private final int mCurrentIndex;
+
+ public DisplayDensityUtils(Context context) {
+ final int normalDensity = DisplayDensityUtils.getNormalDisplayDensity(
+ Display.DEFAULT_DISPLAY);
+ if (normalDensity <= 0) {
+ mEntries = null;
+ mValues = null;
+ mNormalDensity = 0;
+ mCurrentIndex = -1;
+ return;
+ }
+
+ final Resources res = context.getResources();
+ final DisplayMetrics metrics = res.getDisplayMetrics();
+ final int currentDensity = metrics.densityDpi;
+ int currentDensityIndex = -1;
+
+ // Compute number of "larger" and "smaller" scales for this display.
+ final int minDimensionPx = Math.min(metrics.widthPixels, metrics.heightPixels);
+ final int maxDensity = DisplayMetrics.DENSITY_MEDIUM * minDimensionPx / MIN_DIMENSION_DP;
+ final float maxScale = Math.min(MAX_SCALE, maxDensity / (float) normalDensity);
+ final float minScale = MIN_SCALE;
+ final int numLarger = (int) MathUtils.constrain((maxScale - 1) / MIN_SCALE_INTERVAL,
+ 0, SUMMARIES_LARGER.length);
+ final int numSmaller = (int) MathUtils.constrain((1 - minScale) / MIN_SCALE_INTERVAL,
+ 0, SUMMARIES_SMALLER.length);
+
+ String[] entries = new String[1 + numSmaller + numLarger];
+ int[] values = new int[entries.length];
+ int curIndex = 0;
+
+ if (numSmaller > 0) {
+ final float interval = (1 - minScale) / numSmaller;
+ for (int i = numSmaller - 1; i >= 0; i--) {
+ final int density = (int) (normalDensity * (1 - (i + 1) * interval));
+ if (currentDensity == density) {
+ currentDensityIndex = curIndex;
+ }
+ entries[curIndex] = res.getString(SUMMARIES_SMALLER[i]);
+ values[curIndex] = density;
+ curIndex++;
+ }
+ }
+
+ if (currentDensity == normalDensity) {
+ currentDensityIndex = curIndex;
+ }
+ values[curIndex] = normalDensity;
+ entries[curIndex] = res.getString(SUMMARY_NORMAL);
+ curIndex++;
+
+ if (numLarger > 0) {
+ final float interval = (maxScale - 1) / numLarger;
+ for (int i = 0; i < numLarger; i++) {
+ final int density = (int) (normalDensity * (1 + (i + 1) * interval));
+ if (currentDensity == density) {
+ currentDensityIndex = curIndex;
+ }
+ values[curIndex] = density;
+ entries[curIndex] = res.getString(SUMMARIES_LARGER[i]);
+ curIndex++;
+ }
+ }
+
+ final int displayIndex;
+ if (currentDensityIndex >= 0) {
+ displayIndex = currentDensityIndex;
+ } else {
+ // We don't understand the current density. Must have been set by
+ // someone else. Make room for another entry...
+ values = Arrays.copyOf(values, values.length + 1);
+ values[curIndex] = currentDensity;
+
+ entries = Arrays.copyOf(entries, values.length + 1);
+ entries[curIndex] = res.getString(SUMMARY_CUSTOM, currentDensity);
+
+ displayIndex = curIndex;
+ }
+
+ mNormalDensity = normalDensity;
+ mCurrentIndex = displayIndex;
+ mEntries = entries;
+ mValues = values;
+ }
+
+ public String[] getEntries() {
+ return mEntries;
+ }
+
+ public int[] getValues() {
+ return mValues;
+ }
+
+ public int getCurrentIndex() {
+ return mCurrentIndex;
+ }
+
+ public int getNormalDensity() {
+ return mNormalDensity;
+ }
+
+ /**
+ * Returns the normal (default) density for the specified display.
+ *
+ * @param displayId the identifier of the display
+ * @return the normal density of the specified display, or {@code -1} if
+ * the display does not exist or the density could not be obtained
+ */
+ private static int getNormalDisplayDensity(int displayId) {
+ try {
+ final IWindowManager wm = WindowManagerGlobal.getWindowManagerService();
+ return wm.getInitialDisplayDensity(displayId);
+ } catch (RemoteException exc) {
+ return -1;
+ }
+ }
+
+ /**
+ * Asynchronously applies display density changes to the specified display.
+ *
+ * @param displayId the identifier of the display to modify
+ */
+ public static void clearForcedDisplayDensity(final int displayId) {
+ AsyncTask.execute(new Runnable() {
+ @Override
+ public void run() {
+ try {
+ final IWindowManager wm = WindowManagerGlobal.getWindowManagerService();
+ wm.clearForcedDisplayDensity(displayId);
+ } catch (RemoteException exc) {
+ Log.w(LOG_TAG, "Unable to clear forced display density setting");
+ }
+ }
+ });
+ }
+
+ /**
+ * Asynchronously applies display density changes to the specified display.
+ *
+ * @param displayId the identifier of the display to modify
+ * @param density the density to force for the specified display
+ */
+ public static void setForcedDisplayDensity(final int displayId, final int density) {
+ AsyncTask.execute(new Runnable() {
+ @Override
+ public void run() {
+ try {
+ final IWindowManager wm = WindowManagerGlobal.getWindowManagerService();
+ wm.setForcedDisplayDensity(displayId, density);
+ } catch (RemoteException exc) {
+ Log.w(LOG_TAG, "Unable to save forced display density setting");
+ }
+ }
+ });
+ }
+}
diff --git a/src/com/android/settings/display/ScreenZoomPreference.java b/src/com/android/settings/display/ScreenZoomPreference.java
new file mode 100644
index 0000000..78cc49c
--- /dev/null
+++ b/src/com/android/settings/display/ScreenZoomPreference.java
@@ -0,0 +1,53 @@
+/*
+ * 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
+ */
+
+package com.android.settings.display;
+
+import android.content.Context;
+import android.content.Intent;
+import android.support.v4.content.res.TypedArrayUtils;
+import android.support.v7.preference.PreferenceGroup;
+import android.util.AttributeSet;
+
+/**
+ * Preference for changing the density of the display on which the preference
+ * is visible.
+ */
+public class ScreenZoomPreference extends PreferenceGroup {
+ public ScreenZoomPreference(Context context, AttributeSet attrs) {
+ super(context, attrs, TypedArrayUtils.getAttr(context,
+ android.support.v7.preference.R.attr.preferenceScreenStyle,
+ android.R.attr.preferenceScreenStyle));
+
+ setFragment("com.android.settings.display.ScreenZoomSettings");
+
+ final DisplayDensityUtils density = new DisplayDensityUtils(context);
+ final int defaultIndex = density.getCurrentIndex();
+ if (defaultIndex < 0) {
+ setVisible(false);
+ setEnabled(false);
+ } else {
+ final String[] entries = density.getEntries();
+ final int currentIndex = density.getCurrentIndex();
+ setSummary(entries[currentIndex]);
+ }
+ }
+
+ @Override
+ protected boolean isOnSameScreenAsChildren() {
+ return false;
+ }
+}
diff --git a/src/com/android/settings/display/ScreenZoomSettings.java b/src/com/android/settings/display/ScreenZoomSettings.java
new file mode 100644
index 0000000..1ddcaab
--- /dev/null
+++ b/src/com/android/settings/display/ScreenZoomSettings.java
@@ -0,0 +1,272 @@
+/*
+ * 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.
+ */
+
+package com.android.settings.display;
+
+import com.android.settings.InstrumentedFragment;
+import com.android.settings.R;
+import com.android.settings.SettingsPreferenceFragment;
+import com.android.settings.search.BaseSearchIndexProvider;
+import com.android.settings.search.Indexable;
+import com.android.settings.search.SearchIndexableRaw;
+
+import android.annotation.Nullable;
+import android.content.Context;
+import android.content.res.Configuration;
+import android.content.res.Resources;
+import android.os.Bundle;
+import android.view.Display;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.view.ViewGroup;
+import android.view.animation.AccelerateInterpolator;
+import android.view.animation.DecelerateInterpolator;
+import android.view.animation.Interpolator;
+import android.widget.FrameLayout;
+import android.widget.SeekBar;
+import android.widget.SeekBar.OnSeekBarChangeListener;
+import android.widget.TextView;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Preference fragment used to control screen zoom.
+ */
+public class ScreenZoomSettings extends SettingsPreferenceFragment implements Indexable {
+ /** Duration to use when cross-fading between previews. */
+ private static final long CROSS_FADE_DURATION_MS = 400;
+
+ /** Interpolator to use when cross-fading between previews. */
+ private static final Interpolator FADE_IN_INTERPOLATOR = new DecelerateInterpolator();
+
+ /** Interpolator to use when cross-fading between previews. */
+ private static final Interpolator FADE_OUT_INTERPOLATOR = new AccelerateInterpolator();
+
+ private ViewGroup mPreviewFrame;
+ private TextView mLabel;
+ private View mLarger;
+ private View mSmaller;
+
+ private String[] mEntries;
+ private int[] mValues;
+ private int mNormalDensity;
+ private int mInitialIndex;
+
+ private int mCurrentIndex;
+
+ @Override
+ public void onCreate(@Nullable Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ final DisplayDensityUtils density = new DisplayDensityUtils(getContext());
+
+ final int initialIndex = density.getCurrentIndex();
+ if (initialIndex < 0) {
+ // Failed to obtain normal density, which means we failed to
+ // connect to the window manager service. Just use the current
+ // density and don't let the user change anything.
+ final int densityDpi = getResources().getDisplayMetrics().densityDpi;
+ mValues = new int[] { densityDpi };
+ mEntries = new String[] { getString(R.string.screen_zoom_summary_normal) };
+ mInitialIndex = 0;
+ mNormalDensity = densityDpi;
+ } else {
+ mValues = density.getValues();
+ mEntries = density.getEntries();
+ mInitialIndex = initialIndex;
+ mNormalDensity = density.getNormalDensity();
+ }
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ final View root = super.onCreateView(inflater, container, savedInstanceState);
+ final ViewGroup list_container = (ViewGroup) root.findViewById(android.R.id.list_container);
+ list_container.removeAllViews();
+
+ final View content = inflater.inflate(R.layout.screen_zoom_activity, list_container, false);
+ list_container.addView(content);
+
+ mLabel = (TextView) content.findViewById(R.id.current_density);
+
+ // The maximum SeekBar value always needs to be non-zero. If there's
+ // only one available zoom level, we'll handle this by disabling the
+ // seek bar.
+ final int max = Math.max(1, mValues.length - 1);
+
+ final SeekBar seekBar = (SeekBar) content.findViewById(R.id.seek_bar);
+ seekBar.setMax(max);
+ seekBar.setProgress(mInitialIndex);
+ seekBar.setOnSeekBarChangeListener(new OnSeekBarChangeListener() {
+ @Override
+ public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
+ setPreviewLayer(progress, true);
+ }
+
+ @Override
+ public void onStartTrackingTouch(SeekBar seekBar) {}
+
+ @Override
+ public void onStopTrackingTouch(SeekBar seekBar) {}
+ });
+
+ mSmaller = content.findViewById(R.id.smaller);
+ mSmaller.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ final int progress = seekBar.getProgress();
+ if (progress > 0) {
+ seekBar.setProgress(progress - 1, true);
+ }
+ }
+ });
+
+ mLarger = content.findViewById(R.id.larger);
+ mLarger.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ final int progress = seekBar.getProgress();
+ if (progress < seekBar.getMax()) {
+ seekBar.setProgress(progress + 1, true);
+ }
+ }
+ });
+
+ if (mValues.length == 1) {
+ // The larger and smaller buttons will be disabled when we call
+ // setPreviewLayer() later in this method.
+ seekBar.setEnabled(false);
+ }
+
+ mPreviewFrame = (FrameLayout) content.findViewById(R.id.preview_frame);
+
+ // Populate the sample layouts.
+ final Context context = getContext();
+ final Configuration origConfig = context.getResources().getConfiguration();
+ for (int mValue : mValues) {
+ final Configuration config = new Configuration(origConfig);
+ config.densityDpi = mValue;
+
+ // Create a new configuration for the specified density. It won't
+ // have any theme set, so manually apply the current theme.
+ final Context configContext = context.createConfigurationContext(config);
+ configContext.setTheme(context.getThemeResId());
+
+ final LayoutInflater configInflater = LayoutInflater.from(configContext);
+ final View sampleView = configInflater.inflate(
+ R.layout.screen_zoom_preview, mPreviewFrame, false);
+ sampleView.setAlpha(0);
+ sampleView.setVisibility(View.INVISIBLE);
+
+ mPreviewFrame.addView(sampleView);
+ }
+
+ setPreviewLayer(mInitialIndex, false);
+
+ return root;
+ }
+
+ @Override
+ public void onDetach() {
+ super.onDetach();
+
+ // This will adjust the density SLIGHTLY after the activity has
+ // finished, which could be considered a feature or a bug...
+ commit();
+ }
+
+ private void setPreviewLayer(int index, boolean animate) {
+ mLabel.setText(mEntries[index]);
+
+ if (mCurrentIndex >= 0) {
+ final View lastLayer = mPreviewFrame.getChildAt(mCurrentIndex);
+ if (animate) {
+ lastLayer.animate()
+ .alpha(0)
+ .setInterpolator(FADE_OUT_INTERPOLATOR)
+ .setDuration(CROSS_FADE_DURATION_MS)
+ .withEndAction(new Runnable() {
+ @Override
+ public void run() {
+ lastLayer.setVisibility(View.INVISIBLE);
+ }
+ });
+ } else {
+ lastLayer.setAlpha(0);
+ lastLayer.setVisibility(View.INVISIBLE);
+ }
+ }
+
+ final View nextLayer = mPreviewFrame.getChildAt(index);
+ if (animate) {
+ nextLayer.animate()
+ .alpha(1)
+ .setInterpolator(FADE_IN_INTERPOLATOR)
+ .setDuration(CROSS_FADE_DURATION_MS)
+ .withStartAction(new Runnable() {
+ @Override
+ public void run() {
+ nextLayer.setVisibility(View.VISIBLE);
+ }
+ });
+ } else {
+ nextLayer.setVisibility(View.VISIBLE);
+ nextLayer.setAlpha(1);
+ }
+
+ mSmaller.setEnabled(index > 0);
+ mLarger.setEnabled(index < mEntries.length - 1);
+
+ mCurrentIndex = index;
+ }
+
+ /**
+ * Persists the selected density and sends a configuration change.
+ */
+ private void commit() {
+ final int densityDpi = mValues[mCurrentIndex];
+ if (densityDpi == mNormalDensity) {
+ DisplayDensityUtils.clearForcedDisplayDensity(Display.DEFAULT_DISPLAY);
+ } else {
+ DisplayDensityUtils.setForcedDisplayDensity(Display.DEFAULT_DISPLAY, densityDpi);
+ }
+ }
+
+ @Override
+ protected int getMetricsCategory() {
+ return InstrumentedFragment.DISPLAY_SCREEN_ZOOM;
+ }
+
+ /** Index provider used to expose this fragment in search. */
+ public static final SearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
+ new BaseSearchIndexProvider() {
+ @Override
+ public List<SearchIndexableRaw> getRawDataToIndex(Context context, boolean enabled) {
+ final Resources res = context.getResources();
+ final SearchIndexableRaw data = new SearchIndexableRaw(context);
+ data.title = res.getString(R.string.screen_zoom_title);
+ data.screenTitle = res.getString(R.string.screen_zoom_title);
+ data.keywords = res.getString(R.string.screen_zoom_keywords);
+
+ final List<SearchIndexableRaw> result = new ArrayList<>(1);
+ result.add(data);
+ return result;
+ }
+ };
+}
diff --git a/src/com/android/settings/display/TouchBlockingFrameLayout.java b/src/com/android/settings/display/TouchBlockingFrameLayout.java
new file mode 100644
index 0000000..3f5483d
--- /dev/null
+++ b/src/com/android/settings/display/TouchBlockingFrameLayout.java
@@ -0,0 +1,42 @@
+/*
+ * 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.
+ */
+
+package com.android.settings.display;
+
+import android.annotation.Nullable;
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.MotionEvent;
+import android.widget.FrameLayout;
+
+/**
+ * Extension of FrameLayout that consumes all touch events.
+ */
+public class TouchBlockingFrameLayout extends FrameLayout {
+ public TouchBlockingFrameLayout(Context context, @Nullable AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ @Override
+ public boolean onInterceptTouchEvent(MotionEvent ev) {
+ return true;
+ }
+
+ @Override
+ public boolean onTouchEvent(MotionEvent event) {
+ return true;
+ }
+}
diff --git a/src/com/android/settings/location/LocationSettings.java b/src/com/android/settings/location/LocationSettings.java
index 2ed48e9..9974e89 100644
--- a/src/com/android/settings/location/LocationSettings.java
+++ b/src/com/android/settings/location/LocationSettings.java
@@ -17,7 +17,9 @@
package com.android.settings.location;
import android.app.Activity;
+import android.app.admin.DevicePolicyManager;
import android.content.BroadcastReceiver;
+import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
@@ -30,6 +32,7 @@
import android.support.v7.preference.PreferenceCategory;
import android.support.v7.preference.PreferenceGroup;
import android.support.v7.preference.PreferenceScreen;
+import android.support.v14.preference.SwitchPreference;
import android.util.Log;
import android.view.Menu;
import android.view.MenuInflater;
@@ -81,16 +84,10 @@
private static final String TAG = "LocationSettings";
/**
- * Key for managed profile location preference category. Category is shown only
- * if there is a managed profile
+ * Key for managed profile location switch preference. Shown only
+ * if there is a managed profile.
*/
- private static final String KEY_MANAGED_PROFILE_CATEGORY = "managed_profile_location_category";
- /**
- * Key for managed profile location preference. Note it used to be a switch pref and we had to
- * keep the key as strings had been submitted for string freeze before the decision to
- * demote this to a simple preference was made. TODO: Candidate for refactoring.
- */
- private static final String KEY_MANAGED_PROFILE_PREFERENCE = "managed_profile_location_switch";
+ private static final String KEY_MANAGED_PROFILE_SWITCH = "managed_profile_location_switch";
/** Key for preference screen "Mode" */
private static final String KEY_LOCATION_MODE = "location_mode";
/** Key for preference category "Recent location requests" */
@@ -104,7 +101,7 @@
private Switch mSwitch;
private boolean mValidListener = false;
private UserHandle mManagedProfile;
- private Preference mManagedProfilePreference;
+ private SwitchPreference mManagedProfileSwitch;
private Preference mLocationMode;
private PreferenceCategory mCategoryRecentLocationRequests;
/** Receives UPDATE_INTENT */
@@ -250,20 +247,39 @@
mManagedProfile = Utils.getManagedProfile(mUm);
if (mManagedProfile == null) {
// There is no managed profile
- root.removePreference(root.findPreference(KEY_MANAGED_PROFILE_CATEGORY));
- mManagedProfilePreference = null;
+ root.removePreference(root.findPreference(KEY_MANAGED_PROFILE_SWITCH));
+ mManagedProfileSwitch = null;
} else {
- mManagedProfilePreference = root.findPreference(KEY_MANAGED_PROFILE_PREFERENCE);
- mManagedProfilePreference.setOnPreferenceClickListener(null);
+ mManagedProfileSwitch = (SwitchPreference)root
+ .findPreference(KEY_MANAGED_PROFILE_SWITCH);
+ mManagedProfileSwitch.setOnPreferenceClickListener(null);
}
}
- private void changeManagedProfileLocationAccessStatus(boolean enabled, int summaryResId) {
- if (mManagedProfilePreference == null) {
+ private void changeManagedProfileLocationAccessStatus(boolean mainSwitchOn) {
+ if (mManagedProfileSwitch == null) {
return;
}
- mManagedProfilePreference.setEnabled(enabled);
- mManagedProfilePreference.setSummary(summaryResId);
+ boolean enabled = mainSwitchOn;
+ int summaryResId = R.string.switch_off_text;
+ if (mUm.hasUserRestriction(UserManager.DISALLOW_SHARE_LOCATION, mManagedProfile)
+ && getAdminRestrictingManagedProfile() != null) {
+ summaryResId = R.string.managed_profile_location_switch_lockdown;
+ enabled = false;
+ }
+
+ mManagedProfileSwitch.setEnabled(enabled);
+ mManagedProfileSwitch.setOnPreferenceClickListener(null);
+ if (!enabled) {
+ mManagedProfileSwitch.setChecked(false);
+ } else {
+ final boolean isRestricted = isManagedProfileRestrictedByBase();
+ mManagedProfileSwitch.setChecked(!isRestricted);
+ summaryResId = (isRestricted ?
+ R.string.switch_off_text : R.string.switch_on_text);
+ mManagedProfileSwitch.setOnPreferenceClickListener(mManagedProfileSwitchClickListener);
+ }
+ mManagedProfileSwitch.setSummary(summaryResId);
}
/**
@@ -374,18 +390,7 @@
}
}
- if (mManagedProfilePreference != null) {
- if (mUm.hasUserRestriction(UserManager.DISALLOW_SHARE_LOCATION, mManagedProfile)) {
- changeManagedProfileLocationAccessStatus(false,
- R.string.managed_profile_location_switch_lockdown);
- } else {
- if (enabled) {
- changeManagedProfileLocationAccessStatus(true, R.string.switch_on_text);
- } else {
- changeManagedProfileLocationAccessStatus(false, R.string.switch_off_text);
- }
- }
- }
+ changeManagedProfileLocationAccessStatus(enabled);
// As a safety measure, also reloads on location mode change to ensure the settings are
// up-to-date even if an affected app doesn't send the setting changed broadcast.
@@ -404,6 +409,47 @@
}
}
+ private ComponentName getAdminRestrictingManagedProfile() {
+ if (mManagedProfile == null) {
+ return null;
+ }
+ DevicePolicyManager dpm = (DevicePolicyManager)getActivity().getSystemService(
+ Context.DEVICE_POLICY_SERVICE);
+ if (dpm == null) {
+ return null;
+ }
+ List<ComponentName> admins = dpm.getActiveAdminsAsUser(mManagedProfile.getIdentifier());
+ for (int i = 0; i < admins.size(); ++i) {
+ final ComponentName admin = admins.get(i);
+ Bundle restrictions = dpm.getUserRestrictions(admin, mManagedProfile.getIdentifier());
+ if (restrictions != null && restrictions.getBoolean(UserManager.DISALLOW_SHARE_LOCATION,
+ false)) {
+ return admin;
+ }
+ }
+ return null;
+ }
+
+ private boolean isManagedProfileRestrictedByBase() {
+ if (mManagedProfile == null) {
+ return false;
+ }
+ return mUm.hasBaseUserRestriction(UserManager.DISALLOW_SHARE_LOCATION, mManagedProfile);
+ }
+
+ private Preference.OnPreferenceClickListener mManagedProfileSwitchClickListener =
+ new Preference.OnPreferenceClickListener() {
+ @Override
+ public boolean onPreferenceClick(Preference preference) {
+ final boolean switchState = mManagedProfileSwitch.isChecked();
+ mUm.setUserRestriction(UserManager.DISALLOW_SHARE_LOCATION,
+ !switchState, mManagedProfile);
+ mManagedProfileSwitch.setSummary(switchState ?
+ R.string.switch_on_text : R.string.switch_off_text);
+ return true;
+ }
+ };
+
private class PackageEntryClickedListener
implements Preference.OnPreferenceClickListener {
private String mPackage;
diff --git a/src/com/android/settings/search/Ranking.java b/src/com/android/settings/search/Ranking.java
index 4ac4fb8..3d5ff35 100644
--- a/src/com/android/settings/search/Ranking.java
+++ b/src/com/android/settings/search/Ranking.java
@@ -36,6 +36,7 @@
import com.android.settings.applications.ManageDefaultApps;
import com.android.settings.bluetooth.BluetoothSettings;
import com.android.settings.deviceinfo.StorageSettings;
+import com.android.settings.display.ScreenZoomSettings;
import com.android.settings.fuelgauge.BatterySaverSettings;
import com.android.settings.fuelgauge.PowerUsageSummary;
import com.android.settings.inputmethod.InputMethodAndLanguageSettings;
@@ -122,6 +123,7 @@
// Display
sRankMap.put(DisplaySettings.class.getName(), RANK_DISPLAY);
+ sRankMap.put(ScreenZoomSettings.class.getName(), RANK_WIFI);
// Wallpapers
sRankMap.put(WallpaperTypeSettings.class.getName(), RANK_WALLPAPER);
diff --git a/src/com/android/settings/search/SearchIndexableResources.java b/src/com/android/settings/search/SearchIndexableResources.java
index 6d6ca08..f15ff63 100644
--- a/src/com/android/settings/search/SearchIndexableResources.java
+++ b/src/com/android/settings/search/SearchIndexableResources.java
@@ -38,6 +38,7 @@
import com.android.settings.applications.ManageDefaultApps;
import com.android.settings.bluetooth.BluetoothSettings;
import com.android.settings.deviceinfo.StorageSettings;
+import com.android.settings.display.ScreenZoomSettings;
import com.android.settings.fuelgauge.BatterySaverSettings;
import com.android.settings.fuelgauge.PowerUsageSummary;
import com.android.settings.inputmethod.InputMethodAndLanguageSettings;
@@ -131,6 +132,13 @@
HomeSettings.class.getName(),
R.drawable.ic_settings_home));
+ sResMap.put(ScreenZoomSettings.class.getName(),
+ new SearchIndexableResource(
+ Ranking.getRankForClassName(ScreenZoomSettings.class.getName()),
+ NO_DATA_RES_ID,
+ ScreenZoomSettings.class.getName(),
+ R.drawable.ic_settings_display));
+
sResMap.put(DisplaySettings.class.getName(),
new SearchIndexableResource(
Ranking.getRankForClassName(DisplaySettings.class.getName()),
diff --git a/src/com/android/settings/vpn2/AppPreference.java b/src/com/android/settings/vpn2/AppPreference.java
index 84897be..af4192e 100644
--- a/src/com/android/settings/vpn2/AppPreference.java
+++ b/src/com/android/settings/vpn2/AppPreference.java
@@ -39,18 +39,13 @@
private int mState = STATE_DISCONNECTED;
private String mPackageName;
private String mName;
- private int mUid;
+ private int mUserId = UserHandle.USER_NULL;
- public AppPreference(Context context, OnClickListener onManage, final String packageName,
- int uid) {
+ public AppPreference(Context context, OnClickListener onManage) {
super(context, null /* attrs */, onManage);
- mPackageName = packageName;
- mUid = uid;
- update();
}
public PackageInfo getPackageInfo() {
- UserHandle user = new UserHandle(UserHandle.getUserId(mUid));
try {
PackageManager pm = getUserContext().getPackageManager();
return pm.getPackageInfo(mPackageName, 0 /* flags */);
@@ -67,8 +62,18 @@
return mPackageName;
}
- public int getUid() {
- return mUid;
+ public void setPackageName(String name) {
+ mPackageName = name;
+ update();
+ }
+
+ public int getUserId() {
+ return mUserId;
+ }
+
+ public void setUserId(int userId) {
+ mUserId = userId;
+ update();
}
public int getState() {
@@ -81,6 +86,10 @@
}
private void update() {
+ if (mPackageName == null || mUserId == UserHandle.USER_NULL) {
+ return;
+ }
+
final String[] states = getContext().getResources().getStringArray(R.array.vpn_states);
setSummary(mState != STATE_DISCONNECTED ? states[mState] : "");
@@ -116,7 +125,7 @@
}
private Context getUserContext() throws PackageManager.NameNotFoundException {
- UserHandle user = new UserHandle(UserHandle.getUserId(mUid));
+ UserHandle user = UserHandle.of(mUserId);
return getContext().createPackageContextAsUser(
getContext().getPackageName(), 0 /* flags */, user);
}
@@ -128,7 +137,7 @@
if ((result = another.mState - mState) == 0 &&
(result = mName.compareToIgnoreCase(another.mName)) == 0 &&
(result = mPackageName.compareTo(another.mPackageName)) == 0) {
- result = mUid - another.mUid;
+ result = mUserId - another.mUserId;
}
return result;
} else if (preference instanceof ConfigPreference) {
diff --git a/src/com/android/settings/vpn2/ConfigPreference.java b/src/com/android/settings/vpn2/ConfigPreference.java
index a2736a0..c7ecddb 100644
--- a/src/com/android/settings/vpn2/ConfigPreference.java
+++ b/src/com/android/settings/vpn2/ConfigPreference.java
@@ -31,12 +31,15 @@
* state.
*/
public class ConfigPreference extends ManageablePreference {
- private VpnProfile mProfile;
- private int mState = -1;
+ public static int STATE_NONE = -1;
- ConfigPreference(Context context, OnClickListener onManage, VpnProfile profile) {
+ private VpnProfile mProfile;
+
+ /** One of the STATE_* fields from LegacyVpnInfo, or STATE_NONE */
+ private int mState = STATE_NONE;
+
+ ConfigPreference(Context context, OnClickListener onManage) {
super(context, null /* attrs */, onManage);
- setProfile(profile);
}
public VpnProfile getProfile() {
@@ -54,15 +57,16 @@
}
private void update() {
- if (mState < 0) {
+ if (mState == STATE_NONE) {
setSummary("");
} else {
- String[] states = getContext().getResources()
- .getStringArray(R.array.vpn_states);
+ final String[] states = getContext().getResources().getStringArray(R.array.vpn_states);
setSummary(states[mState]);
}
- setIcon(R.mipmap.ic_launcher_settings);
- setTitle(mProfile.name);
+ if (mProfile != null) {
+ setIcon(R.mipmap.ic_launcher_settings);
+ setTitle(mProfile.name);
+ }
notifyHierarchyChanged();
}
@@ -72,7 +76,7 @@
ConfigPreference another = (ConfigPreference) preference;
int result;
if ((result = another.mState - mState) == 0 &&
- (result = mProfile.name.compareTo(another.mProfile.name)) == 0 &&
+ (result = mProfile.name.compareToIgnoreCase(another.mProfile.name)) == 0 &&
(result = mProfile.type - another.mProfile.type) == 0) {
result = mProfile.key.compareTo(another.mProfile.key);
}
diff --git a/src/com/android/settings/vpn2/VpnSettings.java b/src/com/android/settings/vpn2/VpnSettings.java
index b903463..00f6a12 100644
--- a/src/com/android/settings/vpn2/VpnSettings.java
+++ b/src/com/android/settings/vpn2/VpnSettings.java
@@ -16,13 +16,16 @@
package com.android.settings.vpn2;
+import android.annotation.NonNull;
+import android.annotation.UiThread;
+import android.annotation.WorkerThread;
import android.app.AppOpsManager;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
-import android.net.ConnectivityManager;
import android.net.ConnectivityManager.NetworkCallback;
+import android.net.ConnectivityManager;
import android.net.IConnectivityManager;
import android.net.Network;
import android.net.NetworkCapabilities;
@@ -40,7 +43,9 @@
import android.support.v7.preference.Preference;
import android.support.v7.preference.PreferenceGroup;
import android.support.v7.preference.PreferenceScreen;
-import android.util.SparseArray;
+import android.util.ArrayMap;
+import android.util.ArraySet;
+import android.util.Log;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
@@ -57,8 +62,10 @@
import com.google.android.collect.Lists;
import java.util.ArrayList;
-import java.util.HashMap;
+import java.util.Collections;
import java.util.List;
+import java.util.Map;
+import java.util.Set;
import static android.app.AppOpsManager.OP_ACTIVATE_VPN;
@@ -87,8 +94,8 @@
private final KeyStore mKeyStore = KeyStore.getInstance();
- private HashMap<String, ConfigPreference> mConfigPreferences = new HashMap<>();
- private HashMap<String, AppPreference> mAppPreferences = new HashMap<>();
+ private Map<String, ConfigPreference> mConfigPreferences = new ArrayMap<>();
+ private Map<AppVpnInfo, AppPreference> mAppPreferences = new ArrayMap<>();
private Handler mUpdater;
private LegacyVpnInfo mConnectedLegacyVpn;
@@ -211,58 +218,64 @@
public boolean handleMessage(Message message) {
mUpdater.removeMessages(RESCAN_MESSAGE);
- // Pref group within which to list VPNs
- PreferenceGroup vpnGroup = getPreferenceScreen();
- vpnGroup.removeAll();
- mConfigPreferences.clear();
- mAppPreferences.clear();
+ final List<VpnProfile> vpnProfiles = loadVpnProfiles(mKeyStore);
+ final List<AppVpnInfo> vpnApps = getVpnApps();
- // Fetch configured VPN profiles from KeyStore
- for (VpnProfile profile : loadVpnProfiles(mKeyStore)) {
- final ConfigPreference pref = new ConfigPreference(getPrefContext(), mManageListener,
- profile);
- pref.setOnPreferenceClickListener(this);
- mConfigPreferences.put(profile.key, pref);
- vpnGroup.addPreference(pref);
- }
+ final List<LegacyVpnInfo> connectedLegacyVpns = getConnectedLegacyVpns();
+ final List<AppVpnInfo> connectedAppVpns = getConnectedAppVpns();
- // 3rd-party VPN apps can change elsewhere. Reload them every time.
- for (AppOpsManager.PackageOps pkg : getVpnApps()) {
- String key = getVpnIdentifier(UserHandle.getUserId(pkg.getUid()), pkg.getPackageName());
- final AppPreference pref = new AppPreference(getPrefContext(), mManageListener,
- pkg.getPackageName(), pkg.getUid());
- pref.setOnPreferenceClickListener(this);
- mAppPreferences.put(key, pref);
- vpnGroup.addPreference(pref);
- }
+ // Refresh the PreferenceGroup which lists VPNs
+ getActivity().runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ // Find new VPNs by subtracting existing ones from the full set
+ final Set<Preference> updates = new ArraySet<>();
- // Mark out connections with a subtitle
- try {
- // Legacy VPNs
- mConnectedLegacyVpn = null;
- LegacyVpnInfo info = mConnectivityService.getLegacyVpnInfo(UserHandle.myUserId());
- if (info != null) {
- ConfigPreference preference = mConfigPreferences.get(info.key);
- if (preference != null) {
- preference.setState(info.state);
- mConnectedLegacyVpn = info;
+ for (VpnProfile profile : vpnProfiles) {
+ ConfigPreference p = findOrCreatePreference(profile);
+ p.setState(ConfigPreference.STATE_NONE);
+ updates.add(p);
}
- }
+ for (AppVpnInfo app : vpnApps) {
+ AppPreference p = findOrCreatePreference(app);
+ p.setState(AppPreference.STATE_DISCONNECTED);
+ updates.add(p);
+ }
- // Third-party VPNs
- for (UserHandle profile : mUserManager.getUserProfiles()) {
- VpnConfig cfg = mConnectivityService.getVpnConfig(profile.getIdentifier());
- if (cfg != null) {
- final String key = getVpnIdentifier(profile.getIdentifier(), cfg.user);
- final AppPreference preference = mAppPreferences.get(key);
+ // Trim preferences for deleted VPNs
+ mConfigPreferences.values().retainAll(updates);
+ mAppPreferences.values().retainAll(updates);
+
+ final PreferenceGroup vpnGroup = getPreferenceScreen();
+ for (int i = vpnGroup.getPreferenceCount() - 1; i >= 0; i--) {
+ Preference p = vpnGroup.getPreference(i);
+ if (updates.contains(p)) {
+ updates.remove(p);
+ } else {
+ vpnGroup.removePreference(p);
+ }
+ }
+
+ // Show any new preferences on the screen
+ for (Preference pref : updates) {
+ vpnGroup.addPreference(pref);
+ }
+
+ // Mark connected VPNs
+ for (LegacyVpnInfo info : connectedLegacyVpns) {
+ final ConfigPreference preference = mConfigPreferences.get(info.key);
+ if (preference != null) {
+ preference.setState(info.state);
+ }
+ }
+ for (AppVpnInfo app : connectedAppVpns) {
+ final AppPreference preference = mAppPreferences.get(app);
if (preference != null) {
preference.setState(AppPreference.STATE_CONNECTED);
}
}
}
- } catch (RemoteException e) {
- // ignore
- }
+ });
mUpdater.sendEmptyMessageDelayed(RESCAN_MESSAGE, RESCAN_INTERVAL_MS);
return true;
@@ -278,7 +291,7 @@
mConnectedLegacyVpn.intent.send();
return true;
} catch (Exception e) {
- // ignore
+ Log.w(LOG_TAG, "Starting config intent failed", e);
}
}
ConfigDialogFragment.show(this, profile, false /* editing */, true /* exists */);
@@ -289,7 +302,7 @@
if (!connected) {
try {
- UserHandle user = new UserHandle(UserHandle.getUserId(pref.getUid()));
+ UserHandle user = UserHandle.of(pref.getUserId());
Context userContext = getActivity().createPackageContextAsUser(
getActivity().getPackageName(), 0 /* flags */, user);
PackageManager pm = userContext.getPackageManager();
@@ -299,11 +312,11 @@
return true;
}
} catch (PackageManager.NameNotFoundException nnfe) {
- // Fall through
+ Log.w(LOG_TAG, "VPN provider does not exist: " + pref.getPackageName(), nnfe);
}
}
- // Already onnected or no launch intent available - show an info dialog
+ // Already connected or no launch intent available - show an info dialog
PackageInfo pkgInfo = pref.getPackageInfo();
AppDialogFragment.show(this, pkgInfo, pref.getLabel(), false /* editing */, connected);
return true;
@@ -311,6 +324,11 @@
return false;
}
+ @Override
+ protected int getHelpResource() {
+ return R.string.help_url_vpn;
+ }
+
private View.OnClickListener mManageListener = new View.OnClickListener() {
@Override
public void onClick(View view) {
@@ -329,10 +347,6 @@
}
};
- private static String getVpnIdentifier(int userId, String packageName) {
- return Integer.toString(userId)+ "_" + packageName;
- }
-
private NetworkCallback mNetworkCallback = new NetworkCallback() {
@Override
public void onAvailable(Network network) {
@@ -349,18 +363,68 @@
}
};
- @Override
- protected int getHelpResource() {
- return R.string.help_url_vpn;
+ @UiThread
+ private ConfigPreference findOrCreatePreference(VpnProfile profile) {
+ ConfigPreference pref = mConfigPreferences.get(profile.key);
+ if (pref == null) {
+ pref = new ConfigPreference(getPrefContext(), mManageListener);
+ pref.setOnPreferenceClickListener(this);
+ mConfigPreferences.put(profile.key, pref);
+ }
+ pref.setProfile(profile);
+ return pref;
}
- private List<AppOpsManager.PackageOps> getVpnApps() {
- List<AppOpsManager.PackageOps> result = Lists.newArrayList();
+ @UiThread
+ private AppPreference findOrCreatePreference(AppVpnInfo app) {
+ AppPreference pref = mAppPreferences.get(app);
+ if (pref == null) {
+ pref = new AppPreference(getPrefContext(), mManageListener);
+ pref.setOnPreferenceClickListener(this);
+ mAppPreferences.put(app, pref);
+ }
+ pref.setUserId(app.userId);
+ pref.setPackageName(app.packageName);
+ return pref;
+ }
+
+ @WorkerThread
+ private List<LegacyVpnInfo> getConnectedLegacyVpns() {
+ try {
+ mConnectedLegacyVpn = mConnectivityService.getLegacyVpnInfo(UserHandle.myUserId());
+ if (mConnectedLegacyVpn != null) {
+ return Collections.singletonList(mConnectedLegacyVpn);
+ }
+ } catch (RemoteException e) {
+ Log.e(LOG_TAG, "Failure updating VPN list with connected legacy VPNs", e);
+ }
+ return Collections.emptyList();
+ }
+
+ @WorkerThread
+ private List<AppVpnInfo> getConnectedAppVpns() {
+ // Mark connected third-party services
+ List<AppVpnInfo> connections = new ArrayList<>();
+ try {
+ for (UserHandle profile : mUserManager.getUserProfiles()) {
+ VpnConfig config = mConnectivityService.getVpnConfig(profile.getIdentifier());
+ if (config != null && !config.legacy) {
+ connections.add(new AppVpnInfo(profile.getIdentifier(), config.user));
+ }
+ }
+ } catch (RemoteException e) {
+ Log.e(LOG_TAG, "Failure updating VPN list with connected app VPNs", e);
+ }
+ return connections;
+ }
+
+ private List<AppVpnInfo> getVpnApps() {
+ List<AppVpnInfo> result = Lists.newArrayList();
// Build a filter of currently active user profiles.
- SparseArray<Boolean> currentProfileIds = new SparseArray<>();
+ Set<Integer> currentProfileIds = new ArraySet<>();
for (UserHandle profile : mUserManager.getUserProfiles()) {
- currentProfileIds.put(profile.getIdentifier(), Boolean.TRUE);
+ currentProfileIds.add(profile.getIdentifier());
}
// Fetch VPN-enabled apps from AppOps.
@@ -369,7 +433,7 @@
if (apps != null) {
for (AppOpsManager.PackageOps pkg : apps) {
int userId = UserHandle.getUserId(pkg.getUid());
- if (currentProfileIds.get(userId) == null) {
+ if (!currentProfileIds.contains(userId)) {
// Skip packages for users outside of our profile group.
continue;
}
@@ -382,7 +446,7 @@
}
}
if (allowed) {
- result.add(pkg);
+ result.add(new AppVpnInfo(userId, pkg.getPackageName()));
}
}
}
@@ -407,4 +471,29 @@
}
return result;
}
+
+ /** Utility holder for packageName:userId pairs */
+ private static class AppVpnInfo {
+ public int userId;
+ public String packageName;
+
+ public AppVpnInfo(int userId, @NonNull String packageName) {
+ this.userId = userId;
+ this.packageName = packageName;
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (other instanceof AppVpnInfo) {
+ AppVpnInfo that = (AppVpnInfo) other;
+ return userId == that.userId && packageName.equals(that.packageName);
+ }
+ return false;
+ }
+
+ @Override
+ public int hashCode() {
+ return (packageName != null ? packageName.hashCode() : 0) * 31 + userId;
+ }
+ }
}