Merge "[WifiSettings] Align text in Wi-Fi dialog" into mnc-dev
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 0446178..f01110a 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -759,6 +759,26 @@
android:value="true" />
</activity>
+ <activity android:name="Settings$ZenModeEventRuleSettingsActivity"
+ android:exported="true"
+ android:taskAffinity="">
+ <intent-filter android:priority="1">
+ <action android:name="android.settings.ZEN_MODE_EVENT_RULE_SETTINGS" />
+ <category android:name="android.intent.category.DEFAULT" />
+ </intent-filter>
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.DEFAULT" />
+ <category android:name="com.android.settings.SHORTCUT" />
+ </intent-filter>
+ <meta-data android:name="com.android.settings.FRAGMENT_CLASS"
+ android:value="com.android.settings.notification.ZenModeEventRuleSettings" />
+ <meta-data android:name="com.android.settings.TOP_LEVEL_HEADER_ID"
+ android:resource="@id/notification_settings" />
+ <meta-data android:name="com.android.settings.PRIMARY_PROFILE_CONTROLLED"
+ android:value="true" />
+ </activity>
+
<activity android:name="Settings$ZenModeExternalRuleSettingsActivity"
android:exported="true"
android:taskAffinity="">
@@ -1489,8 +1509,17 @@
android:value="true" />
</activity>
- <activity
- android:name="Settings$PublicVolumeSettingsActivity"
+ <activity android:name="Settings$PrivateVolumeSettingsActivity"
+ android:label="@string/storage_settings_title"
+ android:taskAffinity="com.android.settings"
+ android:parentActivityName="Settings$StorageSettingsActivity">
+ <meta-data android:name="com.android.settings.FRAGMENT_CLASS"
+ android:value="com.android.settings.deviceinfo.PrivateVolumeSettings" />
+ <meta-data android:name="com.android.settings.TOP_LEVEL_HEADER_ID"
+ android:resource="@id/storage_settings" />
+ </activity>
+
+ <activity android:name="Settings$PublicVolumeSettingsActivity"
android:label="@string/storage_settings_title"
android:taskAffinity="com.android.settings"
android:parentActivityName="Settings$StorageSettingsActivity">
@@ -1508,8 +1537,7 @@
android:resource="@id/storage_settings" />
</activity>
- <activity
- android:name="Settings$PrivateVolumeForgetActivity"
+ <activity android:name="Settings$PrivateVolumeForgetActivity"
android:label="@string/storage_settings_title"
android:taskAffinity="com.android.settings"
android:parentActivityName="Settings$StorageSettingsActivity"
@@ -1541,17 +1569,20 @@
android:exported="false" />
<activity android:name=".deviceinfo.StorageWizardMigrateProgress"
android:taskAffinity="com.android.settings.storage_wizard"
- android:exported="false" />
+ android:exported="true"
+ android:permission="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />
<activity android:name=".deviceinfo.StorageWizardReady"
android:taskAffinity="com.android.settings.storage_wizard"
- android:exported="false" />
+ android:exported="true"
+ android:permission="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />
<activity android:name=".deviceinfo.StorageWizardMoveConfirm"
android:taskAffinity="com.android.settings.storage_wizard"
android:exported="false" />
<activity android:name=".deviceinfo.StorageWizardMoveProgress"
android:taskAffinity="com.android.settings.storage_wizard"
- android:exported="false" />
+ android:exported="true"
+ android:permission="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />
<!-- Exported for SystemUI to trigger -->
<receiver android:name=".deviceinfo.StorageUnmountReceiver"
diff --git a/res/drawable/ic_add.xml b/res/drawable/ic_add.xml
new file mode 100644
index 0000000..5939c97
--- /dev/null
+++ b/res/drawable/ic_add.xml
@@ -0,0 +1,24 @@
+<!--
+ 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="32.0dp"
+ android:height="32.0dp"
+ android:viewportWidth="48.0"
+ android:viewportHeight="48.0">
+ <path
+ android:fillColor="?android:attr/colorControlNormal"
+ 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"/>
+</vector>
diff --git a/res/drawable/ic_event.xml b/res/drawable/ic_event.xml
new file mode 100644
index 0000000..2ca958f
--- /dev/null
+++ b/res/drawable/ic_event.xml
@@ -0,0 +1,24 @@
+<!--
+ 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="32.0dp"
+ android:height="32.0dp"
+ android:viewportWidth="48.0"
+ android:viewportHeight="48.0">
+ <path
+ android:fillColor="?android:attr/colorControlNormal"
+ android:pathData="M34.0,24.0L24.0,24.0l0.0,10.0l10.0,0.0L34.0,24.0zM32.0,2.0l0.0,4.0L16.0,6.0L16.0,2.0l-4.0,0.0l0.0,4.0l-2.0,0.0c-2.21,0.0 -3.98,1.79 -3.98,4.0L6.0,38.0c0.0,2.21 1.79,4.0 4.0,4.0l28.0,0.0c2.21,0.0 4.0,-1.79 4.0,-4.0L42.0,10.0c0.0,-2.21 -1.79,-4.0 -4.0,-4.0l-2.0,0.0L36.0,2.0l-4.0,0.0zm6.0,36.0L10.0,38.0L10.0,16.0l28.0,0.0l0.0,22.0z"/>
+</vector>
diff --git a/res/drawable/ic_label.xml b/res/drawable/ic_label.xml
new file mode 100644
index 0000000..b1ed068
--- /dev/null
+++ b/res/drawable/ic_label.xml
@@ -0,0 +1,24 @@
+<!--
+ 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="32.0dp"
+ android:height="32.0dp"
+ android:viewportWidth="48.0"
+ android:viewportHeight="48.0">
+ <path
+ android:fillColor="?android:attr/colorControlNormal"
+ android:pathData="M35.27,11.69C34.54,10.67 33.35,10.0 32.0,10.0l-22.0,0.02c-2.21,0.0 -4.0,1.77 -4.0,3.98l0.0,20.0c0.0,2.21 1.79,3.98 4.0,3.98L32.0,38.0c1.35,0.0 2.54,-0.67 3.27,-1.69L44.0,24.0l-8.73,-12.31z"/>
+</vector>
diff --git a/res/drawable/ic_schedule.xml b/res/drawable/ic_schedule.xml
new file mode 100644
index 0000000..c77c50e
--- /dev/null
+++ b/res/drawable/ic_schedule.xml
@@ -0,0 +1,29 @@
+<!--
+ 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="32.0dp"
+ android:height="32.0dp"
+ android:viewportWidth="48.0"
+ android:viewportHeight="48.0">
+ <path
+ android:fillColor="?android:attr/colorControlNormal"
+ android:pathData="M23.99,4.0C12.94,4.0 4.0,12.95 4.0,24.0s8.94,20.0 19.99,20.0C35.04,44.0 44.0,35.05 44.0,24.0S35.04,4.0 23.99,4.0zM24.0,40.0c-8.84,0.0 -16.0,-7.16 -16.0,-16.0S15.16,8.0 24.0,8.0s16.0,7.16 16.0,16.0 -7.16,16.0 -16.0,16.0z"
+ android:fillAlpha=".9"/>
+ <path
+ android:fillColor="?android:attr/colorControlNormal"
+ android:pathData="M25.0,14.0l-3.0,0.0l0.0,12.0l10.49,6.3L34.0,29.84l-9.0,-5.34z"
+ android:fillAlpha=".9"/>
+</vector>
diff --git a/res/drawable/progress_indeterminate_horizontal_material_trimmed.xml b/res/drawable/progress_indeterminate_horizontal_material_trimmed.xml
new file mode 100644
index 0000000..070b9a1
--- /dev/null
+++ b/res/drawable/progress_indeterminate_horizontal_material_trimmed.xml
@@ -0,0 +1,28 @@
+<?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.
+-->
+
+<!-- Variant of progress_indeterminate_horizontal_material in frameworks/base/core/res, which
+ draws the whole height of the progress bar instead having blank space above and below the
+ bar. -->
+<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:drawable="@drawable/vector_drawable_progress_indeterminate_horizontal_trimmed" >
+ <target
+ android:name="rect2_grp"
+ android:animation="@*android:anim/progress_indeterminate_horizontal_rect2" />
+ <target
+ android:name="rect1_grp"
+ android:animation="@*android:anim/progress_indeterminate_horizontal_rect1" />
+</animated-vector>
diff --git a/res/drawable/vector_drawable_progress_indeterminate_horizontal_trimmed.xml b/res/drawable/vector_drawable_progress_indeterminate_horizontal_trimmed.xml
new file mode 100644
index 0000000..39e3a37
--- /dev/null
+++ b/res/drawable/vector_drawable_progress_indeterminate_horizontal_trimmed.xml
@@ -0,0 +1,53 @@
+<?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.
+-->
+
+<!-- Variant of vector_drawable_progress_indeterminate_horizontal in frameworks/base/core/res, which
+ draws the whole height of the progress bar instead having blank space above and below the
+ bar. -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:height="10dp"
+ android:width="360dp"
+ android:viewportHeight="10"
+ android:viewportWidth="360" >
+ <group
+ android:name="progress_group"
+ android:translateX="180"
+ android:translateY="5" >
+ <path
+ android:name="background_track"
+ android:pathData="M -180.0,-5.0 l 360.0,0 l 0,10.0 l -360.0,0 Z"
+ android:fillColor="?android:attr/colorControlActivated"
+ android:fillAlpha="?android:attr/disabledAlpha"/>
+ <group
+ android:name="rect2_grp"
+ android:translateX="-197.60001"
+ android:scaleX="0.1" >
+ <path
+ android:name="rect2"
+ android:pathData="M -144.0,-5.0 l 288.0,0 l 0,10.0 l -288.0,0 Z"
+ android:fillColor="?android:attr/colorControlActivated" />
+ </group>
+ <group
+ android:name="rect1_grp"
+ android:translateX="-522.59998"
+ android:scaleX="0.1" >
+ <path
+ android:name="rect1"
+ android:pathData="M -144.0,-5.0 l 288.0,0 l 0,10.0 l -288.0,0 Z"
+ android:fillColor="?android:attr/colorControlActivated" />
+ </group>
+ </group>
+</vector>
diff --git a/res/layout/manage_applications_item.xml b/res/layout/manage_applications_item.xml
index 042d518..90555c8 100755
--- a/res/layout/manage_applications_item.xml
+++ b/res/layout/manage_applications_item.xml
@@ -59,13 +59,15 @@
android:duplicateParentState="true" />
<TextView
- android:id="@+id/app_size"
+ android:id="@+id/app_summary"
android:layout_column="1"
android:layout_row="1"
android:layout_gravity="fill_horizontal|top"
android:textAppearance="@android:style/TextAppearance.Material.Body1"
android:textColor="?android:attr/textColorSecondary"
android:textAlignment="viewStart"
+ android:singleLine="true"
+ android:ellipsize="marquee"
android:duplicateParentState="true" />
<TextView
diff --git a/res/layout/preference_list_fragment.xml b/res/layout/preference_list_fragment.xml
index 1412381..2e9299c 100644
--- a/res/layout/preference_list_fragment.xml
+++ b/res/layout/preference_list_fragment.xml
@@ -25,7 +25,7 @@
android:background="@android:color/transparent">
<FrameLayout android:id="@+id/pinned_header"
- android:layout_width="wrap_content"
+ android:layout_width="match_parent"
android:layout_height="wrap_content"
android:visibility="gone" />
diff --git a/res/layout/setup_wifi_mac_address.xml b/res/layout/setup_wifi_mac_address.xml
new file mode 100644
index 0000000..8f5703b
--- /dev/null
+++ b/res/layout/setup_wifi_mac_address.xml
@@ -0,0 +1,38 @@
+<?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="@dimen/setup_add_network_item_height"
+ android:gravity="center_vertical"
+ android:orientation="vertical"
+ android:paddingStart="?android:attr/listPreferredItemPaddingStart"
+ android:paddingEnd="?android:attr/listPreferredItemPaddingEnd">
+
+ <TextView
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingStart="@dimen/setup_list_no_icon_padding"
+ android:text="@string/wifi_advanced_mac_address_title" />
+
+ <TextView
+ android:id="@+id/mac_address"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingStart="@dimen/setup_list_no_icon_padding" />
+
+</LinearLayout>
diff --git a/res/layout/wifi_progress_header.xml b/res/layout/wifi_progress_header.xml
new file mode 100644
index 0000000..05518ae
--- /dev/null
+++ b/res/layout/wifi_progress_header.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.
+-->
+
+<ProgressBar xmlns:android="http://schemas.android.com/apk/res/android"
+ style="@style/TrimmedHorizontalProgressBar"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:indeterminate="true" />
diff --git a/res/layout/zen_rule_name.xml b/res/layout/zen_rule_name.xml
index a192c83..b7b0415 100755
--- a/res/layout/zen_rule_name.xml
+++ b/res/layout/zen_rule_name.xml
@@ -23,6 +23,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:singleLine="true"
+ android:hint="@string/zen_mode_rule_name_hint"
android:layout_marginLeft="22dp"
android:layout_marginRight="22dp" >
@@ -32,7 +33,6 @@
<RadioGroup
android:id="@+id/rule_types"
- android:visibility="gone"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="22dp"
@@ -46,9 +46,10 @@
android:layout_height="wrap_content"
android:text="@string/zen_schedule_rule_type_name" />
- <RadioButton android:id="@+id/rule_type_2"
+ <RadioButton android:id="@+id/rule_type_event"
android:layout_width="match_parent"
- android:layout_height="wrap_content" />
+ android:layout_height="wrap_content"
+ android:text="@string/zen_event_rule_type_name" />
<RadioButton android:id="@+id/rule_type_3"
android:layout_width="match_parent"
@@ -58,6 +59,10 @@
android:layout_width="match_parent"
android:layout_height="wrap_content" />
+ <RadioButton android:id="@+id/rule_type_5"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content" />
+
</RadioGroup>
</LinearLayout>
diff --git a/res/menu/storage_volume.xml b/res/menu/storage_volume.xml
index 093a4bb..b461f46 100644
--- a/res/menu/storage_volume.xml
+++ b/res/menu/storage_volume.xml
@@ -28,6 +28,9 @@
android:id="@+id/storage_format"
android:title="@string/storage_menu_format" />
<item
+ android:id="@+id/storage_migrate"
+ android:title="@string/storage_menu_migrate" />
+ <item
android:id="@+id/storage_usb"
android:title="@string/storage_menu_usb" />
</menu>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index f7d5900..9c553a4 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -2285,10 +2285,12 @@
<string name="storage_menu_format">Erase & format</string>
<!-- Storage setting. Menu option for erasing and formatting a storage device [CHAR LIMIT=30]-->
<string name="storage_menu_format_internal">Erase & format as internal storage</string>
- <!-- Storage setting. Menu option for USB transfer settings [CHAR LIMIT=30]-->
- <string name="storage_menu_usb">USB computer connection</string>
+ <!-- Storage setting. Menu option for migrating data to a storage device [CHAR LIMIT=30]-->
+ <string name="storage_menu_migrate">Migrate data</string>
<!-- Storage setting. Menu option for forgetting a storage device [CHAR LIMIT=30]-->
<string name="storage_menu_forget">Forget</string>
+ <!-- Storage setting. Menu option for USB transfer settings [CHAR LIMIT=30]-->
+ <string name="storage_menu_usb">USB computer connection</string>
<!-- Storage setting. Title for USB transfer settings [CHAR LIMIT=30]-->
<string name="storage_title_usb">USB computer connection</string>
@@ -2402,7 +2404,7 @@
<!-- Title of wizard step prompting user to start data migration [CHAR LIMIT=32] -->
<string name="storage_wizard_migrate_confirm_title">Move data now</string>
<!-- Body of wizard step providing details about data migration [CHAR LIMIT=NONE] -->
- <string name="storage_wizard_migrate_confirm_body"><b>The move takes about <xliff:g id="time" example="1 hour">^1</xliff:g>. It will free <xliff:g id="size" example="1.2 GB">^2</xliff:g> of internal storage.</b></string>
+ <string name="storage_wizard_migrate_confirm_body"><b>The move takes about <xliff:g id="time" example="1 hour">^1</xliff:g>. It will free <xliff:g id="size" example="1.2 GB">^2</xliff:g> on <xliff:g id="name" example="Internal storage">^3</xliff:g>.</b></string>
<!-- Title of wizard button prompting user to start data migration [CHAR LIMIT=32] -->
<string name="storage_wizard_migrate_confirm_next">Move</string>
@@ -6059,8 +6061,11 @@
<!-- [CHAR LIMIT=40] Zen mode settings: Rule name option and edit dialog title -->
<string name="zen_mode_rule_name">Rule name</string>
+ <!-- [CHAR LIMIT=40] Zen mode settings: Rule name hint text -->
+ <string name="zen_mode_rule_name_hint">Enter rule name</string>
+
<!-- [CHAR LIMIT=40] Zen mode settings: Add rule menu option name -->
- <string name="zen_mode_time_add_rule">Add rule</string>
+ <string name="zen_mode_add_rule">Add rule</string>
<!-- [CHAR LIMIT=40] Zen mode settings: Delete rule menu option name -->
<string name="zen_mode_delete_rule">Delete rule</string>
@@ -6081,7 +6086,58 @@
<string name="zen_mode_configure_rule">Configure rule</string>
<!-- [CHAR LIMIT=40] Zen mode settings: Schedule rule type name -->
- <string name="zen_schedule_rule_type_name">Schedule rule</string>
+ <string name="zen_schedule_rule_type_name">Time rule</string>
+
+ <!-- [CHAR LIMIT=NONE] Zen mode settings: Schedule rule toast hint when enabled -->
+ <string name="zen_schedule_rule_enabled_toast">Automatic rule set to turn on Do Not Disturb during specified times</string>
+
+ <!-- [CHAR LIMIT=40] Zen mode settings: Event rule type name -->
+ <string name="zen_event_rule_type_name">Event rule</string>
+
+ <!-- [CHAR LIMIT=NONE] Zen mode settings: Event rule toast hint when enabled -->
+ <string name="zen_event_rule_enabled_toast">Automatic rule set to turn on Do Not Disturb during specified events</string>
+
+ <!-- [CHAR LIMIT=40] Zen mode settings: Event-based rule calendar option title -->
+ <string name="zen_mode_event_rule_calendar">Calendar</string>
+
+ <!-- [CHAR LIMIT=40] Zen mode settings: Event-based rule summary fragment: any calendar -->
+ <string name="zen_mode_event_rule_summary_any_calendar">Any calendar</string>
+
+ <!-- [CHAR LIMIT=40] Zen mode settings: Event-based rule summary fragment: any reply -->
+ <string name="zen_mode_event_rule_summary_any_reply">Any reply</string>
+
+ <!-- [CHAR LIMIT=40] Zen mode settings: Event-based rule summary fragment: any reply except no -->
+ <string name="zen_mode_event_rule_summary_any_reply_except_no">Any reply except no</string>
+
+ <!-- [CHAR LIMIT=40] Zen mode settings: Event-based rule summary fragment: replied yes -->
+ <string name="zen_mode_event_rule_summary_replied_yes">Replied yes</string>
+
+ <!-- [CHAR LIMIT=40] Zen mode settings: Event-based rule calendar option value for any calendar-->
+ <string name="zen_mode_event_rule_calendar_any">Any</string>
+
+ <!-- [CHAR LIMIT=40] Zen mode settings: Event-based rule attendance option title -->
+ <string name="zen_mode_event_rule_attendance">Attendance</string>
+
+ <!-- [CHAR LIMIT=40] Zen mode settings: Event-based rule attendance option value: required or optional -->
+ <string name="zen_mode_event_rule_attendance_required_optional">Required or optional</string>
+
+ <!-- [CHAR LIMIT=40] Zen mode settings: Event-based rule attendance option value: required -->
+ <string name="zen_mode_event_rule_attendance_required">Required</string>
+
+ <!-- [CHAR LIMIT=40] Zen mode settings: Event-based rule attendance option value: optional -->
+ <string name="zen_mode_event_rule_attendance_optional">Optional</string>
+
+ <!-- [CHAR LIMIT=40] Zen mode settings: Event-based rule reply option title -->
+ <string name="zen_mode_event_rule_reply">Reply</string>
+
+ <!-- [CHAR LIMIT=40] Zen mode settings: Event-based rule reply option value: Any -->
+ <string name="zen_mode_event_rule_reply_any">Any</string>
+
+ <!-- [CHAR LIMIT=40] Zen mode settings: Event-based rule reply option value: Any except no-->
+ <string name="zen_mode_event_rule_reply_any_except_no">Any except no</string>
+
+ <!-- [CHAR LIMIT=40] Zen mode settings: Event-based rule reply option value: Yes -->
+ <string name="zen_mode_event_rule_reply_yes">Yes</string>
<!-- [CHAR LIMIT=40] Zen mode settings: Text to display if rule isn't found -->
<string name="zen_mode_rule_not_found_text">Rule not found.</string>
@@ -6089,7 +6145,7 @@
<!-- [CHAR LIMIT=40] Zen mode settings: Rule summary template (when enabled) -->
<string name="zen_mode_rule_summary_combination"><xliff:g id="description" example="Sun - Thu">%1$s</xliff:g> / <xliff:g id="mode" example="Alarms only">%2$s</xliff:g></string>
- <!-- [CHAR LIMIT=40] Zen mode settings: Timebased rule days option title -->
+ <!-- [CHAR LIMIT=40] Zen mode settings: Time-based rule days option title -->
<string name="zen_mode_schedule_rule_days">Days</string>
<!-- [CHAR LIMIT=40] Zen mode settings: Downtime days option value, no days set -->
@@ -6304,6 +6360,8 @@
<string name="managed_user_title">Work profile</string>
<!-- Opening string on the dialog that prompts the user to confirm that they really want to delete their existing work profile. The administration app icon and name appear after the final colon. [CHAR LIMIT=NONE] -->
<string name="opening_paragraph_delete_profile_unknown_company">This profile is managed by:</string>
+ <!-- Summary for work profile accounts group. [CHAR LIMIT=25] -->
+ <string name="managing_admin">Managed by <xliff:g id="admin_app_label">%s</xliff:g></string>
<!-- Summary Title for saying that the preference is experimental and will evolve over time due to User feedback. [CHAR LIMIT=NONE] -->
<string name="experimental_preference">(Experimental)</string>
@@ -6423,11 +6481,16 @@
<!-- App notification summary with notifications disabled [CHAR LIMIT=40] -->
<string name="notifications_disabled">Block</string>
<!-- App notification summary with notifications sensitive [CHAR LIMIT=40] -->
- <string name="notifications_sensitive">Sensitive</string>
+ <string name="notifications_sensitive">Sensitive content hidden</string>
<!-- App notification summary with notifications priority [CHAR LIMIT=40] -->
<string name="notifications_priority">Priority</string>
- <!-- App notification summary with notifications priority and sensitive [CHAR LIMIT=40] -->
- <string name="notifications_priority_sensitive">Priority & Sensitive</string>
+ <!-- App notification summary with notification peeking disabled [CHAR LIMIT=40] -->
+ <string name="notifications_no_peeking">No peeking</string>
+ <!-- App notification summary with 2 items [CHAR LIMIT=15] -->
+ <string name="notifications_two_items"><xliff:g id="notif_state" example="Priority">%1$s</xliff:g> / <xliff:g id="notif_state" example="Priority">%2$s</xliff:g></string>
+ <!-- App notification summary with 3 items [CHAR LIMIT=15] -->
+ <string name="notifications_three_items"><xliff:g id="notif_state" example="Priority">%1$s</xliff:g> / <xliff:g id="notif_state" example="Priority">%2$s</xliff:g> / <xliff:g id="notif_state" example="Priority">%3$s</xliff:g></string>
+
<!-- Permissions preference summary [CHAR LIMIT=40] -->
<plurals name="permissions_summary">
@@ -6459,7 +6522,9 @@
<!-- Label for showing apps with priority notifications in list [CHAR LIMIT=30] -->
<string name="filter_notif_priority_apps">Priority</string>
<!-- Label for showing apps with sensitive notifications in list [CHAR LIMIT=30] -->
- <string name="filter_notif_sensitive_apps">Sensitive</string>
+ <string name="filter_notif_sensitive_apps">Sensitive content hidden</string>
+ <!-- Label for showing apps with peeking disabled in list [CHAR LIMIT=30] -->
+ <string name="filter_notif_no_peeking">No peeking</string>
<!-- Label for showing apps with domain URLs (data URI with http or https) in list [CHAR LIMIT=30] -->
<string name="filter_with_domain_urls_apps">With domain URLs</string>
diff --git a/res/values/styles.xml b/res/values/styles.xml
index d0d2ead..cca8a70 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -158,6 +158,12 @@
<item name="android:textColor">?android:attr/colorAccent</item>
</style>
+ <style name="TrimmedHorizontalProgressBar" parent="android:Widget.Material.ProgressBar.Horizontal">
+ <item name="android:indeterminateDrawable">@drawable/progress_indeterminate_horizontal_material_trimmed</item>
+ <item name="android:minHeight">3dip</item>
+ <item name="android:maxHeight">3dip</item>
+ </style>
+
<style name="bt_item">
<item name="android:layout_width">match_parent</item>
<item name="android:layout_height">wrap_content</item>
diff --git a/res/xml/zen_mode_event_rule_settings.xml b/res/xml/zen_mode_event_rule_settings.xml
new file mode 100644
index 0000000..acad96c
--- /dev/null
+++ b/res/xml/zen_mode_event_rule_settings.xml
@@ -0,0 +1,51 @@
+<?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.
+-->
+
+<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
+ android:key="zen_mode_event_rule_settings" >
+
+ <!-- Rule name -->
+ <Preference
+ android:key="rule_name"
+ android:title="@string/zen_mode_rule_name"
+ android:persistent="false" />
+
+ <!-- Calendar -->
+ <com.android.settings.DropDownPreference
+ android:key="calendar"
+ android:title="@string/zen_mode_event_rule_calendar"
+ android:persistent="false" />
+
+ <!-- Attendance -->
+ <com.android.settings.DropDownPreference
+ android:key="attendance"
+ android:title="@string/zen_mode_event_rule_attendance"
+ android:persistent="false" />
+
+ <!-- Reply -->
+ <com.android.settings.DropDownPreference
+ android:key="reply"
+ android:title="@string/zen_mode_event_rule_reply"
+ android:persistent="false" />
+
+ <!-- Zen mode -->
+ <com.android.settings.DropDownPreference
+ android:key="zen_mode"
+ android:title="@string/zen_mode_settings_title"
+ android:persistent="false" />
+
+</PreferenceScreen>
diff --git a/src/com/android/settings/Settings.java b/src/com/android/settings/Settings.java
index 88c8316..6723839 100644
--- a/src/com/android/settings/Settings.java
+++ b/src/com/android/settings/Settings.java
@@ -33,8 +33,9 @@
public static class VpnSettingsActivity extends SettingsActivity { /* empty */ }
public static class DateTimeSettingsActivity extends SettingsActivity { /* empty */ }
public static class StorageSettingsActivity extends SettingsActivity { /* empty */ }
- public static class PublicVolumeSettingsActivity extends SettingsActivity { /* empty */ }
public static class PrivateVolumeForgetActivity extends SettingsActivity { /* empty */ }
+ public static class PrivateVolumeSettingsActivity extends SettingsActivity { /* empty */ }
+ public static class PublicVolumeSettingsActivity extends SettingsActivity { /* empty */ }
public static class WifiSettingsActivity extends SettingsActivity { /* empty */ }
public static class WifiP2pSettingsActivity extends SettingsActivity { /* empty */ }
public static class InputMethodAndLanguageSettingsActivity extends SettingsActivity { /* empty */ }
@@ -99,6 +100,7 @@
public static class ZenModePrioritySettingsActivity extends SettingsActivity { /* empty */ }
public static class ZenModeAutomationSettingsActivity extends SettingsActivity { /* empty */ }
public static class ZenModeScheduleRuleSettingsActivity extends SettingsActivity { /* empty */ }
+ public static class ZenModeEventRuleSettingsActivity extends SettingsActivity { /* empty */ }
public static class ZenModeExternalRuleSettingsActivity extends SettingsActivity { /* empty */ }
public static class NotificationSettingsActivity extends SettingsActivity { /* empty */ }
public static class NotificationAppListActivity extends SettingsActivity { /* empty */ }
diff --git a/src/com/android/settings/SettingsActivity.java b/src/com/android/settings/SettingsActivity.java
index 5e1acb1..502f164 100644
--- a/src/com/android/settings/SettingsActivity.java
+++ b/src/com/android/settings/SettingsActivity.java
@@ -84,6 +84,7 @@
import com.android.settings.dashboard.NoHomeDialogFragment;
import com.android.settings.dashboard.SearchResultsSummary;
import com.android.settings.deviceinfo.PrivateVolumeForget;
+import com.android.settings.deviceinfo.PrivateVolumeSettings;
import com.android.settings.deviceinfo.PublicVolumeSettings;
import com.android.settings.deviceinfo.StorageSettings;
import com.android.settings.deviceinfo.UsbSettings;
@@ -101,6 +102,7 @@
import com.android.settings.notification.NotificationSettings;
import com.android.settings.notification.NotificationStation;
import com.android.settings.notification.OtherSoundSettings;
+import com.android.settings.notification.ZenModeEventRuleSettings;
import com.android.settings.notification.ZenModeExternalRuleSettings;
import com.android.settings.notification.ZenModePrioritySettings;
import com.android.settings.notification.ZenModeSettings;
@@ -310,8 +312,9 @@
com.android.settings.accessibility.ToggleDaltonizerPreferenceFragment.class.getName(),
TextToSpeechSettings.class.getName(),
StorageSettings.class.getName(),
- PublicVolumeSettings.class.getName(),
PrivateVolumeForget.class.getName(),
+ PrivateVolumeSettings.class.getName(),
+ PublicVolumeSettings.class.getName(),
DevelopmentSettings.class.getName(),
UsbSettings.class.getName(),
AndroidBeam.class.getName(),
@@ -341,6 +344,7 @@
WifiCallingSettings.class.getName(),
ZenModePrioritySettings.class.getName(),
ZenModeScheduleRuleSettings.class.getName(),
+ ZenModeEventRuleSettings.class.getName(),
ZenModeExternalRuleSettings.class.getName(),
ProcessStatsUi.class.getName(),
};
diff --git a/src/com/android/settings/SettingsPreferenceFragment.java b/src/com/android/settings/SettingsPreferenceFragment.java
index 17ff4b2..2c566a1 100644
--- a/src/com/android/settings/SettingsPreferenceFragment.java
+++ b/src/com/android/settings/SettingsPreferenceFragment.java
@@ -112,6 +112,14 @@
return mFloatingActionButton;
}
+ public View setPinnedHeaderView(int layoutResId) {
+ final LayoutInflater inflater = getActivity().getLayoutInflater();
+ final View pinnedHeader =
+ inflater.inflate(layoutResId, mPinnedHeaderFrameLayout, false);
+ setPinnedHeaderView(pinnedHeader);
+ return pinnedHeader;
+ }
+
public void setPinnedHeaderView(View pinnedHeader) {
mPinnedHeaderFrameLayout.addView(pinnedHeader);
mPinnedHeaderFrameLayout.setVisibility(View.VISIBLE);
diff --git a/src/com/android/settings/applications/AppOpsDetails.java b/src/com/android/settings/applications/AppOpsDetails.java
index 88591d7..0643b56 100644
--- a/src/com/android/settings/applications/AppOpsDetails.java
+++ b/src/com/android/settings/applications/AppOpsDetails.java
@@ -71,7 +71,7 @@
TextView label = (TextView) appSnippet.findViewById(R.id.app_name);
label.setText(mPm.getApplicationLabel(pkgInfo.applicationInfo));
// Version number of application
- mAppVersion = (TextView) appSnippet.findViewById(R.id.app_size);
+ mAppVersion = (TextView) appSnippet.findViewById(R.id.app_summary);
if (pkgInfo.versionName != null) {
mAppVersion.setVisibility(View.VISIBLE);
diff --git a/src/com/android/settings/applications/AppStateNotificationBridge.java b/src/com/android/settings/applications/AppStateNotificationBridge.java
index 1aa7ebf..4ac8650 100644
--- a/src/com/android/settings/applications/AppStateNotificationBridge.java
+++ b/src/com/android/settings/applications/AppStateNotificationBridge.java
@@ -87,4 +87,15 @@
return info.extraInfo != null && ((AppRow) info.extraInfo).sensitive;
}
};
+
+ public static final AppFilter FILTER_APP_NOTIFICATION_NO_PEEK = new AppFilter() {
+ @Override
+ public void init() {
+ }
+
+ @Override
+ public boolean filterApp(AppEntry info) {
+ return info.extraInfo != null && !((AppRow) info.extraInfo).peekable;
+ }
+ };
}
diff --git a/src/com/android/settings/applications/AppViewHolder.java b/src/com/android/settings/applications/AppViewHolder.java
index 92aa87a..34c9952 100644
--- a/src/com/android/settings/applications/AppViewHolder.java
+++ b/src/com/android/settings/applications/AppViewHolder.java
@@ -45,7 +45,7 @@
holder.rootView = convertView;
holder.appName = (TextView) convertView.findViewById(R.id.app_name);
holder.appIcon = (ImageView) convertView.findViewById(R.id.app_icon);
- holder.summary = (TextView) convertView.findViewById(R.id.app_size);
+ holder.summary = (TextView) convertView.findViewById(R.id.app_summary);
holder.disabled = (TextView) convertView.findViewById(R.id.app_disabled);
holder.checkBox = (CheckBox) convertView.findViewById(R.id.app_on_sdcard);
convertView.setTag(holder);
diff --git a/src/com/android/settings/applications/InstalledAppDetails.java b/src/com/android/settings/applications/InstalledAppDetails.java
index 33a7428..ffd4959 100755
--- a/src/com/android/settings/applications/InstalledAppDetails.java
+++ b/src/com/android/settings/applications/InstalledAppDetails.java
@@ -364,7 +364,7 @@
TextView label = (TextView) appSnippet.findViewById(R.id.app_name);
label.setText(mAppEntry.label);
// Version number of application
- mAppVersion = (TextView) appSnippet.findViewById(R.id.app_size);
+ mAppVersion = (TextView) appSnippet.findViewById(R.id.app_summary);
if (pkgInfo != null && pkgInfo.versionName != null) {
mAppVersion.setVisibility(View.VISIBLE);
@@ -675,15 +675,29 @@
public static CharSequence getNotificationSummary(AppRow appRow, Context context) {
if (appRow.banned) {
return context.getString(R.string.notifications_disabled);
- } else if (appRow.priority) {
- if (appRow.sensitive) {
- return context.getString(R.string.notifications_priority_sensitive);
- }
- return context.getString(R.string.notifications_priority);
- } else if (appRow.sensitive) {
- return context.getString(R.string.notifications_sensitive);
}
- return context.getString(R.string.notifications_enabled);
+ ArrayList<CharSequence> notifSummary = new ArrayList<>();
+ if (appRow.priority) {
+ notifSummary.add(context.getString(R.string.notifications_priority));
+ }
+ if (appRow.sensitive) {
+ notifSummary.add(context.getString(R.string.notifications_sensitive));
+ }
+ if (!appRow.peekable) {
+ notifSummary.add(context.getString(R.string.notifications_no_peeking));
+ }
+ switch (notifSummary.size()) {
+ case 3:
+ return context.getString(R.string.notifications_three_items,
+ notifSummary.get(0), notifSummary.get(1), notifSummary.get(2));
+ case 2:
+ return context.getString(R.string.notifications_two_items,
+ notifSummary.get(0), notifSummary.get(1));
+ case 1:
+ return notifSummary.get(0);
+ default:
+ return context.getString(R.string.notifications_enabled);
+ }
}
static class DisableChanger extends AsyncTask<Object, Object, Object> {
diff --git a/src/com/android/settings/applications/ManageApplications.java b/src/com/android/settings/applications/ManageApplications.java
index e7ee1d4..b9f49d1 100644
--- a/src/com/android/settings/applications/ManageApplications.java
+++ b/src/com/android/settings/applications/ManageApplications.java
@@ -111,11 +111,12 @@
public static final int FILTER_APPS_DISABLED = 2;
public static final int FILTER_APPS_BLOCKED = 3;
public static final int FILTER_APPS_PRIORITY = 4;
- public static final int FILTER_APPS_SENSITIVE = 5;
- public static final int FILTER_APPS_PERSONAL = 6;
- public static final int FILTER_APPS_WORK = 7;
- public static final int FILTER_APPS_WITH_DOMAIN_URLS = 8;
- public static final int FILTER_APPS_USAGE_ACCESS = 9;
+ public static final int FILTER_APPS_NO_PEEKING = 5;
+ public static final int FILTER_APPS_SENSITIVE = 6;
+ public static final int FILTER_APPS_PERSONAL = 7;
+ public static final int FILTER_APPS_WORK = 8;
+ public static final int FILTER_APPS_WITH_DOMAIN_URLS = 9;
+ public static final int FILTER_APPS_USAGE_ACCESS = 10;
// This is the string labels for the filter modes above, the order must be kept in sync.
public static final int[] FILTER_LABELS = new int[] {
@@ -124,6 +125,7 @@
R.string.filter_apps_disabled, // Disabled
R.string.filter_notif_blocked_apps, // Blocked Notifications
R.string.filter_notif_priority_apps, // Priority Notifications
+ R.string.filter_notif_no_peeking, // No peeking Notifications
R.string.filter_notif_sensitive_apps, // Sensitive Notifications
R.string.filter_personal_apps, // Personal
R.string.filter_work_apps, // Work
@@ -138,6 +140,7 @@
ApplicationsState.FILTER_DISABLED, // Disabled
AppStateNotificationBridge.FILTER_APP_NOTIFICATION_BLOCKED, // Blocked Notifications
AppStateNotificationBridge.FILTER_APP_NOTIFICATION_PRIORITY, // Priority Notifications
+ AppStateNotificationBridge.FILTER_APP_NOTIFICATION_NO_PEEK, // No peeking Notifications
AppStateNotificationBridge.FILTER_APP_NOTIFICATION_SENSITIVE, // Sensitive Notifications
ApplicationsState.FILTER_PERSONAL, // Personal
ApplicationsState.FILTER_WORK, // Work
@@ -305,6 +308,7 @@
mFilterAdapter.enableFilter(FILTER_APPS_BLOCKED);
mFilterAdapter.enableFilter(FILTER_APPS_PRIORITY);
mFilterAdapter.enableFilter(FILTER_APPS_SENSITIVE);
+ mFilterAdapter.enableFilter(FILTER_APPS_NO_PEEKING);
}
if (mListType == LIST_TYPE_STORAGE) {
mApplications.setOverrideFilter(new VolumeFilter(mVolumeUuid));
diff --git a/src/com/android/settings/deviceinfo/MigrateEstimateTask.java b/src/com/android/settings/deviceinfo/MigrateEstimateTask.java
new file mode 100644
index 0000000..bc8ff92
--- /dev/null
+++ b/src/com/android/settings/deviceinfo/MigrateEstimateTask.java
@@ -0,0 +1,126 @@
+/*
+ * 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.deviceinfo;
+
+import static com.android.settings.deviceinfo.StorageSettings.TAG;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.net.TrafficStats;
+import android.os.AsyncTask;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.os.storage.StorageManager;
+import android.os.storage.VolumeInfo;
+import android.telecom.Log;
+import android.text.format.DateUtils;
+import android.text.format.Formatter;
+
+import com.android.internal.app.IMediaContainerService;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+public abstract class MigrateEstimateTask extends AsyncTask<Void, Void, Long> implements
+ ServiceConnection {
+ private static final String EXTRA_SIZE_BYTES = "size_bytes";
+
+ private static final ComponentName DEFAULT_CONTAINER_COMPONENT = new ComponentName(
+ "com.android.defcontainer", "com.android.defcontainer.DefaultContainerService");
+
+ /**
+ * Assume roughly a Class 10 card.
+ */
+ private static final long SPEED_ESTIMATE_BPS = 10 * TrafficStats.MB_IN_BYTES;
+
+ private final Context mContext;
+ private final StorageManager mStorage;
+
+ private final CountDownLatch mConnected = new CountDownLatch(1);
+ private IMediaContainerService mService;
+
+ private long mSizeBytes = -1;
+ private long mTimeMillis = -1;
+
+ public MigrateEstimateTask(Context context) {
+ mContext = context;
+ mStorage = context.getSystemService(StorageManager.class);
+ }
+
+ public void copyFrom(Intent intent) {
+ mSizeBytes = intent.getLongExtra(EXTRA_SIZE_BYTES, -1);
+ }
+
+ public void copyTo(Intent intent) {
+ intent.putExtra(EXTRA_SIZE_BYTES, mSizeBytes);
+ }
+
+ @Override
+ protected Long doInBackground(Void... params) {
+ if (mSizeBytes != -1) {
+ return mSizeBytes;
+ }
+
+ final VolumeInfo privateVol = mContext.getPackageManager().getPrimaryStorageCurrentVolume();
+ final VolumeInfo emulatedVol = mStorage.findEmulatedForPrivate(privateVol);
+
+ final String path = emulatedVol.getPath().getAbsolutePath();
+ Log.d(TAG, "Estimating for current path " + path);
+
+ final Intent intent = new Intent().setComponent(DEFAULT_CONTAINER_COMPONENT);
+ mContext.bindServiceAsUser(intent, this, Context.BIND_AUTO_CREATE, UserHandle.OWNER);
+
+ try {
+ if (mConnected.await(15, TimeUnit.SECONDS)) {
+ return mService.calculateDirectorySize(path);
+ }
+ } catch (InterruptedException | RemoteException e) {
+ Log.w(TAG, "Failed to measure " + path);
+ } finally {
+ mContext.unbindService(this);
+ }
+
+ return -1L;
+ }
+
+ @Override
+ protected void onPostExecute(Long result) {
+ mSizeBytes = result;
+ mTimeMillis = (mSizeBytes * DateUtils.SECOND_IN_MILLIS) / SPEED_ESTIMATE_BPS;
+
+ final String size = Formatter.formatFileSize(mContext, mSizeBytes);
+ final String time = DateUtils.formatDuration(mTimeMillis).toString();
+ onPostExecute(size, time);
+ }
+
+ public abstract void onPostExecute(String size, String time);
+
+ @Override
+ public void onServiceConnected(ComponentName name, IBinder service) {
+ mService = IMediaContainerService.Stub.asInterface(service);
+ mConnected.countDown();
+ }
+
+ @Override
+ public void onServiceDisconnected(ComponentName name) {
+ // Ignored; we leave service in place for the background thread to
+ // run into DeadObjectException
+ }
+}
diff --git a/src/com/android/settings/deviceinfo/PrivateVolumeFormat.java b/src/com/android/settings/deviceinfo/PrivateVolumeFormat.java
index e16778f..669f2ed 100644
--- a/src/com/android/settings/deviceinfo/PrivateVolumeFormat.java
+++ b/src/com/android/settings/deviceinfo/PrivateVolumeFormat.java
@@ -67,6 +67,7 @@
final Intent intent = new Intent(getActivity(), StorageWizardFormatProgress.class);
intent.putExtra(DiskInfo.EXTRA_DISK_ID, mDisk.getId());
intent.putExtra(StorageWizardFormatConfirm.EXTRA_FORMAT_PRIVATE, false);
+ intent.putExtra(StorageWizardFormatConfirm.EXTRA_FORGET_UUID, mVolume.getFsUuid());
startActivity(intent);
getActivity().finish();
}
diff --git a/src/com/android/settings/deviceinfo/PrivateVolumeSettings.java b/src/com/android/settings/deviceinfo/PrivateVolumeSettings.java
index 3e2b570..e5f50dd 100644
--- a/src/com/android/settings/deviceinfo/PrivateVolumeSettings.java
+++ b/src/com/android/settings/deviceinfo/PrivateVolumeSettings.java
@@ -34,6 +34,7 @@
import android.os.Environment;
import android.os.UserHandle;
import android.os.UserManager;
+import android.os.storage.DiskInfo;
import android.os.storage.StorageEventListener;
import android.os.storage.StorageManager;
import android.os.storage.VolumeInfo;
@@ -271,6 +272,7 @@
final MenuItem mount = menu.findItem(R.id.storage_mount);
final MenuItem unmount = menu.findItem(R.id.storage_unmount);
final MenuItem format = menu.findItem(R.id.storage_format);
+ final MenuItem migrate = menu.findItem(R.id.storage_migrate);
final MenuItem usb = menu.findItem(R.id.storage_usb);
// Actions live in menu for non-internal private volumes; they're shown
@@ -287,6 +289,11 @@
format.setVisible(true);
}
+ // Only offer to migrate when not current storage
+ final VolumeInfo privateVol = getActivity().getPackageManager()
+ .getPrimaryStorageCurrentVolume();
+ migrate.setVisible(!Objects.equals(mVolume, privateVol));
+
// TODO: show usb if we jumped past first screen
usb.setVisible(false);
}
@@ -312,6 +319,11 @@
startFragment(this, PrivateVolumeFormat.class.getCanonicalName(),
R.string.storage_menu_format, 0, args);
return true;
+ case R.id.storage_migrate:
+ final Intent intent = new Intent(context, StorageWizardMigrateConfirm.class);
+ intent.putExtra(VolumeInfo.EXTRA_VOLUME_ID, mVolume.getId());
+ startActivity(intent);
+ return true;
case R.id.storage_usb:
startFragment(this, UsbSettings.class.getCanonicalName(),
R.string.storage_title_usb, 0, null);
@@ -442,8 +454,8 @@
}
@Override
- public void onVolumeMetadataChanged(String fsUuid) {
- if (Objects.equals(mVolume.getFsUuid(), fsUuid)) {
+ public void onVolumeRecordChanged(VolumeRecord rec) {
+ if (Objects.equals(mVolume.getFsUuid(), rec.getFsUuid())) {
mVolume = mStorageManager.findVolumeById(mVolumeId);
update();
}
diff --git a/src/com/android/settings/deviceinfo/PublicVolumeSettings.java b/src/com/android/settings/deviceinfo/PublicVolumeSettings.java
index 1d7991d..dee644a 100644
--- a/src/com/android/settings/deviceinfo/PublicVolumeSettings.java
+++ b/src/com/android/settings/deviceinfo/PublicVolumeSettings.java
@@ -24,6 +24,7 @@
import android.os.storage.StorageEventListener;
import android.os.storage.StorageManager;
import android.os.storage.VolumeInfo;
+import android.os.storage.VolumeRecord;
import android.preference.Preference;
import android.preference.PreferenceScreen;
import android.provider.DocumentsContract;
@@ -220,8 +221,8 @@
}
@Override
- public void onVolumeMetadataChanged(String fsUuid) {
- if (Objects.equals(mVolume.getFsUuid(), fsUuid)) {
+ public void onVolumeRecordChanged(VolumeRecord rec) {
+ if (Objects.equals(mVolume.getFsUuid(), rec.getFsUuid())) {
mVolume = mStorageManager.findVolumeById(mVolumeId);
update();
}
diff --git a/src/com/android/settings/deviceinfo/StorageWizardBase.java b/src/com/android/settings/deviceinfo/StorageWizardBase.java
index 42c74a5..31f7af4 100644
--- a/src/com/android/settings/deviceinfo/StorageWizardBase.java
+++ b/src/com/android/settings/deviceinfo/StorageWizardBase.java
@@ -35,6 +35,8 @@
import com.android.setupwizardlib.view.NavigationBar.NavigationBarListener;
import java.text.NumberFormat;
+import java.util.List;
+import java.util.Objects;
public abstract class StorageWizardBase extends Activity implements NavigationBarListener {
protected StorageManager mStorage;
@@ -56,7 +58,7 @@
final String diskId = getIntent().getStringExtra(DiskInfo.EXTRA_DISK_ID);
if (!TextUtils.isEmpty(diskId)) {
mDisk = mStorage.findDiskById(diskId);
- } else {
+ } else if (mVolume != null) {
mDisk = mVolume.getDisk();
}
@@ -130,4 +132,14 @@
public void onNavigateNext() {
throw new UnsupportedOperationException();
}
+
+ protected VolumeInfo findFirstVolume(int type) {
+ final List<VolumeInfo> vols = mStorage.getVolumes();
+ for (VolumeInfo vol : vols) {
+ if (Objects.equals(mDisk.getId(), vol.getDiskId()) && (vol.getType() == type)) {
+ return vol;
+ }
+ }
+ return null;
+ }
}
diff --git a/src/com/android/settings/deviceinfo/StorageWizardFormatConfirm.java b/src/com/android/settings/deviceinfo/StorageWizardFormatConfirm.java
index 81073d6..33f2173 100644
--- a/src/com/android/settings/deviceinfo/StorageWizardFormatConfirm.java
+++ b/src/com/android/settings/deviceinfo/StorageWizardFormatConfirm.java
@@ -25,6 +25,7 @@
public class StorageWizardFormatConfirm extends StorageWizardBase {
public static final String EXTRA_FORMAT_PRIVATE = "format_private";
+ public static final String EXTRA_FORGET_UUID = "forget_uuid";
private boolean mFormatPrivate;
@@ -56,6 +57,7 @@
final Intent intent = new Intent(this, StorageWizardFormatProgress.class);
intent.putExtra(DiskInfo.EXTRA_DISK_ID, mDisk.getId());
intent.putExtra(EXTRA_FORMAT_PRIVATE, mFormatPrivate);
+ intent.putExtra(EXTRA_FORGET_UUID, getIntent().getStringExtra(EXTRA_FORGET_UUID));
startActivity(intent);
finishAffinity();
}
diff --git a/src/com/android/settings/deviceinfo/StorageWizardFormatProgress.java b/src/com/android/settings/deviceinfo/StorageWizardFormatProgress.java
index e60bbcf..9ab714a 100644
--- a/src/com/android/settings/deviceinfo/StorageWizardFormatProgress.java
+++ b/src/com/android/settings/deviceinfo/StorageWizardFormatProgress.java
@@ -23,6 +23,8 @@
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.storage.DiskInfo;
+import android.os.storage.VolumeInfo;
+import android.text.TextUtils;
import android.util.Log;
import android.view.View;
import android.widget.Toast;
@@ -72,12 +74,25 @@
protected void onPostExecute(Exception e) {
final Context context = StorageWizardFormatProgress.this;
if (e == null) {
+ final String forgetUuid = getIntent().getStringExtra(
+ StorageWizardFormatConfirm.EXTRA_FORGET_UUID);
+ if (!TextUtils.isEmpty(forgetUuid)) {
+ mStorage.forgetVolume(forgetUuid);
+ }
+
+ final boolean offerMigrate;
if (mFormatPrivate) {
- // TODO: bring back migration once implemented
-// final Intent intent = new Intent(context, StorageWizardMigrate.class);
-// intent.putExtra(DiskInfo.EXTRA_DISK_ID, mDisk.getId());
-// startActivity(intent);
- final Intent intent = new Intent(context, StorageWizardReady.class);
+ // Offer to migrate only if storage is currently internal
+ final VolumeInfo privateVol = getPackageManager()
+ .getPrimaryStorageCurrentVolume();
+ offerMigrate = (privateVol != null
+ && VolumeInfo.ID_PRIVATE_INTERNAL.equals(privateVol.getId()));
+ } else {
+ offerMigrate = false;
+ }
+
+ if (offerMigrate) {
+ final Intent intent = new Intent(context, StorageWizardMigrate.class);
intent.putExtra(DiskInfo.EXTRA_DISK_ID, mDisk.getId());
startActivity(intent);
} else {
diff --git a/src/com/android/settings/deviceinfo/StorageWizardMigrate.java b/src/com/android/settings/deviceinfo/StorageWizardMigrate.java
index 4d42613..7831a07 100644
--- a/src/com/android/settings/deviceinfo/StorageWizardMigrate.java
+++ b/src/com/android/settings/deviceinfo/StorageWizardMigrate.java
@@ -19,8 +19,6 @@
import android.content.Intent;
import android.os.Bundle;
import android.os.storage.DiskInfo;
-import android.text.format.DateUtils;
-import android.text.format.Formatter;
import android.widget.CompoundButton;
import android.widget.CompoundButton.OnCheckedChangeListener;
import android.widget.RadioButton;
@@ -29,6 +27,8 @@
import com.android.settings.R;
public class StorageWizardMigrate extends StorageWizardBase {
+ private MigrateEstimateTask mEstimate;
+
private RadioButton mRadioNow;
private RadioButton mRadioLater;
@@ -39,11 +39,8 @@
Preconditions.checkNotNull(mDisk);
- final String time = DateUtils.formatDuration(0).toString();
- final String size = Formatter.formatFileSize(this, 0);
-
setHeaderText(R.string.storage_wizard_migrate_title, mDisk.getDescription());
- setBodyText(R.string.storage_wizard_migrate_body, mDisk.getDescription(), time, size);
+ setBodyText(R.string.memory_calculating_size);
mRadioNow = (RadioButton) findViewById(R.id.storage_wizard_migrate_now);
mRadioLater = (RadioButton) findViewById(R.id.storage_wizard_migrate_later);
@@ -52,6 +49,17 @@
mRadioLater.setOnCheckedChangeListener(mRadioListener);
mRadioNow.setChecked(true);
+
+ mEstimate = new MigrateEstimateTask(this) {
+ @Override
+ public void onPostExecute(String size, String time) {
+ setBodyText(R.string.storage_wizard_migrate_body,
+ mDisk.getDescription(), time, size);
+ }
+ };
+
+ mEstimate.copyFrom(getIntent());
+ mEstimate.execute();
}
private final OnCheckedChangeListener mRadioListener = new OnCheckedChangeListener() {
@@ -72,6 +80,7 @@
if (mRadioNow.isChecked()) {
final Intent intent = new Intent(this, StorageWizardMigrateConfirm.class);
intent.putExtra(DiskInfo.EXTRA_DISK_ID, mDisk.getId());
+ mEstimate.copyTo(intent);
startActivity(intent);
} else if (mRadioLater.isChecked()) {
final Intent intent = new Intent(this, StorageWizardReady.class);
diff --git a/src/com/android/settings/deviceinfo/StorageWizardMigrateConfirm.java b/src/com/android/settings/deviceinfo/StorageWizardMigrateConfirm.java
index 9aa1441..daa76d7 100644
--- a/src/com/android/settings/deviceinfo/StorageWizardMigrateConfirm.java
+++ b/src/com/android/settings/deviceinfo/StorageWizardMigrateConfirm.java
@@ -17,36 +17,54 @@
package com.android.settings.deviceinfo;
import android.content.Intent;
+import android.content.pm.PackageManager;
import android.os.Bundle;
-import android.os.storage.DiskInfo;
-import android.text.format.DateUtils;
-import android.text.format.Formatter;
+import android.os.storage.VolumeInfo;
-import com.android.internal.util.Preconditions;
import com.android.settings.R;
public class StorageWizardMigrateConfirm extends StorageWizardBase {
+ private MigrateEstimateTask mEstimate;
+
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.storage_wizard_generic);
- Preconditions.checkNotNull(mDisk);
+ // When called with just disk, find the first private volume
+ if (mVolume == null) {
+ mVolume = findFirstVolume(VolumeInfo.TYPE_PRIVATE);
+ }
- final String time = DateUtils.formatDuration(0).toString();
- final String size = Formatter.formatFileSize(this, 0);
+ final VolumeInfo sourceVol = getPackageManager().getPrimaryStorageCurrentVolume();
+ final String sourceDescrip = mStorage.getBestVolumeDescription(sourceVol);
+ final String targetDescrip = mStorage.getBestVolumeDescription(mVolume);
- setHeaderText(R.string.storage_wizard_migrate_confirm_title, mDisk.getDescription());
- setBodyText(R.string.storage_wizard_migrate_confirm_body, time, size);
- setSecondaryBodyText(R.string.storage_wizard_migrate_details, mDisk.getDescription());
+ setHeaderText(R.string.storage_wizard_migrate_confirm_title, targetDescrip);
+ setBodyText(R.string.memory_calculating_size);
+ setSecondaryBodyText(R.string.storage_wizard_migrate_details, targetDescrip);
+
+ mEstimate = new MigrateEstimateTask(this) {
+ @Override
+ public void onPostExecute(String size, String time) {
+ setBodyText(R.string.storage_wizard_migrate_confirm_body, time, size,
+ sourceDescrip);
+ }
+ };
+
+ mEstimate.copyFrom(getIntent());
+ mEstimate.execute();
getNextButton().setText(R.string.storage_wizard_migrate_confirm_next);
}
@Override
public void onNavigateNext() {
+ final int moveId = getPackageManager().movePrimaryStorage(mVolume);
+
final Intent intent = new Intent(this, StorageWizardMigrateProgress.class);
- intent.putExtra(DiskInfo.EXTRA_DISK_ID, mDisk.getId());
+ intent.putExtra(VolumeInfo.EXTRA_VOLUME_ID, mVolume.getId());
+ intent.putExtra(PackageManager.EXTRA_MOVE_ID, moveId);
startActivity(intent);
finishAffinity();
}
diff --git a/src/com/android/settings/deviceinfo/StorageWizardMigrateProgress.java b/src/com/android/settings/deviceinfo/StorageWizardMigrateProgress.java
index b53b250..70d93f8 100644
--- a/src/com/android/settings/deviceinfo/StorageWizardMigrateProgress.java
+++ b/src/com/android/settings/deviceinfo/StorageWizardMigrateProgress.java
@@ -16,13 +16,15 @@
package com.android.settings.deviceinfo;
+import static android.content.pm.PackageManager.EXTRA_MOVE_ID;
import static com.android.settings.deviceinfo.StorageSettings.TAG;
import android.content.Context;
import android.content.Intent;
-import android.os.AsyncTask;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.MoveCallback;
import android.os.Bundle;
-import android.os.SystemClock;
+import android.os.Handler;
import android.os.storage.DiskInfo;
import android.util.Log;
import android.view.View;
@@ -32,45 +34,51 @@
import com.android.settings.R;
public class StorageWizardMigrateProgress extends StorageWizardBase {
+ private int mMoveId;
+
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.storage_wizard_progress);
- Preconditions.checkNotNull(mDisk);
+ Preconditions.checkNotNull(mVolume);
- setHeaderText(R.string.storage_wizard_migrate_progress_title, mDisk.getDescription());
- setBodyText(R.string.storage_wizard_migrate_details, mDisk.getDescription());
+ mMoveId = getIntent().getIntExtra(EXTRA_MOVE_ID, -1);
- setCurrentProgress(20);
+ final String descrip = mStorage.getBestVolumeDescription(mVolume);
+ setHeaderText(R.string.storage_wizard_migrate_progress_title, descrip);
+ setBodyText(R.string.storage_wizard_migrate_details, descrip);
getNextButton().setVisibility(View.GONE);
- new MigrateTask().execute();
+ // Register for updates and push through current status
+ getPackageManager().registerMoveCallback(mCallback, new Handler());
+ mCallback.onStatusChanged(mMoveId, getPackageManager().getMoveStatus(mMoveId), -1);
}
- public class MigrateTask extends AsyncTask<Void, Void, Exception> {
+ private final MoveCallback mCallback = new MoveCallback() {
@Override
- protected Exception doInBackground(Void... params) {
- // TODO: wire up migration
- SystemClock.sleep(2000);
- return null;
- }
+ public void onStatusChanged(int moveId, int status, long estMillis) {
+ if (mMoveId != moveId) return;
- @Override
- protected void onPostExecute(Exception e) {
final Context context = StorageWizardMigrateProgress.this;
- if (e == null) {
- final Intent intent = new Intent(context, StorageWizardReady.class);
- intent.putExtra(DiskInfo.EXTRA_DISK_ID, mDisk.getId());
- startActivity(intent);
+ if (PackageManager.isMoveStatusFinished(status)) {
+ Log.d(TAG, "Finished with status " + status);
+ if (status == PackageManager.MOVE_SUCCEEDED) {
+ if (mDisk != null) {
+ final Intent intent = new Intent(context, StorageWizardReady.class);
+ intent.putExtra(DiskInfo.EXTRA_DISK_ID, mDisk.getId());
+ startActivity(intent);
+ }
+ } else {
+ Toast.makeText(context, getString(R.string.insufficient_storage),
+ Toast.LENGTH_LONG).show();
+ }
finishAffinity();
} else {
- Log.e(TAG, "Failed to migrate", e);
- Toast.makeText(context, e.getMessage(), Toast.LENGTH_LONG).show();
- finishAffinity();
+ setCurrentProgress(status);
}
}
- }
+ };
}
diff --git a/src/com/android/settings/deviceinfo/StorageWizardMoveProgress.java b/src/com/android/settings/deviceinfo/StorageWizardMoveProgress.java
index 1202b9e..86e623f 100644
--- a/src/com/android/settings/deviceinfo/StorageWizardMoveProgress.java
+++ b/src/com/android/settings/deviceinfo/StorageWizardMoveProgress.java
@@ -49,7 +49,7 @@
// Register for updates and push through current status
getPackageManager().registerMoveCallback(mCallback, new Handler());
- mCallback.onStatusChanged(mMoveId, null, getPackageManager().getMoveStatus(mMoveId), -1);
+ mCallback.onStatusChanged(mMoveId, getPackageManager().getMoveStatus(mMoveId), -1);
}
@Override
@@ -60,7 +60,7 @@
private final MoveCallback mCallback = new MoveCallback() {
@Override
- public void onStatusChanged(int moveId, String moveTitle, int status, long estMillis) {
+ public void onStatusChanged(int moveId, int status, long estMillis) {
if (mMoveId != moveId) return;
if (PackageManager.isMoveStatusFinished(status)) {
diff --git a/src/com/android/settings/deviceinfo/StorageWizardReady.java b/src/com/android/settings/deviceinfo/StorageWizardReady.java
index 26038ce..6d8846b 100644
--- a/src/com/android/settings/deviceinfo/StorageWizardReady.java
+++ b/src/com/android/settings/deviceinfo/StorageWizardReady.java
@@ -22,9 +22,6 @@
import com.android.internal.util.Preconditions;
import com.android.settings.R;
-import java.util.List;
-import java.util.Objects;
-
public class StorageWizardReady extends StorageWizardBase {
@Override
protected void onCreate(Bundle savedInstanceState) {
@@ -37,19 +34,14 @@
// TODO: handle mixed partition cases instead of just guessing based on
// first volume type we encounter
- final List<VolumeInfo> vols = mStorage.getVolumes();
- for (VolumeInfo vol : vols) {
- if (!Objects.equals(mDisk.getId(), vol.getDiskId())) continue;
-
- if (vol.getType() == VolumeInfo.TYPE_PUBLIC) {
- setBodyText(R.string.storage_wizard_ready_external_body,
- mDisk.getDescription());
- break;
- } else if (vol.getType() == VolumeInfo.TYPE_PRIVATE) {
- setBodyText(R.string.storage_wizard_ready_internal_body,
- mDisk.getDescription());
- break;
- }
+ final VolumeInfo publicVol = findFirstVolume(VolumeInfo.TYPE_PUBLIC);
+ final VolumeInfo privateVol = findFirstVolume(VolumeInfo.TYPE_PRIVATE);
+ if (publicVol != null) {
+ setBodyText(R.string.storage_wizard_ready_external_body,
+ mDisk.getDescription());
+ } else if (privateVol != null) {
+ setBodyText(R.string.storage_wizard_ready_internal_body,
+ mDisk.getDescription());
}
getNextButton().setText(R.string.done);
diff --git a/src/com/android/settings/fingerprint/FingerprintSettings.java b/src/com/android/settings/fingerprint/FingerprintSettings.java
index 2469f7e..85d3762 100644
--- a/src/com/android/settings/fingerprint/FingerprintSettings.java
+++ b/src/com/android/settings/fingerprint/FingerprintSettings.java
@@ -39,6 +39,7 @@
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
+import android.view.WindowManager;
import android.widget.EditText;
import android.widget.Toast;
@@ -90,7 +91,9 @@
public static class FingerprintSettingsFragment extends SettingsPreferenceFragment
implements OnPreferenceChangeListener, Indexable {
- private static final int MAX_RETRY_ATTEMPTS = 5;
+ private static final int MAX_RETRY_ATTEMPTS = 20;
+ private static final int RESET_HIGHLIGHT_DELAY_MS = 500;
+
private static final String TAG = "FingerprintSettings";
private static final String KEY_FINGERPRINT_ITEM_PREFIX = "key_fingerprint_item";
private static final String KEY_USAGE_CATEGORY = "fingerprint_usage_category";
@@ -101,7 +104,8 @@
private static final String KEY_LAUNCHED_CONFIRM = "launched_confirm";
private static final int MSG_REFRESH_FINGERPRINT_TEMPLATES = 1000;
- private static final int MSG_HIGHLIGHT_FINGERPRINT_ITEM = 1001;
+ private static final int MSG_FINGER_AUTH_SUCCESS = 1001;
+ private static final int MSG_FINGER_AUTH_FAIL = 1002;
private static final int CONFIRM_REQUEST = 101;
private static final int CHOOSE_LOCK_GENERIC_REQUEST = 102;
@@ -118,27 +122,28 @@
private int mMaxFingerprintAttempts;
private byte[] mToken;
private boolean mLaunchedConfirm;
+ private Drawable mHighlightDrawable;
private AuthenticationCallback mAuthCallback = new AuthenticationCallback() {
@Override
public void onAuthenticationSucceeded(AuthenticationResult result) {
- mHandler.obtainMessage(MSG_HIGHLIGHT_FINGERPRINT_ITEM,
- result.getFingerprint().getFingerId(), 0).sendToTarget();
- retryFingerprint(true);
+ int fingerId = result.getFingerprint().getFingerId();
+ mHandler.obtainMessage(MSG_FINGER_AUTH_SUCCESS, fingerId, 0).sendToTarget();
}
public void onAuthenticationFailed() {
- retryFingerprint(true);
+ mHandler.obtainMessage(MSG_FINGER_AUTH_FAIL).sendToTarget();
};
@Override
public void onAuthenticationError(int errMsgId, CharSequence errString) {
// get activity will be null on a screen rotation
- if (getActivity() != null) {
- Toast.makeText(getActivity(), errString, Toast.LENGTH_SHORT);
- if (errMsgId != FingerprintManager.FINGERPRINT_ERROR_CANCELED) {
- retryFingerprint(false);
- }
+ Activity activity = getActivity();
+ if (activity != null) {
+ Toast.makeText(activity, errString, Toast.LENGTH_SHORT);
+ }
+ if (errMsgId != FingerprintManager.FINGERPRINT_ERROR_CANCELED) {
+ retryFingerprint(false);
}
}
@@ -166,8 +171,12 @@
case MSG_REFRESH_FINGERPRINT_TEMPLATES:
removeFingerprintPreference(msg.arg1);
break;
- case MSG_HIGHLIGHT_FINGERPRINT_ITEM:
+ case MSG_FINGER_AUTH_SUCCESS:
highlightFingerprintItem(msg.arg1);
+ retryFingerprint(true);
+ break;
+ case MSG_FINGER_AUTH_FAIL:
+ retryFingerprint(false);
break;
}
};
@@ -206,7 +215,8 @@
KEY_LAUNCHED_CONFIRM, false);
}
- mFingerprintManager = (FingerprintManager) getActivity().getSystemService(
+ Activity activity = getActivity();
+ mFingerprintManager = (FingerprintManager) activity.getSystemService(
Context.FINGERPRINT_SERVICE);
// Need to authenticate a session token if none
@@ -228,17 +238,6 @@
}
}
- private void highlightFingerprintItem(int fpId) {
- String prefName = genKey(fpId);
- Preference pref = mManageCategory.findPreference(prefName);
- if (pref instanceof FingerprintPreference) {
- final FingerprintPreference fpref = (FingerprintPreference) pref;
- fpref.highlight();
- } else {
- Log.w(TAG, "Wrong pref " + (pref != null ? pref.getKey() : "null"));
- }
- }
-
/**
* Important!
*
@@ -306,8 +305,11 @@
super.onResume();
// Make sure we reload the preference hierarchy since fingerprints may be added,
// deleted or renamed.
- createPreferenceHierarchy();
+ updatePreferences();
+ }
+ private void updatePreferences() {
+ createPreferenceHierarchy();
retryFingerprint(true);
}
@@ -345,7 +347,7 @@
private void showRenameDeleteDialog(Preference pref, final Fingerprint fp) {
final Activity activity = getActivity();
- AlertDialog dialog = new AlertDialog.Builder(activity)
+ final AlertDialog dialog = new AlertDialog.Builder(activity)
.setView(R.layout.fingerprint_rename_dialog)
.setPositiveButton(R.string.security_settings_fingerprint_enroll_dialog_ok,
new DialogInterface.OnClickListener() {
@@ -356,6 +358,7 @@
if (!newName.equals(name)) {
if (DEBUG) Log.v(TAG, "rename " + name + " to " + newName);
mFingerprintManager.rename(fp.getFingerId(), newName);
+ updatePreferences();
}
dialog.dismiss();
}
@@ -374,6 +377,16 @@
mDialogTextField = (EditText) dialog.findViewById(R.id.fingerprint_rename_field);
mDialogTextField.setText(fp.getName());
mDialogTextField.selectAll();
+ // show the IME
+ mDialogTextField.setOnFocusChangeListener(new View.OnFocusChangeListener() {
+ @Override
+ public void onFocusChange(View v, boolean hasFocus) {
+ if (hasFocus) {
+ dialog.getWindow().setSoftInputMode(
+ WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE);
+ }
+ }
+ });
}
@Override
@@ -413,6 +426,33 @@
}
}
+ private Drawable getHighlightDrawable() {
+ if (mHighlightDrawable == null) {
+ mHighlightDrawable = getActivity().getDrawable(R.drawable.preference_highlight);
+ }
+ return mHighlightDrawable;
+ }
+
+ private void highlightFingerprintItem(int fpId) {
+ String prefName = genKey(fpId);
+ FingerprintPreference fpref =
+ (FingerprintPreference) mManageCategory.findPreference(prefName);
+ final Drawable highlight = getHighlightDrawable();
+ final View view = fpref.getView();
+ final int centerX = view.getWidth() / 2;
+ final int centerY = view.getHeight() / 2;
+ highlight.setHotspot(centerX, centerY);
+ view.setBackground(highlight);
+ view.setPressed(true);
+ mHandler.postDelayed(new Runnable() {
+ @Override
+ public void run() {
+ view.setPressed(false);
+ view.setBackground(null);
+ }
+ }, RESET_HIGHLIGHT_DELAY_MS);
+ }
+
private void launchChooseOrConfirmLock() {
Intent intent = new Intent();
long challenge = mFingerprintManager.preEnroll();
@@ -423,7 +463,8 @@
intent.setClassName("com.android.settings", ChooseLockGeneric.class.getName());
intent.putExtra(ChooseLockGeneric.ChooseLockGenericFragment.MINIMUM_QUALITY_KEY,
DevicePolicyManager.PASSWORD_QUALITY_SOMETHING);
- intent.putExtra(ChooseLockGeneric.ChooseLockGenericFragment.HIDE_DISABLED_PREFS, true);
+ intent.putExtra(ChooseLockGeneric.ChooseLockGenericFragment.HIDE_DISABLED_PREFS,
+ true);
intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_HAS_CHALLENGE, true);
intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE, challenge);
startActivityForResult(intent, CHOOSE_LOCK_GENERIC_REQUEST);
@@ -432,16 +473,12 @@
}
public static class FingerprintPreference extends Preference {
- private static final int RESET_HIGHLIGHT_DELAY_MS = 500;
private Fingerprint mFingerprint;
private View mView;
- private Drawable mHighlightDrawable;
- private Context mContext;
public FingerprintPreference(Context context, AttributeSet attrs, int defStyleAttr,
int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
- mContext = context;
}
public FingerprintPreference(Context context, AttributeSet attrs, int defStyleAttr) {
this(context, attrs, defStyleAttr, 0);
@@ -455,6 +492,8 @@
this(context, null);
}
+ public View getView() { return mView; }
+
public void setFingerprint(Fingerprint item) {
mFingerprint = item;
}
@@ -463,30 +502,6 @@
return mFingerprint;
}
- private Drawable getHighlightDrawable() {
- if (mHighlightDrawable == null) {
- mHighlightDrawable = mContext.getDrawable(R.drawable.preference_highlight);
- }
- return mHighlightDrawable;
- }
-
- public void highlight() {
- Drawable highlight = getHighlightDrawable();
- final View view = mView;
- view.setBackground(highlight);
- final int centerX = view.getWidth() / 2;
- final int centerY = view.getHeight() / 2;
- highlight.setHotspot(centerX, centerY);
- view.setPressed(true);
- view.postDelayed(new Runnable() {
- @Override
- public void run() {
- view.setPressed(false);
- view.setBackground(null);
- }
- }, RESET_HIGHLIGHT_DELAY_MS);
- }
-
@Override
protected void onBindView(View view) {
super.onBindView(view);
diff --git a/src/com/android/settings/notification/ZenModeAutomationSettings.java b/src/com/android/settings/notification/ZenModeAutomationSettings.java
index dab0a0d..e33e32f 100644
--- a/src/com/android/settings/notification/ZenModeAutomationSettings.java
+++ b/src/com/android/settings/notification/ZenModeAutomationSettings.java
@@ -29,21 +29,22 @@
import android.provider.Settings.Global;
import android.service.notification.ConditionProviderService;
import android.service.notification.ZenModeConfig;
+import android.service.notification.ZenModeConfig.EventInfo;
import android.service.notification.ZenModeConfig.ScheduleInfo;
import android.service.notification.ZenModeConfig.ZenRule;
import android.text.format.DateFormat;
import android.util.Log;
-import android.view.View;
-import android.view.View.OnClickListener;
import com.android.internal.logging.MetricsLogger;
import com.android.settings.R;
import com.android.settings.notification.ManagedServiceSettings.Config;
+import com.android.settings.notification.ZenModeEventRuleSettings.CalendarInfo;
import com.android.settings.notification.ZenRuleNameDialog.RuleInfo;
-import com.android.settings.widget.FloatingActionButton;
import java.text.SimpleDateFormat;
+import java.util.Arrays;
import java.util.Calendar;
+import java.util.Comparator;
import java.util.List;
import java.util.TreeSet;
@@ -68,21 +69,6 @@
}
@Override
- public void onActivityCreated(Bundle savedInstanceState) {
- super.onActivityCreated(savedInstanceState);
- final FloatingActionButton fab = getFloatingActionButton();
- fab.setVisibility(View.VISIBLE);
- fab.setImageResource(R.drawable.ic_menu_add_white);
- fab.setContentDescription(getString(R.string.zen_mode_time_add_rule));
- fab.setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View v) {
- showAddRuleDialog();
- }
- });
- }
-
- @Override
public void onDestroy() {
super.onDestroy();
mServiceListing.setListening(false);
@@ -133,15 +119,32 @@
.putExtra(ZenModeRuleSettingsBase.EXTRA_RULE_ID, ruleId));
}
+ private ZenRuleInfo[] sortedRules() {
+ final ZenRuleInfo[] rt = new ZenRuleInfo[mConfig.automaticRules.size()];
+ for (int i = 0; i < rt.length; i++) {
+ final ZenRuleInfo zri = new ZenRuleInfo();
+ zri.id = mConfig.automaticRules.keyAt(i);
+ zri.rule = mConfig.automaticRules.valueAt(i);
+ rt[i] = zri;
+ }
+ Arrays.sort(rt, RULE_COMPARATOR);
+ return rt;
+ }
+
private void updateControls() {
final PreferenceScreen root = getPreferenceScreen();
root.removeAll();
if (mConfig == null) return;
- for (int i = 0; i < mConfig.automaticRules.size(); i++) {
- final String id = mConfig.automaticRules.keyAt(i);
- final ZenRule rule = mConfig.automaticRules.valueAt(i);
+ final ZenRuleInfo[] sortedRules = sortedRules();
+ for (int i = 0; i < sortedRules.length; i++) {
+ final String id = sortedRules[i].id;
+ final ZenRule rule = sortedRules[i].rule;
final boolean isSchedule = ZenModeConfig.isValidScheduleConditionId(rule.conditionId);
+ final boolean isEvent = ZenModeConfig.isValidEventConditionId(rule.conditionId);
final Preference p = new Preference(mContext);
+ p.setIcon(isSchedule ? R.drawable.ic_schedule
+ : isEvent ? R.drawable.ic_event
+ : R.drawable.ic_label);
p.setTitle(rule.name);
p.setSummary(computeRuleSummary(rule));
p.setPersistent(false);
@@ -149,6 +152,7 @@
@Override
public boolean onPreferenceClick(Preference preference) {
final String action = isSchedule ? ZenModeScheduleRuleSettings.ACTION
+ : isEvent ? ZenModeEventRuleSettings.ACTION
: ZenModeExternalRuleSettings.ACTION;
showRule(action, null, id, rule.name);
return true;
@@ -156,6 +160,18 @@
});
root.addPreference(p);
}
+ final Preference p = new Preference(mContext);
+ p.setIcon(R.drawable.ic_add);
+ p.setTitle(R.string.zen_mode_add_rule);
+ p.setPersistent(false);
+ p.setOnPreferenceClickListener(new OnPreferenceClickListener() {
+ @Override
+ public boolean onPreferenceClick(Preference preference) {
+ showAddRuleDialog();
+ return true;
+ }
+ });
+ root.addPreference(p);
}
@Override
@@ -165,19 +181,69 @@
private String computeRuleSummary(ZenRule rule) {
if (rule == null || !rule.enabled) return getString(R.string.switch_off_text);
- final ScheduleInfo schedule = ZenModeConfig.tryParseScheduleConditionId(rule.conditionId);
final String mode = ZenModeSettings.computeZenModeCaption(getResources(), rule.zenMode);
String summary = getString(R.string.switch_on_text);
+ final ScheduleInfo schedule = ZenModeConfig.tryParseScheduleConditionId(rule.conditionId);
+ final EventInfo event = ZenModeConfig.tryParseEventConditionId(rule.conditionId);
if (schedule != null) {
- final String days = computeContiguousDayRanges(schedule.days);
- final String start = getTime(schedule.startHour, schedule.startMinute);
- final String end = getTime(schedule.endHour, schedule.endMinute);
- final String time = getString(R.string.summary_range_verbal_combination, start, end);
- summary = getString(R.string.zen_mode_rule_summary_combination, days, time);
+ summary = computeScheduleRuleSummary(schedule);
+ } else if (event != null) {
+ summary = computeEventRuleSummary(event);
}
return getString(R.string.zen_mode_rule_summary_combination, summary, mode);
}
+ private String computeScheduleRuleSummary(ScheduleInfo schedule) {
+ final String days = computeContiguousDayRanges(schedule.days);
+ final String start = getTime(schedule.startHour, schedule.startMinute);
+ final String end = getTime(schedule.endHour, schedule.endMinute);
+ final String time = getString(R.string.summary_range_verbal_combination, start, end);
+ return getString(R.string.zen_mode_rule_summary_combination, days, time);
+ }
+
+ private String computeEventRuleSummary(EventInfo event) {
+ final String calendar = computeCalendarName(event);
+ final String attendance = getString(computeAttendance(event));
+ final String reply = getString(computeReply(event));
+ return getString(R.string.zen_mode_rule_summary_combination,
+ getString(R.string.zen_mode_rule_summary_combination, calendar, attendance), reply);
+ }
+
+ private String computeCalendarName(EventInfo event) {
+ if (event.calendar != 0) {
+ final CalendarInfo[] calendars = ZenModeEventRuleSettings.getCalendars(mContext);
+ for (int i = 0; i < calendars.length; i++) {
+ final CalendarInfo calendar = calendars[i];
+ if (calendar.id == event.calendar) {
+ return calendar.name;
+ }
+ }
+ }
+ return getString(R.string.zen_mode_event_rule_summary_any_calendar);
+ }
+
+ private int computeAttendance(EventInfo event) {
+ switch (event.attendance) {
+ case EventInfo.ATTENDANCE_REQUIRED:
+ return R.string.zen_mode_event_rule_attendance_required;
+ case EventInfo.ATTENDANCE_OPTIONAL:
+ return R.string.zen_mode_event_rule_attendance_optional;
+ default:
+ return R.string.zen_mode_event_rule_attendance_required_optional;
+ }
+ }
+
+ private int computeReply(EventInfo event) {
+ switch (event.reply) {
+ case EventInfo.REPLY_ANY_EXCEPT_NO:
+ return R.string.zen_mode_event_rule_summary_any_reply_except_no;
+ case EventInfo.REPLY_YES:
+ return R.string.zen_mode_event_rule_summary_replied_yes;
+ default:
+ return R.string.zen_mode_event_rule_summary_any_reply;
+ }
+ }
+
private String getTime(int hour, int minute) {
mCalendar.set(Calendar.HOUR_OF_DAY, hour);
mCalendar.set(Calendar.MINUTE, minute);
@@ -248,4 +314,24 @@
}
};
+ private static final Comparator<ZenRuleInfo> RULE_COMPARATOR = new Comparator<ZenRuleInfo>() {
+ @Override
+ public int compare(ZenRuleInfo lhs, ZenRuleInfo rhs) {
+ return key(lhs).compareTo(key(rhs));
+ }
+
+ private String key(ZenRuleInfo zri) {
+ final ZenRule rule = zri.rule;
+ final int type = ZenModeConfig.isValidScheduleConditionId(rule.conditionId) ? 1
+ : ZenModeConfig.isValidEventConditionId(rule.conditionId) ? 2
+ : 3;
+ return type + rule.name;
+ }
+ };
+
+ private static class ZenRuleInfo {
+ String id;
+ ZenRule rule;
+ }
+
}
diff --git a/src/com/android/settings/notification/ZenModeEventRuleSettings.java b/src/com/android/settings/notification/ZenModeEventRuleSettings.java
new file mode 100644
index 0000000..38581b6
--- /dev/null
+++ b/src/com/android/settings/notification/ZenModeEventRuleSettings.java
@@ -0,0 +1,180 @@
+/*
+ * 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.notification;
+
+import android.content.Context;
+import android.database.Cursor;
+import android.preference.PreferenceScreen;
+import android.provider.CalendarContract.Calendars;
+import android.provider.Settings;
+import android.service.notification.ZenModeConfig;
+import android.service.notification.ZenModeConfig.EventInfo;
+import android.service.notification.ZenModeConfig.ZenRule;
+
+import com.android.internal.logging.MetricsLogger;
+import com.android.settings.DropDownPreference;
+import com.android.settings.R;
+
+public class ZenModeEventRuleSettings extends ZenModeRuleSettingsBase {
+ private static final String KEY_CALENDAR = "calendar";
+ private static final String KEY_ATTENDANCE = "attendance";
+ private static final String KEY_REPLY = "reply";
+
+ public static final String ACTION = Settings.ACTION_ZEN_MODE_EVENT_RULE_SETTINGS;
+
+ private DropDownPreference mCalendar;
+ private DropDownPreference mAttendance;
+ private DropDownPreference mReply;
+
+ private EventInfo mEvent;
+ private CalendarInfo[] mCalendars;
+
+ @Override
+ protected boolean setRule(ZenRule rule) {
+ mEvent = rule != null ? ZenModeConfig.tryParseEventConditionId(rule.conditionId)
+ : null;
+ return mEvent != null;
+ }
+
+ @Override
+ protected String getZenModeDependency() {
+ return null;
+ }
+
+ @Override
+ protected int getEnabledToastText() {
+ return R.string.zen_event_rule_enabled_toast;
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ reloadCalendar();
+ }
+
+ private void reloadCalendar() {
+ mCalendars = getCalendars(mContext);
+ mCalendar.clearItems();
+ mCalendar.addItem(R.string.zen_mode_event_rule_calendar_any, 0L);
+ for (int i = 0; i < mCalendars.length; i++) {
+ mCalendar.addItem(mCalendars[i].name, mCalendars[i].id);
+ }
+ }
+
+ @Override
+ protected void onCreateInternal() {
+ addPreferencesFromResource(R.xml.zen_mode_event_rule_settings);
+ final PreferenceScreen root = getPreferenceScreen();
+
+ mCalendar = (DropDownPreference) root.findPreference(KEY_CALENDAR);
+ mCalendar.setCallback(new DropDownPreference.Callback() {
+ @Override
+ public boolean onItemSelected(int pos, Object value) {
+ final long calendar = (Long) value;
+ if (calendar == mEvent.calendar) return true;
+ mEvent.calendar = calendar;
+ updateRule(ZenModeConfig.toEventConditionId(mEvent));
+ return true;
+ }
+ });
+
+ mAttendance = (DropDownPreference) root.findPreference(KEY_ATTENDANCE);
+ mAttendance.addItem(R.string.zen_mode_event_rule_attendance_required_optional,
+ EventInfo.ATTENDANCE_REQUIRED_OR_OPTIONAL);
+ mAttendance.addItem(R.string.zen_mode_event_rule_attendance_required,
+ EventInfo.ATTENDANCE_REQUIRED);
+ mAttendance.addItem(R.string.zen_mode_event_rule_attendance_optional,
+ EventInfo.ATTENDANCE_OPTIONAL);
+ mAttendance.setCallback(new DropDownPreference.Callback() {
+ @Override
+ public boolean onItemSelected(int pos, Object value) {
+ final int attendance = (Integer) value;
+ if (attendance == mEvent.attendance) return true;
+ mEvent.attendance = attendance;
+ updateRule(ZenModeConfig.toEventConditionId(mEvent));
+ return true;
+ }
+ });
+
+ mReply = (DropDownPreference) root.findPreference(KEY_REPLY);
+ mReply.addItem(R.string.zen_mode_event_rule_reply_any,
+ EventInfo.REPLY_ANY);
+ mReply.addItem(R.string.zen_mode_event_rule_reply_any_except_no,
+ EventInfo.REPLY_ANY_EXCEPT_NO);
+ mReply.addItem(R.string.zen_mode_event_rule_reply_yes,
+ EventInfo.REPLY_YES);
+ mReply.setCallback(new DropDownPreference.Callback() {
+ @Override
+ public boolean onItemSelected(int pos, Object value) {
+ final int reply = (Integer) value;
+ if (reply == mEvent.reply) return true;
+ mEvent.reply = reply;
+ updateRule(ZenModeConfig.toEventConditionId(mEvent));
+ return true;
+ }
+ });
+
+ reloadCalendar();
+ updateControlsInternal();
+ }
+
+ @Override
+ protected void updateControlsInternal() {
+ mCalendar.setSelectedValue(mEvent.calendar);
+ mAttendance.setSelectedValue(mEvent.attendance);
+ mReply.setSelectedValue(mEvent.reply);
+ }
+
+ @Override
+ protected int getMetricsCategory() {
+ return MetricsLogger.NOTIFICATION_ZEN_MODE_EVENT_RULE;
+ }
+
+ public static CalendarInfo[] getCalendars(Context context) {
+ final String primary = "\"primary\"";
+ final String[] projection = { Calendars._ID, Calendars.CALENDAR_DISPLAY_NAME,
+ "(" + Calendars.ACCOUNT_NAME + "=" + Calendars.OWNER_ACCOUNT + ") AS " + primary };
+ final String selection = primary + " = 1";
+ Cursor cursor = null;
+ try {
+ cursor = context.getContentResolver().query(Calendars.CONTENT_URI, projection,
+ selection, null, null);
+ if (cursor == null) {
+ return new CalendarInfo[0];
+ }
+ final CalendarInfo[] rt = new CalendarInfo[cursor.getCount()];
+ int i = 0;
+ while (cursor.moveToNext()) {
+ final CalendarInfo ci = new CalendarInfo();
+ ci.id = cursor.getLong(0);
+ ci.name = cursor.getString(1);
+ rt[i++] = ci;
+ }
+ return rt;
+ } finally {
+ if (cursor != null) {
+ cursor.close();
+ }
+ }
+ }
+
+ public static class CalendarInfo {
+ public long id;
+ public String name;
+ }
+
+}
diff --git a/src/com/android/settings/notification/ZenModeExternalRuleSettings.java b/src/com/android/settings/notification/ZenModeExternalRuleSettings.java
index 9f9dc8a..8a24e02 100644
--- a/src/com/android/settings/notification/ZenModeExternalRuleSettings.java
+++ b/src/com/android/settings/notification/ZenModeExternalRuleSettings.java
@@ -58,6 +58,11 @@
}
@Override
+ protected int getEnabledToastText() {
+ return 0;
+ }
+
+ @Override
protected void onCreateInternal() {
addPreferencesFromResource(R.xml.zen_mode_external_rule_settings);
final PreferenceScreen root = getPreferenceScreen();
diff --git a/src/com/android/settings/notification/ZenModeRuleSettingsBase.java b/src/com/android/settings/notification/ZenModeRuleSettingsBase.java
index f6bc75f..cf66da8 100644
--- a/src/com/android/settings/notification/ZenModeRuleSettingsBase.java
+++ b/src/com/android/settings/notification/ZenModeRuleSettingsBase.java
@@ -59,11 +59,13 @@
private Preference mRuleName;
private SwitchBar mSwitchBar;
private DropDownPreference mZenMode;
+ private Toast mEnabledToast;
abstract protected void onCreateInternal();
abstract protected boolean setRule(ZenRule rule);
abstract protected String getZenModeDependency();
abstract protected void updateControlsInternal();
+ abstract protected int getEnabledToastText();
@Override
public void onCreate(Bundle icicle) {
@@ -154,6 +156,17 @@
mRule.enabled = enabled;
mRule.snoozing = false;
setZenModeConfig(mConfig);
+ if (enabled) {
+ final int toastText = getEnabledToastText();
+ if (toastText != 0) {
+ mEnabledToast = Toast.makeText(mContext, toastText, Toast.LENGTH_SHORT);
+ mEnabledToast.show();
+ }
+ } else {
+ if (mEnabledToast != null) {
+ mEnabledToast.cancel();
+ }
+ }
}
protected void updateRule(Uri newConditionId) {
@@ -247,10 +260,10 @@
updateRuleName();
updateControlsInternal();
mZenMode.setSelectedValue(mRule.zenMode);
- mDisableListeners = false;
if (mSwitchBar != null) {
mSwitchBar.setChecked(mRule.enabled);
}
+ mDisableListeners = false;
}
}
diff --git a/src/com/android/settings/notification/ZenModeScheduleRuleSettings.java b/src/com/android/settings/notification/ZenModeScheduleRuleSettings.java
index fef3175..b6b87b5 100644
--- a/src/com/android/settings/notification/ZenModeScheduleRuleSettings.java
+++ b/src/com/android/settings/notification/ZenModeScheduleRuleSettings.java
@@ -74,6 +74,11 @@
}
@Override
+ protected int getEnabledToastText() {
+ return R.string.zen_schedule_rule_enabled_toast;
+ }
+
+ @Override
protected void onCreateInternal() {
addPreferencesFromResource(R.xml.zen_mode_schedule_rule_settings);
final PreferenceScreen root = getPreferenceScreen();
diff --git a/src/com/android/settings/notification/ZenRuleNameDialog.java b/src/com/android/settings/notification/ZenRuleNameDialog.java
index 8b44e46..cd5c766 100644
--- a/src/com/android/settings/notification/ZenRuleNameDialog.java
+++ b/src/com/android/settings/notification/ZenRuleNameDialog.java
@@ -24,6 +24,7 @@
import android.content.pm.ServiceInfo;
import android.net.Uri;
import android.service.notification.ZenModeConfig;
+import android.service.notification.ZenModeConfig.EventInfo;
import android.service.notification.ZenModeConfig.ScheduleInfo;
import android.text.Editable;
import android.text.TextUtils;
@@ -50,25 +51,30 @@
private final ArraySet<String> mExistingNames;
private final ServiceListing mServiceListing;
private final RuleInfo[] mExternalRules = new RuleInfo[3];
+ private final boolean mIsNew;
public ZenRuleNameDialog(Context context, ServiceListing serviceListing, String ruleName,
ArraySet<String> existingNames) {
mServiceListing = serviceListing;
+ mIsNew = ruleName == null;
final View v = LayoutInflater.from(context).inflate(R.layout.zen_rule_name, null, false);
mEditText = (EditText) v.findViewById(R.id.rule_name);
- if (ruleName != null) {
+ if (!mIsNew) {
mEditText.setText(ruleName);
}
mEditText.setSelectAllOnFocus(true);
mTypes = (RadioGroup) v.findViewById(R.id.rule_types);
if (mServiceListing != null) {
bindType(R.id.rule_type_schedule, defaultNewSchedule());
+ bindType(R.id.rule_type_event, defaultNewEvent());
bindExternalRules();
mServiceListing.addCallback(mServiceListingCallback);
mServiceListing.reload();
+ } else {
+ mTypes.setVisibility(View.GONE);
}
mDialog = new AlertDialog.Builder(context)
- .setTitle(R.string.zen_mode_rule_name)
+ .setTitle(mIsNew ? R.string.zen_mode_add_rule : R.string.zen_mode_rule_name)
.setView(v)
.setPositiveButton(R.string.okay, new DialogInterface.OnClickListener() {
@Override
@@ -157,12 +163,21 @@
return rt;
}
+ private static RuleInfo defaultNewEvent() {
+ final EventInfo event = new EventInfo();
+ event.calendar = 0; // any
+ event.attendance = EventInfo.ATTENDANCE_REQUIRED_OR_OPTIONAL;
+ event.reply = EventInfo.REPLY_ANY_EXCEPT_NO;
+ final RuleInfo rt = new RuleInfo();
+ rt.settingsAction = ZenModeEventRuleSettings.ACTION;
+ rt.defaultConditionId = ZenModeConfig.toEventConditionId(event);
+ return rt;
+ }
+
private void bindExternalRules() {
- bindType(R.id.rule_type_2, mExternalRules[0]);
- bindType(R.id.rule_type_3, mExternalRules[1]);
- bindType(R.id.rule_type_4, mExternalRules[2]);
- // show radio group if we have at least one external rule type
- mTypes.setVisibility(mExternalRules[0] != null ? View.VISIBLE : View.GONE);
+ bindType(R.id.rule_type_3, mExternalRules[0]);
+ bindType(R.id.rule_type_4, mExternalRules[1]);
+ bindType(R.id.rule_type_5, mExternalRules[2]);
}
private final ServiceListing.Callback mServiceListingCallback = new ServiceListing.Callback() {
diff --git a/src/com/android/settings/print/PrintSettingsFragment.java b/src/com/android/settings/print/PrintSettingsFragment.java
index cea65d7..ebd51d5 100644
--- a/src/com/android/settings/print/PrintSettingsFragment.java
+++ b/src/com/android/settings/print/PrintSettingsFragment.java
@@ -192,11 +192,9 @@
final UserManager um = (UserManager) getSystemService(Context.USER_SERVICE);
mProfileSpinnerAdapter = Utils.createUserSpinnerAdapter(um, getActivity());
if (mProfileSpinnerAdapter != null) {
- mSpinner = (Spinner) getActivity().getLayoutInflater().inflate(
- R.layout.spinner_view, null);
+ mSpinner = (Spinner) setPinnedHeaderView(R.layout.spinner_view);
mSpinner.setAdapter(mProfileSpinnerAdapter);
mSpinner.setOnItemSelectedListener(this);
- setPinnedHeaderView(mSpinner);
}
}
diff --git a/src/com/android/settings/users/RestrictedProfileSettings.java b/src/com/android/settings/users/RestrictedProfileSettings.java
index 03a55d4..7b698cf 100644
--- a/src/com/android/settings/users/RestrictedProfileSettings.java
+++ b/src/com/android/settings/users/RestrictedProfileSettings.java
@@ -22,7 +22,6 @@
import android.content.pm.UserInfo;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
-import android.view.LayoutInflater;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
@@ -59,9 +58,7 @@
@Override
public void onActivityCreated(Bundle savedInstanceState) {
if (mHeaderView == null) {
- mHeaderView = LayoutInflater.from(getActivity()).inflate(
- R.layout.user_info_header, null);
- setPinnedHeaderView(mHeaderView);
+ mHeaderView = setPinnedHeaderView(R.layout.user_info_header);
mHeaderView.setOnClickListener(this);
mUserIconView = (ImageView) mHeaderView.findViewById(android.R.id.icon);
mUserNameView = (TextView) mHeaderView.findViewById(android.R.id.title);
diff --git a/src/com/android/settings/wifi/AccessPointPreference.java b/src/com/android/settings/wifi/AccessPointPreference.java
index 8a24bc9..0f702b2 100644
--- a/src/com/android/settings/wifi/AccessPointPreference.java
+++ b/src/com/android/settings/wifi/AccessPointPreference.java
@@ -36,11 +36,14 @@
private TextView mSummaryView;
private boolean showSummary = true;
+ private boolean mForSavedNetworks = false;
private AccessPoint mAccessPoint;
- public AccessPointPreference(AccessPoint accessPoint, Context context) {
+ public AccessPointPreference(AccessPoint accessPoint, Context context,
+ boolean forSavedNetworks) {
super(context);
mAccessPoint = accessPoint;
+ mForSavedNetworks = forSavedNetworks;
mAccessPoint.setTag(this);
refresh();
}
@@ -104,7 +107,10 @@
* Updates the title and summary; may indirectly call notifyChanged().
*/
public void refresh() {
- setTitle(mAccessPoint.getSsid());
+ if (mForSavedNetworks)
+ setTitle(mAccessPoint.getConfigName());
+ else
+ setTitle(mAccessPoint.getSsid());
final Context context = getContext();
updateIcon(mAccessPoint.getLevel(), context);
@@ -112,7 +118,9 @@
// Force new summary
setSummary(null);
- String summary = mAccessPoint.getSummary();
+ String summary = mForSavedNetworks ? mAccessPoint.getSavedNetworkSummary()
+ : mAccessPoint.getSettingsSummary();
+
if (summary.length() > 0) {
setSummary(summary);
setShowSummary(true);
diff --git a/src/com/android/settings/wifi/SavedAccessPointsWifiSettings.java b/src/com/android/settings/wifi/SavedAccessPointsWifiSettings.java
index 04094b3..04d2107 100644
--- a/src/com/android/settings/wifi/SavedAccessPointsWifiSettings.java
+++ b/src/com/android/settings/wifi/SavedAccessPointsWifiSettings.java
@@ -96,7 +96,7 @@
final Context context = getActivity();
final List<AccessPoint> accessPoints = WifiTracker.getCurrentAccessPoints(context, true,
- false);
+ false, true);
preferenceScreen.removeAll();
@@ -106,7 +106,7 @@
final int accessPointsSize = accessPoints.size();
for (int i = 0; i < accessPointsSize; ++i){
AccessPointPreference preference = new AccessPointPreference(accessPoints.get(i),
- context);
+ context, true);
WifiConfiguration config = accessPoints.get(i).getConfig();
if (config != null) {
int userId = UserHandle.getUserId(config.creatorUid);
@@ -222,7 +222,7 @@
// Add available Wi-Fi access points
final List<AccessPoint> accessPoints = WifiTracker.getCurrentAccessPoints(context,
- true, false);
+ true, false, true);
final int accessPointsSize = accessPoints.size();
for (int i = 0; i < accessPointsSize; ++i){
diff --git a/src/com/android/settings/wifi/WifiConfigController.java b/src/com/android/settings/wifi/WifiConfigController.java
index ee53887..8988495 100644
--- a/src/com/android/settings/wifi/WifiConfigController.java
+++ b/src/com/android/settings/wifi/WifiConfigController.java
@@ -250,8 +250,15 @@
mConfigUi.setSubmitButton(res.getString(R.string.wifi_connect));
} else {
if (state != null) {
- addRow(group, R.string.wifi_status, AccessPoint.getSummary(
- mConfigUi.getContext(), state, !mAccessPoint.isSaved()));
+ WifiConfiguration config = mAccessPoint.getConfig();
+ boolean isEphimeral = mAccessPoint.isSaved() == false;
+ String providerFriendlyName = null;
+ if (config != null && config.isPasspoint()) {
+ providerFriendlyName = config.providerFriendlyName;
+ }
+ String summary = AccessPoint.getSummary(
+ mConfigUi.getContext(), state, isEphimeral, providerFriendlyName);
+ addRow(group, R.string.wifi_status, summary);
}
if (signalLevel != null) {
diff --git a/src/com/android/settings/wifi/WifiSettings.java b/src/com/android/settings/wifi/WifiSettings.java
index 80a56bd..5cb4869 100644
--- a/src/com/android/settings/wifi/WifiSettings.java
+++ b/src/com/android/settings/wifi/WifiSettings.java
@@ -56,6 +56,7 @@
import android.view.MenuItem;
import android.view.View;
import android.widget.AdapterView.AdapterContextMenuInfo;
+import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.TextView.BufferType;
import android.widget.Toast;
@@ -127,6 +128,7 @@
private WriteWifiConfigToNfcDialog mWifiToNfcDialog;
private TextView mEmptyView;
+ private ProgressBar mProgressHeader;
// this boolean extra specifies whether to disable the Next button when not connected. Used by
// account creation outside of setup wizard.
@@ -153,10 +155,19 @@
}
@Override
+ public void onViewCreated(View view, Bundle savedInstanceState) {
+ super.onViewCreated(view, savedInstanceState);
+ final Activity activity = getActivity();
+ if (activity != null) {
+ mProgressHeader = (ProgressBar) setPinnedHeaderView(R.layout.wifi_progress_header);
+ }
+ }
+
+ @Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
- mWifiTracker = new WifiTracker(getActivity(), this, true, true);
+ mWifiTracker = new WifiTracker(getActivity(), this, true, true, false);
mWifiManager = mWifiTracker.getManager();
mConnectListener = new WifiManager.ActionListener() {
@@ -629,7 +640,7 @@
if (accessPoint.getLevel() != -1) {
hasAvailableAccessPoints = true;
AccessPointPreference preference = new AccessPointPreference(accessPoint,
- getActivity());
+ getActivity(), false);
getPreferenceScreen().addPreference(preference);
accessPoint.setListener(this);
@@ -711,7 +722,9 @@
}
protected void setProgressBarVisible(boolean visible) {
- // TODO: show a progress bar when scan is in progress.
+ if (mProgressHeader != null) {
+ mProgressHeader.setVisibility(visible ? View.VISIBLE : View.GONE);
+ }
}
@Override
@@ -891,7 +904,7 @@
// Add saved Wi-Fi access points
final Collection<AccessPoint> accessPoints =
- WifiTracker.getCurrentAccessPoints(context, true, false);
+ WifiTracker.getCurrentAccessPoints(context, true, false, false);
for (AccessPoint accessPoint : accessPoints) {
data = new SearchIndexableRaw(context);
data.title = accessPoint.getSsid();
diff --git a/src/com/android/settings/wifi/WifiSettingsForSetupWizard.java b/src/com/android/settings/wifi/WifiSettingsForSetupWizard.java
index 0c8ee60..b0570cc 100644
--- a/src/com/android/settings/wifi/WifiSettingsForSetupWizard.java
+++ b/src/com/android/settings/wifi/WifiSettingsForSetupWizard.java
@@ -19,6 +19,7 @@
import android.app.Dialog;
import android.net.wifi.WifiConfiguration;
import android.os.Bundle;
+import android.text.TextUtils;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
@@ -46,6 +47,7 @@
private SetupWizardListLayout mLayout;
private View mAddOtherNetworkItem;
private TextView mEmptyFooter;
+ private View mMacAddressFooter;
private boolean mListLastEmpty = false;
@Override
@@ -66,6 +68,9 @@
}
});
+ mMacAddressFooter = inflater.inflate(R.layout.setup_wifi_mac_address, list, false);
+ list.addFooterView(mMacAddressFooter, null, false);
+
final NavigationBar navigationBar = mLayout.getNavigationBar();
if (navigationBar != null) {
WifiSetupActivity activity = (WifiSetupActivity) getActivity();
@@ -82,6 +87,8 @@
if (hasNextButton()) {
getNextButton().setVisibility(View.GONE);
}
+
+ updateMacAddress();
}
@Override
@@ -91,6 +98,12 @@
}
@Override
+ public void onWifiStateChanged(int state) {
+ super.onWifiStateChanged(state);
+ updateMacAddress();
+ }
+
+ @Override
public void registerForContextMenu(View view) {
// Suppressed during setup wizard
}
@@ -137,18 +150,31 @@
protected void updateFooter(boolean isEmpty) {
if (isEmpty != mListLastEmpty) {
final ListView list = getListView();
+ list.removeFooterView(mEmptyFooter);
+ list.removeFooterView(mAddOtherNetworkItem);
+ list.removeFooterView(mMacAddressFooter);
if (isEmpty) {
- list.removeFooterView(mAddOtherNetworkItem);
list.addFooterView(mEmptyFooter, null, false);
} else {
- list.removeFooterView(mEmptyFooter);
list.addFooterView(mAddOtherNetworkItem, null, true);
+ list.addFooterView(mMacAddressFooter, null, false);
}
mListLastEmpty = isEmpty;
}
}
@Override
+ public View setPinnedHeaderView(int layoutResId) {
+ // Pinned header is not supported in setup wizard
+ return null;
+ }
+
+ @Override
+ public void setPinnedHeaderView(View pinnedHeader) {
+ // Pinned header is not supported in setup wizard
+ }
+
+ @Override
protected void setProgressBarVisible(boolean visible) {
if (mLayout != null) {
if (visible) {
@@ -158,4 +184,20 @@
}
}
}
+
+ private void updateMacAddress() {
+ if (mMacAddressFooter != null) {
+ String macAddress = null;
+ if (mWifiManager != null) {
+ android.net.wifi.WifiInfo connectionInfo = mWifiManager.getConnectionInfo();
+ if (connectionInfo != null) {
+ macAddress = connectionInfo.getMacAddress();
+ }
+ }
+ final TextView macAddressTextView =
+ (TextView) mMacAddressFooter.findViewById(R.id.mac_address);
+ macAddressTextView.setText(!TextUtils.isEmpty(macAddress) ?
+ macAddress : getString(R.string.status_unavailable));
+ }
+ }
}
diff --git a/src/com/android/settings/wifi/WifiStatusTest.java b/src/com/android/settings/wifi/WifiStatusTest.java
index 269058c..9789327 100644
--- a/src/com/android/settings/wifi/WifiStatusTest.java
+++ b/src/com/android/settings/wifi/WifiStatusTest.java
@@ -300,7 +300,7 @@
WifiInfo info = mWifiManager.getConnectionInfo();
String summary = AccessPoint.getSummary(this, info.getSSID(),
networkInfo.getDetailedState(),
- info.getNetworkId() == WifiConfiguration.INVALID_NETWORK_ID);
+ info.getNetworkId() == WifiConfiguration.INVALID_NETWORK_ID, null);
mNetworkState.setText(summary);
}
}