Merge "Settings: Add an xliff example to a string param."
diff --git a/Android.mk b/Android.mk
index 9cb7e2e..81f04f7 100644
--- a/Android.mk
+++ b/Android.mk
@@ -19,6 +19,7 @@
LOCAL_PROGUARD_FLAG_FILES := proguard.flags
include frameworks/opt/setupwizard/navigationbar/common.mk
+include frameworks/opt/setupwizard/library/common.mk
include frameworks/base/packages/SettingsLib/common.mk
include $(BUILD_PACKAGE)
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 6d166ad..83ea62a 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -158,6 +158,17 @@
android:value="true" />
</activity>
+ <activity android:name="AirplaneModeVoiceActivity"
+ android:label="@string/wireless_networks_settings_title"
+ android:theme="@android:style/Theme.Material.Light.Voice"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="android.settings.VOICE_CONTROL_AIRPLANE_MODE" />
+ <category android:name="android.intent.category.DEFAULT" />
+ <category android:name="android.intent.category.VOICE" />
+ </intent-filter>
+ </activity>
+
<!-- Top-level settings -->
<activity android:name="Settings$WifiSettingsActivity"
@@ -996,6 +1007,16 @@
android:value="com.android.settings.notification.NotificationStation" />
</activity>
+ <activity android:name=".notification.ZenModeVoiceActivity"
+ android:theme="@android:style/Theme.Material.Light"
+ android:label="@string/zen_mode_settings_title">
+ <intent-filter>
+ <action android:name="android.settings.VOICE_CONTROL_DO_NOT_DISTURB_MODE" />
+ <category android:name="android.intent.category.DEFAULT" />
+ <category android:name="android.intent.category.VOICE" />
+ </intent-filter>
+ </activity>
+
<!--
<activity android:name="Settings$AppOpsSummaryActivity"
android:label="@string/app_ops_settings"
@@ -1467,6 +1488,37 @@
android:resource="@id/storage_settings" />
</activity>
+ <!-- Exported for SystemUI to launch into -->
+ <activity android:name=".deviceinfo.StorageWizardInit"
+ android:theme="@style/SuwThemeMaterial.Light"
+ android:taskAffinity="com.android.settings.storage_wizard"
+ android:exported="true" />
+ <activity android:name=".deviceinfo.StorageWizardFormatConfirm"
+ android:taskAffinity="com.android.settings.storage_wizard"
+ android:exported="false" />
+ <activity android:name=".deviceinfo.StorageWizardFormatProgress"
+ android:taskAffinity="com.android.settings.storage_wizard"
+ android:exported="false" />
+ <activity android:name=".deviceinfo.StorageWizardMigrate"
+ android:taskAffinity="com.android.settings.storage_wizard"
+ android:exported="false" />
+ <activity android:name=".deviceinfo.StorageWizardMigrateConfirm"
+ android:taskAffinity="com.android.settings.storage_wizard"
+ android:exported="false" />
+ <activity android:name=".deviceinfo.StorageWizardMigrateProgress"
+ android:taskAffinity="com.android.settings.storage_wizard"
+ android:exported="false" />
+ <activity android:name=".deviceinfo.StorageWizardReady"
+ android:taskAffinity="com.android.settings.storage_wizard"
+ android:exported="false" />
+
+ <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" />
+
<activity android:name="ApnEditor"
android:label="@string/apn_edit">
<intent-filter>
@@ -1874,6 +1926,17 @@
android:value="true" />
</activity>
+ <activity android:name=".fuelguage.BatterySaverModeVoiceActivity"
+ android:label="@string/power_usage_summary_title"
+ android:theme="@android:style/Theme.Material.Light.Voice"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="android.settings.VOICE_CONTROL_BATTERY_SAVER_MODE" />
+ <category android:name="android.intent.category.DEFAULT" />
+ <category android:name="android.intent.category.VOICE" />
+ </intent-filter>
+ </activity>
+
<activity android:name="Settings$AccountSettingsActivity"
android:label="@string/account_settings_title"
android:taskAffinity=""
diff --git a/res/drawable-hdpi/illustration_horizontal.jpg b/res/drawable-hdpi/illustration_horizontal.jpg
new file mode 100644
index 0000000..428b2f4
--- /dev/null
+++ b/res/drawable-hdpi/illustration_horizontal.jpg
Binary files differ
diff --git a/res/drawable-hdpi/illustration_tile.jpg b/res/drawable-hdpi/illustration_tile.jpg
new file mode 100644
index 0000000..9931a23
--- /dev/null
+++ b/res/drawable-hdpi/illustration_tile.jpg
Binary files differ
diff --git a/res/drawable-mdpi/illustration_horizontal.jpg b/res/drawable-mdpi/illustration_horizontal.jpg
new file mode 100644
index 0000000..52e7993
--- /dev/null
+++ b/res/drawable-mdpi/illustration_horizontal.jpg
Binary files differ
diff --git a/res/drawable-mdpi/illustration_tile.jpg b/res/drawable-mdpi/illustration_tile.jpg
new file mode 100644
index 0000000..7923fb4
--- /dev/null
+++ b/res/drawable-mdpi/illustration_tile.jpg
Binary files differ
diff --git a/res/drawable-nodpi/illustration_generic.jpg b/res/drawable-nodpi/illustration_generic.jpg
new file mode 100644
index 0000000..f37eaf4
--- /dev/null
+++ b/res/drawable-nodpi/illustration_generic.jpg
Binary files differ
diff --git a/res/drawable-sw600dp-hdpi/illustration_generic.jpg b/res/drawable-sw600dp-hdpi/illustration_generic.jpg
new file mode 100644
index 0000000..7aac7f9
--- /dev/null
+++ b/res/drawable-sw600dp-hdpi/illustration_generic.jpg
Binary files differ
diff --git a/res/drawable-sw600dp-mdpi/illustration_generic.jpg b/res/drawable-sw600dp-mdpi/illustration_generic.jpg
new file mode 100644
index 0000000..34d0f33
--- /dev/null
+++ b/res/drawable-sw600dp-mdpi/illustration_generic.jpg
Binary files differ
diff --git a/res/drawable-sw600dp-xhdpi/illustration_generic.jpg b/res/drawable-sw600dp-xhdpi/illustration_generic.jpg
new file mode 100644
index 0000000..4fe849f
--- /dev/null
+++ b/res/drawable-sw600dp-xhdpi/illustration_generic.jpg
Binary files differ
diff --git a/res/drawable-sw600dp-xxhdpi/illustration_generic.jpg b/res/drawable-sw600dp-xxhdpi/illustration_generic.jpg
new file mode 100644
index 0000000..48bca97
--- /dev/null
+++ b/res/drawable-sw600dp-xxhdpi/illustration_generic.jpg
Binary files differ
diff --git a/res/drawable-xhdpi/illustration_horizontal.jpg b/res/drawable-xhdpi/illustration_horizontal.jpg
new file mode 100644
index 0000000..2733f8e
--- /dev/null
+++ b/res/drawable-xhdpi/illustration_horizontal.jpg
Binary files differ
diff --git a/res/drawable-xhdpi/illustration_tile.jpg b/res/drawable-xhdpi/illustration_tile.jpg
new file mode 100644
index 0000000..57bccca
--- /dev/null
+++ b/res/drawable-xhdpi/illustration_tile.jpg
Binary files differ
diff --git a/res/drawable-xxhdpi/illustration_horizontal.jpg b/res/drawable-xxhdpi/illustration_horizontal.jpg
new file mode 100644
index 0000000..aec8d0f
--- /dev/null
+++ b/res/drawable-xxhdpi/illustration_horizontal.jpg
Binary files differ
diff --git a/res/drawable-xxhdpi/illustration_tile.jpg b/res/drawable-xxhdpi/illustration_tile.jpg
new file mode 100644
index 0000000..2ba33fa
--- /dev/null
+++ b/res/drawable-xxhdpi/illustration_tile.jpg
Binary files differ
diff --git a/res/drawable/bg_circle_blue.xml b/res/drawable/bg_circle_blue.xml
new file mode 100644
index 0000000..7f2cb1d
--- /dev/null
+++ b/res/drawable/bg_circle_blue.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shape="oval">
+ <solid android:color="@color/blue" />
+</shape>
diff --git a/res/layout/settings_storage_miscfiles.xml b/res/layout/settings_storage_miscfiles.xml
deleted file mode 100644
index 0360cde..0000000
--- a/res/layout/settings_storage_miscfiles.xml
+++ /dev/null
@@ -1,55 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2010, 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.
-*/
--->
-
-<com.android.settings.deviceinfo.FileItemInfoLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="?android:attr/listPreferredItemHeight"
- android:paddingEnd="?android:attr/scrollbarSize"
- android:background="?android:attr/selectableItemBackground"
- android:gravity="center_vertical"
- android:focusable="true">
-
- <CheckBox android:id="@+id/misc_checkbox"
- android:layout_width="wrap_content"
- android:layout_height="match_parent"
- android:layout_alignParentStart="true"
- android:paddingStart="16dip"
- android:scaleType="fitCenter"
- android:layout_centerVertical="true"/>
-
- <TextView android:id="@+id/misc_filename"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_toEndOf="@id/misc_checkbox"
- android:maxLines="1"
- android:paddingStart="16dip"
- android:textAppearance="?android:attr/textAppearanceSmall"/>
-
- <TextView android:id="@+id/misc_filesize"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_toEndOf="@id/misc_checkbox"
- android:layout_below="@id/misc_filename"
- android:maxLines="1"
- android:paddingStart="16dip"
- android:textStyle="bold"
- android:textAppearance="?android:attr/textAppearanceSmall" />
-</com.android.settings.deviceinfo.FileItemInfoLayout>
-
diff --git a/res/layout/settings_storage_miscfiles_list.xml b/res/layout/settings_storage_miscfiles_list.xml
deleted file mode 100644
index b712073..0000000
--- a/res/layout/settings_storage_miscfiles_list.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2010, 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.
-*/
--->
-
-<FrameLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:paddingEnd="16dip"
- android:paddingStart="16dip">
-
- <ListView android:id="@android:id/list"
- android:layout_width="match_parent"
- android:layout_height="match_parent"/>
-
-</FrameLayout>
-
diff --git a/res/layout/storage_internal_format.xml b/res/layout/storage_internal_format.xml
new file mode 100644
index 0000000..b7a36ca
--- /dev/null
+++ b/res/layout/storage_internal_format.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.
+-->
+
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical">
+
+ <ScrollView
+ android:layout_width="match_parent"
+ android:layout_height="0dp"
+ android:layout_weight="1">
+ <TextView
+ android:id="@+id/body"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingTop="@dimen/suw_description_margin_top"
+ android:paddingBottom="@dimen/suw_description_margin_bottom"
+ android:paddingStart="@dimen/suw_layout_margin_sides"
+ android:paddingEnd="@dimen/suw_layout_margin_sides"
+ android:lineSpacingExtra="@dimen/suw_description_line_spacing_extra"
+ android:textAppearance="@android:style/TextAppearance.Material.Body1"
+ android:textColor="?android:attr/textColorPrimary" />
+ </ScrollView>
+
+ <FrameLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:padding="4dp">
+ <Button
+ android:id="@+id/confirm"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/storage_menu_format" />
+ </FrameLayout>
+
+</LinearLayout>
diff --git a/res/layout/storage_internal_unmount.xml b/res/layout/storage_internal_unmount.xml
new file mode 100644
index 0000000..4779829
--- /dev/null
+++ b/res/layout/storage_internal_unmount.xml
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical">
+
+ <ScrollView
+ android:layout_width="match_parent"
+ android:layout_height="0dp"
+ android:layout_weight="1">
+ <TextView
+ android:id="@+id/body"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingTop="@dimen/suw_description_margin_top"
+ android:paddingBottom="@dimen/suw_description_margin_bottom"
+ android:paddingStart="@dimen/suw_layout_margin_sides"
+ android:paddingEnd="@dimen/suw_layout_margin_sides"
+ android:lineSpacingExtra="@dimen/suw_description_line_spacing_extra"
+ android:textAppearance="@android:style/TextAppearance.Material.Body1"
+ android:textColor="?android:attr/textColorPrimary" />
+ </ScrollView>
+
+ <Space
+ android:layout_width="0dp"
+ android:layout_height="0dp"
+ android:layout_weight="1" />
+
+ <FrameLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:padding="4dp">
+ <Button
+ android:id="@+id/confirm"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/storage_menu_unmount" />
+ </FrameLayout>
+
+</LinearLayout>
diff --git a/res/layout/storage_wizard_generic.xml b/res/layout/storage_wizard_generic.xml
new file mode 100644
index 0000000..4f0cef9
--- /dev/null
+++ b/res/layout/storage_wizard_generic.xml
@@ -0,0 +1,54 @@
+<?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.
+-->
+
+<com.android.setupwizardlib.SetupWizardLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ android:id="@+id/setup_wizard_layout"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ app:suwBackgroundTile="@drawable/illustration_tile"
+ app:suwIllustrationHorizontalTile="@drawable/illustration_horizontal"
+ app:suwIllustrationImage="@drawable/illustration_generic">
+
+ <LinearLayout
+ style="@style/SuwContentFrame"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical">
+
+ <TextView
+ android:id="@+id/storage_wizard_body"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/suw_description_margin_top"
+ android:lineSpacingExtra="@dimen/suw_description_line_spacing_extra"
+ android:textAppearance="@android:style/TextAppearance.Material.Body1"
+ android:textColor="?android:attr/textColorPrimary" />
+
+ <TextView
+ android:id="@+id/storage_wizard_second_body"
+ android:visibility="gone"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/suw_description_margin_top"
+ android:lineSpacingExtra="@dimen/suw_description_line_spacing_extra"
+ android:textAppearance="@android:style/TextAppearance.Material.Body1"
+ android:textColor="?android:attr/textColorPrimary" />
+
+ </LinearLayout>
+
+</com.android.setupwizardlib.SetupWizardLayout>
diff --git a/res/layout/storage_wizard_init.xml b/res/layout/storage_wizard_init.xml
new file mode 100644
index 0000000..421477c
--- /dev/null
+++ b/res/layout/storage_wizard_init.xml
@@ -0,0 +1,73 @@
+<?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.
+-->
+
+<com.android.setupwizardlib.SetupWizardLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ android:id="@+id/setup_wizard_layout"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ app:suwBackgroundTile="@drawable/illustration_tile"
+ app:suwIllustrationHorizontalTile="@drawable/illustration_horizontal"
+ app:suwIllustrationImage="@drawable/illustration_generic">
+
+ <!-- android:layout="@layout/suw_template_short" -->
+
+ <LinearLayout
+ style="@style/SuwContentFrame"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical">
+
+ <RadioButton
+ android:id="@+id/storage_wizard_init_external_title"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/suw_description_margin_top"
+ android:lineSpacingExtra="@dimen/suw_description_line_spacing_extra"
+ android:textAppearance="@android:style/TextAppearance.Material.Subhead"
+ android:textColor="?android:attr/textColorPrimary"
+ android:text="@string/storage_wizard_init_external_title" />
+ <TextView
+ android:id="@+id/storage_wizard_init_external_summary"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:lineSpacingExtra="@dimen/suw_description_line_spacing_extra"
+ android:textAppearance="@android:style/TextAppearance.Material.Body1"
+ android:textColor="?android:attr/textColorSecondary"
+ android:text="@string/storage_wizard_init_external_summary" />
+
+ <RadioButton
+ android:id="@+id/storage_wizard_init_internal_title"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/suw_description_margin_top"
+ android:lineSpacingExtra="@dimen/suw_description_line_spacing_extra"
+ android:textAppearance="@android:style/TextAppearance.Material.Subhead"
+ android:textColor="?android:attr/textColorPrimary"
+ android:text="@string/storage_wizard_init_internal_title" />
+ <TextView
+ android:id="@+id/storage_wizard_init_internal_summary"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:lineSpacingExtra="@dimen/suw_description_line_spacing_extra"
+ android:textAppearance="@android:style/TextAppearance.Material.Body1"
+ android:textColor="?android:attr/textColorSecondary"
+ android:text="@string/storage_wizard_init_internal_summary" />
+
+ </LinearLayout>
+
+</com.android.setupwizardlib.SetupWizardLayout>
diff --git a/res/layout/storage_wizard_migrate.xml b/res/layout/storage_wizard_migrate.xml
new file mode 100644
index 0000000..827a5d2
--- /dev/null
+++ b/res/layout/storage_wizard_migrate.xml
@@ -0,0 +1,63 @@
+<?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.
+-->
+
+<com.android.setupwizardlib.SetupWizardLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ android:id="@+id/setup_wizard_layout"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ app:suwBackgroundTile="@drawable/illustration_tile"
+ app:suwIllustrationHorizontalTile="@drawable/illustration_horizontal"
+ app:suwIllustrationImage="@drawable/illustration_generic">
+
+ <LinearLayout
+ style="@style/SuwContentFrame"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical">
+
+ <TextView
+ android:id="@+id/storage_wizard_body"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/suw_description_margin_top"
+ android:lineSpacingExtra="@dimen/suw_description_line_spacing_extra"
+ android:textAppearance="@android:style/TextAppearance.Material.Body1"
+ android:textColor="?android:attr/textColorPrimary" />
+
+ <RadioButton
+ android:id="@+id/storage_wizard_migrate_now"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/suw_description_margin_top"
+ android:lineSpacingExtra="@dimen/suw_description_line_spacing_extra"
+ android:textAppearance="@android:style/TextAppearance.Material.Subhead"
+ android:textColor="?android:attr/textColorPrimary"
+ android:text="@string/storage_wizard_migrate_now" />
+ <RadioButton
+ android:id="@+id/storage_wizard_migrate_later"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="8dp"
+ android:lineSpacingExtra="@dimen/suw_description_line_spacing_extra"
+ android:textAppearance="@android:style/TextAppearance.Material.Subhead"
+ android:textColor="?android:attr/textColorPrimary"
+ android:text="@string/storage_wizard_migrate_later" />
+
+ </LinearLayout>
+
+</com.android.setupwizardlib.SetupWizardLayout>
diff --git a/res/layout/storage_wizard_progress.xml b/res/layout/storage_wizard_progress.xml
new file mode 100644
index 0000000..52fd203
--- /dev/null
+++ b/res/layout/storage_wizard_progress.xml
@@ -0,0 +1,59 @@
+<?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.
+-->
+
+<com.android.setupwizardlib.SetupWizardLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ android:id="@+id/setup_wizard_layout"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ app:suwBackgroundTile="@drawable/illustration_tile"
+ app:suwIllustrationHorizontalTile="@drawable/illustration_horizontal"
+ app:suwIllustrationImage="@drawable/illustration_generic">
+
+ <LinearLayout
+ style="@style/SuwContentFrame"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical">
+
+ <ProgressBar
+ android:id="@+id/storage_wizard_progress"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/suw_description_margin_top"
+ android:indeterminate="false"
+ style="?android:attr/progressBarStyleHorizontal" />
+ <TextView
+ android:id="@+id/storage_wizard_progress_summary"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:lineSpacingExtra="@dimen/suw_description_line_spacing_extra"
+ android:textAppearance="@android:style/TextAppearance.Material.Body1"
+ android:textColor="?android:attr/textColorSecondary" />
+
+ <TextView
+ android:id="@+id/storage_wizard_body"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/suw_description_margin_top"
+ android:lineSpacingExtra="@dimen/suw_description_line_spacing_extra"
+ android:textAppearance="@android:style/TextAppearance.Material.Body1"
+ android:textColor="?android:attr/textColorPrimary" />
+
+ </LinearLayout>
+
+</com.android.setupwizardlib.SetupWizardLayout>
diff --git a/res/layout/storage_wizard_ready.xml b/res/layout/storage_wizard_ready.xml
new file mode 100644
index 0000000..5cb2e33
--- /dev/null
+++ b/res/layout/storage_wizard_ready.xml
@@ -0,0 +1,44 @@
+<?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.
+-->
+
+<com.android.setupwizardlib.SetupWizardLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ android:id="@+id/setup_wizard_layout"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ app:suwBackgroundTile="@drawable/illustration_tile"
+ app:suwIllustrationHorizontalTile="@drawable/illustration_horizontal"
+ app:suwIllustrationImage="@drawable/illustration_generic">
+
+ <LinearLayout
+ style="@style/SuwContentFrame"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical">
+
+ <TextView
+ android:id="@+id/storage_wizard_ready_body"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/suw_description_margin_top"
+ android:lineSpacingExtra="@dimen/suw_description_line_spacing_extra"
+ android:textAppearance="@android:style/TextAppearance.Material.Body1"
+ android:textColor="?android:attr/textColorPrimary" />
+
+ </LinearLayout>
+
+</com.android.setupwizardlib.SetupWizardLayout>
diff --git a/res/layout/voice_interaction.xml b/res/layout/voice_interaction.xml
new file mode 100644
index 0000000..13c4341
--- /dev/null
+++ b/res/layout/voice_interaction.xml
@@ -0,0 +1,23 @@
+<?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.
+-->
+
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/fragment_root"
+ android:paddingLeft="8dp"
+ android:paddingRight="8dp"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+</FrameLayout>
diff --git a/res/layout/voice_item_row.xml b/res/layout/voice_item_row.xml
new file mode 100644
index 0000000..8576a57
--- /dev/null
+++ b/res/layout/voice_item_row.xml
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical" >
+ <LinearLayout
+ android:id="@+id/row_one"
+ android:orientation="horizontal"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_alignParentStart="true"
+ android:layout_marginTop="20dp"
+ android:layout_marginBottom="20dp">
+
+ <TextView
+ android:layout_width="0px"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:id="@+id/voice_item_label" />
+
+ <TextView
+ android:layout_width="100px"
+ android:layout_height="100px"
+ android:gravity="center_horizontal|center_vertical"
+ android:background="@drawable/bg_circle_blue"
+ android:textAppearance="?android:attr/textAppearanceMediumInverse"
+ android:textStyle="bold"
+ android:id="@+id/voice_item_position" />
+ </LinearLayout>
+</LinearLayout>
diff --git a/res/values/colors.xml b/res/values/colors.xml
index 2d0c741..0d0637c 100644
--- a/res/values/colors.xml
+++ b/res/values/colors.xml
@@ -17,6 +17,7 @@
<resources>
<color name="black">#000</color>
<color name="red">#F00</color>
+ <color name="blue">#00F</color>
<color name="material_empty_color_light">#FFCED7DB</color>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index dec729a..a0b0653 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -16,16 +16,12 @@
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<!-- Strings for Dialog yes button -->
<string name="yes">"Yes"</string>
-
<!-- Strings for Dialog no button -->
<string name="no">"No"</string>
-
<!-- Strings for Dialog create button -->
<string name="create">Create</string>
-
<!-- Strings for Dialog allow button -->
<string name="allow">Allow</string>
-
<!-- Strings for Dialog deny button -->
<string name="deny">Deny</string>
@@ -586,15 +582,14 @@
<!-- Button label for generic cancel action [CHAR LIMIT=20] -->
<string name="cancel">Cancel</string>
-
<!-- Button label for generic OK action [CHAR LIMIT=20] -->
<string name="okay">OK</string>
-
<!-- Button label for generic forget action [CHAR LIMIT=20] -->
<string name="forget">Forget</string>
-
<!-- Button label for generic save action [CHAR LIMIT=20] -->
<string name="save">Save</string>
+ <!-- Button label for generic done action [CHAR LIMIT=20] -->
+ <string name="done">Done</string>
<!-- Title of the Settings activity shown within the application itself. -->
<string name="settings_label">Settings</string>
@@ -2326,6 +2321,99 @@
<!-- Title of dialog prompting user to rename a storage volume [CHAR LIMIT=32]-->
<string name="storage_rename_title">Rename storage</string>
+ <!-- Body of dialog informing user about consequences of formatting an internal storage device [CHAR LIMIT=NONE]-->
+ <string name="storage_internal_format_details">After formatting, you can use this <xliff:g id="name" example="SD card">^1</xliff:g> in other devices.
+\n\nAll data on this <xliff:g id="name" example="SD card">^1</xliff:g> will be erased. Consider backing up first.
+\n\n<b>Back up photos & other media</b>
+\nMove your media files to alternative storage on this device, or transfer them to a computer using a USB cable.
+\n\n<b>Back up apps</b>
+\nAll apps stored on this <xliff:g id="name" example="SD card">^1</xliff:g> will be uninstalled and their data will be erased. To keep these apps, move them to alternative storage on this device.</string>
+
+ <!-- Body of dialog informing user about consequences of ejecting an internal storage device [CHAR LIMIT=NONE]-->
+ <string name="storage_internal_unmount_details"><b>When you eject this <xliff:g id="name" example="SD card">^1</xliff:g>, apps stored on it will stop working, and media files stored on it will not be available until it is reinserted.</b>
+\n\nThis <xliff:g id="name" example="SD card">^1</xliff:g> is formatted to work on this device only. It won\'t work on any others.</string>
+
+ <!-- Title of wizard step prompting user to setup a storage device [CHAR LIMIT=32] -->
+ <string name="storage_wizard_init_title">Set up your <xliff:g id="name" example="SD card">^1</xliff:g></string>
+ <!-- Title of wizard choice to use storage device as external storage [CHAR LIMIT=64] -->
+ <string name="storage_wizard_init_external_title">Use as portable storage</string>
+ <!-- Summary of wizard choice to use storage device as external storage [CHAR LIMIT=NONE] -->
+ <string name="storage_wizard_init_external_summary">For moving photos and other media between devices.</string>
+ <!-- Title of wizard choice to use storage device as internal storage [CHAR LIMIT=64] -->
+ <string name="storage_wizard_init_internal_title">Use as internal storage</string>
+ <!-- Summary of wizard choice to use storage device as internal storage [CHAR LIMIT=NONE] -->
+ <string name="storage_wizard_init_internal_summary">For storing anything on this device only, including apps and photos. Requires formatting that prevents it from working with other devices.</string>
+
+ <!-- Title of wizard step prompting user to format a storage device [CHAR LIMIT=32] -->
+ <string name="storage_wizard_format_confirm_title">Format as internal storage</string>
+ <!-- Body of wizard step prompting user to format a storage device [CHAR LIMIT=NONE] -->
+ <string name="storage_wizard_format_confirm_body">This requires the <xliff:g id="name" example="SD card">^1</xliff:g> to be formatted to make it secure.
+\n\nAfter formatting, this <xliff:g id="name" example="SD card">^1</xliff:g> will only work in this device.
+\n\n<b>Formatting erases all data currently stored on the <xliff:g id="name" example="SD card">^1</xliff:g>.</b> To avoid losing the data, consider backing it up.
+ </string>
+ <!-- Next button text of wizard step prompting user to format a storage device [CHAR LIMIT=32] -->
+ <string name="storage_wizard_format_confirm_next">Erase & format</string>
+
+ <!-- Title of wizard step showing formatting progress [CHAR LIMIT=32] -->
+ <string name="storage_wizard_format_progress_title">Formatting <xliff:g id="name" example="SD card">^1</xliff:g>\u2026</string>
+ <!-- Body of wizard step showing formatting progress [CHAR LIMIT=NONE] -->
+ <string name="storage_wizard_format_progress_body">Don\'t remove the <xliff:g id="name" example="SD card">^1</xliff:g> while it\'s formatting.</string>
+
+ <!-- Title of wizard step prompting user to migrate data to new storage [CHAR LIMIT=32] -->
+ <string name="storage_wizard_migrate_title">Move data to new storage</string>
+ <!-- Body of wizard step prompting user to migrate data to new storage [CHAR LIMIT=NONE] -->
+ <string name="storage_wizard_migrate_body">You can move your photos, files, and app data to this new <xliff:g id="name" example="SD card">^1</xliff:g>.
+\n\nThe move takes about <xliff:g id="time" example="1 hour">^2</xliff:g> and will free <xliff:g id="size" example="1.2 GB">^3</xliff:g> on internal storage. Some apps won\'t work while it\'s underway.
+ </string>
+ <!-- Title of wizard choice to migrate data right now [CHAR LIMIT=64] -->
+ <string name="storage_wizard_migrate_now">Move now</string>
+ <!-- Title of wizard choice to migrate data at later time [CHAR LIMIT=NONE] -->
+ <string name="storage_wizard_migrate_later">Move later</string>
+
+ <!-- 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>
+ <!-- Title of wizard button prompting user to start data migration [CHAR LIMIT=32] -->
+ <string name="storage_wizard_migrate_confirm_next">Move</string>
+
+ <!-- Title of wizard step showing migration progress [CHAR LIMIT=32] -->
+ <string name="storage_wizard_migrate_progress_title">Moving data\u2026</string>
+
+ <!-- Body of wizard step providing details about data migration [CHAR LIMIT=NONE] -->
+ <string name="storage_wizard_migrate_details">During the move:
+\n\u2022 Don\'t remove the <xliff:g id="name" example="SD card">^1</xliff:g>.
+\n\u2022 Some apps won\'t work correctly.
+\n\u2022 Keep the device charged.
+ </string>
+
+ <!-- Title of wizard step indicating that storage is ready [CHAR LIMIT=32] -->
+ <string name="storage_wizard_ready_title"><xliff:g id="name" example="SD card">^1</xliff:g> is ready</string>
+ <!-- Body of wizard step indicating that external storage is ready [CHAR LIMIT=NONE] -->
+ <string name="storage_wizard_ready_external_body">
+ Your <xliff:g id="name" example="SD card">^1</xliff:g> is all set to use with photos and other media.
+ </string>
+ <!-- Body of wizard step indicating that internal storage is ready [CHAR LIMIT=NONE] -->
+ <string name="storage_wizard_ready_internal_body">Your new <xliff:g id="name" example="SD card">^1</xliff:g> is working.
+\n\nTo move photos, files, and app data to this device, go to Settings > Storage.
+ </string>
+
+ <!-- Title of wizard step prompting user to move an app [CHAR LIMIT=32] -->
+ <string name="storage_wizard_move_confirm_title">Move <xliff:g id="app" example="Calculator">^1</xliff:g></string>
+ <!-- Body of wizard step prompting user to move an app [CHAR LIMIT=NONE] -->
+ <string name="storage_wizard_move_confirm_body">Moving <xliff:g id="app" example="Calculator">^1</xliff:g> and its data to <xliff:g id="name" example="SD card">^2</xliff:g> will take only a few moments. You won\'t be able to use the app until the move is complete.
+\n\nDon\'t remove the <xliff:g id="name" example="SD card">^2</xliff:g> during the move.
+ </string>
+
+ <!-- Title of wizard step showing app move progress [CHAR LIMIT=32] -->
+ <string name="storage_wizard_move_progress_title">Moving <xliff:g id="app" example="Calculator">^1</xliff:g>\u2026</string>
+ <!-- Body of wizard step showing app move progress [CHAR LIMIT=NONE] -->
+ <string name="storage_wizard_move_progress_body">Don\'t remove the <xliff:g id="name" example="SD card">^1</xliff:g> during the move.
+\n\nThe <xliff:g id="app" example="Calculator">^2</xliff:g> app on this device won\'t be available until the move is complete.
+ </string>
+ <!-- Title of wizard button offering to cancel move [CHAR LIMIT=32] -->
+ <string name="storage_wizard_move_progress_cancel">Cancel move</string>
+
<!-- Phone info screen, section titles: -->
<string name="battery_status_title">Battery status</string>
<!-- Phone info screen, section titles: -->
@@ -5991,6 +6079,93 @@
<!-- [CHAR LIMIT=60] Zen mode settings: End time option: Summary text value format when end time = next day -->
<string name="zen_mode_end_time_next_day_summary_format"><xliff:g id="formatted_time" example="7:00 AM">%s</xliff:g> next day</string>
+ <!-- [CHAR LIMIT=NONE] Zen mode voice: Prompt read for interruption type -->
+ <string name="zen_mode_interruptions_voice_prompt">When would you like to be interrupted?</string>
+
+ <!-- [CHAR LIMIT=NONE] Zen mode voice: Prompt read for zen mode duration -->
+ <string name="zen_mode_duration_voice_prompt">For how long?</string>
+
+ <!-- [CHAR LIMIT=NONE] Zen mode voice: Comma delimited synonyms for important interriuptions -->
+ <string name="zen_mode_option_important_voice_synonyms">important,priority,priority notifications</string>
+
+ <!-- [CHAR LIMIT=NONE] Zen mode voice: Comma delimited synonyms for alarm interriuptions -->
+ <string name="zen_mode_option_alarms_voice_synonyms">alarms</string>
+
+ <!-- [CHAR LIMIT=60] Zen mode voice: Off [CHAR LIMIT=60] -->
+ <string name="zen_mode_option_off">Off</string>
+
+ <!-- [CHAR LIMIT=NONE] Zen mode voice: Comma delimited synonyms for off interriuptions -->
+ <string name="zen_mode_option_off_voice_synonyms">off,all,everything</string>
+
+ <!-- [CHAR LIMIT=NONE] Zen mode voice: Comma delimited synonyms for no interriuptions -->
+ <string name="zen_mode_option_no_interruptions_voice_synonyms">none,nothing,no interruptions</string>
+
+ <!-- [CHAR LIMIT=40] Zen mode voice: Label for indefinite mode duration -->
+ <string name="zen_mode_duration_indefinte_voice_label">Indefinitely</string>
+
+ <!-- [CHAR LIMIT=40] Zen mode voice: Label for duration in minutes -->
+ <plurals name="zen_mode_duration_minutes_voice_label">
+ <item quantity="one"><xliff:g id="count" example="1">%d</xliff:g> minute</item>
+ <item quantity="other"><xliff:g id="count" example="10">%d</xliff:g> minutes</item>
+ </plurals>
+
+ <!-- [CHAR LIMIT=40] Zen mode voice: Label for duration in hours -->
+ <plurals name="zen_mode_duration_hours_voice_label">
+ <item quantity="one"><xliff:g id="count" example="1">%d</xliff:g> hour</item>
+ <item quantity="other"><xliff:g id="count" example="10">%d</xliff:g> hours</item>
+ </plurals>
+
+ <!-- [CHAR LIMIT=NONE] Zen mode voice - spoken summary: important only duration indefinite. -->
+ <string name="zen_mode_summary_priority_indefinitely">Change to priority notifications only indefinitely</string>
+
+ <!-- [CHAR LIMIT=NONE] Zen mode voice- spoken summary: important only duration minutes. -->
+ <plurals name="zen_mode_summary_priority_by_minute">
+ <item quantity="one">Change to priority notifications only for one minute until <xliff:g id="formattedTime" example="10:00 PM">%2$s</xliff:g></item>
+ <item quantity="other">Change to priority notifications only for <xliff:g id="duration" example="2">%1$d</xliff:g> minutes until <xliff:g id="formattedTime" example="10:00 PM">%2$s</xliff:g></item>
+ </plurals>
+
+ <!-- [CHAR LIMIT=NONE] Zen mode voice- spoken summary: important only duration hours. -->
+ <plurals name="zen_mode_summary_priority_by_hour">
+ <item quantity="one">Change to priority notifications only for one hour until <xliff:g id="formattedTime" example="10:00 PM">%2$s</xliff:g></item>
+ <item quantity="other">Change to priority notifications only for <xliff:g id="duration" example="2">%1$d</xliff:g> hours (until <xliff:g id="formattedTime" example="10:00 PM">%2$s</xliff:g>)</item>
+ </plurals>
+
+ <!-- [CHAR LIMIT=NONE] Zen mode voice - spoken summary: alarms only duration indefinite. -->
+ <string name="zen_mode_summary_alarams_only_indefinite">Change to alarms only indefinitely</string>
+
+ <!-- [CHAR LIMIT=NONE] Zen mode voice- spoken summary: alarms only duration minutes. -->
+ <plurals name="zen_mode_summary_alarms_only_by_minute">
+ <item quantity="one">Change to alarms only for one minute until <xliff:g id="formattedTime" example="10:00 PM">%2$s</xliff:g></item>
+ <item quantity="other">Change to alarms only for <xliff:g id="duration" example="2">%1$d</xliff:g> minutes (until <xliff:g id="formattedTime" example="10:00 PM">%2$s</xliff:g>)</item>
+ </plurals>
+
+ <!-- [CHAR LIMIT=NONE] Zen mode voice- spoken summary: alarms only duration hours. -->
+ <plurals name="zen_mode_summary_alarms_only_by_hour">
+ <item quantity="one">Change to alarms only for one hour until <xliff:g id="formattedTime" example="10:00 PM">%2$s</xliff:g></item>
+ <item quantity="other">Change to alarms only for <xliff:g id="duration" example="2">%1$d</xliff:g> hours until <xliff:g id="formattedTime" example="10:00 PM">%2$s</xliff:g></item>
+ </plurals>
+
+ <!-- [CHAR LIMIT=NONE] Zen mode voice - spoken summary: no interruptions duration indefinite. -->
+ <string name="zen_mode_summary_no_interruptions_indefinite">Change to don\'t interrupt indefinitely</string>
+
+ <!-- [CHAR LIMIT=NONE] Zen mode voice- spoken summary: alarms only duration minutes. -->
+ <plurals name="zen_mode_summary_no_interruptions_by_minute">
+ <item quantity="one">Change to don\'t interrupt for one minute until <xliff:g id="formattedTime" example="10:00 PM">%2$s</xliff:g></item>
+ <item quantity="other">Change to don\'t interrupt for <xliff:g id="duration" example="2">%1$d</xliff:g> minutes (until <xliff:g id="formattedTime" example="10:00 PM">%2$s</xliff:g>)</item>
+ </plurals>
+
+ <!-- [CHAR LIMIT=NONE] Zen mode voice- spoken summary: alarms only duration hours. -->
+ <plurals name="zen_mode_summary_no_interruptions_by_hour">
+ <item quantity="one">Change to don\'t interrupt for one hour until <xliff:g id="formattedTime" example="10:00 PM">%2$s</xliff:g></item>
+ <item quantity="other">Change to don\'t interrupt for <xliff:g id="duration" example="2">%1$d</xliff:g> hours until <xliff:g id="formattedTime" example="10:00 PM">%2$s</xliff:g></item>
+ </plurals>
+
+ <!-- [CHAR LIMIT=NONE] Zen mode voice - spoken summary: off. -->
+ <string name="zen_mode_summary_always">Change to always interrupt</string>
+
+ <!-- [CHAR LIMIT=NONE] Zen mode voice: Comma delimited synonyms for indefinte duration -->
+ <string name="zen_mode_duration_indefinite_voice_synonyms">forever</string>
+
<!-- [CHAR LIMIT=20] Notifications settings: Apps section header -->
<string name="notification_settings_apps_title">App notifications</string>
@@ -6187,6 +6362,9 @@
<!-- Description for advanced menu option to reset app preferences [CHAR LIMIT=NONE] -->
<string name="reset_app_preferences_description">Reset preferences across all apps to defaults</string>
+ <!-- Summary for a trust agent that was disabled by the device policy [LIMIT=NONE] -->
+ <string name="trust_agent_disabled_device_admin">Disabled by administrator</string>
+
<!-- Description of settings item that leads to list of all apps [CHAR LIMIT=NONE] -->
<string name="all_apps_summary"><xliff:g id="count" example="10">%d</xliff:g> apps installed, including system and downloaded apps</string>
diff --git a/src/com/android/settings/AirplaneModeVoiceActivity.java b/src/com/android/settings/AirplaneModeVoiceActivity.java
index 3ab0c37..e0649e4 100644
--- a/src/com/android/settings/AirplaneModeVoiceActivity.java
+++ b/src/com/android/settings/AirplaneModeVoiceActivity.java
@@ -20,6 +20,8 @@
import android.provider.Settings;
import android.util.Log;
+import com.android.settings.utils.VoiceSettingsActivity;
+
/**
* Activity for modifying the {@link Settings.Global#AIRPLANE_MODE_ON AIRPLANE_MODE_ON}
* setting using the Voice Interaction API.
@@ -27,14 +29,14 @@
public class AirplaneModeVoiceActivity extends VoiceSettingsActivity {
private static final String TAG = "AirplaneModeVoiceActivity";
- protected void onVoiceSettingInteraction(Intent intent) {
+ protected boolean onVoiceSettingInteraction(Intent intent) {
if (intent.hasExtra(Settings.EXTRA_AIRPLANE_MODE_ENABLED)) {
- boolean enabled =
- intent.getBooleanExtra(Settings.EXTRA_AIRPLANE_MODE_ENABLED, false);
Settings.Global.putInt(getContentResolver(),
- Settings.Global.AIRPLANE_MODE_ON, enabled ? 1 : 0);
+ Settings.Global.AIRPLANE_MODE_ON,
+ intent.getBooleanExtra(Settings.EXTRA_AIRPLANE_MODE_ENABLED, false) ? 1 : 0);
} else {
Log.v(TAG, "Missing airplane mode extra");
}
+ return true;
}
}
diff --git a/src/com/android/settings/PrivacySettings.java b/src/com/android/settings/PrivacySettings.java
index 4eb8a9e..6eb22fb 100644
--- a/src/com/android/settings/PrivacySettings.java
+++ b/src/com/android/settings/PrivacySettings.java
@@ -204,7 +204,7 @@
if (summary != null) {
mConfigure.setSummary(summary);
} else {
- mConfigure.setSummary(R.string.backup_configure_account_default_summary);
+ //mConfigure.setSummary(R.string.backup_configure_account_default_summary);
}
}
diff --git a/src/com/android/settings/SecuritySettings.java b/src/com/android/settings/SecuritySettings.java
index fd99536..30b7590 100644
--- a/src/com/android/settings/SecuritySettings.java
+++ b/src/com/android/settings/SecuritySettings.java
@@ -362,7 +362,7 @@
private void addTrustAgentSettings(PreferenceGroup securityCategory) {
final boolean hasSecurity = mLockPatternUtils.isSecure();
ArrayList<TrustAgentComponentInfo> agents =
- getActiveTrustAgents(getPackageManager(), mLockPatternUtils);
+ getActiveTrustAgents(getPackageManager(), mLockPatternUtils, mDPM);
for (int i = 0; i < agents.size(); i++) {
final TrustAgentComponentInfo agent = agents.get(i);
Preference trustAgentPreference =
@@ -377,7 +377,11 @@
trustAgentPreference.setIntent(intent);
// Add preference to the settings menu.
securityCategory.addPreference(trustAgentPreference);
- if (!hasSecurity) {
+
+ if (agent.disabledByAdministrator) {
+ trustAgentPreference.setEnabled(false);
+ trustAgentPreference.setSummary(R.string.trust_agent_disabled_device_admin);
+ } else if (!hasSecurity) {
trustAgentPreference.setEnabled(false);
trustAgentPreference.setSummary(R.string.disabled_because_no_backup_security);
}
@@ -422,11 +426,15 @@
}
private static ArrayList<TrustAgentComponentInfo> getActiveTrustAgents(
- PackageManager pm, LockPatternUtils utils) {
+ PackageManager pm, LockPatternUtils utils, DevicePolicyManager dpm) {
ArrayList<TrustAgentComponentInfo> result = new ArrayList<TrustAgentComponentInfo>();
List<ResolveInfo> resolveInfos = pm.queryIntentServices(TRUST_AGENT_INTENT,
PackageManager.GET_META_DATA);
List<ComponentName> enabledTrustAgents = utils.getEnabledTrustAgents();
+
+ boolean disableTrustAgents = (dpm.getKeyguardDisabledFeatures(null)
+ & DevicePolicyManager.KEYGUARD_DISABLE_TRUST_AGENTS) != 0;
+
if (enabledTrustAgents != null && !enabledTrustAgents.isEmpty()) {
for (int i = 0; i < resolveInfos.size(); i++) {
ResolveInfo resolveInfo = resolveInfos.get(i);
@@ -438,6 +446,10 @@
!enabledTrustAgents.contains(
TrustAgentUtils.getComponentName(resolveInfo)) ||
TextUtils.isEmpty(trustAgentComponentInfo.title)) continue;
+ if (disableTrustAgents && dpm.getTrustAgentConfiguration(
+ null, TrustAgentUtils.getComponentName(resolveInfo)) == null) {
+ trustAgentComponentInfo.disabledByAdministrator = true;
+ }
result.add(trustAgentComponentInfo);
if (ONLY_ONE_TRUST_AGENT) break;
}
@@ -772,7 +784,8 @@
final LockPatternUtils lockPatternUtils = new LockPatternUtils(context);
if (lockPatternUtils.isSecure()) {
ArrayList<TrustAgentComponentInfo> agents =
- getActiveTrustAgents(context.getPackageManager(), lockPatternUtils);
+ getActiveTrustAgents(context.getPackageManager(), lockPatternUtils,
+ context.getSystemService(DevicePolicyManager.class));
for (int i = 0; i < agents.size(); i++) {
final TrustAgentComponentInfo agent = agents.get(i);
data = new SearchIndexableRaw(context);
diff --git a/src/com/android/settings/SettingsActivity.java b/src/com/android/settings/SettingsActivity.java
index 0fdf04b..e8be34a 100644
--- a/src/com/android/settings/SettingsActivity.java
+++ b/src/com/android/settings/SettingsActivity.java
@@ -100,6 +100,7 @@
import com.android.settings.notification.NotificationStation;
import com.android.settings.notification.OtherSoundSettings;
import com.android.settings.notification.ZenModeExternalRuleSettings;
+import com.android.settings.notification.ZenModePrioritySettings;
import com.android.settings.notification.ZenModeSettings;
import com.android.settings.notification.ZenModeScheduleRuleSettings;
import com.android.settings.print.PrintJobSettingsFragment;
@@ -335,6 +336,7 @@
OtherSoundSettings.class.getName(),
ApnSettings.class.getName(),
WifiCallingSettings.class.getName(),
+ ZenModePrioritySettings.class.getName(),
ZenModeScheduleRuleSettings.class.getName(),
ZenModeExternalRuleSettings.class.getName(),
};
diff --git a/src/com/android/settings/TrustAgentSettings.java b/src/com/android/settings/TrustAgentSettings.java
index 1427d5f..4c6b4ee 100644
--- a/src/com/android/settings/TrustAgentSettings.java
+++ b/src/com/android/settings/TrustAgentSettings.java
@@ -18,6 +18,7 @@
import java.util.List;
+import android.app.admin.DevicePolicyManager;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
@@ -38,9 +39,11 @@
public class TrustAgentSettings extends SettingsPreferenceFragment implements
Preference.OnPreferenceChangeListener {
private static final String SERVICE_INTERFACE = TrustAgentService.SERVICE_INTERFACE;
+
private ArrayMap<ComponentName, AgentInfo> mAvailableAgents;
private final ArraySet<ComponentName> mActiveAgents = new ArraySet<ComponentName>();
private LockPatternUtils mLockPatternUtils;
+ private DevicePolicyManager mDpm;
public static final class AgentInfo {
CharSequence label;
@@ -69,6 +72,7 @@
@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
+ mDpm = getActivity().getSystemService(DevicePolicyManager.class);
addPreferencesFromResource(R.xml.trust_agent_settings);
}
@@ -89,6 +93,10 @@
PreferenceGroup category =
(PreferenceGroup) getPreferenceScreen().findPreference("trust_agents");
category.removeAll();
+
+ boolean disabledByDevicePolicy = (mDpm.getKeyguardDisabledFeatures(null)
+ & DevicePolicyManager.KEYGUARD_DISABLE_TRUST_AGENTS) != 0;
+
final int count = mAvailableAgents.size();
for (int i = 0; i < count; i++) {
AgentInfo agent = mAvailableAgents.valueAt(i);
@@ -100,6 +108,13 @@
preference.setPersistent(false);
preference.setOnPreferenceChangeListener(this);
preference.setChecked(mActiveAgents.contains(agent.component));
+
+ if (disabledByDevicePolicy
+ && mDpm.getTrustAgentConfiguration(null, agent.component) == null) {
+ preference.setEnabled(false);
+ preference.setSummary(R.string.trust_agent_disabled_device_admin);
+ }
+
category.addPreference(agent.preference);
}
}
diff --git a/src/com/android/settings/TrustAgentUtils.java b/src/com/android/settings/TrustAgentUtils.java
index 31a073c..109663a 100644
--- a/src/com/android/settings/TrustAgentUtils.java
+++ b/src/com/android/settings/TrustAgentUtils.java
@@ -57,6 +57,7 @@
ComponentName componentName;
String title;
String summary;
+ boolean disabledByAdministrator;
}
public static ComponentName getComponentName(ResolveInfo resolveInfo) {
diff --git a/src/com/android/settings/VoiceSettingsActivity.java b/src/com/android/settings/VoiceSettingsActivity.java
deleted file mode 100644
index b5e8ede..0000000
--- a/src/com/android/settings/VoiceSettingsActivity.java
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.settings;
-
-import android.app.Activity;
-import android.content.Intent;
-import android.os.Bundle;
-import android.util.Log;
-
-/**
- * Activity for modifying a setting using the Voice Interaction API. This activity
- * MUST only modify the setting if the intent was sent using
- * {@link android.service.voice.VoiceInteractionSession#startVoiceActivity startVoiceActivity}.
- */
-abstract public class VoiceSettingsActivity extends Activity {
-
- private static final String TAG = "VoiceSettingsActivity";
-
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
-
- if (isVoiceInteraction()) {
- // Only permit if this is a voice interaction.
- onVoiceSettingInteraction(getIntent());
- } else {
- Log.v(TAG, "Cannot modify settings without voice interaction");
- }
- finish();
- }
-
- /**
- * Modify the setting as a voice interaction. The activity will finish
- * after this method is called.
- */
- abstract protected void onVoiceSettingInteraction(Intent intent);
-}
diff --git a/src/com/android/settings/deviceinfo/FileItemInfoLayout.java b/src/com/android/settings/deviceinfo/FileItemInfoLayout.java
deleted file mode 100644
index 542d7c9..0000000
--- a/src/com/android/settings/deviceinfo/FileItemInfoLayout.java
+++ /dev/null
@@ -1,80 +0,0 @@
-// Copyright 2011 Google Inc. All Rights Reserved.
-
-package com.android.settings.deviceinfo;
-
-import android.content.Context;
-import android.os.Environment.UserEnvironment;
-import android.os.UserHandle;
-import android.util.AttributeSet;
-import android.view.ViewDebug;
-import android.widget.CheckBox;
-import android.widget.Checkable;
-import android.widget.RelativeLayout;
-import android.widget.TextView;
-
-import com.android.settings.R;
-
-/**
- * Handles display of a single row entry on Settings --> Storage --> Misc Files screen
- */
-public class FileItemInfoLayout extends RelativeLayout implements Checkable {
- private TextView mFileNameView;
- private TextView mFileSizeView;
- private CheckBox mCheckbox;
-
- private static final int sLengthExternalStorageDirPrefix = new UserEnvironment(
- UserHandle.myUserId()).getExternalStorageDirectory().getAbsolutePath().length() + 1;
-
- public FileItemInfoLayout(Context context) {
- this(context, null);
- }
-
- public FileItemInfoLayout(Context context, AttributeSet attrs) {
- this(context, attrs, 0);
- }
-
- public FileItemInfoLayout(Context context, AttributeSet attrs, int defStyle) {
- super(context, attrs, defStyle);
- }
-
- public void toggle() {
- setChecked(!mCheckbox.isChecked());
- }
-
- /* (non-Javadoc)
- * @see android.view.View#onFinishInflate()
- */
- @Override
- protected void onFinishInflate() {
- super.onFinishInflate();
- mFileNameView = (TextView) findViewById(R.id.misc_filename);
- mFileSizeView = (TextView) findViewById(R.id.misc_filesize);
- mCheckbox = (CheckBox) findViewById(R.id.misc_checkbox);
- }
-
- public void setFileName(String fileName) {
- mFileNameView.setText(fileName.substring(sLengthExternalStorageDirPrefix));
- }
-
- public void setFileSize(String filesize) {
- mFileSizeView.setText(filesize);
- }
-
- @ViewDebug.ExportedProperty
- public boolean isChecked() {
- return mCheckbox.isChecked();
- }
-
- public CheckBox getCheckBox() {
- return mCheckbox;
- }
-
- /**
- * <p>Changes the checked state of this text view.</p>
- *
- * @param checked true to check the text, false to uncheck it
- */
- public void setChecked(boolean checked) {
- mCheckbox.setChecked(checked);
- }
-}
\ No newline at end of file
diff --git a/src/com/android/settings/deviceinfo/PrivateVolumeFormatConfirm.java b/src/com/android/settings/deviceinfo/PrivateVolumeFormatConfirm.java
new file mode 100644
index 0000000..12994d5
--- /dev/null
+++ b/src/com/android/settings/deviceinfo/PrivateVolumeFormatConfirm.java
@@ -0,0 +1,74 @@
+/*
+ * 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 android.content.Intent;
+import android.os.Bundle;
+import android.os.storage.DiskInfo;
+import android.os.storage.StorageManager;
+import android.os.storage.VolumeInfo;
+import android.text.TextUtils;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.view.ViewGroup;
+import android.widget.Button;
+import android.widget.TextView;
+
+import com.android.internal.logging.MetricsLogger;
+import com.android.settings.InstrumentedFragment;
+import com.android.settings.R;
+
+public class PrivateVolumeFormatConfirm extends InstrumentedFragment {
+ private VolumeInfo mVolume;
+ private DiskInfo mDisk;
+
+ @Override
+ protected int getMetricsCategory() {
+ return MetricsLogger.DEVICEINFO_STORAGE;
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ final StorageManager storage = getActivity().getSystemService(StorageManager.class);
+ final String volumeId = getArguments().getString(StorageSettings.EXTRA_VOLUME_ID);
+ mVolume = storage.findVolumeById(volumeId);
+ mDisk = storage.findDiskByVolumeId(volumeId);
+
+ final View view = inflater.inflate(R.layout.storage_internal_format, container, false);
+ final TextView body = (TextView) view.findViewById(R.id.body);
+ final Button confirm = (Button) view.findViewById(R.id.confirm);
+
+ body.setText(TextUtils.expandTemplate(getText(R.string.storage_internal_format_details),
+ mDisk.getDescription()));
+ confirm.setOnClickListener(mConfirmListener);
+
+ return view;
+ }
+
+ private final OnClickListener mConfirmListener = new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ final Intent intent = new Intent(getActivity(), StorageWizardFormatProgress.class);
+ intent.putExtra(StorageWizardBase.EXTRA_DISK_ID, mDisk.id);
+ intent.putExtra(StorageWizardFormatProgress.EXTRA_FORMAT_PUBLIC, true);
+ startActivity(intent);
+ getActivity().finish();
+ }
+ };
+}
diff --git a/src/com/android/settings/deviceinfo/PrivateVolumeSettings.java b/src/com/android/settings/deviceinfo/PrivateVolumeSettings.java
index efb9a07..95a5874 100644
--- a/src/com/android/settings/deviceinfo/PrivateVolumeSettings.java
+++ b/src/com/android/settings/deviceinfo/PrivateVolumeSettings.java
@@ -58,9 +58,7 @@
import com.android.settings.SettingsPreferenceFragment;
import com.android.settings.deviceinfo.StorageMeasurement.MeasurementDetails;
import com.android.settings.deviceinfo.StorageMeasurement.MeasurementReceiver;
-import com.android.settings.deviceinfo.StorageSettings.FormatTask;
import com.android.settings.deviceinfo.StorageSettings.MountTask;
-import com.android.settings.deviceinfo.StorageSettings.UnmountTask;
import com.google.android.collect.Lists;
import java.io.File;
@@ -82,6 +80,7 @@
private StorageManager mStorageManager;
private UserManager mUserManager;
+ private String mVolumeId;
private VolumeInfo mVolume;
private VolumeInfo mSharedVolume;
@@ -119,8 +118,10 @@
mUserManager = context.getSystemService(UserManager.class);
mStorageManager = context.getSystemService(StorageManager.class);
- final String volId = getArguments().getString(EXTRA_VOLUME_ID);
- mVolume = Preconditions.checkNotNull(mStorageManager.findVolumeById(volId));
+ mVolumeId = getArguments().getString(EXTRA_VOLUME_ID);
+ mVolume = mStorageManager.findVolumeById(mVolumeId);
+
+ Preconditions.checkNotNull(mVolume);
Preconditions.checkState(mVolume.type == VolumeInfo.TYPE_PRIVATE);
addPreferencesFromResource(R.xml.device_info_storage_volume);
@@ -233,6 +234,14 @@
@Override
public void onResume() {
super.onResume();
+
+ // Refresh to verify that we haven't been formatted away
+ mVolume = mStorageManager.findVolumeById(mVolumeId);
+ if (mVolume == null) {
+ getActivity().finish();
+ return;
+ }
+
mStorageManager.registerListener(mStorageListener);
refresh();
}
@@ -283,6 +292,7 @@
@Override
public boolean onOptionsItemSelected(MenuItem item) {
final Context context = getActivity();
+ final Bundle args = new Bundle();
switch (item.getItemId()) {
case R.id.storage_rename:
RenameFragment.show(this);
@@ -291,10 +301,14 @@
new MountTask(context, mVolume.id).execute();
return true;
case R.id.storage_unmount:
- new UnmountTask(context, mVolume.id).execute();
+ args.putString(StorageSettings.EXTRA_VOLUME_ID, mVolume.id);
+ startFragment(this, PrivateVolumeUnmountConfirm.class.getCanonicalName(),
+ R.string.storage_menu_unmount, 0, args);
return true;
case R.id.storage_format:
- new FormatTask(context, mVolume.id).execute();
+ args.putString(StorageSettings.EXTRA_VOLUME_ID, mVolume.id);
+ startFragment(this, PrivateVolumeFormatConfirm.class.getCanonicalName(),
+ R.string.storage_menu_format, 0, args);
return true;
case R.id.storage_usb:
startFragment(this, UsbSettings.class.getCanonicalName(),
diff --git a/src/com/android/settings/deviceinfo/PrivateVolumeUnmountConfirm.java b/src/com/android/settings/deviceinfo/PrivateVolumeUnmountConfirm.java
new file mode 100644
index 0000000..78283fc
--- /dev/null
+++ b/src/com/android/settings/deviceinfo/PrivateVolumeUnmountConfirm.java
@@ -0,0 +1,71 @@
+/*
+ * 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 android.os.Bundle;
+import android.os.storage.DiskInfo;
+import android.os.storage.StorageManager;
+import android.os.storage.VolumeInfo;
+import android.text.TextUtils;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.view.ViewGroup;
+import android.widget.Button;
+import android.widget.TextView;
+
+import com.android.internal.logging.MetricsLogger;
+import com.android.settings.InstrumentedFragment;
+import com.android.settings.R;
+import com.android.settings.deviceinfo.StorageSettings.UnmountTask;
+
+public class PrivateVolumeUnmountConfirm extends InstrumentedFragment {
+ private VolumeInfo mVolume;
+ private DiskInfo mDisk;
+
+ @Override
+ protected int getMetricsCategory() {
+ return MetricsLogger.DEVICEINFO_STORAGE;
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ final StorageManager storage = getActivity().getSystemService(StorageManager.class);
+ final String volumeId = getArguments().getString(StorageSettings.EXTRA_VOLUME_ID);
+ mVolume = storage.findVolumeById(volumeId);
+ mDisk = storage.findDiskByVolumeId(volumeId);
+
+ final View view = inflater.inflate(R.layout.storage_internal_unmount, container, false);
+ final TextView body = (TextView) view.findViewById(R.id.body);
+ final Button confirm = (Button) view.findViewById(R.id.confirm);
+
+ body.setText(TextUtils.expandTemplate(getText(R.string.storage_internal_unmount_details),
+ mDisk.getDescription()));
+ confirm.setOnClickListener(mConfirmListener);
+
+ return view;
+ }
+
+ private final OnClickListener mConfirmListener = new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ new UnmountTask(getActivity(), mVolume.id).execute();
+ getActivity().finish();
+ }
+ };
+}
diff --git a/src/com/android/settings/deviceinfo/PublicVolumeSettings.java b/src/com/android/settings/deviceinfo/PublicVolumeSettings.java
index 6edfc92..ef116b2 100644
--- a/src/com/android/settings/deviceinfo/PublicVolumeSettings.java
+++ b/src/com/android/settings/deviceinfo/PublicVolumeSettings.java
@@ -19,9 +19,10 @@
import static com.android.settings.deviceinfo.StorageSettings.EXTRA_VOLUME_ID;
import android.content.Context;
+import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
-import android.os.SystemProperties;
+import android.os.storage.DiskInfo;
import android.os.storage.StorageEventListener;
import android.os.storage.StorageManager;
import android.os.storage.VolumeInfo;
@@ -52,7 +53,9 @@
private StorageManager mStorageManager;
+ private String mVolumeId;
private VolumeInfo mVolume;
+ private DiskInfo mDisk;
private int mNextOrder = 0;
@@ -94,6 +97,11 @@
Preconditions.checkNotNull(mVolume);
Preconditions.checkState(mVolume.type == VolumeInfo.TYPE_PUBLIC);
+ mDisk = mStorageManager.findDiskByVolumeId(mVolume.id);
+ Preconditions.checkNotNull(mDisk);
+
+ mVolumeId = mVolume.id;
+
addPreferencesFromResource(R.xml.device_info_storage_volume);
mGraph = buildGraph();
@@ -127,7 +135,7 @@
screen.addPreference(mUnmount);
}
screen.addPreference(mFormat);
- if (SystemProperties.getBoolean(PREF_FORMAT_INTERNAL, false)) {
+ if ((mDisk.flags & DiskInfo.FLAG_ADOPTABLE) != 0) {
screen.addPreference(mFormatInternal);
}
@@ -167,6 +175,14 @@
@Override
public void onResume() {
super.onResume();
+
+ // Refresh to verify that we haven't been formatted away
+ mVolume = mStorageManager.findVolumeById(mVolumeId);
+ if (mVolume == null) {
+ getActivity().finish();
+ return;
+ }
+
mStorageManager.registerListener(mStorageListener);
refresh();
}
@@ -187,7 +203,9 @@
} else if (pref == mFormat) {
new FormatTask(context, mVolume.id).execute();
} else if (pref == mFormatInternal) {
- // TODO: implement this
+ final Intent intent = new Intent(context, StorageWizardFormatConfirm.class);
+ intent.putExtra(StorageWizardBase.EXTRA_DISK_ID, mDisk.id);
+ startActivity(intent);
}
return super.onPreferenceTreeClick(preferenceScreen, pref);
diff --git a/src/com/android/settings/deviceinfo/StorageWizardBase.java b/src/com/android/settings/deviceinfo/StorageWizardBase.java
new file mode 100644
index 0000000..a3f4d79
--- /dev/null
+++ b/src/com/android/settings/deviceinfo/StorageWizardBase.java
@@ -0,0 +1,136 @@
+/*
+ * 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 android.app.Activity;
+import android.graphics.Color;
+import android.os.Bundle;
+import android.os.storage.DiskInfo;
+import android.os.storage.StorageManager;
+import android.os.storage.VolumeInfo;
+import android.text.TextUtils;
+import android.view.View;
+import android.view.WindowManager;
+import android.widget.Button;
+import android.widget.ProgressBar;
+import android.widget.TextView;
+
+import com.android.settings.R;
+import com.android.setupwizardlib.SetupWizardLayout;
+import com.android.setupwizardlib.view.NavigationBar;
+import com.android.setupwizardlib.view.NavigationBar.NavigationBarListener;
+
+import java.text.NumberFormat;
+
+public abstract class StorageWizardBase extends Activity implements NavigationBarListener {
+ protected static final String EXTRA_DISK_ID = "disk_id";
+ protected static final String EXTRA_VOLUME_ID = "volume_id";
+
+ protected StorageManager mStorage;
+
+ protected VolumeInfo mVolume;
+ protected DiskInfo mDisk;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ mStorage = getSystemService(StorageManager.class);
+
+ final String volumeId = getIntent().getStringExtra(EXTRA_VOLUME_ID);
+ if (!TextUtils.isEmpty(volumeId)) {
+ mVolume = mStorage.findVolumeById(volumeId);
+ }
+
+ final String diskId = getIntent().getStringExtra(EXTRA_DISK_ID);
+ if (!TextUtils.isEmpty(diskId)) {
+ mDisk = mStorage.findDiskById(diskId);
+ } else {
+ mDisk = mStorage.findDiskByVolumeId(volumeId);
+ }
+
+ setTheme(R.style.SuwThemeMaterial_Light);
+ }
+
+ @Override
+ protected void onPostCreate(Bundle savedInstanceState) {
+ super.onPostCreate(savedInstanceState);
+
+ getWindow().addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS |
+ WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN |
+ WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR);
+
+ getNavigationBar().setSystemUiVisibility(
+ View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
+
+ getWindow().setStatusBarColor(Color.TRANSPARENT);
+
+ getNavigationBar().setNavigationBarListener(this);
+ getBackButton().setVisibility(View.GONE);
+ }
+
+ protected NavigationBar getNavigationBar() {
+ return (NavigationBar) findViewById(R.id.suw_layout_navigation_bar);
+ }
+
+ protected Button getBackButton() {
+ return getNavigationBar().getBackButton();
+ }
+
+ protected Button getNextButton() {
+ return getNavigationBar().getNextButton();
+ }
+
+ protected SetupWizardLayout getSetupWizardLayout() {
+ return (SetupWizardLayout) findViewById(R.id.setup_wizard_layout);
+ }
+
+ protected ProgressBar getProgressBar() {
+ return (ProgressBar) findViewById(R.id.storage_wizard_progress);
+ }
+
+ protected void setCurrentProgress(int progress) {
+ getProgressBar().setProgress(progress);
+ ((TextView) findViewById(R.id.storage_wizard_progress_summary)).setText(
+ NumberFormat.getPercentInstance().format((double) progress / 100));
+ }
+
+ protected void setHeaderText(int resId, String... args) {
+ getSetupWizardLayout().setHeaderText(TextUtils.expandTemplate(getText(resId), args));
+ }
+
+ protected void setBodyText(int resId, String... args) {
+ ((TextView) findViewById(R.id.storage_wizard_body)).setText(
+ TextUtils.expandTemplate(getText(resId), args));
+ }
+
+ protected void setSecondaryBodyText(int resId, String... args) {
+ final TextView secondBody = ((TextView) findViewById(R.id.storage_wizard_second_body));
+ secondBody.setText(TextUtils.expandTemplate(getText(resId), args));
+ secondBody.setVisibility(View.VISIBLE);
+ }
+
+ @Override
+ public void onNavigateBack() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void onNavigateNext() {
+ throw new UnsupportedOperationException();
+ }
+}
diff --git a/src/com/android/settings/deviceinfo/StorageWizardFormatConfirm.java b/src/com/android/settings/deviceinfo/StorageWizardFormatConfirm.java
new file mode 100644
index 0000000..37235de
--- /dev/null
+++ b/src/com/android/settings/deviceinfo/StorageWizardFormatConfirm.java
@@ -0,0 +1,48 @@
+/*
+ * 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 android.content.Intent;
+import android.os.Bundle;
+
+import com.android.internal.util.Preconditions;
+import com.android.settings.R;
+
+public class StorageWizardFormatConfirm extends StorageWizardBase {
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.storage_wizard_generic);
+
+ Preconditions.checkNotNull(mDisk);
+
+ setHeaderText(R.string.storage_wizard_format_confirm_title);
+ setBodyText(R.string.storage_wizard_format_confirm_body,
+ mDisk.getDescription());
+
+ // TODO: make this a big red scary button
+ getNextButton().setText(R.string.storage_wizard_format_confirm_next);
+ }
+
+ @Override
+ public void onNavigateNext() {
+ final Intent intent = new Intent(this, StorageWizardFormatProgress.class);
+ intent.putExtra(EXTRA_DISK_ID, mDisk.id);
+ startActivity(intent);
+ finishAffinity();
+ }
+}
diff --git a/src/com/android/settings/deviceinfo/StorageWizardFormatProgress.java b/src/com/android/settings/deviceinfo/StorageWizardFormatProgress.java
new file mode 100644
index 0000000..286f1a4
--- /dev/null
+++ b/src/com/android/settings/deviceinfo/StorageWizardFormatProgress.java
@@ -0,0 +1,89 @@
+/*
+ * 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.Context;
+import android.content.Intent;
+import android.os.AsyncTask;
+import android.os.Bundle;
+import android.util.Log;
+import android.view.View;
+import android.widget.Toast;
+
+import com.android.internal.util.Preconditions;
+import com.android.settings.R;
+
+public class StorageWizardFormatProgress extends StorageWizardBase {
+ public static final String EXTRA_FORMAT_PUBLIC = "format_private";
+
+ private boolean mFormatPublic;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.storage_wizard_progress);
+
+ Preconditions.checkNotNull(mDisk);
+
+ mFormatPublic = getIntent().getBooleanExtra(EXTRA_FORMAT_PUBLIC, false);
+
+ setHeaderText(R.string.storage_wizard_format_progress_title, mDisk.getDescription());
+ setBodyText(R.string.storage_wizard_format_progress_body, mDisk.getDescription());
+
+ setCurrentProgress(20);
+
+ getNextButton().setVisibility(View.GONE);
+
+ new PartitionTask().execute();
+ }
+
+ public class PartitionTask extends AsyncTask<Void, Void, Exception> {
+ @Override
+ protected Exception doInBackground(Void... params) {
+ try {
+ if (mFormatPublic) {
+ mStorage.partitionPublic(mDisk.id);
+ } else {
+ mStorage.partitionPrivate(mDisk.id);
+ }
+ return null;
+ } catch (Exception e) {
+ return e;
+ }
+ }
+
+ @Override
+ protected void onPostExecute(Exception e) {
+ final Context context = StorageWizardFormatProgress.this;
+ if (e == null) {
+ if (!mFormatPublic) {
+ final Intent intent = new Intent(context, StorageWizardMigrate.class);
+ intent.putExtra(EXTRA_DISK_ID, mDisk.id);
+ startActivity(intent);
+ }
+ finishAffinity();
+
+ } else {
+ Log.e(TAG, "Failed to partition", e);
+ Toast.makeText(context, e.getMessage(), Toast.LENGTH_LONG).show();
+ finishAffinity();
+ }
+ }
+ }
+}
diff --git a/src/com/android/settings/deviceinfo/StorageWizardInit.java b/src/com/android/settings/deviceinfo/StorageWizardInit.java
new file mode 100644
index 0000000..bb5e08f
--- /dev/null
+++ b/src/com/android/settings/deviceinfo/StorageWizardInit.java
@@ -0,0 +1,83 @@
+/*
+ * 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 android.content.Intent;
+import android.os.Bundle;
+import android.widget.CompoundButton;
+import android.widget.CompoundButton.OnCheckedChangeListener;
+import android.widget.RadioButton;
+
+import com.android.internal.util.Preconditions;
+import com.android.settings.R;
+
+public class StorageWizardInit extends StorageWizardBase {
+ private RadioButton mRadioExternal;
+ private RadioButton mRadioInternal;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.storage_wizard_init);
+
+ Preconditions.checkNotNull(mDisk);
+
+ setHeaderText(R.string.storage_wizard_init_title, mDisk.getDescription());
+
+ mRadioExternal = (RadioButton) findViewById(R.id.storage_wizard_init_external_title);
+ mRadioInternal = (RadioButton) findViewById(R.id.storage_wizard_init_internal_title);
+
+ mRadioExternal.setOnCheckedChangeListener(mRadioListener);
+ mRadioInternal.setOnCheckedChangeListener(mRadioListener);
+
+ findViewById(R.id.storage_wizard_init_external_summary).setPadding(
+ mRadioExternal.getCompoundPaddingLeft(), 0,
+ mRadioExternal.getCompoundPaddingRight(), 0);
+ findViewById(R.id.storage_wizard_init_internal_summary).setPadding(
+ mRadioExternal.getCompoundPaddingLeft(), 0,
+ mRadioExternal.getCompoundPaddingRight(), 0);
+
+ getNextButton().setEnabled(false);
+ }
+
+ private final OnCheckedChangeListener mRadioListener = new OnCheckedChangeListener() {
+ @Override
+ public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
+ if (isChecked) {
+ if (buttonView == mRadioExternal) {
+ mRadioInternal.setChecked(false);
+ } else if (buttonView == mRadioInternal) {
+ mRadioExternal.setChecked(false);
+ }
+ getNextButton().setEnabled(true);
+ }
+ }
+ };
+
+ @Override
+ public void onNavigateNext() {
+ if (mRadioExternal.isChecked()) {
+ final Intent intent = new Intent(this, StorageWizardReady.class);
+ intent.putExtra(EXTRA_DISK_ID, mDisk.id);
+ startActivity(intent);
+ } else if (mRadioInternal.isChecked()) {
+ final Intent intent = new Intent(this, StorageWizardFormatConfirm.class);
+ intent.putExtra(EXTRA_DISK_ID, mDisk.id);
+ startActivity(intent);
+ }
+ }
+}
diff --git a/src/com/android/settings/deviceinfo/StorageWizardMigrate.java b/src/com/android/settings/deviceinfo/StorageWizardMigrate.java
new file mode 100644
index 0000000..2afdc15
--- /dev/null
+++ b/src/com/android/settings/deviceinfo/StorageWizardMigrate.java
@@ -0,0 +1,81 @@
+/*
+ * 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 android.content.Intent;
+import android.os.Bundle;
+import android.text.format.DateUtils;
+import android.text.format.Formatter;
+import android.widget.CompoundButton;
+import android.widget.CompoundButton.OnCheckedChangeListener;
+import android.widget.RadioButton;
+
+import com.android.internal.util.Preconditions;
+import com.android.settings.R;
+
+public class StorageWizardMigrate extends StorageWizardBase {
+ private RadioButton mRadioNow;
+ private RadioButton mRadioLater;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.storage_wizard_migrate);
+
+ 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);
+
+ mRadioNow = (RadioButton) findViewById(R.id.storage_wizard_migrate_now);
+ mRadioLater = (RadioButton) findViewById(R.id.storage_wizard_migrate_later);
+
+ mRadioNow.setOnCheckedChangeListener(mRadioListener);
+ mRadioLater.setOnCheckedChangeListener(mRadioListener);
+
+ mRadioNow.setChecked(true);
+ }
+
+ private final OnCheckedChangeListener mRadioListener = new OnCheckedChangeListener() {
+ @Override
+ public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
+ if (isChecked) {
+ if (buttonView == mRadioNow) {
+ mRadioLater.setChecked(false);
+ } else if (buttonView == mRadioLater) {
+ mRadioNow.setChecked(false);
+ }
+ }
+ }
+ };
+
+ @Override
+ public void onNavigateNext() {
+ if (mRadioNow.isChecked()) {
+ final Intent intent = new Intent(this, StorageWizardMigrateConfirm.class);
+ intent.putExtra(EXTRA_DISK_ID, mDisk.id);
+ startActivity(intent);
+ } else if (mRadioLater.isChecked()) {
+ final Intent intent = new Intent(this, StorageWizardReady.class);
+ intent.putExtra(EXTRA_DISK_ID, mDisk.id);
+ startActivity(intent);
+ }
+ }
+}
diff --git a/src/com/android/settings/deviceinfo/StorageWizardMigrateConfirm.java b/src/com/android/settings/deviceinfo/StorageWizardMigrateConfirm.java
new file mode 100644
index 0000000..4a6fed6
--- /dev/null
+++ b/src/com/android/settings/deviceinfo/StorageWizardMigrateConfirm.java
@@ -0,0 +1,52 @@
+/*
+ * 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 android.content.Intent;
+import android.os.Bundle;
+import android.text.format.DateUtils;
+import android.text.format.Formatter;
+
+import com.android.internal.util.Preconditions;
+import com.android.settings.R;
+
+public class StorageWizardMigrateConfirm extends StorageWizardBase {
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.storage_wizard_generic);
+
+ Preconditions.checkNotNull(mDisk);
+
+ final String time = DateUtils.formatDuration(0).toString();
+ final String size = Formatter.formatFileSize(this, 0);
+
+ 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());
+
+ getNextButton().setText(R.string.storage_wizard_migrate_confirm_next);
+ }
+
+ @Override
+ public void onNavigateNext() {
+ final Intent intent = new Intent(this, StorageWizardMigrateProgress.class);
+ intent.putExtra(EXTRA_DISK_ID, mDisk.id);
+ startActivity(intent);
+ finishAffinity();
+ }
+}
diff --git a/src/com/android/settings/deviceinfo/StorageWizardMigrateProgress.java b/src/com/android/settings/deviceinfo/StorageWizardMigrateProgress.java
new file mode 100644
index 0000000..0589694
--- /dev/null
+++ b/src/com/android/settings/deviceinfo/StorageWizardMigrateProgress.java
@@ -0,0 +1,75 @@
+/*
+ * 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.Context;
+import android.content.Intent;
+import android.os.AsyncTask;
+import android.os.Bundle;
+import android.os.SystemClock;
+import android.util.Log;
+import android.view.View;
+import android.widget.Toast;
+
+import com.android.internal.util.Preconditions;
+import com.android.settings.R;
+
+public class StorageWizardMigrateProgress extends StorageWizardBase {
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.storage_wizard_progress);
+
+ Preconditions.checkNotNull(mDisk);
+
+ setHeaderText(R.string.storage_wizard_migrate_progress_title, mDisk.getDescription());
+ setBodyText(R.string.storage_wizard_migrate_details, mDisk.getDescription());
+
+ setCurrentProgress(20);
+
+ getNextButton().setVisibility(View.GONE);
+
+ new MigrateTask().execute();
+ }
+
+ public class MigrateTask extends AsyncTask<Void, Void, Exception> {
+ @Override
+ protected Exception doInBackground(Void... params) {
+ // TODO: wire up migration
+ SystemClock.sleep(2000);
+ return null;
+ }
+
+ @Override
+ protected void onPostExecute(Exception e) {
+ final Context context = StorageWizardMigrateProgress.this;
+ if (e == null) {
+ final Intent intent = new Intent(context, StorageWizardReady.class);
+ intent.putExtra(EXTRA_DISK_ID, mDisk.id);
+ startActivity(intent);
+ finishAffinity();
+
+ } else {
+ Log.e(TAG, "Failed to migrate", e);
+ Toast.makeText(context, e.getMessage(), Toast.LENGTH_LONG).show();
+ finishAffinity();
+ }
+ }
+ }
+}
diff --git a/src/com/android/settings/deviceinfo/StorageWizardReady.java b/src/com/android/settings/deviceinfo/StorageWizardReady.java
new file mode 100644
index 0000000..c950986
--- /dev/null
+++ b/src/com/android/settings/deviceinfo/StorageWizardReady.java
@@ -0,0 +1,59 @@
+/*
+ * 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 android.os.Bundle;
+import android.os.storage.VolumeInfo;
+
+import com.android.internal.util.Preconditions;
+import com.android.settings.R;
+
+public class StorageWizardReady extends StorageWizardBase {
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.storage_wizard_generic);
+
+ Preconditions.checkNotNull(mDisk);
+
+ setHeaderText(R.string.storage_wizard_ready_title, mDisk.getDescription());
+
+ // TODO: handle mixed partition cases instead of just guessing based on
+ // first volume type we encounter
+ for (String volId : mDisk.volumes) {
+ final VolumeInfo vol = mStorage.findVolumeById(volId);
+ if (vol == null) continue;
+
+ if (vol.type == VolumeInfo.TYPE_PUBLIC) {
+ setBodyText(R.string.storage_wizard_ready_external_body,
+ mDisk.getDescription());
+ break;
+ } else if (vol.type == VolumeInfo.TYPE_PRIVATE) {
+ setBodyText(R.string.storage_wizard_ready_internal_body,
+ mDisk.getDescription());
+ break;
+ }
+ }
+
+ getNextButton().setText(R.string.done);
+ }
+
+ @Override
+ public void onNavigateNext() {
+ finishAffinity();
+ }
+}
diff --git a/src/com/android/settings/fuelgauge/BatterySaverModeVoiceActivity.java b/src/com/android/settings/fuelgauge/BatterySaverModeVoiceActivity.java
new file mode 100644
index 0000000..4494887
--- /dev/null
+++ b/src/com/android/settings/fuelgauge/BatterySaverModeVoiceActivity.java
@@ -0,0 +1,51 @@
+/*
+ * 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.fuelguage;
+
+import static android.provider.Settings.EXTRA_BATTERY_SAVER_MODE_ENABLED;
+
+import android.content.Context;
+import android.content.Intent;
+import android.os.PowerManager;
+import android.provider.Settings;
+import android.util.Log;
+
+import com.android.settings.utils.VoiceSettingsActivity;
+
+/**
+ * Activity for modifying the {@link android.os.PowerManager} power save mode
+ * setting using the Voice Interaction API.
+ */
+public class BatterySaverModeVoiceActivity extends VoiceSettingsActivity {
+ private static final String TAG = "BatterySaverModeVoiceActivity";
+
+ protected boolean onVoiceSettingInteraction(Intent intent) {
+ if (intent.hasExtra(EXTRA_BATTERY_SAVER_MODE_ENABLED)) {
+ PowerManager powerManager = (PowerManager) getSystemService(Context.POWER_SERVICE);
+ if (powerManager.setPowerSaveMode(
+ intent.getBooleanExtra(EXTRA_BATTERY_SAVER_MODE_ENABLED, false))) {
+ notifySuccess(null);
+ } else {
+ Log.v(TAG, "Unable to set power mode");
+ notifyFailure(null);
+ }
+ } else {
+ Log.v(TAG, "Missing battery saver mode extra");
+ }
+ return true;
+ }
+}
diff --git a/src/com/android/settings/notification/ZenModeVoiceActivity.java b/src/com/android/settings/notification/ZenModeVoiceActivity.java
new file mode 100644
index 0000000..c7c1151
--- /dev/null
+++ b/src/com/android/settings/notification/ZenModeVoiceActivity.java
@@ -0,0 +1,241 @@
+/*
+ * 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 static android.provider.Settings.EXTRA_DO_NOT_DISTURB_MODE_MINUTES;
+import static android.provider.Settings.EXTRA_DO_NOT_DISTURB_MODE_ENABLED;
+
+import com.android.settings.R;
+import com.android.settings.utils.VoiceSelectionAdapter;
+import com.android.settings.utils.VoiceSelection;
+import com.android.settings.utils.VoiceSelectionFragment;
+import com.android.settings.utils.VoiceSettingsActivity;
+
+import android.app.Fragment;
+import android.app.NotificationManager;
+import android.content.Context;
+import android.content.Intent;
+import android.content.res.Resources;
+import android.os.UserHandle;
+import android.provider.Settings.Global;
+import android.service.notification.Condition;
+import android.service.notification.ZenModeConfig;
+import android.text.format.DateFormat;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Locale;
+
+/**
+ * Activity for modifying the Zen mode (Do not disturb) by voice
+ * using the Voice Interaction API.
+ */
+public class ZenModeVoiceActivity extends VoiceSettingsActivity {
+ private static final String TAG = "ZenModeVoiceActivity";
+ private static final int MINUTES_MS = 60 * 1000;
+
+ @Override
+ protected boolean onVoiceSettingInteraction(Intent intent) {
+ setContentView(R.layout.voice_interaction);
+ pickNotificationMode(intent);
+ return false;
+ }
+
+ /**
+ * Start a voice interaction to ask what kind of interruptions should
+ * be permitted. The intent can optionally include extra information about the type
+ * of interruptions desired or how long interruptions should be limited to that are
+ * used as hints.
+ */
+ private void pickNotificationMode(final Intent intent) {
+ boolean enabled = intent.getBooleanExtra(EXTRA_DO_NOT_DISTURB_MODE_ENABLED, false);
+ boolean specified = intent.hasExtra(EXTRA_DO_NOT_DISTURB_MODE_ENABLED);
+
+ List<VoiceSelection> states = new ArrayList<VoiceSelection>();
+ if (!specified || enabled) {
+ states.add(new ModeSelection(this, Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS,
+ R.string.zen_mode_option_important_interruptions,
+ R.string.zen_mode_option_important_voice_synonyms));
+ states.add(new ModeSelection(this, Global.ZEN_MODE_ALARMS,
+ R.string.zen_mode_option_alarms,
+ R.string.zen_mode_option_alarms_voice_synonyms));
+ states.add(new ModeSelection(this, Global.ZEN_MODE_NO_INTERRUPTIONS,
+ R.string.zen_mode_option_no_interruptions,
+ R.string.zen_mode_option_no_interruptions_voice_synonyms));
+ }
+ if (!specified || !enabled) {
+ states.add(new ModeSelection(this, Global.ZEN_MODE_OFF,
+ R.string.zen_mode_option_off,
+ R.string.zen_mode_option_off_voice_synonyms));
+ }
+ VoiceSelectionFragment fragment = new VoiceSelectionFragment();
+ fragment.setArguments(VoiceSelectionFragment.createArguments(
+ getString(R.string.zen_mode_interruptions_voice_prompt)));
+ fragment.setListAdapter(
+ new VoiceSelectionAdapter(this, R.layout.voice_item_row, states));
+ fragment.setOnItemSelectedHandler(new VoiceSelection.OnItemSelectedListener() {
+ @Override
+ public void onItemSelected(int index, VoiceSelection selection) {
+ int mode = ((ModeSelection) selection).mMode;
+ ConditionSelection conditionSelection = getConditionSelection(
+ intent.getIntExtra(EXTRA_DO_NOT_DISTURB_MODE_MINUTES, 0));
+ if (mode != Global.ZEN_MODE_OFF) {
+ if (conditionSelection == null) {
+ pickDuration(selection.getLabel(), mode);
+ return;
+ }
+ }
+ setZenModeConfig(mode, conditionSelection.mCondition);
+ notifySuccess(getChangeSummary(mode, conditionSelection));
+ finish();
+ }
+ });
+ showFragment(fragment, "pick_mode_fragment");
+ }
+
+ /**
+ * Start a voice interaction to ask for the zen mode duration.
+ */
+ private void pickDuration(CharSequence label, final int mode) {
+ setTitle(label.toString());
+ List<VoiceSelection> states = new ArrayList<VoiceSelection>();
+ states.add(new ConditionSelection(null, -1,
+ getString(R.string.zen_mode_duration_indefinte_voice_label),
+ getString(R.string.zen_mode_duration_indefinite_voice_synonyms)));
+ for (int i = ZenModeConfig.MINUTE_BUCKETS.length - 1; i >= 0; --i) {
+ states.add(getConditionSelection(ZenModeConfig.MINUTE_BUCKETS[i]));
+ }
+
+ VoiceSelectionFragment fragment = new VoiceSelectionFragment();
+ fragment.setArguments(VoiceSelectionFragment.createArguments(
+ getString(R.string.zen_mode_duration_voice_prompt)));
+ fragment.setListAdapter(
+ new VoiceSelectionAdapter(this, R.layout.voice_item_row, states));
+ fragment.setOnItemSelectedHandler(new VoiceSelection.OnItemSelectedListener() {
+ @Override
+ public void onItemSelected(int index, VoiceSelection item) {
+ ConditionSelection selection = ((ConditionSelection) item);
+ setZenModeConfig(mode, selection.mCondition);
+ notifySuccess(getChangeSummary(mode, selection));
+ finish();
+ }
+ });
+ showFragment(fragment, "pick_duration_fragment");
+ }
+
+ private void showFragment(Fragment fragment, String tag) {
+ getFragmentManager()
+ .beginTransaction()
+ .replace(R.id.fragment_root, fragment, tag)
+ .commit();
+ }
+
+ private void setZenModeConfig(int mode, Condition condition) {
+ if (condition != null) {
+ NotificationManager.from(this).setZenMode(mode, condition.id, TAG);
+ } else {
+ NotificationManager.from(this).setZenMode(mode, null, TAG);
+ }
+ }
+
+ /**
+ * Produce a summary of the Zen mode change to be read aloud as TTS.
+ */
+ private CharSequence getChangeSummary(int mode, ConditionSelection duration) {
+ int indefinite = -1;
+ int byMinute = -1;
+ int byHour = -1;
+
+ switch (mode) {
+ case Global.ZEN_MODE_ALARMS:
+ indefinite = R.string.zen_mode_summary_alarams_only_indefinite;
+ byMinute = R.plurals.zen_mode_summary_alarms_only_by_minute;
+ byHour = R.plurals.zen_mode_summary_alarms_only_by_hour;
+ break;
+ case Global.ZEN_MODE_NO_INTERRUPTIONS:
+ indefinite = R.string.zen_mode_summary_no_interruptions_indefinite;
+ byMinute = R.plurals.zen_mode_summary_no_interruptions_by_minute;
+ byHour = R.plurals.zen_mode_summary_no_interruptions_by_hour;
+ break;
+ case Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS:
+ indefinite = R.string.zen_mode_summary_priority_indefinitely;
+ byMinute = R.plurals.zen_mode_summary_priority_by_minute;
+ byHour = R.plurals.zen_mode_summary_priority_by_hour;
+ break;
+ default:
+ case Global.ZEN_MODE_OFF:
+ indefinite = R.string.zen_mode_summary_always;
+ break;
+ };
+
+ if (duration == null || duration.mCondition == null) {
+ return getString(indefinite);
+ }
+
+ long time = System.currentTimeMillis() + duration.mMinutes * MINUTES_MS;
+ String skeleton = DateFormat.is24HourFormat(this, UserHandle.myUserId()) ? "Hm" : "hma";
+ String pattern = DateFormat.getBestDateTimePattern(Locale.getDefault(), skeleton);
+ CharSequence formattedTime = DateFormat.format(pattern, time);
+ Resources res = getResources();
+
+ if (duration.mMinutes < 60) {
+ return res.getQuantityString(byMinute,
+ duration.mMinutes, duration.mMinutes, formattedTime);
+ } else {
+ int hours = duration.mMinutes / 60;
+ return res.getQuantityString(byHour, hours, hours, formattedTime);
+ }
+ }
+
+ private ConditionSelection getConditionSelection(int minutes) {
+ Condition condition = ZenModeConfig.toTimeCondition(this, minutes, UserHandle.myUserId());
+ Resources res = getResources();
+ if (minutes <= 0) {
+ return null;
+ } else if (minutes < 60) {
+ String label = res.getQuantityString(R.plurals.zen_mode_duration_minutes_voice_label,
+ minutes, minutes);
+ return new ConditionSelection(condition, minutes, label, Integer.toString(minutes));
+ } else {
+ int hours = minutes / 60;
+ String label = res.getQuantityString(R.plurals.zen_mode_duration_hours_voice_label,
+ hours, hours);
+ return new ConditionSelection(condition, minutes, label, Integer.toString(hours));
+ }
+ }
+
+ private static class ConditionSelection extends VoiceSelection {
+ Condition mCondition;
+ int mMinutes;
+
+ public ConditionSelection(Condition condition, int minutes, CharSequence label,
+ CharSequence synonyms) {
+ super(label, synonyms);
+ mMinutes = minutes;
+ mCondition = condition;
+ }
+ }
+
+ private static class ModeSelection extends VoiceSelection {
+ int mMode;
+
+ public ModeSelection(Context context, int mode, int label, int synonyms) {
+ super(context.getString(label), context.getString(synonyms));
+ mMode = mode;
+ }
+ }
+}
diff --git a/src/com/android/settings/utils/VoiceSelection.java b/src/com/android/settings/utils/VoiceSelection.java
new file mode 100644
index 0000000..997d2cc
--- /dev/null
+++ b/src/com/android/settings/utils/VoiceSelection.java
@@ -0,0 +1,74 @@
+/*
+ * 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.utils;
+
+import android.app.VoiceInteractor.PickOptionRequest.Option;
+import android.os.Bundle;
+import android.text.TextUtils;
+
+/**
+ * Model for a single item that can be selected by a {@link VoiceSelectionFragment}.
+ * Each item consists of a visual label and several alternative synonyms for the item
+ * that can be used to identify the item by voice.
+ */
+public class VoiceSelection {
+ final CharSequence mLabel;
+ final CharSequence[] mSynonyms;
+
+ /**
+ * Created a new selectable item with a visual label and a set of synonyms.
+ */
+ public VoiceSelection(CharSequence label, CharSequence synonyms) {
+ mLabel = label;
+ mSynonyms = TextUtils.split(synonyms.toString(), ",");
+ }
+
+ /**
+ * Created a new selectable item with a visual label and no synonyms.
+ */
+ public VoiceSelection(CharSequence label) {
+ mLabel = label;
+ mSynonyms = null;
+ }
+
+ public CharSequence getLabel() {
+ return mLabel;
+ }
+
+ public CharSequence[] getSynonyms() {
+ return mSynonyms;
+ }
+
+ Option toOption(int index) {
+ Option result = new Option(mLabel);
+ Bundle extras = new Bundle();
+ extras.putInt("index", index);
+ result.setExtras(extras);
+
+ for (CharSequence synonym : mSynonyms) {
+ result.addSynonym(synonym);
+ }
+ return result;
+ }
+
+ /**
+ * Listener interface for when an item is selected.
+ */
+ public interface OnItemSelectedListener {
+ abstract void onItemSelected(int position, VoiceSelection selection);
+ };
+}
diff --git a/src/com/android/settings/utils/VoiceSelectionAdapter.java b/src/com/android/settings/utils/VoiceSelectionAdapter.java
new file mode 100644
index 0000000..2c060c2
--- /dev/null
+++ b/src/com/android/settings/utils/VoiceSelectionAdapter.java
@@ -0,0 +1,63 @@
+/*
+ * 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.utils;
+
+import android.content.Context;
+import android.widget.ArrayAdapter;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.TextView;
+
+import android.app.Activity;
+import com.android.settings.R;
+
+import java.util.List;
+import android.util.Log;
+
+/**
+ * Array adapter for selecting an item by voice interaction. Each row includes a visual
+ * indication of the 1-indexed position of the item so that a user can easily say
+ * "number 4" to select it.
+ */
+public class VoiceSelectionAdapter extends ArrayAdapter<VoiceSelection> {
+ public VoiceSelectionAdapter(Context context, int resource, List<VoiceSelection> objects) {
+ super(context, resource, objects);
+ }
+
+ @Override
+ public View getView(int position, View convertView, ViewGroup parent) {
+ VoiceSelection item = getItem(position);
+ View row = convertView;
+ if (row == null) {
+ LayoutInflater inflater = ((Activity) getContext()).getLayoutInflater();
+ row = inflater.inflate(R.layout.voice_item_row, parent, false);
+ }
+
+ TextView label = (TextView) row.findViewById(R.id.voice_item_label);
+ if (label != null) {
+ label.setText(item.getLabel());
+ }
+
+ TextView positionLabel = (TextView) row.findViewById(R.id.voice_item_position);
+ if (positionLabel != null) {
+ positionLabel.setText(Integer.toString(position + 1));
+ }
+
+ return row;
+ }
+};
diff --git a/src/com/android/settings/utils/VoiceSelectionFragment.java b/src/com/android/settings/utils/VoiceSelectionFragment.java
new file mode 100644
index 0000000..c2e80d3
--- /dev/null
+++ b/src/com/android/settings/utils/VoiceSelectionFragment.java
@@ -0,0 +1,133 @@
+/*
+ * 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.utils;
+
+import android.app.ListFragment;
+import android.app.VoiceInteractor;
+import android.app.VoiceInteractor.PickOptionRequest;
+import android.app.VoiceInteractor.PickOptionRequest.Option;
+import android.os.Bundle;
+import android.view.View;
+import android.widget.ArrayAdapter;
+import android.widget.ListAdapter;
+import android.widget.ListView;
+
+import java.util.List;
+
+/**
+ * An Activity fragment that presents a set of options as a visual list and also allows
+ * items to be selected by the users voice.
+ */
+public class VoiceSelectionFragment extends ListFragment {
+ private static final String EXTRA_SELECTION_PROMPT = "selection_prompt";
+
+ private CharSequence mPrompt = null;
+ private VoiceInteractor.Request mRequest = null;
+ private VoiceInteractor mVoiceInteractor = null;
+ private VoiceSelection.OnItemSelectedListener mOnItemSelectedListener = null;
+
+ /**
+ * No-args ctor required for fragment.
+ */
+ public VoiceSelectionFragment() {}
+
+ @Override
+ public void onCreate(Bundle args) {
+ super.onCreate(args);
+ mPrompt = getArguments().getCharSequence(EXTRA_SELECTION_PROMPT);
+ }
+
+ /**
+ * Set the prompt spoken when the fragment is presented.
+ */
+ static public Bundle createArguments(CharSequence prompt) {
+ Bundle args = new Bundle();
+ args.putCharSequence(EXTRA_SELECTION_PROMPT, prompt);
+ return args;
+ }
+
+ private VoiceSelection getSelectionAt(int position) {
+ return ((ArrayAdapter<VoiceSelection>) getListAdapter()).getItem(position);
+ }
+
+ @Override
+ public void onStart() {
+ super.onStart();
+
+ final int numItems = getListAdapter().getCount();
+ if (numItems <= 0) {
+ return;
+ }
+
+ Option[] options = new Option[numItems];
+ for (int idx = 0; idx < numItems; idx++) {
+ options[idx] = getSelectionAt(idx).toOption(idx);
+ }
+ mRequest = new PickOptionRequest(mPrompt, options, null) {
+ @Override
+ public void onPickOptionResult(boolean isComplete, Option[] options, Bundle args) {
+ if (!isComplete || options == null) {
+ return;
+ }
+ if (options.length == 1 && mOnItemSelectedListener != null) {
+ int idx = options[0].getExtras().getInt("index", -1);
+ mOnItemSelectedListener.onItemSelected(idx, getSelectionAt(idx));
+ } else {
+ onCancel();
+ }
+ }
+ };
+ mVoiceInteractor = getActivity().getVoiceInteractor();
+ if (mVoiceInteractor != null) {
+ mVoiceInteractor.submitRequest(mRequest);
+ }
+ }
+
+ @Override
+ public void onDetach() {
+ super.onDetach();
+ mVoiceInteractor = null;
+ }
+
+ @Override
+ public void onListItemClick(ListView l, View v, int position, long id) {
+ if (mRequest != null) {
+ mRequest.cancel();
+ mRequest = null;
+ }
+
+ if (mOnItemSelectedListener != null) {
+ mOnItemSelectedListener.onItemSelected(position, getSelectionAt(position));
+ }
+ }
+
+
+ /**
+ * Sets the selection handler for an item either by voice or by touch.
+ */
+ public void setOnItemSelectedHandler(VoiceSelection.OnItemSelectedListener listener) {
+ mOnItemSelectedListener = listener;
+ }
+
+ /**
+ * Called when the user cancels the interaction. The default implementation is to
+ * finish the activity.
+ */
+ public void onCancel() {
+ getActivity().finish();
+ }
+};
diff --git a/src/com/android/settings/utils/VoiceSettingsActivity.java b/src/com/android/settings/utils/VoiceSettingsActivity.java
new file mode 100644
index 0000000..ac5b8be
--- /dev/null
+++ b/src/com/android/settings/utils/VoiceSettingsActivity.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.utils;
+
+import android.app.Activity;
+import android.app.VoiceInteractor;
+import android.app.VoiceInteractor.CompleteVoiceRequest;
+import android.content.Intent;
+import android.os.Bundle;
+import android.util.Log;
+
+/**
+ * Activity for modifying a setting using the Voice Interaction API. This activity
+ * will only allow modifying the setting if the intent was sent using
+ * {@link android.service.voice.VoiceInteractionSession#startVoiceActivity startVoiceActivity}
+ * by the current Voice Interaction Service.
+ */
+abstract public class VoiceSettingsActivity extends Activity {
+
+ private static final String TAG = "VoiceSettingsActivity";
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ if (isVoiceInteraction() || savedInstanceState == null) {
+ // Only permit if this is a voice interaction.
+ if (onVoiceSettingInteraction(getIntent())) {
+ // If it's complete, finish.
+ finish();
+ }
+ } else {
+ Log.v(TAG, "Cannot modify settings without voice interaction");
+ finish();
+ }
+ }
+
+ /**
+ * Modify the setting as a voice interaction. Should return true if the
+ * voice interaction is complete or false if more interaction is required.
+ */
+ abstract protected boolean onVoiceSettingInteraction(Intent intent);
+
+ /**
+ * Send a notification that the interaction was successful. If {@link prompt} is
+ * not null, then it will be read to the user.
+ */
+ protected void notifySuccess(CharSequence prompt) {
+ if (getVoiceInteractor() != null) {
+ getVoiceInteractor().submitRequest(new CompleteVoiceRequest(prompt, null));
+ }
+ }
+
+ /**
+ * Indicates when the setting could not be changed.
+ */
+ protected void notifyFailure(String reason) {
+ getVoiceInteractor().submitRequest(new VoiceInteractor.AbortVoiceRequest(reason, null));
+ }
+}