Merge "Skip indexing content while user is locked." into nyc-dev am: c416433a9e
am: a592e55e5f
* commit 'a592e55e5ff8e7b4e799745f076888e6bbbcdf55':
Change-Id: Ie64ecbe217deec122560d62b94816c92e5970301
diff --git a/Android.mk b/Android.mk
index 61734fb..537004e 100644
--- a/Android.mk
+++ b/Android.mk
@@ -1,6 +1,16 @@
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
+LOCAL_SRC_FILES := \
+ $(call all-logtags-files-under, src)
+
+LOCAL_MODULE := settings-logtags
+
+include $(BUILD_STATIC_JAVA_LIBRARY)
+
+# Build the Settings APK
+include $(CLEAR_VARS)
+
LOCAL_JAVA_LIBRARIES := bouncycastle core-oj telephony-common ims-common
LOCAL_STATIC_JAVA_LIBRARIES := \
android-support-v4 \
@@ -9,13 +19,13 @@
android-support-v7-preference \
android-support-v7-appcompat \
android-support-v14-preference \
- jsr305
+ jsr305 \
+ settings-logtags
LOCAL_MODULE_TAGS := optional
LOCAL_SRC_FILES := \
- $(call all-java-files-under, src) \
- src/com/android/settings/EventLogTags.logtags
+ $(call all-java-files-under, src)
LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res \
frameworks/support/v7/preference/res \
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 061f2d4..e2d4f42 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -81,6 +81,7 @@
<uses-permission android:name="android.permission.CHANGE_APP_IDLE_STATE" />
<uses-permission android:name="android.permission.PEERS_MAC_ADDRESS"/>
<uses-permission android:name="android.permission.MANAGE_NOTIFICATIONS"/>
+ <uses-permission android:name="android.permission.DELETE_PACKAGES"/>
<application android:label="@string/settings_label"
android:icon="@mipmap/ic_launcher_settings"
@@ -1579,7 +1580,7 @@
android:enabled="false"
android:exported="true"
android:taskAffinity="com.android.wizard"
- android:theme="@style/SetupWizardDisableAppStartingTheme"
+ android:theme="@style/SuwThemeGlif.Light"
android:icon="@drawable/ic_suggested_notifications">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
@@ -2902,6 +2903,17 @@
android:value="true" />
</activity>
+ <activity android:name="Settings$DeletionHelperActivity"
+ android:label="@string/deletion_helper_title"
+ android:taskAffinity="">
+ <intent-filter android:priority="1">
+ <action android:name="android.settings.DELETION_HELPER_SETTINGS" />
+ <category android:name="android.intent.category.DEFAULT" />
+ </intent-filter>
+ <meta-data android:name="com.android.settings.FRAGMENT_CLASS"
+ android:value="com.android.settings.deletionhelper.DeletionHelperFragment" />
+ </activity>
+
<service
android:name=".SettingsDumpService"
android:exported="true"
diff --git a/proguard.flags b/proguard.flags
index 3c3300e..f3c218a 100644
--- a/proguard.flags
+++ b/proguard.flags
@@ -17,6 +17,7 @@
-keep class com.android.settings.users.*
-keep class com.android.settings.nfc.*
-keep class com.android.settings.notification.*
+-keep class com.android.settings.overlay.FeatureFactoryImpl
-keep class com.android.settings.accessibility.*FragmentForSetupWizard
-keep class com.android.settings.display.*FragmentForSetupWizard
diff --git a/res/values-sw360dp/aliases.xml b/res/color/sliding_tab_title_text_color.xml
similarity index 69%
copy from res/values-sw360dp/aliases.xml
copy to res/color/sliding_tab_title_text_color.xml
index a10585b..925ab97 100644
--- a/res/values-sw360dp/aliases.xml
+++ b/res/color/sliding_tab_title_text_color.xml
@@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2016 The Android Open Source Project
+<!--
+ Copyright (C) 2016 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.
@@ -14,7 +15,8 @@
limitations under the License.
-->
-<resources>
- <item name="setup_choose_lock_pattern_template" type="layout">@layout/suw_template</item>
-</resources>
-
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:state_selected="false"
+ android:color="#b3ffffff"/>
+ <item android:color="@android:color/white"/>
+</selector>
diff --git a/res/drawable-hdpi/ic_bt_config.png b/res/drawable-hdpi/ic_bt_config.png
deleted file mode 100644
index a204936..0000000
--- a/res/drawable-hdpi/ic_bt_config.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/ic_bt_imaging.png b/res/drawable-hdpi/ic_bt_imaging.png
deleted file mode 100644
index 62624ee..0000000
--- a/res/drawable-hdpi/ic_bt_imaging.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/ic_bt_laptop.png b/res/drawable-hdpi/ic_bt_laptop.png
deleted file mode 100644
index 42c3dc5..0000000
--- a/res/drawable-hdpi/ic_bt_laptop.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-mdpi/ic_bt_config.png b/res/drawable-mdpi/ic_bt_config.png
deleted file mode 100644
index d266b39..0000000
--- a/res/drawable-mdpi/ic_bt_config.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-mdpi/ic_bt_imaging.png b/res/drawable-mdpi/ic_bt_imaging.png
deleted file mode 100644
index 76234a6..0000000
--- a/res/drawable-mdpi/ic_bt_imaging.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-mdpi/ic_bt_laptop.png b/res/drawable-mdpi/ic_bt_laptop.png
deleted file mode 100644
index 792e8df..0000000
--- a/res/drawable-mdpi/ic_bt_laptop.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xhdpi/ic_bt_config.png b/res/drawable-xhdpi/ic_bt_config.png
deleted file mode 100644
index 46077be..0000000
--- a/res/drawable-xhdpi/ic_bt_config.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xhdpi/ic_bt_imaging.png b/res/drawable-xhdpi/ic_bt_imaging.png
deleted file mode 100644
index 9ea3b85..0000000
--- a/res/drawable-xhdpi/ic_bt_imaging.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xhdpi/ic_bt_laptop.png b/res/drawable-xhdpi/ic_bt_laptop.png
deleted file mode 100644
index 1c053c8..0000000
--- a/res/drawable-xhdpi/ic_bt_laptop.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_bt_config.png b/res/drawable-xxhdpi/ic_bt_config.png
deleted file mode 100644
index ad964b4..0000000
--- a/res/drawable-xxhdpi/ic_bt_config.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_bt_imaging.png b/res/drawable-xxhdpi/ic_bt_imaging.png
deleted file mode 100644
index a0058dc..0000000
--- a/res/drawable-xxhdpi/ic_bt_imaging.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_bt_laptop.png b/res/drawable-xxhdpi/ic_bt_laptop.png
deleted file mode 100644
index bca7145..0000000
--- a/res/drawable-xxhdpi/ic_bt_laptop.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xxxhdpi/ic_bt_config.png b/res/drawable-xxxhdpi/ic_bt_config.png
deleted file mode 100644
index e89d484..0000000
--- a/res/drawable-xxxhdpi/ic_bt_config.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xxxhdpi/ic_bt_imaging.png b/res/drawable-xxxhdpi/ic_bt_imaging.png
deleted file mode 100644
index f0ffb52..0000000
--- a/res/drawable-xxxhdpi/ic_bt_imaging.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xxxhdpi/ic_bt_laptop.png b/res/drawable-xxxhdpi/ic_bt_laptop.png
deleted file mode 100644
index 2d758bd..0000000
--- a/res/drawable-xxxhdpi/ic_bt_laptop.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable/ic_bt_config.xml b/res/drawable/ic_bt_config.xml
new file mode 100644
index 0000000..316c674
--- /dev/null
+++ b/res/drawable/ic_bt_config.xml
@@ -0,0 +1,36 @@
+<!--
+ Copyright (C) 2016 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0"
+ android:tint="?android:attr/colorAccent">
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M19.43,12.98c0.04,-0.32 0.07,-0.64 0.07,-0.98s-0.03,-0.66
+ -0.07,-0.98l2.11,-1.65c0.19,-0.15 0.24,-0.42 0.12,-0.64l-2,-3.46c-0.12,-0.22 -0.39,-0.3
+ -0.61,-0.22l-2.49,1c-0.52,-0.4 -1.08,-0.73 -1.69,-0.98l-0.38,-2.65C14.46,2.18 14.25,2
+ 14,2h-4c-0.25,0 -0.46,0.18 -0.49,0.42l-0.38,2.65c-0.61,0.25 -1.17,0.59
+ -1.69,0.98l-2.49,-1c-0.23,-0.09 -0.49,0 -0.61,0.22l-2,3.46c-0.13,0.22 -0.07,0.49
+ 0.12,0.64l2.11,1.65c-0.04,0.32 -0.07,0.65 -0.07,0.98s0.03,0.66
+ 0.07,0.98l-2.11,1.65c-0.19,0.15 -0.24,0.42 -0.12,0.64l2,3.46c0.12,0.22 0.39,0.3
+ 0.61,0.22l2.49,-1c0.52,0.4 1.08,0.73 1.69,0.98l0.38,2.65c0.03,0.24 0.24,0.42
+ 0.49,0.42h4c0.25,0 0.46,-0.18 0.49,-0.42l0.38,-2.65c0.61,-0.25
+ 1.17,-0.59 1.69,-0.98l2.49,1c0.23,0.09 0.49,0 0.61,-0.22l2,-3.46c0.12,-0.22 0.07,-0.49
+ -0.12,-0.64l-2.11,-1.65zM12,15.5c-1.93,0 -3.5,-1.57
+ -3.5,-3.5s1.57,-3.5 3.5,-3.5 3.5,1.57 3.5,3.5 -1.57,3.5 -3.5,3.5z"/>
+</vector>
\ No newline at end of file
diff --git a/res/drawable/ic_bt_imaging.xml b/res/drawable/ic_bt_imaging.xml
new file mode 100644
index 0000000..01e78c0
--- /dev/null
+++ b/res/drawable/ic_bt_imaging.xml
@@ -0,0 +1,27 @@
+<!--
+ Copyright (C) 2016 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0"
+ android:tint="?android:attr/colorAccent">
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M19,8L5,8c-1.66,0 -3,1.34 -3,3v6h4v4h12v-4h4v-6c0,-1.66 -1.34,-3
+ -3,-3zM16,19L8,19v-5h8v5zM19,12c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1 1,0.45 1,1 -0.45,1
+ -1,1zM18,3L6,3v4h12L18,3z"/>
+</vector>
\ No newline at end of file
diff --git a/res/drawable/ic_bt_laptop.xml b/res/drawable/ic_bt_laptop.xml
new file mode 100644
index 0000000..bf2fd49
--- /dev/null
+++ b/res/drawable/ic_bt_laptop.xml
@@ -0,0 +1,26 @@
+<!--
+ Copyright (C) 2016 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0"
+ android:tint="?android:attr/colorAccent">
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M20,18c1.1,0 2,-0.9 2,-2V6c0,-1.1 -0.9,-2 -2,-2H4c-1.1,0
+ -2,0.9 -2,2v10c0,1.1 0.9,2 2,2H0v2h24v-2h-4zM4,6h16v10H4V6z"/>
+</vector>
\ No newline at end of file
diff --git a/res/drawable/ic_fingerprint_header.xml b/res/drawable/ic_fingerprint_header.xml
new file mode 100644
index 0000000..e7ac81a
--- /dev/null
+++ b/res/drawable/ic_fingerprint_header.xml
@@ -0,0 +1,38 @@
+<!--
+ Copyright (C) 2016 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License
+-->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="32dp"
+ android:height="32dp"
+ android:tint="?android:attr/colorPrimary"
+ android:viewportHeight="32.0"
+ android:viewportWidth="32.0">
+ <path
+ android:fillColor="#ffffff"
+ android:pathData="M23.7,5.9c-0.1,0.0 -0.2,0.0 -0.3,-0.1C21.0,4.5 18.6,3.9 16.0,3.9c-2.5,0.0 -4.6,0.6 -6.9,1.9C8.8,6.0 8.3,5.9 8.1,5.5C7.9,5.2 8.0,4.7 8.4,4.5c2.5,-1.4 4.9,-2.1 7.7,-2.1c2.8,0.0 5.4,0.7 8.0,2.1c0.4,0.2 0.5,0.6 0.3,1.0C24.2,5.7 24.0,5.9 23.7,5.9z" />
+ <path
+ android:fillColor="#ffffff"
+ android:pathData="M5.3,13.2c-0.1,0.0 -0.3,0.0 -0.4,-0.1c-0.3,-0.2 -0.4,-0.7 -0.2,-1.0c1.3,-1.9 2.9,-3.4 4.9,-4.5c4.1,-2.2 9.3,-2.2 13.4,0.0c1.9,1.1 3.6,2.5 4.9,4.4c0.2,0.3 0.1,0.8 -0.2,1.0c-0.3,0.2 -0.8,0.1 -1.0,-0.2c-1.2,-1.7 -2.6,-3.0 -4.3,-4.0c-3.7,-2.0 -8.3,-2.0 -12.0,0.0c-1.7,0.9 -3.2,2.3 -4.3,4.0C5.7,13.1 5.5,13.2 5.3,13.2z" />
+ <path
+ android:fillColor="#ffffff"
+ android:pathData="M13.3,29.6c-0.2,0.0 -0.4,-0.1 -0.5,-0.2c-1.1,-1.2 -1.7,-2.0 -2.6,-3.6c-0.9,-1.7 -1.4,-3.7 -1.4,-5.9c0.0,-4.1 3.3,-7.4 7.4,-7.4c4.1,0.0 7.4,3.3 7.4,7.4c0.0,0.4 -0.3,0.7 -0.7,0.7s-0.7,-0.3 -0.7,-0.7c0.0,-3.3 -2.7,-5.9 -5.9,-5.9c-3.3,0.0 -5.9,2.7 -5.9,5.9c0.0,2.0 0.4,3.8 1.2,5.2c0.8,1.6 1.4,2.2 2.4,3.3c0.3,0.3 0.3,0.8 0.0,1.0C13.7,29.5 13.5,29.6 13.3,29.6z" />
+ <path
+ android:fillColor="#ffffff"
+ android:pathData="M22.6,27.1c-1.6,0.0 -2.9,-0.4 -4.1,-1.2c-1.9,-1.4 -3.1,-3.6 -3.1,-6.0c0.0,-0.4 0.3,-0.7 0.7,-0.7s0.7,0.3 0.7,0.7c0.0,1.9 0.9,3.7 2.5,4.8c0.9,0.6 1.9,1.0 3.2,1.0c0.3,0.0 0.8,0.0 1.3,-0.1c0.4,-0.1 0.8,0.2 0.8,0.6c0.1,0.4 -0.2,0.8 -0.6,0.8C23.4,27.1 22.8,27.1 22.6,27.1z" />
+ <path
+ android:fillColor="#ffffff"
+ android:pathData="M20.0,29.9c-0.1,0.0 -0.1,0.0 -0.2,0.0c-2.1,-0.6 -3.4,-1.4 -4.8,-2.9c-1.8,-1.9 -2.8,-4.4 -2.8,-7.1c0.0,-2.2 1.8,-4.1 4.1,-4.1c2.2,0.0 4.1,1.8 4.1,4.1c0.0,1.4 1.2,2.6 2.6,2.6c1.4,0.0 2.6,-1.2 2.6,-2.6c0.0,-5.1 -4.2,-9.3 -9.3,-9.3c-3.6,0.0 -6.9,2.1 -8.4,5.4C7.3,17.1 7.0,18.4 7.0,19.8c0.0,1.1 0.1,2.7 0.9,4.9c0.1,0.4 -0.1,0.8 -0.4,0.9c-0.4,0.1 -0.8,-0.1 -0.9,-0.4c-0.6,-1.8 -0.9,-3.6 -0.9,-5.4c0.0,-1.6 0.3,-3.1 0.9,-4.4c1.7,-3.8 5.6,-6.3 9.8,-6.3c5.9,0.0 10.7,4.8 10.7,10.7c0.0,2.2 -1.8,4.1 -4.1,4.1s-4.0,-1.8 -4.0,-4.1c0.0,-1.4 -1.2,-2.6 -2.6,-2.6c-1.4,0.0 -2.6,1.2 -2.6,2.6c0.0,2.3 0.9,4.5 2.4,6.1c1.2,1.3 2.4,2.0 4.2,2.5c0.4,0.1 0.6,0.5 0.5,0.9C20.6,29.7 20.3,29.9 20.0,29.9z" />
+</vector>
diff --git a/res/drawable/ic_forum_24dp.xml b/res/drawable/ic_forum_24dp.xml
new file mode 100644
index 0000000..34c0869
--- /dev/null
+++ b/res/drawable/ic_forum_24dp.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2016 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<vector
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0"
+ android:tint="?android:attr/colorAccent">
+ <path
+ android:fillColor="#FFFFFFFF"
+ android:pathData="M21,6h-2v9H6v2c0,0.55 0.45,1 1,1h11l4,4V7c0,-0.55 -0.45,-1
+ -1,-1zm-4,6V3c0,-0.55 -0.45,-1 -1,-1H3c-0.55,0 -1,0.45 -1,1v14l4,-4h10c0.55,0
+ 1,-0.45 1,-1z"/>
+</vector>
\ No newline at end of file
diff --git a/res/drawable/ic_help_24dp.xml b/res/drawable/ic_help_24dp.xml
new file mode 100644
index 0000000..5fd1e79
--- /dev/null
+++ b/res/drawable/ic_help_24dp.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2016 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<vector
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0"
+ android:tint="?android:attr/colorAccent">
+ <path
+ android:fillColor="#FFFFFFFF"
+ android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48
+ 10,-10S17.52,2 12,2zm1,17h-2v-2h2v2zm2.07,-7.75l-0.9,0.92C13.45,12.9 13,13.5
+ 13,15h-2v-0.5c0,-1.1 0.45,-2.1 1.17,-2.83l1.24,-1.26c0.37,-0.36 0.59,-0.86 0.59,-1.41
+ 0,-1.1 -0.9,-2 -2,-2s-2,0.9 -2,2H8c0,-2.21 1.79,-4 4,-4s4,1.79 4,4c0,0.88
+ -0.36,1.68 -0.93,2.25z"/>
+</vector>
\ No newline at end of file
diff --git a/res/drawable/ic_keyboard_arrow_down_black_32.xml b/res/drawable/ic_keyboard_arrow_down_black_32.xml
new file mode 100644
index 0000000..12ce9c2
--- /dev/null
+++ b/res/drawable/ic_keyboard_arrow_down_black_32.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2016 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="32dp"
+ android:height="32dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M7.41,7.84L12,12.42l4.59,-4.58L18,9.25l-6,6 -6,-6z"/>
+</vector>
\ No newline at end of file
diff --git a/res/drawable/ic_keyboard_arrow_up_black_32.xml b/res/drawable/ic_keyboard_arrow_up_black_32.xml
new file mode 100644
index 0000000..d419800
--- /dev/null
+++ b/res/drawable/ic_keyboard_arrow_up_black_32.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2016 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="32dp"
+ android:height="32dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M7.41,15.41L12,10.83l4.59,4.58L18,14l-6,-6 -6,6z"/>
+</vector>
\ No newline at end of file
diff --git a/res/drawable/ic_lightbulb_outline_24.xml b/res/drawable/ic_lightbulb_outline_24.xml
new file mode 100644
index 0000000..89cf8fa
--- /dev/null
+++ b/res/drawable/ic_lightbulb_outline_24.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2016 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0"
+ android:tint="?android:attr/colorAccent">
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M9,21c0,0.55 0.45,1 1,1h4c0.55,0 1,-0.45 1,-1v-1L9,20v1zM12,2C8.14,2
+ 5,5.14 5,9c0,2.38 1.19,4.47 3,5.74L8,17c0,0.55 0.45,1 1,1h6c0.55,0 1,-0.45
+ 1,-1v-2.26c1.81,-1.27 3,-3.36 3,-5.74 0,-3.86 -3.14,-7
+ -7,-7zM14.85,13.1l-0.85,0.6L14,16h-4v-2.3l-0.85,-0.6C7.8,12.16 7,10.63 7,9c0,-2.76
+ 2.24,-5 5,-5s5,2.24 5,5c0,1.63 -0.8,3.16 -2.15,4.1z"/>
+</vector>
\ No newline at end of file
diff --git a/res/drawable/ic_lock.xml b/res/drawable/ic_lock.xml
new file mode 100644
index 0000000..975cbf5
--- /dev/null
+++ b/res/drawable/ic_lock.xml
@@ -0,0 +1,24 @@
+<!--
+ Copyright (C) 2016 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="32dp"
+ android:height="32dp"
+ android:viewportHeight="24.0"
+ android:viewportWidth="24.0">
+ <path
+ android:fillColor="?android:attr/colorPrimary"
+ android:pathData="M18,8h-1L17,6c0,-2.76 -2.24,-5 -5,-5S7,3.24 7,6v2L6,8c-1.1,0 -2,0.9 -2,2v10c0,1.1 0.9,2 2,2h12c1.1,0 2,-0.9 2,-2L20,10c0,-1.1 -0.9,-2 -2,-2zM12,17c-1.1,0 -2,-0.9 -2,-2s0.9,-2 2,-2 2,0.9 2,2 -0.9,2 -2,2zM15.1,8L8.9,8L8.9,6c0,-1.71 1.39,-3.1 3.1,-3.1 1.71,0 3.1,1.39 3.1,3.1v2z" />
+</vector>
diff --git a/res/values-sw360dp/aliases.xml b/res/drawable/selectable_card_grey.xml
similarity index 69%
copy from res/values-sw360dp/aliases.xml
copy to res/drawable/selectable_card_grey.xml
index a10585b..e4c73ba 100644
--- a/res/values-sw360dp/aliases.xml
+++ b/res/drawable/selectable_card_grey.xml
@@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2016 The Android Open Source Project
+<!--
+ Copyright (C) 2016 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -14,7 +15,8 @@
limitations under the License.
-->
-<resources>
- <item name="setup_choose_lock_pattern_template" type="layout">@layout/suw_template</item>
-</resources>
-
+<ripple
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:color="?android:attr/colorControlHighlight">
+ <item android:drawable="@color/card_background_grey"/>
+</ripple>
diff --git a/res/drawable/switchbar_background.xml b/res/drawable/switchbar_background.xml
index ac340be..3d729fd 100644
--- a/res/drawable/switchbar_background.xml
+++ b/res/drawable/switchbar_background.xml
@@ -16,6 +16,6 @@
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
android:color="?android:attr/colorControlHighlight">
- <item android:drawable="@color/switchbar_background_color" />
+ <item android:drawable="?attr/colorSecondary" />
</ripple>
diff --git a/res/layout-land/fingerprint_enroll_enrolling.xml b/res/layout-land/fingerprint_enroll_enrolling.xml
index c72c029..8154d0c 100644
--- a/res/layout-land/fingerprint_enroll_enrolling.xml
+++ b/res/layout-land/fingerprint_enroll_enrolling.xml
@@ -15,7 +15,7 @@
~ limitations under the License
-->
-<com.android.setupwizardlib.SetupWizardLayout
+<com.android.setupwizardlib.GlifLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/setup_wizard_layout"
android:layout_width="match_parent"
@@ -33,17 +33,17 @@
<!-- Both texts are kept as separate text views so it doesn't jump around in portrait.
See layouts/fingerprint_enroll_enrolling_base.xml. -->
- <FrameLayout
+ <RelativeLayout
android:layout_width="0dp"
android:layout_weight="1"
- android:layout_height="wrap_content"
- android:layout_gravity="center_vertical">
+ android:layout_height="wrap_content">
<TextView
style="@style/TextAppearance.FingerprintMessage"
android:id="@+id/start_message"
android:layout_width="match_parent"
android:layout_height="wrap_content"
+ android:layout_alignParentTop="true"
android:text="@string/security_settings_fingerprint_enroll_start_message"/>
<TextView
@@ -51,10 +51,21 @@
android:id="@+id/repeat_message"
android:layout_width="match_parent"
android:layout_height="wrap_content"
+ android:layout_alignParentTop="true"
android:text="@string/security_settings_fingerprint_enroll_repeat_message"
android:visibility="invisible"/>
- </FrameLayout>
+ <Button
+ android:id="@+id/skip_button"
+ style="@style/SetupWizardButton.Negative"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentBottom="true"
+ android:layout_marginBottom="8dp"
+ android:text="@string/skip_label"
+ android:visibility="gone" />
+
+ </RelativeLayout>
<FrameLayout
android:layout_width="0dp"
@@ -79,4 +90,4 @@
</LinearLayout>
-</com.android.setupwizardlib.SetupWizardLayout>
+</com.android.setupwizardlib.GlifLayout>
diff --git a/res/layout-land/fingerprint_enroll_find_sensor.xml b/res/layout-land/fingerprint_enroll_find_sensor.xml
index 81d1dac..60d93a6 100644
--- a/res/layout-land/fingerprint_enroll_find_sensor.xml
+++ b/res/layout-land/fingerprint_enroll_find_sensor.xml
@@ -15,7 +15,7 @@
~ limitations under the License
-->
-<com.android.setupwizardlib.SetupWizardLayout
+<com.android.setupwizardlib.GlifLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/setup_wizard_layout"
android:layout_width="match_parent"
@@ -70,4 +70,4 @@
</LinearLayout>
-</com.android.setupwizardlib.SetupWizardLayout>
+</com.android.setupwizardlib.GlifLayout>
diff --git a/res/layout-land/fingerprint_enroll_finish.xml b/res/layout-land/fingerprint_enroll_finish.xml
index e051f15..a84f46d 100644
--- a/res/layout-land/fingerprint_enroll_finish.xml
+++ b/res/layout-land/fingerprint_enroll_finish.xml
@@ -15,7 +15,7 @@
~ limitations under the License
-->
-<com.android.setupwizardlib.SetupWizardLayout
+<com.android.setupwizardlib.GlifLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/setup_wizard_layout"
android:layout_width="match_parent"
@@ -50,7 +50,7 @@
style="@style/TextAppearance.FingerprintMessage"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_marginTop="@dimen/suw_description_margin_top"
+ android:layout_marginTop="@dimen/suw_description_glif_margin_top"
android:text="@string/setup_fingerprint_enroll_finish_message_secondary"
android:textColor="?android:attr/textColorSecondary"
android:visibility="gone" />
@@ -100,4 +100,4 @@
</LinearLayout>
-</com.android.setupwizardlib.SetupWizardLayout>
+</com.android.setupwizardlib.GlifLayout>
diff --git a/res/layout-land/setup_choose_lock_pattern.xml b/res/layout-land/setup_choose_lock_pattern.xml
index 6ee8e81..86f1841 100644
--- a/res/layout-land/setup_choose_lock_pattern.xml
+++ b/res/layout-land/setup_choose_lock_pattern.xml
@@ -15,15 +15,13 @@
limitations under the License.
-->
-<com.android.setupwizardlib.SetupWizardLayout
+<com.android.setupwizardlib.GlifLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:settings="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
- settings:suwBackgroundTile="@drawable/setup_illustration_tile"
- settings:suwHeaderText="@string/wifi_setup_wizard_title"
- settings:suwIllustrationHorizontalTile="@drawable/setup_illustration_horizontal_tile"
- settings:suwIllustrationImage="@drawable/setup_illustration_lock_screen">
+ android:icon="@drawable/ic_lock"
+ settings:suwHeaderText="@string/lock_settings_picker_title">
<com.android.internal.widget.LinearLayoutWithDefaultTouchRecepient
android:id="@+id/topLayout"
@@ -49,40 +47,30 @@
android:gravity="start|bottom"
android:textSize="18sp" />
- <Button android:id="@+id/retryButton"
- style="@android:style/Widget.Material.Button.Borderless.Colored"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="start"
- android:layout_marginStart="-12dp"
- android:minWidth="0dp"
- android:text="@string/lockpattern_retry_button_text" />
-
<!-- footer can show a message, or confirm / restart buttons -->
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="0dip"
- android:layout_weight="1.0"
- android:visibility="gone">
+ android:layout_weight="1.0">
<!-- confirm / restart buttons -->
<LinearLayout android:id="@+id/buttonContainer"
- style="@style/SecurityPreferenceButtonContainer"
android:layout_centerHorizontal="true"
android:layout_alignParentBottom="true"
+ android:gravity="end"
android:orientation="horizontal">
<!-- left / top button: skip, or re-try -->
<Button android:id="@+id/footerLeftButton"
- style="@style/SecurityPreferenceButton"
- android:layout_width="match_parent"
+ style="@style/SetupWizardButton.Negative"
+ android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/lockpattern_restart_button_text" />
<!-- right / bottom button: confirm or ok -->
<Button android:id="@+id/footerRightButton"
- style="@style/SecurityPreferenceButton"
- android:layout_width="match_parent"
+ style="@style/SetupWizardButton.Positive"
+ android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/lockpattern_confirm_button_text" />
@@ -110,4 +98,4 @@
</com.android.internal.widget.LinearLayoutWithDefaultTouchRecepient>
-</com.android.setupwizardlib.SetupWizardLayout>
+</com.android.setupwizardlib.GlifLayout>
diff --git a/res/layout-land/setup_fingerprint_enroll_find_sensor.xml b/res/layout-land/setup_fingerprint_enroll_find_sensor.xml
index 3873e00..bb2c02d 100644
--- a/res/layout-land/setup_fingerprint_enroll_find_sensor.xml
+++ b/res/layout-land/setup_fingerprint_enroll_find_sensor.xml
@@ -15,7 +15,7 @@
~ limitations under the License
-->
-<com.android.setupwizardlib.SetupWizardLayout
+<com.android.setupwizardlib.GlifLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/setup_wizard_layout"
android:layout_width="match_parent"
@@ -70,4 +70,4 @@
</LinearLayout>
-</com.android.setupwizardlib.SetupWizardLayout>
+</com.android.setupwizardlib.GlifLayout>
diff --git a/res/layout/app_item.xml b/res/layout/app_item.xml
index ea0008e..15a9014 100644
--- a/res/layout/app_item.xml
+++ b/res/layout/app_item.xml
@@ -60,6 +60,14 @@
android:textColor="?android:attr/textColorSecondary"
android:duplicateParentState="true" />
+ <Switch
+ android:id="@android:id/switch_widget"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentRight="true"
+ android:background="@null"
+ android:visibility="gone"/>
+
<FrameLayout
android:id="@android:id/widget_frame"
android:layout_width="wrap_content"
diff --git a/res/values-sw360dp/aliases.xml b/res/layout/dashboard_container.xml
similarity index 74%
rename from res/values-sw360dp/aliases.xml
rename to res/layout/dashboard_container.xml
index a10585b..4cab75c 100644
--- a/res/values-sw360dp/aliases.xml
+++ b/res/layout/dashboard_container.xml
@@ -14,7 +14,8 @@
limitations under the License.
-->
-<resources>
- <item name="setup_choose_lock_pattern_template" type="layout">@layout/suw_template</item>
-</resources>
-
+<android.support.v4.view.ViewPager
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/pager"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"/>
diff --git a/res/values-sw360dp/aliases.xml b/res/layout/dashboard_container_header.xml
similarity index 66%
copy from res/values-sw360dp/aliases.xml
copy to res/layout/dashboard_container_header.xml
index a10585b..a12f249 100644
--- a/res/values-sw360dp/aliases.xml
+++ b/res/layout/dashboard_container_header.xml
@@ -14,7 +14,10 @@
limitations under the License.
-->
-<resources>
- <item name="setup_choose_lock_pattern_template" type="layout">@layout/suw_template</item>
-</resources>
-
+<com.android.settings.widget.SlidingTabLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ android:id="@+id/sliding_tabs"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:background="?android:attr/colorPrimary"/>
diff --git a/res/layout/dashboard_spacer.xml b/res/layout/dashboard_spacer.xml
index 19ef8ff..b26f1e5 100644
--- a/res/layout/dashboard_spacer.xml
+++ b/res/layout/dashboard_spacer.xml
@@ -14,6 +14,8 @@
limitations under the License.
-->
-<View xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="6dp" />
+<View
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="6dp"
+ android:background="@color/card_background_grey"/>
diff --git a/res/layout/fingerprint_enroll_enrolling_base.xml b/res/layout/fingerprint_enroll_enrolling_base.xml
index c93de4e..4b9c32e 100644
--- a/res/layout/fingerprint_enroll_enrolling_base.xml
+++ b/res/layout/fingerprint_enroll_enrolling_base.xml
@@ -15,7 +15,7 @@
~ limitations under the License
-->
-<com.android.setupwizardlib.SetupWizardLayout
+<com.android.setupwizardlib.GlifLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/setup_wizard_layout"
android:layout_width="match_parent"
@@ -35,7 +35,7 @@
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_marginTop="@dimen/suw_description_margin_top">
+ android:layout_marginTop="@dimen/suw_description_glif_margin_top">
<TextView
style="@style/TextAppearance.FingerprintMessage"
@@ -70,6 +70,15 @@
android:accessibilityLiveRegion="polite"
android:visibility="invisible"/>
+ <Button
+ android:id="@+id/skip_button"
+ style="@style/SetupWizardButton.Negative"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="end"
+ android:text="@string/skip_label"
+ android:visibility="gone" />
+
</LinearLayout>
-</com.android.setupwizardlib.SetupWizardLayout>
+</com.android.setupwizardlib.GlifLayout>
diff --git a/res/layout/fingerprint_enroll_find_sensor_base.xml b/res/layout/fingerprint_enroll_find_sensor_base.xml
index 3f69a0a..471c289 100644
--- a/res/layout/fingerprint_enroll_find_sensor_base.xml
+++ b/res/layout/fingerprint_enroll_find_sensor_base.xml
@@ -15,7 +15,7 @@
~ limitations under the License
-->
-<com.android.setupwizardlib.SetupWizardLayout
+<com.android.setupwizardlib.GlifLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/setup_wizard_layout"
android:layout_width="match_parent"
@@ -47,7 +47,7 @@
style="@style/TextAppearance.FingerprintMessage"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_marginTop="@dimen/suw_description_margin_top"
+ android:layout_marginTop="@dimen/suw_description_glif_margin_top"
android:text="@string/security_settings_fingerprint_enroll_find_sensor_message"/>
<View
@@ -63,9 +63,8 @@
android:layout_marginBottom="4dp"
android:layout_marginEnd="-12dp"
android:layout_gravity="end"
- android:gravity="end|center_vertical"
android:text="@string/fingerprint_enroll_button_next" />
</LinearLayout>
</FrameLayout>
-</com.android.setupwizardlib.SetupWizardLayout>
+</com.android.setupwizardlib.GlifLayout>
diff --git a/res/layout/fingerprint_enroll_finish_base.xml b/res/layout/fingerprint_enroll_finish_base.xml
index 15ee22a..21eb4e2 100644
--- a/res/layout/fingerprint_enroll_finish_base.xml
+++ b/res/layout/fingerprint_enroll_finish_base.xml
@@ -15,7 +15,7 @@
~ limitations under the License
-->
-<com.android.setupwizardlib.SetupWizardLayout
+<com.android.setupwizardlib.GlifLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/setup_wizard_layout"
android:layout_width="match_parent"
@@ -35,7 +35,7 @@
style="@style/TextAppearance.FingerprintMessage"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_marginTop="@dimen/suw_description_margin_top"
+ android:layout_marginTop="@dimen/suw_description_glif_margin_top"
android:text="@string/security_settings_fingerprint_enroll_finish_message"/>
<TextView
@@ -43,7 +43,7 @@
style="@style/TextAppearance.FingerprintMessage"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_marginTop="@dimen/suw_description_margin_top"
+ android:layout_marginTop="@dimen/suw_description_glif_margin_top"
android:text="@string/setup_fingerprint_enroll_finish_message_secondary"
android:textColor="?android:attr/textColorSecondary"
android:visibility="gone" />
@@ -91,11 +91,10 @@
android:id="@+id/next_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:gravity="end|center_vertical"
android:text="@string/security_settings_fingerprint_enroll_done" />
</LinearLayout>
</LinearLayout>
-</com.android.setupwizardlib.SetupWizardLayout>
+</com.android.setupwizardlib.GlifLayout>
diff --git a/res/layout/fingerprint_enroll_introduction.xml b/res/layout/fingerprint_enroll_introduction.xml
index f43bdb6..6d1c699 100644
--- a/res/layout/fingerprint_enroll_introduction.xml
+++ b/res/layout/fingerprint_enroll_introduction.xml
@@ -15,10 +15,10 @@
limitations under the License
-->
-<com.android.setupwizardlib.SetupWizardRecyclerLayout
+<com.android.setupwizardlib.GlifRecyclerLayout
xmlns:android="http://schemas.android.com/apk/res/android"
+ style="?attr/fingerprint_layout_theme"
android:id="@+id/setup_wizard_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:entries="@xml/fingerprint_enroll_introduction_items"
- style="?attr/fingerprint_layout_theme" />
+ android:entries="@xml/fingerprint_enroll_introduction_items" />
diff --git a/res/layout/preference_list_fragment.xml b/res/layout/preference_list_fragment.xml
index 9f1e076..6e540c4 100644
--- a/res/layout/preference_list_fragment.xml
+++ b/res/layout/preference_list_fragment.xml
@@ -83,6 +83,7 @@
android:visibility="gone">
<Button android:id="@+id/back_button"
+ style="?android:attr/buttonBarButtonStyle"
android:layout_width="150dip"
android:layout_height="wrap_content"
android:layout_margin="5dip"
@@ -97,7 +98,8 @@
android:layout_alignParentEnd="true">
<Button android:id="@+id/skip_button"
- android:layout_width="150dip"
+ style="?android:attr/buttonBarButtonStyle"
+ android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="5dip"
android:text="@*android:string/skip_button_label"
@@ -105,7 +107,8 @@
/>
<Button android:id="@+id/next_button"
- android:layout_width="150dip"
+ style="?android:attr/buttonBarButtonStyle"
+ android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="5dip"
android:text="@*android:string/next_button_label"
diff --git a/res/layout/setup_choose_lock_generic_fingerprint_header.xml b/res/layout/setup_choose_lock_generic_fingerprint_header.xml
index d16aec4..b19bec1 100644
--- a/res/layout/setup_choose_lock_generic_fingerprint_header.xml
+++ b/res/layout/setup_choose_lock_generic_fingerprint_header.xml
@@ -20,10 +20,10 @@
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:minHeight="56dp"
- android:paddingBottom="@dimen/suw_description_margin_bottom_lists"
+ android:paddingBottom="@dimen/suw_description_glif_margin_bottom_lists"
android:paddingStart="?android:attr/listPreferredItemPaddingStart"
android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
- android:paddingTop="@dimen/suw_description_margin_top"
+ android:paddingTop="@dimen/suw_description_glif_margin_top"
android:text="@string/setup_lock_settings_picker_fingerprint_message"
android:lineSpacingExtra="@dimen/suw_description_line_spacing_extra"
android:textAppearance="?android:attr/textAppearanceListItem" />
diff --git a/res/layout/setup_choose_lock_generic_header.xml b/res/layout/setup_choose_lock_generic_header.xml
index 78cd618..9a3547d 100644
--- a/res/layout/setup_choose_lock_generic_header.xml
+++ b/res/layout/setup_choose_lock_generic_header.xml
@@ -20,10 +20,10 @@
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:minHeight="56dp"
- android:paddingBottom="@dimen/suw_description_margin_bottom_lists"
+ android:paddingBottom="@dimen/suw_description_glif_margin_bottom_lists"
android:paddingStart="?android:attr/listPreferredItemPaddingStart"
android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
- android:paddingTop="@dimen/suw_description_margin_top"
+ android:paddingTop="@dimen/suw_description_glif_margin_top"
android:text="@string/setup_lock_settings_picker_message"
android:lineSpacingExtra="@dimen/suw_description_line_spacing_extra"
android:textAppearance="?android:attr/textAppearanceListItem" />
diff --git a/res/layout/setup_choose_lock_password.xml b/res/layout/setup_choose_lock_password.xml
index 164233c..a91a671 100644
--- a/res/layout/setup_choose_lock_password.xml
+++ b/res/layout/setup_choose_lock_password.xml
@@ -15,15 +15,13 @@
limitations under the License.
-->
-<com.android.setupwizardlib.SetupWizardLayout
+<com.android.setupwizardlib.GlifLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:settings="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
- settings:suwBackgroundTile="@drawable/setup_illustration_tile"
- settings:suwHeaderText="@string/wifi_setup_wizard_title"
- settings:suwIllustrationHorizontalTile="@drawable/setup_illustration_horizontal_tile"
- settings:suwIllustrationImage="@drawable/setup_illustration_lock_screen">
+ android:icon="@drawable/ic_lock"
+ settings:suwHeaderText="@string/lockpassword_choose_your_password_header">
<LinearLayout
style="@style/SuwContentFrame"
@@ -45,45 +43,42 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
- android:layout_marginStart="30dip"
- android:layout_marginEnd="30dip"
android:gravity="center"
android:inputType="textPassword"
android:imeOptions="actionNext|flagNoExtractUi"
android:textSize="24sp"
style="@style/TextAppearance.PasswordEntry"/>
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:clipChildren="false"
+ android:clipToPadding="false"
+ android:gravity="end"
+ android:orientation="horizontal">
+
+ <!-- left : cancel -->
+ <Button android:id="@+id/cancel_button"
+ style="@style/SetupWizardButton.Negative"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/lockpassword_cancel_label" />
+
+ <!-- right : continue -->
+ <Button android:id="@+id/next_button"
+ style="@style/SetupWizardButton.Positive"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/lockpassword_continue_label" />
+
+ </LinearLayout>
+
<!-- Spacer between password entry and keyboard -->
<View
android:layout_width="match_parent"
android:layout_height="0dip"
android:layout_weight="1"/>
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="horizontal"
- android:visibility="gone"
- style="@style/SecurityPreferenceButtonContainer">
-
- <!-- left : cancel -->
- <Button android:id="@+id/cancel_button"
- android:layout_width="0dip"
- android:layout_height="wrap_content"
- android:layout_weight="1"
- android:text="@string/lockpassword_cancel_label"
- style="@style/SecurityPreferenceButton"/>
-
- <!-- right : continue -->
- <Button android:id="@+id/next_button"
- android:layout_width="0dip"
- android:layout_height="wrap_content"
- android:layout_weight="1"
- android:text="@string/lockpassword_continue_label"
- style="@style/SecurityPreferenceButton"/>
-
- </LinearLayout>
-
<!-- Alphanumeric keyboard -->
<com.android.internal.widget.PasswordEntryKeyboardView android:id="@+id/keyboard"
android:layout_width="match_parent"
@@ -94,4 +89,4 @@
</LinearLayout>
-</com.android.setupwizardlib.SetupWizardLayout>
+</com.android.setupwizardlib.GlifLayout>
diff --git a/res/layout/setup_choose_lock_pattern_common.xml b/res/layout/setup_choose_lock_pattern_common.xml
index 0a38637..20e46f3 100644
--- a/res/layout/setup_choose_lock_pattern_common.xml
+++ b/res/layout/setup_choose_lock_pattern_common.xml
@@ -16,16 +16,13 @@
-->
<!-- Used in phone portrait and tablet, as referenced in alias.xml. -->
-<com.android.setupwizardlib.SetupWizardLayout
+<com.android.setupwizardlib.GlifLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:settings="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:layout="@layout/setup_choose_lock_pattern_template"
- settings:suwBackgroundTile="@drawable/setup_illustration_tile"
- settings:suwHeaderText="@string/wifi_setup_wizard_title"
- settings:suwIllustrationHorizontalTile="@drawable/setup_illustration_horizontal_tile"
- settings:suwIllustrationImage="@drawable/setup_illustration_lock_screen">
+ android:icon="@drawable/ic_lock"
+ settings:suwHeaderText="@string/wifi_setup_wizard_title">
<com.android.internal.widget.LinearLayoutWithDefaultTouchRecepient
android:id="@+id/topLayout"
@@ -50,18 +47,34 @@
android:gravity="center"
android:textSize="18sp" />
- <Button android:id="@+id/retryButton"
- style="@android:style/Widget.Material.Button.Borderless.Colored"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center_horizontal"
- android:text="@string/lockpattern_retry_button_text"/>
-
<com.android.internal.widget.LockPatternView android:id="@+id/lockPattern"
android:layout_width="match_parent"
android:layout_height="0dip"
android:layout_weight="4" />
+ <!-- Buttons are hidden during setup, and use the buttons in setup navigation bar instead -->
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:gravity="end"
+ android:orientation="horizontal">
+
+ <!-- left : cancel, or re-try -->
+ <Button android:id="@+id/footerLeftButton"
+ style="@style/SetupWizardButton.Negative"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/lockpattern_tutorial_cancel_label" />
+
+ <!-- right : confirm or ok -->
+ <Button android:id="@+id/footerRightButton"
+ style="@style/SetupWizardButton.Positive"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/lockpattern_tutorial_continue_label" />
+
+ </LinearLayout>
+
</LinearLayout>
<TextView android:id="@+id/footerText"
@@ -72,32 +85,6 @@
android:textSize="14sp"
android:visibility="gone"/>
- <!-- Buttons are hidden during setup, and use the buttons in setup navigation bar instead -->
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="horizontal"
- android:visibility="gone"
- style="@style/SecurityPreferenceButtonContainer">
-
- <!-- left : cancel, or re-try -->
- <Button android:id="@+id/footerLeftButton"
- android:layout_width="0dip"
- android:layout_height="wrap_content"
- android:layout_weight="1"
- android:text="@string/lockpattern_tutorial_cancel_label"
- style="@style/SecurityPreferenceButton"/>
-
- <!-- right : confirm or ok -->
- <Button android:id="@+id/footerRightButton"
- android:layout_width="0dip"
- android:layout_height="wrap_content"
- android:layout_weight="1"
- android:text="@string/lockpattern_tutorial_continue_label"
- style="@style/SecurityPreferenceButton"/>
-
- </LinearLayout>
-
</com.android.internal.widget.LinearLayoutWithDefaultTouchRecepient>
-</com.android.setupwizardlib.SetupWizardLayout>
+</com.android.setupwizardlib.GlifLayout>
diff --git a/res/layout/setup_encryption_interstitial_header.xml b/res/layout/setup_encryption_interstitial_header.xml
index a6e7c30..9601fa8 100644
--- a/res/layout/setup_encryption_interstitial_header.xml
+++ b/res/layout/setup_encryption_interstitial_header.xml
@@ -20,9 +20,9 @@
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:minHeight="56dp"
- android:paddingBottom="@dimen/suw_description_margin_bottom_lists"
+ android:paddingBottom="@dimen/suw_description_glif_margin_bottom_lists"
android:paddingStart="?android:attr/listPreferredItemPaddingStart"
android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
- android:paddingTop="@dimen/suw_description_margin_top"
+ android:paddingTop="@dimen/suw_description_glif_margin_top"
android:lineSpacingExtra="@dimen/suw_description_line_spacing_extra"
android:textAppearance="?android:attr/textAppearanceListItem" />
diff --git a/res/layout/setup_fingerprint_enroll_find_sensor_base.xml b/res/layout/setup_fingerprint_enroll_find_sensor_base.xml
index 184d6b9..45af088 100644
--- a/res/layout/setup_fingerprint_enroll_find_sensor_base.xml
+++ b/res/layout/setup_fingerprint_enroll_find_sensor_base.xml
@@ -15,7 +15,7 @@
limitations under the License
-->
-<com.android.setupwizardlib.SetupWizardLayout
+<com.android.setupwizardlib.GlifLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/setup_wizard_layout"
android:layout_width="match_parent"
@@ -47,7 +47,7 @@
style="@style/TextAppearance.FingerprintMessage"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_marginTop="@dimen/suw_description_margin_top"
+ android:layout_marginTop="@dimen/suw_description_glif_margin_top"
android:text="@string/security_settings_fingerprint_enroll_find_sensor_message"/>
<View
@@ -68,4 +68,4 @@
</LinearLayout>
</FrameLayout>
-</com.android.setupwizardlib.SetupWizardLayout>
+</com.android.setupwizardlib.GlifLayout>
diff --git a/res/layout/setup_preference.xml b/res/layout/setup_preference.xml
index f5496f4..298bc9a 100644
--- a/res/layout/setup_preference.xml
+++ b/res/layout/setup_preference.xml
@@ -15,11 +15,8 @@
limitations under the License.
-->
-<com.android.setupwizardlib.SetupWizardPreferenceLayout
+<com.android.setupwizardlib.GlifPreferenceLayout
xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:settings="http://schemas.android.com/apk/res-auto"
android:id="@android:id/list_container"
android:layout_width="match_parent"
- android:layout_height="match_parent"
- settings:suwBackgroundTile="@drawable/setup_illustration_tile"
- settings:suwIllustrationHorizontalTile="@drawable/setup_illustration_horizontal_tile" />
+ android:layout_height="match_parent" />
diff --git a/res/layout/setup_redaction_interstitial.xml b/res/layout/setup_redaction_interstitial.xml
index 1b96d20..6a85de1 100644
--- a/res/layout/setup_redaction_interstitial.xml
+++ b/res/layout/setup_redaction_interstitial.xml
@@ -15,31 +15,25 @@
limitations under the License
-->
-<com.android.setupwizardlib.SetupWizardLayout
+<com.android.setupwizardlib.GlifLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:settings="http://schemas.android.com/apk/res-auto"
android:id="@+id/setup_wizard_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
- settings:suwBackgroundTile="@drawable/setup_illustration_tile"
- settings:suwHeaderText="@string/lock_screen_notifications_interstitial_title"
- settings:suwIllustrationHorizontalTile="@drawable/setup_illustration_horizontal_tile"
- settings:suwIllustrationImage="@drawable/setup_illustration_lock_screen">
+ android:icon="@drawable/ic_lock"
+ settings:suwHeaderText="@string/lock_screen_notifications_interstitial_title">
<LinearLayout
style="@style/SuwContentFrame"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:orientation="vertical"
- android:paddingStart="?attr/side_margin"
- android:paddingEnd="?attr/side_margin">
+ android:orientation="vertical">
<TextView
- style="@style/SuwDescription"
+ style="@style/SuwDescription.Glif"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_marginStart="?android:attr/listPreferredItemPaddingStart"
- android:layout_marginEnd="?android:attr/listPreferredItemPaddingEnd"
android:text="@string/lock_screen_notifications_interstitial_message" />
<RadioGroup
@@ -47,8 +41,6 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/redaction_vertical_margins"
- android:layout_marginStart="?android:attr/listPreferredItemPaddingStart"
- android:layout_marginEnd="?android:attr/listPreferredItemPaddingEnd"
android:checkedButton="@+id/redact_sensitive">
<com.android.settings.RestrictedRadioButton
@@ -81,8 +73,17 @@
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/redaction_vertical_margins"
android:text="@string/lockscreen_remote_input" />
+
</RadioGroup>
+ <Button
+ android:id="@+id/redaction_next_button"
+ style="@style/SetupWizardButton.Positive"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="end"
+ android:text="@string/next_label" />
+
</LinearLayout>
-</com.android.setupwizardlib.SetupWizardLayout>
+</com.android.setupwizardlib.GlifLayout>
diff --git a/res/values-sw360dp/aliases.xml b/res/layout/sliding_tab_indicator_view.xml
similarity index 69%
copy from res/values-sw360dp/aliases.xml
copy to res/layout/sliding_tab_indicator_view.xml
index a10585b..9b2942f 100644
--- a/res/values-sw360dp/aliases.xml
+++ b/res/layout/sliding_tab_indicator_view.xml
@@ -14,7 +14,9 @@
limitations under the License.
-->
-<resources>
- <item name="setup_choose_lock_pattern_template" type="layout">@layout/suw_template</item>
-</resources>
-
+<View
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/sliding_tab_selected_indicator"
+ android:layout_width="wrap_content"
+ android:layout_height="@dimen/pager_tabs_selected_indicator_height"
+ android:background="?android:attr/colorAccent"/>
diff --git a/res/layout/sliding_tab_title_view.xml b/res/layout/sliding_tab_title_view.xml
new file mode 100644
index 0000000..1a4328f
--- /dev/null
+++ b/res/layout/sliding_tab_title_view.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2016 Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<TextView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="0dp"
+ android:layout_weight="1"
+ android:layout_height="wrap_content"
+ android:background="?android:attr/selectableItemBackground"
+ android:ellipsize="end"
+ android:gravity="center"
+ android:maxLines="1"
+ android:padding="@dimen/pager_tabs_title_padding"
+ android:textColor="@color/sliding_tab_title_text_color"
+ android:textAllCaps="true"/>
diff --git a/res/layout/suggestion_header.xml b/res/layout/suggestion_header.xml
index c48553e..b30df60 100644
--- a/res/layout/suggestion_header.xml
+++ b/res/layout/suggestion_header.xml
@@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2016 The Android Open Source Project
+<!--
+ Copyright (C) 2016 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -20,27 +21,31 @@
android:layout_height="@dimen/dashboard_category_height"
android:clickable="true"
android:focusable="true"
- android:background="@drawable/selectable_card"
- android:elevation="@dimen/dashboard_category_elevation"
+ android:background="@drawable/selectable_card_grey"
android:gravity="center_vertical" >
-
- <TextView android:id="@android:id/title"
+ <ImageView
+ android:id="@android:id/icon"
+ android:layout_width="@dimen/dashboard_tile_image_size"
+ android:layout_height="@dimen/dashboard_tile_image_size"
+ android:layout_marginStart="@dimen/dashboard_tile_image_margin_start"
+ android:layout_marginEnd="@dimen/dashboard_tile_image_margin_end"
+ android:src="@drawable/ic_expand_more"/>
+ <TextView
+ android:id="@android:id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_weight="1"
- android:paddingStart="16dp"
android:singleLine="true"
android:textAppearance="@style/TextAppearance.TileTitle"
android:textColor="?android:attr/colorAccent"
- android:alpha=".87"
android:ellipsize="marquee"
- android:fadingEdge="horizontal" />
-
- <ImageView android:id="@android:id/icon"
- android:layout_width="@dimen/dashboard_tile_image_size"
- android:layout_height="@dimen/dashboard_tile_image_size"
- android:layout_marginStart="@dimen/suggestion_arrow_margin"
- android:layout_marginEnd="@dimen/suggestion_arrow_margin"
- android:src="@drawable/ic_expand_more" />
-
+ android:fadingEdge="horizontal"/>
+ <TextView
+ android:id="@android:id/summary"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:gravity="end"
+ android:paddingEnd="16dp"
+ android:textAppearance="@style/TextAppearance.TileTitle"
+ android:textColor="?android:attr/colorAccent"/>
</LinearLayout>
diff --git a/res/layout/suggestion_tile.xml b/res/layout/suggestion_tile.xml
index 10c9558..9ffd455 100644
--- a/res/layout/suggestion_tile.xml
+++ b/res/layout/suggestion_tile.xml
@@ -18,70 +18,58 @@
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
+ android:background="@drawable/selectable_card_grey"
android:clickable="true"
android:focusable="true"
- android:background="@drawable/selectable_card"
- android:elevation="@dimen/dashboard_category_elevation"
- android:orientation="vertical" >
+ android:gravity="center_vertical"
+ android:minHeight="@dimen/dashboard_tile_minimum_height">
- <View
- android:layout_width="match_parent"
- android:layout_height="1dp"
- android:background="?android:attr/listDivider" />
+ <ImageView
+ android:id="@android:id/icon"
+ android:layout_width="@dimen/dashboard_tile_image_size"
+ android:layout_height="@dimen/dashboard_tile_image_size"
+ android:layout_marginStart="@dimen/dashboard_tile_image_margin_start"
+ android:layout_marginEnd="@dimen/dashboard_tile_image_margin_end"
+ android:scaleType="centerInside"/>
- <LinearLayout
- android:layout_width="match_parent"
+ <RelativeLayout
+ android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:gravity="center_vertical"
- android:minHeight="@dimen/dashboard_tile_minimum_height">
+ android:layout_weight="1">
+
+ <TextView android:id="@android:id/title"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:singleLine="true"
+ android:textAppearance="@style/TextAppearance.TileTitle"
+ android:ellipsize="marquee"
+ android:fadingEdge="horizontal"/>
+
+ <TextView android:id="@android:id/summary"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_below="@android:id/title"
+ android:layout_alignStart="@android:id/title"
+ android:textAppearance="@style/TextAppearance.Small"
+ android:textColor="?android:attr/textColorSecondary"/>
+
+ </RelativeLayout>
+
+ <FrameLayout
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent">
<ImageView
- android:id="@android:id/icon"
- android:layout_width="@dimen/dashboard_tile_image_size"
- android:layout_height="@dimen/dashboard_tile_image_size"
- android:scaleType="centerInside"
- android:layout_marginStart="@dimen/dashboard_tile_image_margin_start"
- android:layout_marginEnd="@dimen/dashboard_tile_image_margin_end" />
-
- <RelativeLayout
+ android:id="@+id/overflow"
+ style="?android:attr/actionOverflowButtonStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_weight="1">
+ android:paddingStart="16dp"
+ android:paddingTop="16dp"
+ android:paddingEnd="18dp"
+ android:paddingBottom="16dp"
+ android:gravity="top"/>
- <TextView android:id="@android:id/title"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:singleLine="true"
- android:textAppearance="@style/TextAppearance.TileTitle"
- android:ellipsize="marquee"
- android:fadingEdge="horizontal" />
+ </FrameLayout>
- <TextView android:id="@android:id/summary"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_below="@android:id/title"
- android:layout_alignStart="@android:id/title"
- android:textAppearance="@style/TextAppearance.Small"
- android:textColor="?android:attr/textColorSecondary" />
-
- </RelativeLayout>
-
- <FrameLayout
- android:layout_width="wrap_content"
- android:layout_height="match_parent">
-
- <ImageView android:id="@+id/overflow"
- android:layout_width="44dp"
- android:layout_height="44dp"
- android:paddingStart="16dp"
- android:paddingBottom="16dp"
- android:paddingTop="12dp"
- android:paddingEnd="12dp"
- android:gravity="top"
- style="?android:attr/actionOverflowButtonStyle" />
-
- </FrameLayout>
-
- </LinearLayout>
-
-</LinearLayout>
+</LinearLayout>
\ No newline at end of file
diff --git a/res/layout/support_disclaimer_content.xml b/res/layout/support_disclaimer_content.xml
new file mode 100644
index 0000000..c7a5689
--- /dev/null
+++ b/res/layout/support_disclaimer_content.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ android:padding="24dp">
+
+ <TextView
+ android:id="@+id/support_disclaimer_text"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/support_disclaimer_content"/>
+
+</LinearLayout>
diff --git a/res/layout/support_escalation_options.xml b/res/layout/support_escalation_options.xml
new file mode 100644
index 0000000..6b88908
--- /dev/null
+++ b/res/layout/support_escalation_options.xml
@@ -0,0 +1,67 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2016 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:background="@color/card_background_grey"
+ android:gravity="center_horizontal"
+ android:paddingBottom="40dp">
+ <LinearLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="8dp"
+ android:layout_marginEnd="8dp"
+ android:gravity="center_horizontal"
+ android:orientation="vertical">
+ <Button
+ android:id="@android:id/text1"
+ style="@style/SupportPrimaryButton"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_margin="8dp"/>
+ <TextView
+ android:id="@+id/summary1"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="14dp"
+ android:textAppearance="@style/TextAppearance.Small"
+ android:textColor="?android:attr/textColorSecondary"/>
+ </LinearLayout>
+ <LinearLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="8dp"
+ android:layout_marginEnd="8dp"
+ android:gravity="center_horizontal"
+ android:orientation="vertical">
+ <Button
+ android:id="@android:id/text2"
+ style="@style/SupportPrimaryButton"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_margin="8dp"/>
+ <TextView
+ android:id="@+id/summary2"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="14dp"
+ android:textAppearance="@style/TextAppearance.Small"
+ android:textColor="?android:attr/textColorSecondary"/>
+ </LinearLayout>
+</LinearLayout>
diff --git a/res/values-sw360dp/aliases.xml b/res/layout/support_fragment.xml
similarity index 68%
copy from res/values-sw360dp/aliases.xml
copy to res/layout/support_fragment.xml
index a10585b..481a548 100644
--- a/res/values-sw360dp/aliases.xml
+++ b/res/layout/support_fragment.xml
@@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2016 The Android Open Source Project
+<!--
+ Copyright (C) 2016 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -14,7 +15,8 @@
limitations under the License.
-->
-<resources>
- <item name="setup_choose_lock_pattern_template" type="layout">@layout/suw_template</item>
-</resources>
-
+<android.support.v7.widget.RecyclerView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/support_items"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"/>
\ No newline at end of file
diff --git a/res/layout/support_item_subtitle.xml b/res/layout/support_item_subtitle.xml
new file mode 100644
index 0000000..d4a528a
--- /dev/null
+++ b/res/layout/support_item_subtitle.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2016 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<TextView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@android:id/text1"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingBottom="16dp"
+ android:paddingEnd="8dp"
+ android:paddingStart="8dp"
+ android:paddingTop="8dp"
+ android:textAppearance="@style/TextAppearance.CategoryTitle"/>
\ No newline at end of file
diff --git a/res/layout/support_item_title.xml b/res/layout/support_item_title.xml
new file mode 100644
index 0000000..0110da0
--- /dev/null
+++ b/res/layout/support_item_title.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2016 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:background="@color/card_background_grey"
+ android:paddingTop="40dp"
+ android:paddingBottom="42dp"
+ android:paddingStart="56dp"
+ android:paddingEnd="56dp"
+ android:orientation="vertical">
+ <TextView
+ android:id="@android:id/text1"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:gravity="center_horizontal"
+ android:textAppearance="@style/TextAppearance.SupportTitle"/>
+ <TextView
+ android:id="@android:id/text2"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:gravity="center_horizontal"
+ android:paddingTop="8dp"
+ android:textAppearance="@style/TextAppearance.Small"
+ android:textColor="?android:attr/textColorSecondary"/>
+</LinearLayout>
\ No newline at end of file
diff --git a/res/layout/support_sign_in_button.xml b/res/layout/support_sign_in_button.xml
new file mode 100644
index 0000000..fb789e8
--- /dev/null
+++ b/res/layout/support_sign_in_button.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2016 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:background="@color/card_background_grey"
+ android:gravity="center_horizontal"
+ android:orientation="vertical">
+ <Button
+ android:id="@android:id/text1"
+ style="@style/SupportPrimaryButton"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_margin="8dp"/>
+ <Button
+ android:id="@android:id/text2"
+ style="@style/SupportSecondaryButton"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginBottom="16dp"
+ android:minHeight="48dp"/>
+</LinearLayout>
\ No newline at end of file
diff --git a/res/layout/support_tile.xml b/res/layout/support_tile.xml
new file mode 100644
index 0000000..e07e173
--- /dev/null
+++ b/res/layout/support_tile.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2016 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:background="?android:attr/selectableItemBackground"
+ android:gravity="center_vertical"
+ android:minHeight="@dimen/dashboard_tile_minimum_height"
+ android:orientation="horizontal">
+ <ImageView
+ android:id="@android:id/icon"
+ android:layout_width="@dimen/dashboard_tile_image_size"
+ android:layout_height="@dimen/dashboard_tile_image_size"
+ android:scaleType="centerInside"
+ android:layout_marginStart="@dimen/dashboard_tile_image_margin_start"
+ android:layout_marginEnd="@dimen/dashboard_tile_image_margin_end"/>
+ <TextView
+ android:id="@android:id/text1"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:singleLine="true"
+ android:textAppearance="@style/TextAppearance.TileTitle"
+ android:ellipsize="end"
+ android:fadingEdge="horizontal"/>
+</LinearLayout>
\ No newline at end of file
diff --git a/res/layout/suw_item_link_description.xml b/res/layout/suw_item_link_description.xml
deleted file mode 100644
index 5396de1e..0000000
--- a/res/layout/suw_item_link_description.xml
+++ /dev/null
@@ -1,71 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- Copyright (C) 2016 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:tools="http://schemas.android.com/tools"
- style="@style/SuwItemContainer"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="horizontal"
- android:paddingTop="@dimen/suw_description_margin_top"
- android:paddingBottom="@dimen/suw_description_margin_bottom_lists">
-
- <FrameLayout
- android:id="@+id/suw_items_icon_container"
- android:layout_width="@dimen/suw_items_icon_container_width"
- android:layout_height="wrap_content"
- android:layout_gravity="center_vertical"
- android:gravity="start">
-
- <ImageView
- android:id="@+id/suw_items_icon"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- tools:ignore="ContentDescription" />
-
- </FrameLayout>
-
- <LinearLayout
- android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:layout_weight="1"
- android:orientation="vertical">
-
- <com.android.settings.widget.LinkTextView
- android:id="@+id/suw_items_title"
- style="@style/SuwItemTitle"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:gravity="start"
- android:lineSpacingExtra="@dimen/suw_description_line_spacing_extra"
- android:textAlignment="viewStart"
- android:textAppearance="@style/TextAppearance.SuwDescription"
- tools:ignore="UnusedAttribute" />
-
- <com.android.settings.widget.LinkTextView
- android:id="@+id/suw_items_summary"
- style="@style/SuwItemSummary"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:gravity="start"
- android:textAlignment="viewStart"
- android:visibility="gone"
- tools:ignore="UnusedAttribute" />
-
- </LinearLayout>
-
-</LinearLayout>
diff --git a/res/layout/switch_bar.xml b/res/layout/switch_bar.xml
index a31bd3e..8b69a1d 100644
--- a/res/layout/switch_bar.xml
+++ b/res/layout/switch_bar.xml
@@ -44,7 +44,7 @@
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:background="@null"
- android:theme="@style/ThemeOverlay.SwitchBar" />
+ android:theme="@style/ThemeOverlay.SwitchBar.Settings" />
</merge>
diff --git a/res/menu/storage_volume.xml b/res/menu/storage_volume.xml
index efa468c..bf9f985 100644
--- a/res/menu/storage_volume.xml
+++ b/res/menu/storage_volume.xml
@@ -30,4 +30,7 @@
<item
android:id="@+id/storage_migrate"
android:title="@string/storage_menu_migrate" />
+ <item
+ android:id="@+id/storage_free"
+ android:title="@string/storage_menu_free" />
</menu>
diff --git a/res/values/aliases.xml b/res/values/aliases.xml
index a783c79..0901157 100644
--- a/res/values/aliases.xml
+++ b/res/values/aliases.xml
@@ -23,6 +23,5 @@
<item name="fingerprint_enroll_finish" type="layout">@layout/fingerprint_enroll_finish_base</item>
<item name="setup_choose_lock_pattern" type="layout">@layout/setup_choose_lock_pattern_common</item>
<item name="setup_fingerprint_enroll_find_sensor" type="layout">@layout/setup_fingerprint_enroll_find_sensor_base</item>
- <item name="setup_choose_lock_pattern_template" type="layout">@layout/suw_template_short</item>
</resources>
diff --git a/res/values/arrays.xml b/res/values/arrays.xml
index 8adf331..6827e5b 100644
--- a/res/values/arrays.xml
+++ b/res/values/arrays.xml
@@ -1031,4 +1031,18 @@
<item>Red</item>
</string-array>
+ <!-- Automatic storage management settings. The amount of days for the automatic storage manager
+ to retain. These are shown in a list dialog. [CHAR LIMIT=70] -->
+ <string-array name="automatic_storage_management_days">
+ <item>Over 30 days old</item>
+ <item>Over 60 days old</item>
+ <item>Over 90 days old</item>
+ </string-array>
+
+ <string-array name="automatic_storage_management_days_values" translatable="false">
+ <item>30</item>
+ <item>60</item>
+ <item>90</item>
+ </string-array>
+
</resources>
diff --git a/res/values/attrs.xml b/res/values/attrs.xml
index 0a072ae..ca3d247 100644
--- a/res/values/attrs.xml
+++ b/res/values/attrs.xml
@@ -121,6 +121,8 @@
<attr name="switchBarMarginEnd" format="dimension" />
<attr name="switchBarBackgroundColor" format="color" />
+ <attr name="colorSecondary" format="color" />
+
<attr name="preferenceBackgroundColor" format="color" />
<!-- Confirm device credentials screen -->
diff --git a/res/values/bools.xml b/res/values/bools.xml
index 5ee0f7c..6f04457 100644
--- a/res/values/bools.xml
+++ b/res/values/bools.xml
@@ -40,4 +40,7 @@
<!-- Whether none security option is hide or not (country specific). -->
<bool name="config_hide_none_security_option">false</bool>
+
+ <!--Whether the storage manager exists. -->
+ <bool name="config_has_storage_manager">false</bool>
</resources>
diff --git a/res/values/colors.xml b/res/values/colors.xml
index a9756ad..3b66469 100644
--- a/res/values/colors.xml
+++ b/res/values/colors.xml
@@ -74,14 +74,10 @@
<color name="card_background">#ffffffff</color>
- <color name="switchbar_background_color">#ff37474f</color>
- <color name="switch_accent_color">#ff7fcac3</color>
-
<color name="wifi_divider">#ffe0e0e0</color>
<color name="sim_noitification">@*android:color/material_deep_teal_500</color>
<color name="warning">#ff5621</color>
- <color name="confirm_device_credential_dark_background">#263238</color>
<color name="confirm_device_credential_transparent_black">#60000000</color>
<color name="fab_ripple">#1fffffff</color><!-- 12% white -->
<color name="fab_shape">?android:attr/colorAccent</color>
@@ -101,13 +97,11 @@
<!-- Accent color that matches the settings launcher icon -->
<color name="icon_accent">#ffabffec</color>
- <color name="summary_default_start">#ff009587</color>
- <color name="summary_default_end">#ffced7db</color>
-
<color name="importance_icon_tint">#8a000000</color>
<color name="importance_disabled_tint">#4d000000</color>
<!-- Accessibility SUW colors -->
+ <color name="material_blue_400">#5e97f6</color>
<color name="material_blue_500">#4285F4</color>
<color name="material_blue_700">#3367D6</color>
@@ -131,4 +125,12 @@
<color name="usage_graph_dots">#B0BEC5</color>
+ <color name="card_background_grey">#eeeeee</color>
+
+ <color name="primary_color">@color/material_blue_grey_900</color>
+ <color name="primary_dark_color">@color/material_blue_grey_950</color>
+ <color name="secondary_color">#ff37474f</color>
+ <color name="accent_color">@color/accent_material_light</color>
+ <color name="accent_color_lighter">#ff7fcac3</color>
+
</resources>
diff --git a/res/values/config.xml b/res/values/config.xml
index 3f25fc6..6cae9cf 100755
--- a/res/values/config.xml
+++ b/res/values/config.xml
@@ -38,4 +38,6 @@
<!-- When true enable color temperature setting. -->
<bool name="config_enableColorTemperature">false</bool>
+ <!-- Fully-qualified class name for the implementation of the FeatureFactory to be instantiated. -->
+ <string name="config_featureFactory" translatable="false">com.android.settings.overlay.FeatureFactoryImpl</string>
</resources>
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index ef7efa2..c50e226 100755
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -59,6 +59,8 @@
<dimen name="appwidget_min_height">40dip</dimen>
<dimen name="pager_tabs_padding">0dp</dimen>
+ <dimen name="pager_tabs_title_padding">16dp</dimen>
+ <dimen name="pager_tabs_selected_indicator_height">3dp</dimen>
<!-- Minimum width for the popup for updating a user's photo. -->
<dimen name="update_user_photo_popup_min_width">300dip</dimen>
@@ -117,8 +119,6 @@
<dimen name="dashboard_tile_image_margin_start">16dp</dimen>
<dimen name="dashboard_tile_image_margin_end">32dp</dimen>
- <dimen name="suggestion_arrow_margin">16dp</dimen>
-
<!-- SwitchBar margin start / end -->
<dimen name="switchbar_margin_start">16dp</dimen>
<dimen name="switchbar_margin_end">16dp</dimen>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 0166448..333a106 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -741,7 +741,7 @@
<!-- Introduction title shown in fingerprint enrollment to introduce the fingerprint feature[CHAR LIMIT=29] -->
<string name="security_settings_fingerprint_enroll_introduction_title">Unlock with fingerprint</string>
<!-- Introduction detail message shown in fingerprint enrollment dialog [CHAR LIMIT=NONE]-->
- <string name="security_settings_fingerprint_enroll_introduction_message">Just touch the fingerprint sensor to unlock your phone, authorize purchases, or sign in to apps. Be careful whose fingerprints you add. Even one added print can do any of these things.\n\nNote: Your fingerprint may be less secure than a strong pattern or PIN. <annotation id="url">Learn more</annotation></string>
+ <string name="security_settings_fingerprint_enroll_introduction_message">Just touch the fingerprint sensor to unlock your phone, authorize purchases, or sign in to apps. Be careful whose fingerprints you add. Even one added print can do any of these things.\n\nNote: Your fingerprint may be less secure than a strong pattern or PIN.</string>
<!-- Button text to cancel enrollment from the introduction [CHAR LIMIT=22] -->
<string name="security_settings_fingerprint_enroll_introduction_cancel">Cancel</string>
<!-- Button text to continue to the next screen from the introduction [CHAR LIMIT=22] -->
@@ -2456,6 +2456,10 @@
<string name="storage_menu_set_up">Set up</string>
<!-- Storage setting. Menu option for exploring a storage device [CHAR LIMIT=30]-->
<string name="storage_menu_explore">Explore</string>
+ <!-- Storage setting. Menu option for using the deletion helper. [CHAR LIMIT=30] -->
+ <string name="storage_menu_free">Free up space</string>
+ <!-- Storage setting. Menu option for accessing the storage manager settings. [CHAR LIMIT=30] -->
+ <string name="storage_menu_manage">Manage storage</string>
<!-- Storage setting. Title for USB transfer settings [CHAR LIMIT=30]-->
<string name="storage_title_usb">USB computer connection</string>
@@ -5535,8 +5539,6 @@
<!-- Help URI, Default [DO NOT TRANSLATE] -->
<string name="help_uri_default" translatable="false"></string>
- <!-- Help URI, Dashboard [DO NOT TRANSLATE] -->
- <string name="help_uri_dashboard" translatable="false"></string>
<!-- Help URI, Android beam [DO NOT TRANSLATE] -->
<string name="help_uri_beam" translatable="false"></string>
<!-- Help URI, Display [DO NOT TRANSLATE] -->
@@ -7202,7 +7204,10 @@
<string name="condition_work_summary">Apps, background sync, and other features related to your work profile are turned off.</string>
<!-- Title for the suggestions section on the dashboard [CHAR LIMIT=30] -->
- <string name="suggestions_title">Suggestions (<xliff:g name="count" example="3">%1$d</xliff:g>)</string>
+ <string name="suggestions_title">Suggestions</string>
+
+ <!-- Summary for the suggestions section on the dashboard, representing number of suggestions. [CHAR LIMIT=10] -->
+ <string name="suggestions_summary">+<xliff:g name="count" example="3">%1$d</xliff:g></string>
<!-- Name of option to remove a suggestion from the list [CHAR LIMIT=30] -->
<string name="suggestion_remove">Remove</string>
@@ -7453,6 +7458,10 @@
<string name="notification_suggestion_title">Control lock screen notifications</string>
<!-- Summary of notification suggestion during optional steps of setup. [CHAR_LIMIT=80] -->
<string name="notification_suggestion_summary">Show or hide notification content</string>
+ <!-- Setting tab title for all setting options. [CHAR LIMIT=20] -->
+ <string name="page_tab_title_summary">All</string>
+ <!-- Setting tab title for support setting options. [CHAR LIMIT=20] -->
+ <string name="page_tab_title_support">Support</string>
<!-- Summary of developer options to set the smallest width of the screen [CHAR LIMIT=60]-->
<string name="developer_density_summary"><xliff:g name="count" example="320">%d</xliff:g> dp</string>
@@ -7475,6 +7484,67 @@
<!-- [CHAR LIMIT=60] Name of dev option called demo mode -->
<string name="demo_mode">Demo mode</string>
+ <!-- Activity title for deletion helper. [CHAR LIMIT=25] -->
+ <string name="deletion_helper_title">Remove from Device</string>
+ <!-- Preference group title for the list of apps to uninstall. [CHAR LIMIT=40]-->
+ <string name="deletion_helper_apps_title">Apps</string>
+ <!-- Summary of how much storage an app is using and the number of days since last use. [CHAR LIMIT=NONE]-->
+ <string name="deletion_helper_app_summary"><xliff:g id="used" example="1.2GB">%1$s</xliff:g>, last used <xliff:g id="days" example="67">%2$d</xliff:g> days ago</string>
+ <!-- Summary of how much storage an app is using when it has never been used before. [CHAR LIMIT=NONE]-->
+ <string name="deletion_helper_app_summary_never_used"><xliff:g id="used" example="1.2GB">%1$s</xliff:g>, never used before</string>
+ <!-- Summary of how much storage an app is using when its last use is unknown. [CHAR LIMIT=NONE]-->
+ <string name="deletion_helper_app_summary_unknown_used"><xliff:g id="used" example="1.2GB">%1$s</xliff:g>, not sure when last used</string>
+ <!-- Button which clears out storage in the deletion helper. [CHAR LIMIT=60]-->
+ <string name="deletion_helper_free_button">Free up <xliff:g id="freeable" example="1.2GB">%1$s</xliff:g></string>
+
+ <!-- Title text for connecting to customer support [CHAR LIMIT=80]-->
+ <string name="support_escalation_title">Around-the-clock support</string>
+
+ <!-- Summary text for connecting to customer support [CHAR LIMIT=NONE]-->
+ <string name="support_escalation_summary">You can request a support call or chat and we\'ll get back to you with a quickness</string>
+
+ <!-- Title text that indicates there is not internet connection. [CHAR LIMIT=80]-->
+ <string name="support_offline_title">You\'re offline</string>
+
+ <!-- Summary text telling user to connect to Internet in order to request customer support. [CHAR LIMIT=NONE]-->
+ <string name="support_offline_summary">To reach support, first connect to Wi-Fi or data.</string>
+
+ <!-- Title text for showing a list of help options [CHAR LIMIT=80]-->
+ <string name="support_more_help_title">More help</string>
+
+ <!-- Button label for contacting customer support by phone [CHAR LIMIT=20]-->
+ <string name="support_escalation_by_phone">Support call</string>
+
+ <!-- Button label for contacting customer support by email [CHAR LIMIT=20]-->
+ <string name="support_escalation_by_email">Support email</string>
+
+ <!-- Button label for contacting customer support by chat [CHAR LIMIT=20]-->
+ <string name="support_escalation_by_chat">Support chat</string>
+
+ <!-- Button label for visiting help forum [CHAR LIMIT=60]-->
+ <string name="support_forum_title">Help forum</string>
+
+ <!-- Button label for visiting the tips & tricks site [CHAR LIMIT=60]-->
+ <string name="support_tips_and_tricks_title">Tips & tricks</string>
+
+ <!-- Title text that indicates user needs to sign in to get customer support. [CHAR LIMIT=80]-->
+ <string name="support_sign_in_required_title">Sign in for support</string>
+
+ <!-- Summary text that indicates user needs to sign-in to get real time customer support. [CHAR LIMIT=NONE]-->
+ <string name="support_sign_in_required_summary" translatable="false"></string>
+
+ <!-- Button label for signing in an account [CHAR LIMIT=40]-->
+ <string name="support_sign_in_button_text">Sign in</string>
+
+ <!-- Button label that redirects user who needs help for signin to help screen [CHAR LIMIT=NONE]-->
+ <string name="support_sign_in_required_help">Can\'t access your account?</string>
+
+ <!-- Dialog title displayed before initiating real time support [CHAR LIMIT=80]-->
+ <string name="support_disclaimer_title">Send system information</string>
+
+ <!-- Dialog content displayed before initiating real time support [CHAR LIMIT=NONE]-->
+ <string name="support_disclaimer_content">To help address your issue quickly, we need system information for diagnosis.</string>
+
<!-- [CHAR LIMIT=60] Title of work profile setting page -->
<string name="managed_profile_settings_title">Work profile settings</string>
<!-- [CHAR LIMIT=60] The preference title for enabling cross-profile remote contact search -->
@@ -7482,6 +7552,27 @@
<!-- [CHAR LIMIT=NONE] The preference summary for enabling cross-profile remote contact search -->
<string name="managed_profile_contact_search_summary">Allow contact searches by your organization to identify callers and contacts</string>
+ <!-- Time in hours -->
+ <plurals name="hours">
+ <item quantity="one">1 hour</item>
+ <item quantity="other"><xliff:g id="number" example="7">%s</xliff:g> hours</item>
+ </plurals>
+
+ <!-- Time in minutes -->
+ <plurals name="minutes">
+ <item quantity="one">1 minute</item>
+ <item quantity="other"><xliff:g id="number" example="7">%s</xliff:g> minutes</item>
+ </plurals>
+
+ <!-- Time in seconds -->
+ <plurals name="seconds">
+ <item quantity="one">1 second</item>
+ <item quantity="other"><xliff:g id="number" example="7">%s</xliff:g> seconds</item>
+ </plurals>
+
+ <!-- Estimated wait time range for real time supports -->
+ <string name="support_estimated_wait_time">~<xliff:g id="ESTIMATE" example="2 minutes">%1$s</xliff:g> wait</string>
+
<!-- Message for telling the user the kind of BT device being displayed in list. -->
<string name="bluetooth_talkback_computer">Computer</string>
@@ -7502,4 +7593,62 @@
<!-- Message for telling the user the kind of BT device being displayed in list. -->
<string name="bluetooth_talkback_bluetooth">Bluetooth</string>
+
+ <!-- Preference group title for the photos and videos deletion service. [CHAR LIMIT=40]-->
+ <string name="deletion_helper_photos_title">Photos & Videos (<xliff:g id="num_items">%1$d</xliff:g>)</string>
+
+ <!-- Summary of how much backed up storage that photos and videos service can clear from the local device. [CHAR LIMIT=NONE]-->
+ <string name="deletion_helper_photos_summary"><xliff:g id="used" example="1.2GB">%1$s</xliff:g>, older than <xliff:g id="days">%2$d</xliff:g> days</string>
+
+ <!-- Preference title for the downloads deletion service. [CHAR LIMIT=40]-->
+ <string name="deletion_helper_downloads_title">Downloads (<xliff:g id="numItems" example="67">%1$d</xliff:g>)</string>
+
+ <!-- Summary of how much stale data can be cleared from the local download folder. [CHAR LIMIT=NONE]-->
+ <string name="deletion_helper_downloads_summary"><xliff:g id="used" example="1.2GB">%1$s</xliff:g> • last modified <xliff:g id="days">%2$s</xliff:g></string>
+
+ <!-- Summary for when when there is nothing in the downloads folder to clear. [CHAR LIMIT=NONE]-->
+ <string name="deletion_helper_downloads_summary_empty"><xliff:g id="used" example="1.2GB">%1$s</xliff:g></string>
+
+ <!-- Message to warn the user before clearing space in the deletion helper. [CHAR LIMIT=NONE] -->
+ <string name="deletion_helper_clear_dialog_message">Remove <xliff:g id="clearable_bytes" example="1.2GB">%1$s</xliff:g> from your device.</string>
+
+ <!-- Button label for the dialog prompt for clearing data in deletion helper. [CHAR LIMIT=40] -->
+ <string name="deletion_helper_clear_dialog_remove">Remove</string>
+
+ <!-- Used as title on the automatic storage manager settings. [CHAR LIMIT=60] -->
+ <string name="automatic_storage_manager_settings">Storage manager</string>
+
+ <!-- Used as wall of text to describe the feature. [CHAR LIMIT=NONE] -->
+ <string name="automatic_storage_manager_text">To help free up storage space, storage manager removes backed up photos and videos from your device.</string>
+
+ <!-- Dropdown preference title for dropdown describing how many days of data to retain.-->
+ <string name="automatic_storage_manager_days_title">Remove photos & videos</string>
+
+ <!-- Title for the dialog to up sell the storage manager. [CHAR LIMIT=NONE] -->
+ <string name="deletion_helper_upsell_title"><xliff:g id="used" example="1.2GB">%1$s</xliff:g> now free. Manage storage automatically?</string>
+ <!-- Summary for the dialog to up sell the storage manager. [CHAR LIMIT=NONE] -->
+ <string name="deletion_helper_upsell_summary">Let Storage manager automatically free up space by removing backed up content from your device?</string>
+ <!-- Button to delay turning on the storage manager on the storage manager upsell. [CHAR LIMIT=20]-->
+ <string name="deletion_helper_upsell_cancel">No thanks</string>
+ <!-- Button to activate the storage manager on the storage manager upsell. [CHAR LIMIT=20]-->
+ <string name="deletion_helper_upsell_activate">Turn on</string>
+
+ <!-- Title for the apps category in the deletion helper, showing how many apps to delete. [CHAR LIMIT=40]-->
+ <string name="deletion_helper_apps_group_title">Apps (<xliff:g id="num_items">%1$d</xliff:g>)</string>
+
+ <!-- Summary for the apps category in the deletion helper, showing how many space to clear. [CHAR LIMIT=NONE]-->
+ <string name="deletion_helper_apps_group_summary"><xliff:g id="used" example="1.2GB">%1$s</xliff:g></string>
+
+ <!-- Category title for the automatic settings in the storage manager settings. [CHAR LIMIT=40] -->
+ <string name="deletion_helper_automatic_title">Automatic</string>
+
+ <!-- Category title for the manual settings in the storage manager settings. [CHAR LIMIT=40] -->
+ <string name="deletion_helper_manual_title">Manual</string>
+
+ <!-- Preference menu title for accessing the deletion helper from the storage manager settings. [CHAR LIMIT=30]-->
+ <string name="deletion_helper_preference_title">Free space now</string>
+
+ <!-- Preference title for the automatic storage manager toggle. [CHAR LIMIT=60]-->
+ <string name="automatic_storage_manager_preference_title">Storage manager</string>
+
</resources>
diff --git a/res/values/styles.xml b/res/values/styles.xml
index bfe2d1c..24d7905 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -286,6 +286,10 @@
<item name="android:singleLine">true</item>
</style>
+ <style name="SetupWizardButton.Negative" parent="@android:style/Widget.Material.Button.Borderless" />
+
+ <style name="SetupWizardButton.Positive" parent="@android:style/Widget.Material.Button.Colored" />
+
<style name="vpn_label">
<item name="android:layout_width">match_parent</item>
<item name="android:layout_height">wrap_content</item>
@@ -350,16 +354,23 @@
<item name="android:textColor">@color/warning</item>
</style>
- <style name="FingerprintLayoutTheme">
- <item name="suwBackground">@drawable/fp_enrollment_header</item>
- <item name="suwIllustrationAspectRatio">@dimen/fingerprint_illustration_aspect_ratio</item>
- <item name="suwDecorPaddingTop">@dimen/fingerprint_decor_padding_top</item>
+ <style name="TextAppearance.SupportTitle"
+ parent="@android:style/TextAppearance.Material.Subhead">
+ <item name="android:textColor">?android:attr/colorAccent</item>
+ <item name="android:textSize">24sp</item>
</style>
- <style name="SetupWizardFingerprintLayoutTheme">
- <item name="suwBackgroundTile">@drawable/setup_illustration_tile</item>
- <item name="suwIllustration">@drawable/setup_illustration_lock_screen</item>
- <item name="suwIllustrationHorizontalTile">@drawable/setup_illustration_horizontal_tile</item>
+ <style name="TextAppearance.SupportSummary" parent="TextAppearance.CategoryTitle"/>
+
+ <style name="SupportPrimaryButton" parent="android:Widget.Material.Button.Colored"/>
+
+ <style name="SupportSecondaryButton"
+ parent="android:Widget.Material.Button.Borderless.Colored">
+ <item name="android:textSize">12sp</item>
+ </style>
+
+ <style name="FingerprintLayoutTheme">
+ <item name="android:icon">@drawable/ic_fingerprint_header</item>
</style>
<style name="TextAppearance.ConfirmDeviceCredentialsErrorText"
diff --git a/res/values/themes.xml b/res/values/themes.xml
index ef9e1e0..694c5c6 100644
--- a/res/values/themes.xml
+++ b/res/values/themes.xml
@@ -32,15 +32,13 @@
<item name="android:windowBackground">@null</item>
</style>
- <style name="SetupWizardTheme" parent="SuwThemeMaterial">
+ <style name="SetupWizardTheme" parent="SuwThemeGlif">
<!-- For all Alert Dialogs -->
<item name="android:alertDialogTheme">@style/ThemeOverlay.AlertDialog</item>
<item name="android:colorPrimary">@color/suw_color_accent_dark</item>
- <item name="android:listPreferredItemPaddingEnd">@dimen/suw_layout_margin_sides</item>
- <item name="android:listPreferredItemPaddingStart">@dimen/suw_layout_margin_sides</item>
<item name="android:windowBackground">?android:attr/colorBackground</item>
<item name="@*android:preferencePanelStyle">@*android:style/PreferencePanel.Dialog</item>
- <item name="fingerprint_layout_theme">@style/SetupWizardFingerprintLayoutTheme</item>
+ <item name="fingerprint_layout_theme">@style/FingerprintLayoutTheme</item>
<item name="fingerprint_progress_bar_size">@dimen/setup_fingerprint_progress_bar_size</item>
<item name="fingerprint_ring_radius">@dimen/setup_fingerprint_ring_radius</item>
<item name="ic_menu_add">@drawable/ic_menu_add_dark</item>
@@ -59,15 +57,13 @@
<item name="@*android:errorColor">@color/setup_lock_pattern_view_error_color_dark</item>
</style>
- <style name="SetupWizardTheme.Light" parent="SuwThemeMaterial.Light">
+ <style name="SetupWizardTheme.Light" parent="SuwThemeGlif.Light">
<!-- For all Alert Dialogs -->
<item name="android:alertDialogTheme">@style/ThemeOverlay.AlertDialog</item>
<item name="android:colorPrimary">@color/suw_color_accent_light</item>
- <item name="android:listPreferredItemPaddingEnd">@dimen/suw_layout_margin_sides</item>
- <item name="android:listPreferredItemPaddingStart">@dimen/suw_layout_margin_sides</item>
<item name="android:windowBackground">?android:attr/colorBackground</item>
<item name="@*android:preferencePanelStyle">@*android:style/PreferencePanel.Dialog</item>
- <item name="fingerprint_layout_theme">@style/SetupWizardFingerprintLayoutTheme</item>
+ <item name="fingerprint_layout_theme">@style/FingerprintLayoutTheme</item>
<item name="fingerprint_progress_bar_size">@dimen/setup_fingerprint_progress_bar_size</item>
<item name="fingerprint_ring_radius">@dimen/setup_fingerprint_ring_radius</item>
<item name="ic_menu_add">@drawable/ic_menu_add_light</item>
@@ -78,7 +74,7 @@
<item name="wifi_signal_color">@color/setup_wizard_wifi_color_light</item>
<item name="wifi_signal">@drawable/wifi_signal</item>
<item name="preferenceBackgroundColor">?android:attr/colorBackground</item>
- <item name="preferenceTheme">@style/PreferenceTheme.SetupWizard</item>
+ <item name="preferenceTheme">@style/PreferenceTheme.SetupWizard.Light</item>
<!-- LockPatternView colors -->
<item name="@*android:regularColor">@color/setup_lock_pattern_view_regular_color_light</item>
@@ -100,7 +96,7 @@
<item name="android:windowAnimationStyle">@null</item>
</style>
- <style name="PreferenceTheme" parent="@android:style/Theme.DeviceDefault.Settings">
+ <style name="PreferenceTheme" parent="Theme.SettingsBase">
<item name="@android:preferenceStyle">@style/Preference</item>
<item name="@android:editTextPreferenceStyle">@style/EditTextPreference</item>
<item name="@dropdownPreferenceStyle">@style/Preference.DropDown.Material</item>
@@ -108,9 +104,11 @@
<item name="apnPreferenceStyle">@style/ApnPreference</item>
</style>
- <style name="PreferenceTheme.SetupWizard">
- <item name="android:listPreferredItemPaddingEnd">@dimen/suw_layout_margin_sides</item>
- <item name="android:listPreferredItemPaddingStart">@dimen/suw_layout_margin_sides</item>
+ <style name="PreferenceTheme.SetupWizard" parent="SetupWizardTheme">
+ <item name="preferenceFragmentStyle">@style/SetupWizardPreferenceFragmentStyle</item>
+ </style>
+
+ <style name="PreferenceTheme.SetupWizard.Light" parent="SetupWizardTheme.Light">
<item name="preferenceFragmentStyle">@style/SetupWizardPreferenceFragmentStyle</item>
</style>
@@ -134,7 +132,11 @@
layouts against a remote context using our local theme colors. Due to the implementation
details of Theme, we can't reference any local resources and MUST instead use the values
directly. So use #ff263238 instead of @color/theme_primary and so on. -->
- <style name="Theme.SettingsBase" parent="@android:style/Theme.Material.Settings" />
+ <style name="Theme.SettingsBase" parent="@android:style/Theme.Material.Settings">
+ <item name="android:colorPrimary">@color/primary_color</item>
+ <item name="android:colorAccent">@color/accent_color</item>
+ <item name="colorSecondary">@color/secondary_color</item>
+ </style>
<style name="Theme.Settings" parent="Theme.SettingsBase">
<item name="preferenceTheme">@style/PreferenceTheme</item>
@@ -198,18 +200,22 @@
</style>
<style name="ThemeOverlay.SwitchBar.Settings" parent="@android:style/ThemeOverlay.Material.Dark.ActionBar">
+ <item name="android:colorAccent">@color/accent_color_lighter</item>
<item name="switchBarMarginStart">@dimen/switchbar_subsettings_margin_start</item>
<item name="switchBarMarginEnd">@dimen/switchbar_subsettings_margin_end</item>
- <item name="switchBarBackgroundColor">@color/switchbar_background_color</item>
+ <item name="switchBarBackgroundColor">?attr/colorSecondary</item>
</style>
<style name="ThemeOverlay.SwitchBar.SubSettings" parent="@android:style/ThemeOverlay.Material.Dark.ActionBar">
<item name="switchBarMarginStart">@dimen/switchbar_subsettings_margin_start</item>
<item name="switchBarMarginEnd">@dimen/switchbar_subsettings_margin_end</item>
- <item name="switchBarBackgroundColor">@color/switchbar_background_color</item>
+ <item name="switchBarBackgroundColor">?attr/colorSecondary</item>
</style>
<style name="Theme.DialogWhenLarge" parent="@*android:style/Theme.Material.Settings.DialogWhenLarge">
+ <item name="android:colorPrimary">@color/primary_color</item>
+ <item name="android:colorAccent">@color/accent_color</item>
+ <item name="colorSecondary">@color/secondary_color</item>
<!-- Redefine the ActionBar style for contentInsetStart -->
<item name="android:actionBarStyle">@style/Theme.ActionBar</item>
@@ -241,6 +247,7 @@
</style>
<style name="Theme.AlertDialog" parent="@*android:style/Theme.Material.Settings.Dialog.Alert">
+ <item name="android:colorAccent">@color/accent_color</item>
<item name="android:windowSoftInputMode">adjustResize</item>
<!-- Redefine the ActionBar style for contentInsetStart -->
@@ -255,24 +262,17 @@
<item name="preferenceBackgroundColor">@android:color/transparent</item>
</style>
- <!-- Used to color the switch bar controls -->
- <style name="ThemeOverlay.SwitchBar" parent="@android:style/ThemeOverlay">
- <!-- Used by controls, e.g. CheckBox, ProgressBar, etc. -->
- <item name="android:colorAccent">@color/switch_accent_color</item>
- <item name="switchBarBackgroundColor">@color/switchbar_background_color</item>
- </style>
-
<style name="Theme.ConfirmDeviceCredentials" parent="Theme.SubSettings">
<item name="confirmDeviceCredentialsSideMargin">16dp</item>
<item name="confirmDeviceCredentialsTopMargin">16dp</item>
</style>
<style name="Theme.ConfirmDeviceCredentialsDark" parent="@android:style/Theme.Material">
- <item name="android:colorPrimary">@*android:color/material_blue_grey_900</item>
- <item name="android:colorPrimaryDark">@*android:color/material_blue_grey_950</item>
+ <item name="android:colorPrimary">@color/primary_color</item>
+ <item name="android:colorAccent">@color/accent_color_lighter</item>
<item name="android:windowActionBar">false</item>
<item name="android:windowNoTitle">true</item>
- <item name="android:windowBackground">@color/confirm_device_credential_dark_background</item>
+ <item name="android:windowBackground">?android:attr/colorPrimary</item>
<item name="confirmDeviceCredentialsSideMargin">32dp</item>
<item name="confirmDeviceCredentialsTopMargin">32dp</item>
@@ -290,13 +290,15 @@
</style>
<style name="Theme.FingerprintEnroll" parent="@*android:style/Theme.Material.Settings.NoActionBar">
+ <item name="android:colorAccent">@color/suw_color_accent_glif_light</item>
+ <item name="android:colorPrimary">@color/suw_color_accent_glif_light</item>
<item name="android:listPreferredItemHeight">@dimen/suw_items_preferred_height</item>
<item name="android:listPreferredItemPaddingEnd">@dimen/suw_layout_margin_sides</item>
<item name="android:listPreferredItemPaddingStart">@dimen/suw_layout_margin_sides</item>
<item name="android:textAppearanceListItemSmall">@android:style/TextAppearance.Material.Body1</item>
<item name="android:windowAnimationStyle">@style/Animation.SuwWindowAnimation</item>
- <item name="selectableItemBackground">?android:attr/selectableItemBackground</item>
+ <item name="selectableItemBackground">?android:attr/selectableItemBackground</item>
<item name="suwDividerCondition">both</item>
<item name="suwListItemIconColor">?android:attr/colorAccent</item>
<item name="suwMarginSides">@dimen/suw_layout_margin_sides</item>
diff --git a/res/xml/automatic_storage_management_settings.xml b/res/xml/automatic_storage_management_settings.xml
new file mode 100644
index 0000000..282f89a
--- /dev/null
+++ b/res/xml/automatic_storage_management_settings.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:settings="http://schemas.android.com/apk/res-auto"
+ android:title="@string/automatic_storage_manager_settings" >
+
+ <PreferenceCategory
+ android:key="automatic"
+ android:title="@string/deletion_helper_automatic_title">
+
+ <SwitchPreference
+ android:key="storage_manager_active"
+ android:title="@string/automatic_storage_manager_preference_title"
+ android:summary="@string/automatic_storage_manager_text"/>
+
+ <DropDownPreference
+ android:key="days"
+ android:summary="%s"
+ android:title="@string/automatic_storage_manager_days_title"
+ android:entries="@array/automatic_storage_management_days"
+ android:entryValues="@array/automatic_storage_management_days_values"/>
+
+ </PreferenceCategory>
+
+ <PreferenceCategory
+ android:key="manual"
+ android:title="@string/deletion_helper_manual_title">
+
+ <Preference
+ android:key="deletion_helper"
+ android:title="@string/deletion_helper_preference_title"/>
+
+ </PreferenceCategory>
+
+</PreferenceScreen>
\ No newline at end of file
diff --git a/res/xml/deletion_helper_list.xml b/res/xml/deletion_helper_list.xml
new file mode 100644
index 0000000..64bd3b5
--- /dev/null
+++ b/res/xml/deletion_helper_list.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
+ android:title="@string/deletion_helper_title">
+
+ <com.android.settings.PhotosDeletionPreference
+ android:key="delete_photos" />
+
+ <com.android.settings.deletionhelper.DownloadsDeletionPreferenceGroup
+ android:key="delete_downloads"
+ android:icon="@drawable/ic_keyboard_arrow_down_black_32"/>
+
+ <com.android.settings.CollapsibleCheckboxPreferenceGroup
+ android:key="apps_group"
+ android:icon="@drawable/ic_keyboard_arrow_down_black_32"/>
+
+</PreferenceScreen>
diff --git a/res/xml/development_prefs.xml b/res/xml/development_prefs.xml
index 44cf585..cdee328 100644
--- a/res/xml/development_prefs.xml
+++ b/res/xml/development_prefs.xml
@@ -51,10 +51,11 @@
android:title="@string/bt_hci_snoop_log"
android:summary="@string/bt_hci_snoop_log_summary"/>
- <SwitchPreference
+ <com.android.settingslib.RestrictedSwitchPreference
android:key="oem_unlock_enable"
android:title="@string/oem_unlock_enable"
- android:summary="@string/oem_unlock_enable_summary"/>
+ android:summary="@string/oem_unlock_enable_summary"
+ settings:useAdditionalSummary="true"/>
<PreferenceScreen
android:key="running_apps"
diff --git a/res/xml/fingerprint_enroll_introduction_items.xml b/res/xml/fingerprint_enroll_introduction_items.xml
index 4cb18a6..28a3f6b 100644
--- a/res/xml/fingerprint_enroll_introduction_items.xml
+++ b/res/xml/fingerprint_enroll_introduction_items.xml
@@ -20,7 +20,7 @@
<Item
android:enabled="false"
android:id="@+id/fingerprint_introduction_message"
- android:layout="@layout/suw_item_link_description"/>
+ android:layout="@layout/suw_items_description" />
<Item
android:id="@+id/next_button"
diff --git a/src/com/android/settings/CollapsibleCheckboxPreferenceGroup.java b/src/com/android/settings/CollapsibleCheckboxPreferenceGroup.java
new file mode 100644
index 0000000..a0f9d98
--- /dev/null
+++ b/src/com/android/settings/CollapsibleCheckboxPreferenceGroup.java
@@ -0,0 +1,147 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings;
+
+import android.content.Context;
+import android.support.v7.preference.Preference;
+import android.support.v7.preference.PreferenceGroup;
+import android.support.v7.preference.PreferenceViewHolder;
+import android.util.AttributeSet;
+
+import android.util.Log;
+import android.util.TypedValue;
+import android.view.View;
+import android.widget.Checkable;
+import android.widget.TextView;
+
+import java.util.LinkedHashMap;
+
+/**
+ * CollapsibleCheckboxPreferenceGroup is a preference group that can be expanded or collapsed and
+ * also has a checkbox.
+ */
+public class CollapsibleCheckboxPreferenceGroup extends PreferenceGroup implements
+ View.OnClickListener {
+ private boolean mCollapsed;
+ private boolean mChecked;
+
+ public CollapsibleCheckboxPreferenceGroup(Context context) {
+ this(context, null);
+ }
+
+ public CollapsibleCheckboxPreferenceGroup(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ setWidgetLayoutResource(com.android.settings.R.layout.preference_widget_checkbox);
+ }
+
+ @Override
+ public void onBindViewHolder(PreferenceViewHolder holder) {
+ super.onBindViewHolder(holder);
+ View checkbox = holder.findViewById(com.android.internal.R.id.checkbox);
+ if (checkbox != null && checkbox instanceof Checkable) {
+ ((Checkable) checkbox).setChecked(mChecked);
+ checkbox.setClickable(true);
+ checkbox.setFocusable(true);
+ checkbox.setOnClickListener(this);
+ }
+
+ final TextView titleView = (TextView) holder.findViewById(android.R.id.title);
+ if (titleView != null) {
+ Context context = getContext();
+ TypedValue value = new TypedValue();
+ context.getTheme().resolveAttribute(android.R.attr.colorAccent, value, true);
+ titleView.setTextColor(context.getColor(value.resourceId));
+ }
+ }
+
+ @Override
+ public boolean addPreference(Preference p) {
+ super.addPreference(p);
+ p.setVisible(!isCollapsed());
+ return true;
+ }
+
+ // The preference click handler.
+ @Override
+ protected void onClick() {
+ super.onClick();
+ setCollapse(!isCollapsed());
+ }
+
+ // The checkbox view click handler.
+ @Override
+ public void onClick(View v) {
+ setChecked(!isChecked());
+ }
+
+ /**
+ * Return if the view is collapsed.
+ */
+ public boolean isCollapsed() {
+ return mCollapsed;
+ }
+
+ /**
+ * Returns the checked state of the preference.
+ */
+ public boolean isChecked() {
+ return mChecked;
+ }
+
+ /**
+ * Sets the checked state and notifies listeners of the state change.
+ */
+ public void setChecked(boolean checked) {
+ if (mChecked != checked) {
+ mChecked = checked;
+
+ callChangeListener(checked);
+ notifyDependencyChange(shouldDisableDependents());
+ notifyChanged();
+ }
+ }
+
+ private void setCollapse(boolean isCollapsed) {
+ if (mCollapsed == isCollapsed) {
+ return;
+ }
+
+ mCollapsed = isCollapsed;
+ if (isCollapsed) {
+ hideDropdownPreferences();
+ } else {
+ showDropdownPreferences();
+ }
+ }
+
+ private void showDropdownPreferences() {
+ setAllPreferencesVisibility(true);
+ setIcon(R.drawable.ic_keyboard_arrow_down_black_32);
+ }
+
+ private void hideDropdownPreferences() {
+ setAllPreferencesVisibility(false);
+ setIcon(R.drawable.ic_keyboard_arrow_up_black_32);
+ }
+
+ private void setAllPreferencesVisibility(boolean visible) {
+ for (int i = 0; i < getPreferenceCount(); i++) {
+ Preference p = getPreference(i);
+ p.setVisible(visible);
+ }
+ }
+}
diff --git a/src/com/android/settings/DeletionPreference.java b/src/com/android/settings/DeletionPreference.java
new file mode 100644
index 0000000..93d76e6
--- /dev/null
+++ b/src/com/android/settings/DeletionPreference.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.drawable.Drawable;
+import android.support.v7.preference.Preference;
+import android.support.v7.preference.Preference.OnPreferenceChangeListener;
+import android.support.v7.preference.CheckBoxPreference;
+import android.support.v7.preference.PreferenceViewHolder;
+import android.util.AttributeSet;
+import android.util.TypedValue;
+import android.text.format.Formatter;
+import android.widget.TextView;
+import com.android.settings.deletionhelper.DeletionType;
+
+/**
+ * Preference to handle the deletion of various data types in the Deletion Helper.
+ */
+public abstract class DeletionPreference extends CheckBoxPreference implements
+ DeletionType.FreeableChangedListener, OnPreferenceChangeListener {
+ private DeletionType.FreeableChangedListener mListener;
+ private boolean mChecked;
+ private long mFreeableBytes;
+ private int mFreeableItems;
+ private DeletionType mDeletionService;
+
+ public DeletionPreference(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ setOnPreferenceChangeListener(this);
+ }
+
+ @Override
+ public void onBindViewHolder(PreferenceViewHolder holder) {
+ super.onBindViewHolder(holder);
+ final TextView titleView = (TextView) holder.findViewById(android.R.id.title);
+ if (titleView != null) {
+ titleView.setTextColor(getTintColor(getContext()));
+ }
+ }
+
+ /**
+ * Returns the number of bytes which can be cleared by the deletion service.
+ * @return The number of bytes.
+ */
+ public long getFreeableBytes() {
+ return mChecked ? mFreeableBytes : 0;
+ }
+
+ /**
+ * Register a listener to be called back on when the freeable bytes have changed.
+ * @param listener The callback listener.
+ */
+ public void registerFreeableChangedListener(DeletionType.FreeableChangedListener listener) {
+ mListener = listener;
+ }
+
+ /**
+ * Registers a deletion service to update the preference's information.
+ * @param deletionService A photo/video deletion service.
+ */
+ public void registerDeletionService(DeletionType deletionService) {
+ mDeletionService = deletionService;
+ if (mDeletionService != null) {
+ mDeletionService.registerFreeableChangedListener(this);
+ }
+ }
+
+ /**
+ * Returns the deletion service powering the preference.
+ * @return The deletion service.
+ */
+ public DeletionType getDeletionService() {
+ return mDeletionService;
+ }
+
+ @Override
+ public void onFreeableChanged(int numItems, long freeableBytes) {
+ mFreeableItems = numItems;
+ mFreeableBytes = freeableBytes;
+ maybeUpdateListener();
+ }
+
+ @Override
+ public boolean onPreferenceChange(Preference preference, Object newValue) {
+ mChecked = (boolean) newValue;
+ maybeUpdateListener();
+ return true;
+ }
+
+ private int getTintColor(Context context) {
+ TypedValue value = new TypedValue();
+ context.getTheme().resolveAttribute(android.R.attr.colorAccent, value, true);
+ return context.getColor(value.resourceId);
+ }
+
+ private void maybeUpdateListener() {
+ if (mListener != null) {
+ mListener.onFreeableChanged(mFreeableItems, getFreeableBytes());
+ }
+ }
+}
diff --git a/src/com/android/settings/DevelopmentSettings.java b/src/com/android/settings/DevelopmentSettings.java
index 1fd8451..6a0abe3 100644
--- a/src/com/android/settings/DevelopmentSettings.java
+++ b/src/com/android/settings/DevelopmentSettings.java
@@ -239,7 +239,7 @@
private SwitchPreference mBugreportInPower;
private RestrictedSwitchPreference mKeepScreenOn;
private SwitchPreference mBtHciSnoopLog;
- private SwitchPreference mEnableOemUnlock;
+ private RestrictedSwitchPreference mEnableOemUnlock;
private SwitchPreference mDebugViewAttributes;
private SwitchPreference mForceAllowOnExternal;
@@ -372,7 +372,7 @@
mBugreportInPower = findAndInitSwitchPref(BUGREPORT_IN_POWER_KEY);
mKeepScreenOn = (RestrictedSwitchPreference) findAndInitSwitchPref(KEEP_SCREEN_ON);
mBtHciSnoopLog = findAndInitSwitchPref(BT_HCI_SNOOP_LOG);
- mEnableOemUnlock = findAndInitSwitchPref(ENABLE_OEM_UNLOCK);
+ mEnableOemUnlock = (RestrictedSwitchPreference) findAndInitSwitchPref(ENABLE_OEM_UNLOCK);
if (!showEnableOemUnlockPreference()) {
removePreference(mEnableOemUnlock);
mEnableOemUnlock = null;
@@ -1014,12 +1014,28 @@
flashLockState = mOemUnlockManager.getFlashLockState();
}
- return flashLockState != PersistentDataBlockManager.FLASH_LOCK_UNLOCKED;
+ return flashLockState != PersistentDataBlockManager.FLASH_LOCK_UNLOCKED
+ && Settings.Global.getInt(getActivity().getContentResolver(),
+ Settings.Global.OEM_UNLOCK_DISALLOWED, 0) == 0;
}
private void updateOemUnlockOptions() {
if (mEnableOemUnlock != null) {
+ // Showing mEnableOemUnlock preference as device has persistent data block.
+ mEnableOemUnlock.setDisabledByAdmin(null);
mEnableOemUnlock.setEnabled(enableOemUnlockPreference());
+ if (mEnableOemUnlock.isEnabled()) {
+ // mEnableOemUnlock is enabled as device's flash lock is unlocked.
+ if (RestrictedLockUtils.hasBaseUserRestriction(getActivity(),
+ UserManager.DISALLOW_FACTORY_RESET, UserHandle.myUserId())) {
+ // Set mEnableOemUnlock to disabled as restriction is set, but not by admin.
+ mEnableOemUnlock.setEnabled(false);
+ } else {
+ // Check restriction, disable mEnableOemUnlock and apply policy transparency.
+ mEnableOemUnlock
+ .checkRestrictionAndSetDisabled(UserManager.DISALLOW_FACTORY_RESET);
+ }
+ }
}
}
diff --git a/src/com/android/settings/InstrumentedFragment.java b/src/com/android/settings/InstrumentedFragment.java
index 0e3528a..3977426 100644
--- a/src/com/android/settings/InstrumentedFragment.java
+++ b/src/com/android/settings/InstrumentedFragment.java
@@ -16,11 +16,11 @@
package com.android.settings;
-import com.android.internal.logging.MetricsLogger;
-
import android.os.Bundle;
import android.support.v14.preference.PreferenceFragment;
+import com.android.internal.logging.MetricsLogger;
+
/**
* Instrumented fragment that logs visibility state.
*/
@@ -30,6 +30,9 @@
// Used by PreferenceActivity for the dummy fragment it adds, no useful data here.
public static final int PREFERENCE_ACTIVITY_FRAGMENT = UNDECLARED + 1;
+ public static final int DASHBOARD_CONTAINER = UNDECLARED + 2;
+
+ public static final int SUPPORT_FRAGMENT = UNDECLARED + 3;
/**
* Declare the view of this category.
diff --git a/src/com/android/settings/PhotosDeletionPreference.java b/src/com/android/settings/PhotosDeletionPreference.java
new file mode 100644
index 0000000..643b3f1
--- /dev/null
+++ b/src/com/android/settings/PhotosDeletionPreference.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.drawable.Drawable;
+import android.util.AttributeSet;
+import android.text.format.Formatter;
+
+/**
+ * Preference to handle the deletion of photos and videos in the Deletion Helper.
+ */
+public class PhotosDeletionPreference extends DeletionPreference {
+ public static final int DAYS_TO_KEEP = 30;
+
+ public PhotosDeletionPreference(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ setIcon(getIcon(context));
+ updatePreferenceText(0, 0);
+ }
+
+ /**
+ * Updates the title and summary of the preference with fresh information.
+ */
+ public void updatePreferenceText(int items, long bytes) {
+ Context context = getContext();
+ setTitle(context.getString(R.string.deletion_helper_photos_title, items));
+ setSummary(context.getString(R.string.deletion_helper_photos_summary,
+ Formatter.formatFileSize(context, bytes), DAYS_TO_KEEP));
+ }
+
+ @Override
+ public void onFreeableChanged(int items, long bytes) {
+ super.onFreeableChanged(items, bytes);
+ updatePreferenceText(items, bytes);
+ }
+
+ private Drawable getIcon(Context context) {
+ final Drawable iconDrawable;
+ try {
+ Resources resources = context.getResources();
+ final int resId = resources.getIdentifier("ic_photos_black_24", "drawable",
+ context.getPackageName());
+ iconDrawable = context.getDrawable(resId);
+ } catch (Resources.NotFoundException e) {
+ return null;
+ }
+ return iconDrawable;
+ }
+}
diff --git a/src/com/android/settings/Settings.java b/src/com/android/settings/Settings.java
index 82e41cb..1eb3af4 100644
--- a/src/com/android/settings/Settings.java
+++ b/src/com/android/settings/Settings.java
@@ -139,6 +139,7 @@
public static class ScreenLockSuggestionActivity extends ChooseLockGeneric { /* empty */ }
public static class WallpaperSettingsActivity extends SettingsActivity { /* empty */ }
public static class ManagedProfileSettingsActivity extends SettingsActivity { /* empty */ }
+ public static class DeletionHelperActivity extends SettingsActivity { /* empty */ }
// Categories.
public static class WirelessSettings extends SettingsActivity { /* empty */ }
diff --git a/src/com/android/settings/SettingsActivity.java b/src/com/android/settings/SettingsActivity.java
index 9c8d410..bd6619e 100644
--- a/src/com/android/settings/SettingsActivity.java
+++ b/src/com/android/settings/SettingsActivity.java
@@ -49,6 +49,7 @@
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.SearchView;
+
import com.android.internal.util.ArrayUtils;
import com.android.settings.Settings.WifiSettingsActivity;
import com.android.settings.accessibility.AccessibilitySettings;
@@ -69,9 +70,10 @@
import com.android.settings.applications.WriteSettingsDetails;
import com.android.settings.applications.VrListenerSettings;
import com.android.settings.bluetooth.BluetoothSettings;
-import com.android.settings.dashboard.DashboardSummary;
+import com.android.settings.dashboard.DashboardContainerFragment;
import com.android.settings.dashboard.SearchResultsSummary;
import com.android.settings.datausage.DataUsageSummary;
+import com.android.settings.deletionhelper.DeletionHelperFragment;
import com.android.settings.deviceinfo.PrivateVolumeForget;
import com.android.settings.deviceinfo.PrivateVolumeSettings;
import com.android.settings.deviceinfo.PublicVolumeSettings;
@@ -103,6 +105,7 @@
import com.android.settings.notification.ZenModeScheduleRuleSettings;
import com.android.settings.notification.ZenModeSettings;
import com.android.settings.notification.ZenModeVisualInterruptionSettings;
+import com.android.settings.overlay.FeatureFactory;
import com.android.settings.print.PrintJobSettingsFragment;
import com.android.settings.print.PrintSettingsFragment;
import com.android.settings.qstile.DevelopmentTiles;
@@ -330,6 +333,7 @@
WallpaperTypeSettings.class.getName(),
VrListenerSettings.class.getName(),
ManagedProfileSettings.class.getName(),
+ DeletionHelperFragment.class.getName(),
};
@@ -615,7 +619,7 @@
// Show Search affordance
mDisplaySearch = true;
mInitialTitleResId = R.string.dashboard_title;
- switchToFragment(DashboardSummary.class.getName(), null, false, false,
+ switchToFragment(DashboardContainerFragment.class.getName(), null, false, false,
mInitialTitleResId, mInitialTitle, false);
}
}
@@ -689,7 +693,7 @@
}
/**
- * Sets the id of the view continaing the main content. Should be called before calling super's
+ * Sets the id of the view containing the main content. Should be called before calling super's
* onCreate.
*/
protected void setMainContentId(int contentId) {
@@ -731,7 +735,7 @@
setTitleFromBackStack();
}
- private int setTitleFromBackStack() {
+ private void setTitleFromBackStack() {
final int count = getFragmentManager().getBackStackEntryCount();
if (count == 0) {
@@ -740,13 +744,11 @@
} else {
setTitle(mInitialTitle);
}
- return 0;
+ return;
}
FragmentManager.BackStackEntry bse = getFragmentManager().getBackStackEntryAt(count - 1);
setTitleFromBackStackEntry(bse);
-
- return count;
}
private void setTitleFromBackStackEntry(FragmentManager.BackStackEntry bse) {
@@ -1200,6 +1202,7 @@
if (current != null && current instanceof SearchResultsSummary) {
mSearchResultsFragment = (SearchResultsSummary) current;
} else {
+ setContentHeaderView(null);
mSearchResultsFragment = (SearchResultsSummary) switchToFragment(
SearchResultsSummary.class.getName(), null, false, true,
R.string.search_results_title, null, true);
diff --git a/src/com/android/settings/SetupChooseLockGeneric.java b/src/com/android/settings/SetupChooseLockGeneric.java
index bc3a2ec..f561609 100644
--- a/src/com/android/settings/SetupChooseLockGeneric.java
+++ b/src/com/android/settings/SetupChooseLockGeneric.java
@@ -16,7 +16,6 @@
package com.android.settings;
-import android.app.Activity;
import android.app.admin.DevicePolicyManager;
import android.content.ComponentName;
import android.content.Context;
@@ -25,20 +24,18 @@
import android.content.res.Resources;
import android.os.Bundle;
import android.os.UserHandle;
-import android.support.v7.preference.Preference;
import android.support.v14.preference.PreferenceFragment;
+import android.support.v7.preference.Preference;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
-import android.widget.Button;
import android.widget.LinearLayout;
import com.android.internal.widget.LockPatternUtils;
import com.android.settings.fingerprint.SetupSkipDialog;
-import com.android.setupwizardlib.SetupWizardLayout;
-import com.android.setupwizardlib.SetupWizardPreferenceLayout;
-import com.android.setupwizardlib.view.NavigationBar;
+import com.android.settings.utils.SettingsDividerItemDecoration;
+import com.android.setupwizardlib.GlifPreferenceLayout;
/**
* Setup Wizard's version of ChooseLockGeneric screen. It inherits the logic and basic structure
@@ -74,8 +71,7 @@
layout.setFitsSystemWindows(false);
}
- public static class SetupChooseLockGenericFragment extends ChooseLockGenericFragment
- implements NavigationBar.NavigationBarListener {
+ public static class SetupChooseLockGenericFragment extends ChooseLockGenericFragment {
public static final String EXTRA_PASSWORD_QUALITY = ":settings:password_quality";
@@ -83,24 +79,15 @@
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
- SetupWizardUtils.setImmersiveMode(getActivity());
-
- SetupWizardPreferenceLayout layout = (SetupWizardPreferenceLayout) view;
+ GlifPreferenceLayout layout = (GlifPreferenceLayout) view;
+ layout.setDividerItemDecoration(new SettingsDividerItemDecoration(getContext()));
layout.setDividerInset(getContext().getResources().getDimensionPixelSize(
- R.dimen.suw_items_text_divider_inset));
- final NavigationBar navigationBar = layout.getNavigationBar();
- Button nextButton = navigationBar.getNextButton();
- nextButton.setText(null);
- nextButton.setEnabled(false);
- navigationBar.setNavigationBarListener(this);
+ R.dimen.suw_items_glif_text_divider_inset));
- layout.setIllustration(R.drawable.setup_illustration_lock_screen,
- R.drawable.setup_illustration_horizontal_tile);
- if (!mForFingerprint) {
- layout.setHeaderText(R.string.setup_lock_settings_picker_title);
- } else {
- layout.setHeaderText(R.string.lock_settings_picker_title);
- }
+ layout.setIcon(getContext().getDrawable(R.drawable.ic_lock));
+ layout.setHeaderText(mForFingerprint ?
+ R.string.lock_settings_picker_title
+ : R.string.setup_lock_settings_picker_title);
// Use the dividers in SetupWizardRecyclerLayout. Suppress the dividers in
// PreferenceFragment.
@@ -143,7 +130,7 @@
@Override
public RecyclerView onCreateRecyclerView(LayoutInflater inflater, ViewGroup parent,
Bundle savedInstanceState) {
- SetupWizardPreferenceLayout layout = (SetupWizardPreferenceLayout) parent;
+ GlifPreferenceLayout layout = (GlifPreferenceLayout) parent;
return layout.onCreateRecyclerView(inflater, parent, savedInstanceState);
}
@@ -251,17 +238,5 @@
SetupWizardUtils.copySetupExtras(getActivity().getIntent(), intent);
return intent;
}
-
- @Override
- public void onNavigateBack() {
- Activity activity = getActivity();
- if (activity != null) {
- activity.onBackPressed();
- }
- }
-
- @Override
- public void onNavigateNext() {
- }
}
}
diff --git a/src/com/android/settings/SetupChooseLockPassword.java b/src/com/android/settings/SetupChooseLockPassword.java
index d483d8f..94cc728 100644
--- a/src/com/android/settings/SetupChooseLockPassword.java
+++ b/src/com/android/settings/SetupChooseLockPassword.java
@@ -16,7 +16,6 @@
package com.android.settings;
-import android.app.Activity;
import android.app.Fragment;
import android.content.Context;
import android.content.Intent;
@@ -27,9 +26,7 @@
import android.view.ViewGroup;
import android.widget.LinearLayout;
-import com.android.setupwizardlib.SetupWizardLayout;
-import com.android.setupwizardlib.util.SystemBarHelper;
-import com.android.setupwizardlib.view.NavigationBar;
+import com.android.setupwizardlib.GlifLayout;
/**
* Setup Wizard's version of ChooseLockPassword screen. It inherits the logic and basic structure
@@ -91,27 +88,21 @@
super.onApplyThemeResource(theme, resid, first);
}
- public static class SetupChooseLockPasswordFragment extends ChooseLockPasswordFragment
- implements NavigationBar.NavigationBarListener {
+ public static class SetupChooseLockPasswordFragment extends ChooseLockPasswordFragment {
- private SetupWizardLayout mLayout;
- private NavigationBar mNavigationBar;
+ private GlifLayout mLayout;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
- mLayout = (SetupWizardLayout) inflater.inflate(
+ mLayout = (GlifLayout) inflater.inflate(
R.layout.setup_choose_lock_password, container, false);
- mNavigationBar = mLayout.getNavigationBar();
- mNavigationBar.setNavigationBarListener(this);
return mLayout;
}
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
- SystemBarHelper.setImeInsetView(mLayout);
- SetupWizardUtils.setImmersiveMode(getActivity());
mLayout.setHeaderText(getActivity().getTitle());
}
@@ -119,28 +110,5 @@
protected Intent getRedactionInterstitialIntent(Context context) {
return null;
}
-
- @Override
- protected void setNextEnabled(boolean enabled) {
- mNavigationBar.getNextButton().setEnabled(enabled);
- }
-
- @Override
- protected void setNextText(int text) {
- mNavigationBar.getNextButton().setText(text);
- }
-
- @Override
- public void onNavigateBack() {
- final Activity activity = getActivity();
- if (activity != null) {
- activity.onBackPressed();
- }
- }
-
- @Override
- public void onNavigateNext() {
- handleNext();
- }
}
}
diff --git a/src/com/android/settings/SetupChooseLockPattern.java b/src/com/android/settings/SetupChooseLockPattern.java
index 8a7842d..2978196 100644
--- a/src/com/android/settings/SetupChooseLockPattern.java
+++ b/src/com/android/settings/SetupChooseLockPattern.java
@@ -16,7 +16,6 @@
package com.android.settings;
-import android.app.Activity;
import android.app.Fragment;
import android.content.Context;
import android.content.Intent;
@@ -26,11 +25,9 @@
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
-import android.widget.Button;
import android.widget.LinearLayout;
-import com.android.setupwizardlib.SetupWizardLayout;
-import com.android.setupwizardlib.view.NavigationBar;
+import com.android.setupwizardlib.GlifLayout;
/**
* Setup Wizard's version of ChooseLockPattern screen. It inherits the logic and basic structure
@@ -86,87 +83,20 @@
super.onApplyThemeResource(theme, resid, first);
}
- public static class SetupChooseLockPatternFragment extends ChooseLockPatternFragment
- implements NavigationBar.NavigationBarListener {
-
- private NavigationBar mNavigationBar;
- private Button mRetryButton;
+ public static class SetupChooseLockPatternFragment extends ChooseLockPatternFragment {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
- final SetupWizardLayout layout = (SetupWizardLayout) inflater.inflate(
+ final GlifLayout layout = (GlifLayout) inflater.inflate(
R.layout.setup_choose_lock_pattern, container, false);
- mNavigationBar = layout.getNavigationBar();
- mNavigationBar.setNavigationBarListener(this);
layout.setHeaderText(getActivity().getTitle());
return layout;
}
@Override
- public void onViewCreated(View view, Bundle savedInstanceState) {
- mRetryButton = (Button) view.findViewById(R.id.retryButton);
- mRetryButton.setOnClickListener(this);
- super.onViewCreated(view, savedInstanceState);
- SetupWizardUtils.setImmersiveMode(getActivity());
- }
-
- @Override
protected Intent getRedactionInterstitialIntent(Context context) {
return null;
}
-
- @Override
- public void onClick(View v) {
- if (v == mRetryButton) {
- handleLeftButton();
- } else {
- super.onClick(v);
- }
- }
-
- @Override
- protected void setRightButtonEnabled(boolean enabled) {
- mNavigationBar.getNextButton().setEnabled(enabled);
- }
-
- @Override
- protected void setRightButtonText(int text) {
- mNavigationBar.getNextButton().setText(text);
- }
-
- @Override
- protected void updateStage(Stage stage) {
- super.updateStage(stage);
- // Only enable the button for retry
- mRetryButton.setEnabled(stage == Stage.FirstChoiceValid);
-
- switch (stage) {
- case Introduction:
- case HelpScreen:
- case ChoiceTooShort:
- case FirstChoiceValid:
- mRetryButton.setVisibility(View.VISIBLE);
- break;
- case NeedToConfirm:
- case ConfirmWrong:
- case ChoiceConfirmed:
- mRetryButton.setVisibility(View.INVISIBLE);
- break;
- }
- }
-
- @Override
- public void onNavigateBack() {
- final Activity activity = getActivity();
- if (activity != null) {
- activity.onBackPressed();
- }
- }
-
- @Override
- public void onNavigateNext() {
- handleRightButton();
- }
}
}
diff --git a/src/com/android/settings/SetupEncryptionInterstitial.java b/src/com/android/settings/SetupEncryptionInterstitial.java
index 39c8af1..56585b1 100644
--- a/src/com/android/settings/SetupEncryptionInterstitial.java
+++ b/src/com/android/settings/SetupEncryptionInterstitial.java
@@ -16,7 +16,6 @@
package com.android.settings;
-import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.res.Resources;
@@ -25,13 +24,11 @@
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
-import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.TextView;
-import com.android.setupwizardlib.SetupWizardLayout;
-import com.android.setupwizardlib.SetupWizardPreferenceLayout;
-import com.android.setupwizardlib.view.NavigationBar;
+import com.android.settings.utils.SettingsDividerItemDecoration;
+import com.android.setupwizardlib.GlifPreferenceLayout;
/**
* Setup Wizard's version of EncryptionInterstitial screen. It inherits the logic and basic
@@ -78,30 +75,19 @@
layout.setFitsSystemWindows(false);
}
- public static class SetupEncryptionInterstitialFragment extends EncryptionInterstitialFragment
- implements NavigationBar.NavigationBarListener {
+ public static class SetupEncryptionInterstitialFragment extends EncryptionInterstitialFragment {
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
- final SetupWizardPreferenceLayout layout = (SetupWizardPreferenceLayout) view;
+ final GlifPreferenceLayout layout = (GlifPreferenceLayout) view;
+ layout.setDividerItemDecoration(new SettingsDividerItemDecoration(getContext()));
layout.setDividerInset(getContext().getResources().getDimensionPixelSize(
- R.dimen.suw_items_icon_divider_inset));
- layout.setIllustration(R.drawable.setup_illustration_lock_screen,
- R.drawable.setup_illustration_horizontal_tile);
-
- final NavigationBar navigationBar = layout.getNavigationBar();
- navigationBar.setNavigationBarListener(this);
- Button nextButton = navigationBar.getNextButton();
- nextButton.setText(null);
- nextButton.setEnabled(false);
+ R.dimen.suw_items_glif_icon_divider_inset));
+ layout.setIcon(getContext().getDrawable(R.drawable.ic_lock));
layout.setHeaderText(R.string.encryption_interstitial_header);
- Activity activity = getActivity();
- if (activity != null) {
- SetupWizardUtils.setImmersiveMode(activity);
- }
// Use the dividers in SetupWizardRecyclerLayout. Suppress the dividers in
// PreferenceFragment.
@@ -118,21 +104,8 @@
@Override
public RecyclerView onCreateRecyclerView(LayoutInflater inflater, ViewGroup parent,
Bundle savedInstanceState) {
- SetupWizardPreferenceLayout layout = (SetupWizardPreferenceLayout) parent;
+ GlifPreferenceLayout layout = (GlifPreferenceLayout) parent;
return layout.onCreateRecyclerView(inflater, parent, savedInstanceState);
}
-
- @Override
- public void onNavigateBack() {
- final Activity activity = getActivity();
- if (activity != null) {
- activity.onBackPressed();
- }
- }
-
- @Override
- public void onNavigateNext() {
- // next is handled via the onPreferenceTreeClick method in EncryptionInterstitial
- }
}
}
diff --git a/src/com/android/settings/SetupRedactionInterstitial.java b/src/com/android/settings/SetupRedactionInterstitial.java
index e487a50..225fe46 100644
--- a/src/com/android/settings/SetupRedactionInterstitial.java
+++ b/src/com/android/settings/SetupRedactionInterstitial.java
@@ -16,20 +16,16 @@
package com.android.settings;
-import android.app.Activity;
-import android.content.Context;
import android.content.Intent;
import android.content.res.Resources;
import android.os.Bundle;
-import android.os.UserHandle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
+import android.widget.Button;
import android.widget.LinearLayout;
import com.android.settings.notification.RedactionInterstitial;
-import com.android.setupwizardlib.SetupWizardLayout;
-import com.android.setupwizardlib.view.NavigationBar;
/**
* Setup Wizard's version of RedactionInterstitial screen. It inherits the logic and basic structure
@@ -67,7 +63,7 @@
}
public static class SetupRedactionInterstitialFragment extends RedactionInterstitialFragment
- implements NavigationBar.NavigationBarListener {
+ implements View.OnClickListener {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
@@ -78,29 +74,19 @@
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
- final SetupWizardLayout layout =
- (SetupWizardLayout) view.findViewById(R.id.setup_wizard_layout);
-
- final NavigationBar navigationBar = layout.getNavigationBar();
- navigationBar.setNavigationBarListener(this);
- navigationBar.getBackButton().setVisibility(View.GONE);
- SetupWizardUtils.setImmersiveMode(getActivity());
+ final Button button = (Button) view.findViewById(R.id.redaction_next_button);
+ button.setOnClickListener(this);
}
@Override
- public void onNavigateBack() {
- final Activity activity = getActivity();
- if (activity != null) {
- activity.onBackPressed();
- }
- }
-
- @Override
- public void onNavigateNext() {
- final SetupRedactionInterstitial activity = (SetupRedactionInterstitial) getActivity();
- if (activity != null) {
- activity.setResult(RESULT_OK, activity.getResultIntentData());
- finish();
+ public void onClick(View v) {
+ if (v.getId() == R.id.redaction_next_button) {
+ final SetupRedactionInterstitial activity =
+ (SetupRedactionInterstitial) getActivity();
+ if (activity != null) {
+ activity.setResult(RESULT_OK, activity.getResultIntentData());
+ finish();
+ }
}
}
}
diff --git a/src/com/android/settings/SetupWizardUtils.java b/src/com/android/settings/SetupWizardUtils.java
index 71501b1..5563c3b 100644
--- a/src/com/android/settings/SetupWizardUtils.java
+++ b/src/com/android/settings/SetupWizardUtils.java
@@ -24,14 +24,6 @@
import com.android.setupwizardlib.util.WizardManagerHelper;
public class SetupWizardUtils {
- private static final String TAG = "SetupWizardUtils";
-
- // From WizardManager (must match constants maintained there)
- public static final String EXTRA_SCRIPT_URI = "scriptUri";
-
- public static boolean isUsingWizardManager(Activity activity) {
- return activity.getIntent().hasExtra(EXTRA_SCRIPT_URI);
- }
public static int getTheme(Intent intent) {
if (WizardManagerHelper.isLightTheme(intent, true)) {
diff --git a/src/com/android/settings/SummaryPreference.java b/src/com/android/settings/SummaryPreference.java
index 0943a2b..38449b1 100644
--- a/src/com/android/settings/SummaryPreference.java
+++ b/src/com/android/settings/SummaryPreference.java
@@ -33,6 +33,7 @@
private String mUnits;
private int mLeft, mMiddle, mRight;
+ private boolean mColorsSet = false;
private float mLeftRatio, mMiddleRatio, mRightRatio;
private String mStartLabel;
private String mEndLabel;
@@ -40,8 +41,6 @@
public SummaryPreference(Context context, AttributeSet attrs) {
super(context, attrs);
setLayoutResource(R.layout.settings_summary_preference);
- mLeft = context.getColor(R.color.summary_default_start);
- mRight = context.getColor(R.color.summary_default_end);
}
public void setAmount(String amount) {
@@ -77,6 +76,7 @@
mLeft = left;
mMiddle = middle;
mRight = right;
+ mColorsSet = true;
notifyChanged();
}
@@ -86,7 +86,9 @@
LinearColorBar colorBar = (LinearColorBar) holder.itemView.findViewById(R.id.color_bar);
colorBar.setRatios(mLeftRatio, mMiddleRatio, mRightRatio);
- colorBar.setColors(mLeft, mMiddle, mRight);
+ if (mColorsSet) {
+ colorBar.setColors(mLeft, mMiddle, mRight);
+ }
if (!TextUtils.isEmpty(mStartLabel) || !TextUtils.isEmpty(mEndLabel)) {
holder.findViewById(R.id.label_bar).setVisibility(View.VISIBLE);
diff --git a/src/com/android/settings/Utils.java b/src/com/android/settings/Utils.java
index 4eaad7d..90f2726 100644
--- a/src/com/android/settings/Utils.java
+++ b/src/com/android/settings/Utils.java
@@ -759,9 +759,13 @@
* devices allow users to flash other OSes to them.
*/
static void setOemUnlockEnabled(Context context, boolean enabled) {
- PersistentDataBlockManager manager =(PersistentDataBlockManager)
- context.getSystemService(Context.PERSISTENT_DATA_BLOCK_SERVICE);
- manager.setOemUnlockEnabled(enabled);
+ try {
+ PersistentDataBlockManager manager = (PersistentDataBlockManager)
+ context.getSystemService(Context.PERSISTENT_DATA_BLOCK_SERVICE);
+ manager.setOemUnlockEnabled(enabled);
+ } catch (SecurityException e) {
+ Log.e(TAG, "Fail to set oem unlock.", e);
+ }
}
/**
diff --git a/src/com/android/settings/applications/LinearColorBar.java b/src/com/android/settings/applications/LinearColorBar.java
index 158a625..53b6ab6 100644
--- a/src/com/android/settings/applications/LinearColorBar.java
+++ b/src/com/android/settings/applications/LinearColorBar.java
@@ -4,6 +4,7 @@
package com.android.settings.applications;
import android.content.Context;
+import android.content.res.Resources;
import android.graphics.Canvas;
import android.graphics.LinearGradient;
import android.graphics.Paint;
@@ -12,12 +13,12 @@
import android.graphics.Shader;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
+import android.util.TypedValue;
import android.view.MotionEvent;
import android.widget.LinearLayout;
public class LinearColorBar extends LinearLayout {
- static final int LEFT_COLOR = 0xff009688;
- static final int MIDDLE_COLOR = 0xff009688;
+
static final int RIGHT_COLOR = 0xffced7db;
static final int GRAY_COLOR = 0xff555555;
static final int WHITE_COLOR = 0xffffffff;
@@ -26,8 +27,8 @@
private float mYellowRatio;
private float mGreenRatio;
- private int mLeftColor = LEFT_COLOR;
- private int mMiddleColor = MIDDLE_COLOR;
+ private int mLeftColor;
+ private int mMiddleColor;
private int mRightColor = RIGHT_COLOR;
private boolean mShowIndicator = true;
@@ -70,7 +71,11 @@
? 2 : 1;
mEdgeGradientPaint.setStrokeWidth(mLineWidth);
mEdgeGradientPaint.setAntiAlias(true);
-
+
+ Resources.Theme theme = context.getTheme();
+ TypedValue typedValue = new TypedValue();
+ theme.resolveAttribute(android.R.attr.colorAccent, typedValue, true);
+ mLeftColor = mMiddleColor = context.getColor(typedValue.resourceId);
}
public void setOnRegionTappedListener(OnRegionTappedListener listener) {
diff --git a/src/com/android/settings/dashboard/DashboardAdapter.java b/src/com/android/settings/dashboard/DashboardAdapter.java
index c54311a..7c76794 100644
--- a/src/com/android/settings/dashboard/DashboardAdapter.java
+++ b/src/com/android/settings/dashboard/DashboardAdapter.java
@@ -163,10 +163,7 @@
countItem(null, R.layout.suggestion_header, hasSuggestions, NS_SPACER);
resetCount();
if (mSuggestions != null) {
- int maxSuggestions = mSuggestionMode == SUGGESTION_MODE_DEFAULT
- ? Math.min(DEFAULT_SUGGESTION_COUNT, mSuggestions.size())
- : mSuggestionMode == SUGGESTION_MODE_EXPANDED ? mSuggestions.size()
- : 0;
+ int maxSuggestions = getDisplayableSuggestionCount();
for (int i = 0; i < mSuggestions.size(); i++) {
countItem(mSuggestions.get(i), R.layout.suggestion_tile, i < maxSuggestions,
NS_SUGGESTION);
@@ -208,6 +205,14 @@
mId++;
}
+ private int getDisplayableSuggestionCount() {
+ final int suggestionSize = mSuggestions.size();
+ return mSuggestionMode == SUGGESTION_MODE_DEFAULT
+ ? Math.min(DEFAULT_SUGGESTION_COUNT, suggestionSize)
+ : mSuggestionMode == SUGGESTION_MODE_EXPANDED
+ ? suggestionSize : 0;
+ }
+
@Override
public DashboardItemHolder onCreateViewHolder(ViewGroup parent, int viewType) {
return new DashboardItemHolder(LayoutInflater.from(parent.getContext()).inflate(
@@ -299,6 +304,14 @@
holder.icon.setImageResource(hasMoreSuggestions() ? R.drawable.ic_expand_more
: R.drawable.ic_expand_less);
holder.title.setText(mContext.getString(R.string.suggestions_title, mSuggestions.size()));
+ final int undisplayedSuggestionCount =
+ mSuggestions.size() - getDisplayableSuggestionCount();
+ if (undisplayedSuggestionCount == 0) {
+ holder.summary.setText(null);
+ } else {
+ holder.summary.setText(
+ mContext.getString(R.string.suggestions_summary, undisplayedSuggestionCount));
+ }
holder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
diff --git a/src/com/android/settings/dashboard/DashboardContainerFragment.java b/src/com/android/settings/dashboard/DashboardContainerFragment.java
new file mode 100644
index 0000000..31712d2
--- /dev/null
+++ b/src/com/android/settings/dashboard/DashboardContainerFragment.java
@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.dashboard;
+
+import android.app.Activity;
+import android.app.Fragment;
+import android.app.FragmentManager;
+import android.content.Context;
+import android.os.Bundle;
+import android.support.v13.app.FragmentPagerAdapter;
+import android.support.v4.view.ViewPager;
+import android.view.LayoutInflater;
+import android.view.Menu;
+import android.view.MenuInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+import com.android.settings.InstrumentedFragment;
+import com.android.settings.R;
+import com.android.settings.overlay.FeatureFactory;
+import com.android.settings.overlay.SupportFeatureProvider;
+import com.android.settings.widget.SlidingTabLayout;
+import com.android.settingslib.drawer.SettingsDrawerActivity;
+import com.android.settingslib.HelpUtils;
+
+/**
+ * Container for Dashboard fragments.
+ */
+public final class DashboardContainerFragment extends InstrumentedFragment {
+
+ private static final int INDEX_SUMMARY_FRAGMENT = 0;
+ private static final int INDEX_SUPPORT_FRAGMENT = 1;
+
+ private ViewPager mViewPager;
+ private View mHeaderView;
+ private DashboardViewPagerAdapter mPagerAdapter;
+
+ @Override
+ protected int getMetricsCategory() {
+ return DASHBOARD_CONTAINER;
+ }
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setHasOptionsMenu(true);
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup parent, Bundle savedInstanceState) {
+ final View content = inflater.inflate(R.layout.dashboard_container, parent, false);
+ mViewPager = (ViewPager) content.findViewById(R.id.pager);
+ mPagerAdapter = new DashboardViewPagerAdapter(getContext(), getChildFragmentManager());
+ mViewPager.setAdapter(mPagerAdapter);
+ mHeaderView = inflater.inflate(R.layout.dashboard_container_header, parent, false);
+ ((SlidingTabLayout) mHeaderView).setViewPager(mViewPager);
+ return content;
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ if (mPagerAdapter.getCount() > 1) {
+ final Activity activity = getActivity();
+ if (activity instanceof SettingsDrawerActivity) {
+ ((SettingsDrawerActivity) getActivity()).setContentHeaderView(mHeaderView);
+ }
+ }
+ }
+
+ private static final class DashboardViewPagerAdapter extends FragmentPagerAdapter {
+
+ private final Context mContext;
+ private final SupportFeatureProvider mSupportFeatureProvider;
+
+ public DashboardViewPagerAdapter(Context context, FragmentManager fragmentManager) {
+ super(fragmentManager);
+ mContext = context;
+ mSupportFeatureProvider =
+ FeatureFactory.getFactory(context).getSupportFeatureProvider(context);
+ }
+
+ @Override
+ public CharSequence getPageTitle(int position) {
+ switch (position) {
+ case INDEX_SUMMARY_FRAGMENT:
+ return mContext.getString(R.string.page_tab_title_summary);
+ case INDEX_SUPPORT_FRAGMENT:
+ return mContext.getString(R.string.page_tab_title_support);
+ }
+ return super.getPageTitle(position);
+ }
+
+ @Override
+ public Fragment getItem(int position) {
+ switch (position) {
+ case INDEX_SUMMARY_FRAGMENT:
+ return new DashboardSummary();
+ case INDEX_SUPPORT_FRAGMENT:
+ return new SupportFragment();
+ default:
+ throw new IllegalArgumentException(
+ String.format(
+ "Position %d does not map to a valid dashboard fragment",
+ position));
+ }
+ }
+
+ @Override
+ public int getCount() {
+ return mSupportFeatureProvider == null ? 1 : 2;
+ }
+ }
+}
diff --git a/src/com/android/settings/dashboard/DashboardSummary.java b/src/com/android/settings/dashboard/DashboardSummary.java
index 18b941c..9acc9a5 100644
--- a/src/com/android/settings/dashboard/DashboardSummary.java
+++ b/src/com/android/settings/dashboard/DashboardSummary.java
@@ -22,10 +22,9 @@
import android.support.v7.widget.LinearLayoutManager;
import android.util.Log;
import android.view.LayoutInflater;
-import android.view.Menu;
-import android.view.MenuInflater;
import android.view.View;
import android.view.ViewGroup;
+
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.MetricsProto.MetricsEvent;
import com.android.settings.InstrumentedFragment;
@@ -85,7 +84,6 @@
List<DashboardCategory> categories =
((SettingsActivity) getActivity()).getDashboardCategories();
mSummaryLoader = new SummaryLoader(getActivity(), categories);
- setHasOptionsMenu(true);
Context context = getContext();
mConditionManager = ConditionManager.get(context);
mSuggestionParser = new SuggestionParser(context,
@@ -102,14 +100,6 @@
}
@Override
- public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
- super.onCreateOptionsMenu(menu, inflater);
- if (getActivity() == null) return;
- HelpUtils.prepareHelpMenuItem(getActivity(), menu, R.string.help_uri_dashboard,
- getClass().getName());
- }
-
- @Override
public void onResume() {
long startTime = System.currentTimeMillis();
super.onResume();
diff --git a/src/com/android/settings/dashboard/SupportFragment.java b/src/com/android/settings/dashboard/SupportFragment.java
new file mode 100644
index 0000000..d9dc4f9
--- /dev/null
+++ b/src/com/android/settings/dashboard/SupportFragment.java
@@ -0,0 +1,159 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.dashboard;
+
+import android.accounts.Account;
+import android.accounts.AccountManager;
+import android.accounts.OnAccountsUpdateListener;
+import android.app.Activity;
+import android.content.Context;
+import android.net.ConnectivityManager;
+import android.net.Network;
+import android.net.NetworkCapabilities;
+import android.net.NetworkInfo;
+import android.net.NetworkRequest;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Looper;
+import android.support.v7.widget.LinearLayoutManager;
+import android.support.v7.widget.RecyclerView;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+import com.android.settings.InstrumentedFragment;
+import com.android.settings.R;
+import com.android.settings.overlay.FeatureFactory;
+import com.android.settings.overlay.SupportFeatureProvider;
+
+/**
+ * Fragment for support tab in SettingsGoogle.
+ */
+public final class SupportFragment extends InstrumentedFragment implements View.OnClickListener,
+ OnAccountsUpdateListener {
+
+ private final Handler mHandler = new Handler(Looper.getMainLooper());
+ private final ConnectivityManager.NetworkCallback mNetworkCallback =
+ new ConnectivityManager.NetworkCallback() {
+
+ @Override
+ public void onCapabilitiesChanged(Network network,
+ NetworkCapabilities capabilities) {
+ postConnectivityChanged();
+ }
+
+ @Override
+ public void onAvailable(Network network) {
+ postConnectivityChanged();
+ }
+
+ @Override
+ public void onLost(Network network) {
+ postConnectivityChanged();
+ }
+ };
+
+ private Activity mActivity;
+ private View mContent;
+ private RecyclerView mRecyclerView;
+ private SupportItemAdapter mSupportItemAdapter;
+ private AccountManager mAccountManager;
+ private SupportFeatureProvider mSupportFeatureProvider;
+ private ConnectivityManager mConnectivityManager;
+
+ @Override
+ protected int getMetricsCategory() {
+ return SUPPORT_FRAGMENT;
+ }
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ mActivity = getActivity();
+ mAccountManager = AccountManager.get(mActivity);
+ mSupportFeatureProvider =
+ FeatureFactory.getFactory(mActivity).getSupportFeatureProvider(mActivity);
+ mSupportItemAdapter = new SupportItemAdapter(mActivity, mSupportFeatureProvider,
+ this /* itemClickListener */);
+ mConnectivityManager =
+ (ConnectivityManager) mActivity.getSystemService(Context.CONNECTIVITY_SERVICE);
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ mContent = inflater.inflate(R.layout.support_fragment, container, false);
+ mRecyclerView = (RecyclerView) mContent.findViewById(R.id.support_items);
+ mRecyclerView.setLayoutManager(new LinearLayoutManager(
+ getActivity(), LinearLayoutManager.VERTICAL, false /* reverseLayout */));
+ mRecyclerView.setAdapter(mSupportItemAdapter);
+ return mContent;
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ // Monitor account change.
+ mAccountManager.addOnAccountsUpdatedListener(
+ this /* listener */, null /* handler */, true /* updateImmediately */);
+ // Monitor connectivity
+ mConnectivityManager.registerNetworkCallback(
+ new NetworkRequest.Builder()
+ .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
+ .build(),
+ mNetworkCallback);
+ }
+
+ @Override
+ public void onPause() {
+ super.onPause();
+ // Stop monitor account change.
+ mAccountManager.removeOnAccountsUpdatedListener(this /* listener */);
+ // Stop monitor connectivity.
+ mConnectivityManager.unregisterNetworkCallback(mNetworkCallback);
+ }
+
+ @Override
+ public void onAccountsUpdated(Account[] accounts) {
+ // Account changed, update support items.
+ mSupportItemAdapter.setAccount(
+ mSupportFeatureProvider.getSupportEligibleAccount(mActivity));
+ }
+
+ @Override
+ public void onClick(View v) {
+ final SupportItemAdapter.ViewHolder vh =
+ (SupportItemAdapter.ViewHolder) mRecyclerView.getChildViewHolder(v);
+ mSupportItemAdapter.onItemClicked(vh.getAdapterPosition());
+ }
+
+ private void postConnectivityChanged() {
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ if (mSupportItemAdapter != null) {
+ mSupportItemAdapter.setHasInternet(hasInternet());
+ }
+ }
+ });
+ }
+
+ private boolean hasInternet() {
+ final NetworkInfo activeNetwork = mConnectivityManager.getActiveNetworkInfo();
+ return activeNetwork != null && activeNetwork.isConnectedOrConnecting();
+ }
+}
diff --git a/src/com/android/settings/dashboard/SupportItemAdapter.java b/src/com/android/settings/dashboard/SupportItemAdapter.java
new file mode 100644
index 0000000..4956464
--- /dev/null
+++ b/src/com/android/settings/dashboard/SupportItemAdapter.java
@@ -0,0 +1,396 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.settings.dashboard;
+
+import android.accounts.Account;
+import android.annotation.DrawableRes;
+import android.annotation.LayoutRes;
+import android.annotation.StringRes;
+import android.app.Activity;
+import android.app.DialogFragment;
+import android.content.Intent;
+import android.support.v7.widget.RecyclerView;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import com.android.settings.R;
+import com.android.settings.overlay.SupportFeatureProvider;
+import com.android.settings.support.SupportDisclaimerDialogFragment;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+
+import static com.android.settings.overlay.SupportFeatureProvider.SupportType.CHAT;
+import static com.android.settings.overlay.SupportFeatureProvider.SupportType.PHONE;
+
+/**
+ * Item adapter for support tiles.
+ */
+public final class SupportItemAdapter extends RecyclerView.Adapter<SupportItemAdapter.ViewHolder> {
+
+ private static final int TYPE_TITLE = R.layout.support_item_title;
+ private static final int TYPE_SUBTITLE = R.layout.support_item_subtitle;
+ private static final int TYPE_ESCALATION_OPTIONS = R.layout.support_escalation_options;
+ private static final int TYPE_SUPPORT_TILE = R.layout.support_tile;
+ private static final int TYPE_SIGN_IN_BUTTON = R.layout.support_sign_in_button;
+
+ private final Activity mActivity;
+ private final EscalationClickListener mEscalationClickListener;
+ private final SupportFeatureProvider mSupportFeatureProvider;
+ private final View.OnClickListener mItemClickListener;
+ private final List<SupportData> mSupportData;
+
+ private boolean mHasInternet;
+ private Account mAccount;
+
+ public SupportItemAdapter(Activity activity, SupportFeatureProvider supportFeatureProvider,
+ View.OnClickListener itemClickListener) {
+ mActivity = activity;
+ mSupportFeatureProvider = supportFeatureProvider;
+ mItemClickListener = itemClickListener;
+ mEscalationClickListener = new EscalationClickListener();
+ mSupportData = new ArrayList<>();
+ // Optimistically assume we have Internet access. It will be updated later to correct value.
+ mHasInternet = true;
+ setAccount(mSupportFeatureProvider.getSupportEligibleAccount(mActivity));
+ refreshData();
+ }
+
+ @Override
+ public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
+ return new ViewHolder(LayoutInflater.from(parent.getContext()).inflate(
+ viewType, parent, false));
+ }
+
+ @Override
+ public void onBindViewHolder(ViewHolder holder, int position) {
+ final SupportData data = mSupportData.get(position);
+ switch (holder.getItemViewType()) {
+ case TYPE_SIGN_IN_BUTTON:
+ bindSignInPromoTile(holder, data);
+ break;
+ case TYPE_ESCALATION_OPTIONS:
+ bindEscalationOptions(holder, data);
+ break;
+ default:
+ bindSupportTile(holder, data);
+ break;
+ }
+ }
+
+ @Override
+ public int getItemViewType(int position) {
+ return mSupportData.get(position).type;
+ }
+
+ @Override
+ public int getItemCount() {
+ return mSupportData.size();
+ }
+
+ /**
+ * Called when a support item is clicked.
+ */
+ public void onItemClicked(int position) {
+ if (position >= 0 && position < mSupportData.size()) {
+ final SupportData data = mSupportData.get(position);
+ if (data.intent != null) {
+ mActivity.startActivityForResult(data.intent, 0);
+ }
+ }
+ }
+
+ public void setHasInternet(boolean hasInternet) {
+ if (mHasInternet != hasInternet) {
+ mHasInternet = hasInternet;
+ refreshData();
+ }
+ }
+
+ public void setAccount(Account account) {
+ if (!Objects.equals(mAccount, account)) {
+ mAccount = account;
+ refreshData();
+ }
+ }
+
+ /**
+ * Create data for the adapter. If there is already data in the adapter, they will be
+ * destroyed and recreated.
+ */
+ private void refreshData() {
+ mSupportData.clear();
+ if (mAccount == null) {
+ addSignInPromo();
+ } else {
+ addEscalationCards();
+ }
+ addMoreHelpItems();
+ notifyDataSetChanged();
+ }
+
+ private void addEscalationCards() {
+ if (mHasInternet) {
+ mSupportData.add(new SupportData.Builder(TYPE_TITLE)
+ .setText1(R.string.support_escalation_title)
+ .setText2(R.string.support_escalation_summary)
+ .build());
+ } else {
+ mSupportData.add(new SupportData.Builder(TYPE_TITLE)
+ .setText1(R.string.support_offline_title)
+ .setText2(R.string.support_offline_summary)
+ .build());
+ }
+ final SupportData.Builder builder = new SupportData.Builder(TYPE_ESCALATION_OPTIONS);
+ if (mSupportFeatureProvider.isSupportTypeEnabled(mActivity, PHONE)) {
+ builder.setText1(R.string.support_escalation_by_phone);
+ builder.setSummary1(mSupportFeatureProvider.getEstimatedWaitTime(mActivity, PHONE));
+ }
+ if (mSupportFeatureProvider.isSupportTypeEnabled(mActivity, CHAT)) {
+ builder.setText2(R.string.support_escalation_by_chat);
+ builder.setSummary2(mSupportFeatureProvider.getEstimatedWaitTime(mActivity, CHAT));
+ }
+ mSupportData.add(builder.build());
+ }
+
+ private void addSignInPromo() {
+ mSupportData.add(new SupportData.Builder(TYPE_TITLE)
+ .setText1(R.string.support_sign_in_required_title)
+ .setText2(R.string.support_sign_in_required_summary)
+ .build());
+ mSupportData.add(new SupportData.Builder(TYPE_SIGN_IN_BUTTON)
+ .setText1(R.string.support_sign_in_button_text)
+ .setText2(R.string.support_sign_in_required_help)
+ .build());
+ }
+
+ private void addMoreHelpItems() {
+ mSupportData.add(new SupportData.Builder(TYPE_SUBTITLE)
+ .setText1(R.string.support_more_help_title)
+ .build());
+ mSupportData.add(new SupportData.Builder(TYPE_SUPPORT_TILE)
+ .setIcon(R.drawable.ic_forum_24dp)
+ .setText1(R.string.support_forum_title)
+ .setIntent(mSupportFeatureProvider.getForumIntent())
+ .build());
+ mSupportData.add(new SupportData.Builder(TYPE_SUPPORT_TILE)
+ .setIcon(R.drawable.ic_lightbulb_outline_24)
+ .setText1(R.string.support_tips_and_tricks_title)
+ .setIntent(mSupportFeatureProvider.getTipsAndTricksIntent(mActivity))
+ .build());
+ mSupportData.add(new SupportData.Builder(TYPE_SUPPORT_TILE)
+ .setIcon(R.drawable.ic_help_24dp)
+ .setText1(R.string.help_feedback_label)
+ .setIntent(mSupportFeatureProvider.getHelpIntent(mActivity))
+ .build());
+ }
+
+ private void bindEscalationOptions(ViewHolder holder, SupportData data) {
+ if (data.text1 == 0) {
+ holder.text1View.setVisibility(View.GONE);
+ } else {
+ holder.text1View.setText(data.text1);
+ holder.text1View.setOnClickListener(mEscalationClickListener);
+ holder.text1View.setEnabled(mHasInternet);
+ holder.text1View.setVisibility(View.VISIBLE);
+ }
+ if (data.text2 == 0) {
+ holder.text2View.setVisibility(View.GONE);
+ } else {
+ holder.text2View.setText(data.text2);
+ holder.text2View.setOnClickListener(mEscalationClickListener);
+ holder.text2View.setEnabled(mHasInternet);
+ holder.text2View.setVisibility(View.VISIBLE);
+ }
+ if (holder.summary1View != null) {
+ holder.summary1View.setText(data.summary1);
+ holder.summary1View.setVisibility(mHasInternet ? View.VISIBLE : View.GONE);
+ }
+ if (holder.summary2View != null) {
+ holder.summary2View.setText(data.summary2);
+ holder.summary2View.setVisibility(mHasInternet ? View.VISIBLE : View.GONE);
+ }
+ }
+
+ private void bindSignInPromoTile(ViewHolder holder, SupportData data) {
+ holder.text1View.setText(data.text1);
+ holder.text2View.setText(data.text2);
+ holder.text1View.setOnClickListener(mEscalationClickListener);
+ holder.text2View.setOnClickListener(mEscalationClickListener);
+ }
+
+ private void bindSupportTile(ViewHolder holder, SupportData data) {
+ if (holder.iconView != null) {
+ holder.iconView.setImageResource(data.icon);
+ }
+ if (holder.text1View != null) {
+ holder.text1View.setText(data.text1);
+ }
+ if (holder.text2View != null) {
+ holder.text2View.setText(data.text2);
+ }
+ holder.itemView.setOnClickListener(mItemClickListener);
+ }
+
+ /**
+ * Show a disclaimer dialog and start support action after disclaimer has been acknowledged.
+ */
+ private void tryStartDisclaimerAndSupport(final @SupportFeatureProvider.SupportType int type) {
+ if (mSupportFeatureProvider.shouldShowDisclaimerDialog(mActivity)) {
+ DialogFragment fragment = SupportDisclaimerDialogFragment.newInstance(mAccount, type);
+ fragment.show(mActivity.getFragmentManager(), SupportDisclaimerDialogFragment.TAG);
+ return;
+ }
+ mSupportFeatureProvider.startSupport(mActivity, mAccount, type);
+ }
+
+ /**
+ * Click handler for starting escalation options.
+ */
+ private final class EscalationClickListener implements View.OnClickListener {
+ @Override
+ public void onClick(final View v) {
+ if (mAccount == null) {
+ switch (v.getId()) {
+ case android.R.id.text1:
+ mActivity.startActivityForResult(
+ mSupportFeatureProvider.getAccountLoginIntent(),
+ 0 /* requestCode */);
+ break;
+ case android.R.id.text2:
+ mActivity.startActivityForResult(
+ mSupportFeatureProvider.getSignInHelpIntent(mActivity),
+ 0 /* requestCode */);
+ break;
+ }
+ } else {
+ switch (v.getId()) {
+ case android.R.id.text1:
+ tryStartDisclaimerAndSupport(PHONE);
+ break;
+ case android.R.id.text2:
+ tryStartDisclaimerAndSupport(CHAT);
+ break;
+ }
+ }
+ }
+ }
+
+ /**
+ * {@link RecyclerView.ViewHolder} for support items.
+ */
+ static final class ViewHolder extends RecyclerView.ViewHolder {
+
+ final ImageView iconView;
+ final TextView text1View;
+ final TextView text2View;
+ final TextView summary1View;
+ final TextView summary2View;
+
+ ViewHolder(View itemView) {
+ super(itemView);
+ iconView = (ImageView) itemView.findViewById(android.R.id.icon);
+ text1View = (TextView) itemView.findViewById(android.R.id.text1);
+ text2View = (TextView) itemView.findViewById(android.R.id.text2);
+ summary1View = (TextView) itemView.findViewById(R.id.summary1);
+ summary2View = (TextView) itemView.findViewById(R.id.summary2);
+ }
+ }
+
+ /**
+ * Data for a single support item.
+ */
+ private static final class SupportData {
+
+ final Intent intent;
+ @LayoutRes
+ final int type;
+ @DrawableRes
+ final int icon;
+ @StringRes
+ final int text1;
+ @StringRes
+ final int text2;
+ final String summary1;
+ final String summary2;
+
+ private SupportData(Builder builder) {
+ this.type = builder.mType;
+ this.icon = builder.mIcon;
+ this.text1 = builder.mText1;
+ this.text2 = builder.mText2;
+ this.summary1 = builder.mSummary1;
+ this.summary2 = builder.mSummary2;
+ this.intent = builder.mIntent;
+ }
+
+ static final class Builder {
+ @LayoutRes
+ private final int mType;
+ @DrawableRes
+ private int mIcon;
+ @StringRes
+ private int mText1;
+ @StringRes
+ private int mText2;
+ private String mSummary1;
+ private String mSummary2;
+ private Intent mIntent;
+
+ Builder(@LayoutRes int type) {
+ mType = type;
+ }
+
+ Builder setIcon(@DrawableRes int icon) {
+ mIcon = icon;
+ return this;
+ }
+
+ Builder setText1(@StringRes int text1) {
+ mText1 = text1;
+ return this;
+ }
+
+ Builder setSummary1(String summary1) {
+ mSummary1 = summary1;
+ return this;
+ }
+
+ Builder setText2(@StringRes int text2) {
+ mText2 = text2;
+ return this;
+ }
+
+ Builder setSummary2(String summary2) {
+ mSummary2 = summary2;
+ return this;
+ }
+
+ Builder setIntent(Intent intent) {
+ mIntent = intent;
+ return this;
+ }
+
+ SupportData build() {
+ return new SupportData(this);
+ }
+ }
+ }
+}
diff --git a/src/com/android/settings/deletionhelper/AppDeletionPreference.java b/src/com/android/settings/deletionhelper/AppDeletionPreference.java
new file mode 100644
index 0000000..97420c2
--- /dev/null
+++ b/src/com/android/settings/deletionhelper/AppDeletionPreference.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+package com.android.settings.deletionhelper;
+
+import android.content.Context;
+import android.support.v14.preference.SwitchPreference;
+import android.support.v7.preference.Preference;
+import android.support.v7.preference.PreferenceViewHolder;
+import android.text.format.Formatter;
+import android.view.View;
+import android.widget.Switch;
+import android.widget.TextView;
+import com.android.settings.deletionhelper.AppStateUsageStatsBridge.UsageStatsState;
+import com.android.settings.R;
+
+import com.android.settingslib.applications.ApplicationsState;
+import com.android.settingslib.applications.ApplicationsState.AppEntry;
+
+/**
+ * Preference item for an app with a switch to signify if it should be uninstalled.
+ * This shows the name and icon of the app along with the days since its last use.
+ */
+public class AppDeletionPreference extends SwitchPreference {
+ private AppEntry mEntry;
+ private Context mContext;
+
+ public AppDeletionPreference(Context context, AppEntry item, ApplicationsState state) {
+ super(context);
+ mEntry = item;
+ mContext = context;
+ setLayoutResource(com.android.settings.R.layout.preference_app);
+ setWidgetLayoutResource(R.layout.widget_text_views);
+
+ synchronized (item) {
+ state.ensureIcon(item);
+ if (item.icon != null)
+ setIcon(item.icon);
+ if (item.label != null)
+ setTitle(item.label);
+ }
+ }
+
+ @Override
+ public void onBindViewHolder(PreferenceViewHolder holder) {
+ super.onBindViewHolder(holder);
+ Switch switchWidget = (Switch) holder.findViewById(com.android.internal.R.id.switch_widget);
+ switchWidget.setVisibility(View.VISIBLE);
+
+ TextView summary = (TextView) holder.findViewById(R.id.widget_text1);
+ updateSummaryText(summary);
+ }
+
+ public String getPackageName() {
+ return mEntry.label;
+ }
+
+ private void updateSummaryText(TextView summary) {
+ if (mEntry.extraInfo == null) return;
+ if (mEntry.size == ApplicationsState.SIZE_UNKNOWN ||
+ mEntry.size == ApplicationsState.SIZE_INVALID) {
+ return;
+ }
+
+ UsageStatsState extraData = (UsageStatsState) mEntry.extraInfo;
+ String fileSize = Formatter.formatFileSize(mContext, mEntry.size);
+ if (extraData.daysSinceLastUse == AppStateUsageStatsBridge.NEVER_USED) {
+ summary.setText(mContext.getString(R.string.deletion_helper_app_summary_never_used,
+ fileSize));
+ } else if (extraData.daysSinceLastUse == AppStateUsageStatsBridge.UNKNOWN_LAST_USE) {
+ summary.setText(mContext.getString(R.string.deletion_helper_app_summary_unknown_used,
+ fileSize));
+ } else {
+ summary.setText(mContext.getString(R.string.deletion_helper_app_summary,
+ fileSize,
+ extraData.daysSinceLastUse));
+ }
+ }
+
+}
diff --git a/src/com/android/settings/deletionhelper/AppStateUsageStatsBridge.java b/src/com/android/settings/deletionhelper/AppStateUsageStatsBridge.java
new file mode 100644
index 0000000..36c4196
--- /dev/null
+++ b/src/com/android/settings/deletionhelper/AppStateUsageStatsBridge.java
@@ -0,0 +1,152 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.settings.deletionhelper;
+
+import android.app.usage.UsageStats;
+import android.app.usage.UsageStatsManager;
+import android.content.Context;
+import android.content.pm.ApplicationInfo;
+
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.util.Log;
+import com.android.settings.applications.AppStateBaseBridge;
+import com.android.settingslib.applications.ApplicationsState;
+import com.android.settingslib.applications.ApplicationsState.AppEntry;
+import com.android.settingslib.applications.ApplicationsState.AppFilter;
+
+import java.util.ArrayList;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Connects data from the UsageStatsManager to the ApplicationsState.
+ */
+public class AppStateUsageStatsBridge extends AppStateBaseBridge {
+ private static final String TAG = "AppStateUsageStatsBridge";
+ private UsageStatsManager mUsageStatsManager;
+ private PackageManager mPm;
+ public static final long NEVER_USED = -1;
+ public static final long UNKNOWN_LAST_USE = -2;
+
+ public AppStateUsageStatsBridge(Context context, ApplicationsState appState,
+ Callback callback) {
+ super(appState, callback);
+ mUsageStatsManager =
+ (UsageStatsManager) context.getSystemService(Context.USAGE_STATS_SERVICE);
+ mPm = context.getPackageManager();
+ }
+
+ @Override
+ protected void loadAllExtraInfo() {
+ ArrayList<AppEntry> apps = mAppSession.getAllApps();
+ if (apps == null) return;
+
+ final Map<String, UsageStats> map = mUsageStatsManager.queryAndAggregateUsageStats(0,
+ System.currentTimeMillis());
+ for (AppEntry entry : apps) {
+ UsageStats usageStats = map.get(entry.info.packageName);
+ entry.extraInfo = new UsageStatsState(getDaysSinceLastUse(usageStats),
+ getDaysSinceInstalled(entry.info.packageName));
+ }
+ }
+
+ @Override
+ protected void updateExtraInfo(AppEntry app, String pkg, int uid) {
+ Map<String, UsageStats> map = mUsageStatsManager.queryAndAggregateUsageStats(0,
+ System.currentTimeMillis());
+ UsageStats usageStats = map.get(app.info.packageName);
+ app.extraInfo = new UsageStatsState(getDaysSinceLastUse(usageStats),
+ getDaysSinceInstalled(app.info.packageName));
+ }
+
+ private long getDaysSinceLastUse(UsageStats stats) {
+ if (stats == null) {
+ return NEVER_USED;
+ }
+ long lastUsed = stats.getLastTimeUsed();
+ // Sometimes, a usage is recorded without a time and we don't know when the use was.
+ if (lastUsed == 0) {
+ return UNKNOWN_LAST_USE;
+ }
+ return TimeUnit.MILLISECONDS.toDays(System.currentTimeMillis() - lastUsed);
+ }
+
+ private long getDaysSinceInstalled(String packageName) {
+ PackageInfo pi = null;
+ try {
+ pi = mPm.getPackageInfo(packageName, 0);
+ } catch (PackageManager.NameNotFoundException e) {
+ Log.e(TAG, packageName + " was not found.");
+ }
+
+ if (pi == null) {
+ return NEVER_USED;
+ }
+
+ return (TimeUnit.MILLISECONDS.toDays(System.currentTimeMillis() - pi.firstInstallTime));
+ }
+
+ /**
+ * Filters only non-system apps which haven't been used in the last 60 days. If an app's last
+ * usage is unknown, it is skipped.
+ */
+ public static final AppFilter FILTER_USAGE_STATS = new AppFilter() {
+ private long UNUSED_DAYS_DELETION_THRESHOLD = 60;
+
+ @Override
+ public void init() {
+ }
+
+ @Override
+ public boolean filterApp(AppEntry info) {
+ if (info == null) return false;
+ return isExtraInfoValid(info.extraInfo) && !isBundled(info)
+ && !isPersistentProcess(info);
+ }
+
+ private boolean isExtraInfoValid(Object extraInfo) {
+ if (extraInfo == null || !(extraInfo instanceof UsageStatsState)) {
+ return false;
+ }
+
+ UsageStatsState state = (UsageStatsState) extraInfo;
+ long mostRecentUse = Math.max(state.daysSinceFirstInstall, state.daysSinceLastUse);
+ return mostRecentUse >= UNUSED_DAYS_DELETION_THRESHOLD || mostRecentUse == NEVER_USED;
+ }
+
+ private boolean isBundled(AppEntry info) {
+ return (info.info.flags & ApplicationInfo.FLAG_SYSTEM) != 0;
+ }
+
+ private boolean isPersistentProcess(AppEntry info) {
+ return (info.info.flags & ApplicationInfo.FLAG_PERSISTENT) != 0;
+ }
+ };
+
+ /**
+ * UsageStatsState contains the days since the last use and first install of a given app.
+ */
+ public static class UsageStatsState {
+ public long daysSinceLastUse;
+ public long daysSinceFirstInstall;
+
+ public UsageStatsState(long daysSinceLastUse, long daysSinceFirstInstall) {
+ this.daysSinceLastUse = daysSinceLastUse;
+ this.daysSinceFirstInstall = daysSinceFirstInstall;
+ }
+ }
+}
diff --git a/src/com/android/settings/deletionhelper/AutomaticStorageManagerSettings.java b/src/com/android/settings/deletionhelper/AutomaticStorageManagerSettings.java
new file mode 100644
index 0000000..bb99725
--- /dev/null
+++ b/src/com/android/settings/deletionhelper/AutomaticStorageManagerSettings.java
@@ -0,0 +1,104 @@
+/**
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.deletionhelper;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.util.Log;
+import android.view.View;
+import android.widget.Switch;
+import android.support.v14.preference.SwitchPreference;
+import android.support.v7.preference.DropDownPreference;
+import android.support.v7.preference.Preference;
+import android.support.v7.preference.Preference.OnPreferenceChangeListener;
+import android.support.v7.preference.PreferenceScreen;
+
+import com.android.internal.logging.MetricsProto.MetricsEvent;
+import com.android.settings.SettingsActivity;
+import com.android.settings.SettingsPreferenceFragment;
+import com.android.settings.R;
+import com.android.settings.widget.SwitchBar;
+import com.android.settings.widget.SwitchBar.OnSwitchChangeListener;
+
+/**
+ * AutomaticStorageManagerSettings is the Settings screen for configuration and management of the
+ * automatic storage manager.
+ */
+public class AutomaticStorageManagerSettings extends SettingsPreferenceFragment implements
+ OnPreferenceChangeListener, Preference.OnPreferenceClickListener {
+ private static final String KEY_DAYS = "days";
+ private static final String KEY_DELETION_HELPER = "deletion_helper";
+ private static final String KEY_STORAGE_MANAGER_SWITCH = "storage_manager_active";
+
+ private DropDownPreference mDaysToRetain;
+ private Preference mDeletionHelper;
+ private SwitchPreference mStorageManagerSwitch;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ addPreferencesFromResource(R.xml.automatic_storage_management_settings);
+ }
+
+ @Override
+ public void onActivityCreated(Bundle savedInstanceState) {
+ super.onActivityCreated(savedInstanceState);
+ mDaysToRetain = (DropDownPreference) findPreference(KEY_DAYS);
+ mDaysToRetain.setOnPreferenceChangeListener(this);
+
+ mDeletionHelper = findPreference(KEY_DELETION_HELPER);
+ mDeletionHelper.setOnPreferenceClickListener(this);
+
+ mStorageManagerSwitch = (SwitchPreference) findPreference(KEY_STORAGE_MANAGER_SWITCH);
+ mStorageManagerSwitch.setOnPreferenceChangeListener(this);
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ mDaysToRetain.setEnabled(mStorageManagerSwitch.isChecked());
+ }
+
+ @Override
+ public boolean onPreferenceChange(Preference preference, Object newValue) {
+ switch (preference.getKey()) {
+ case KEY_STORAGE_MANAGER_SWITCH:
+ boolean checked = (boolean) newValue;
+ mDaysToRetain.setEnabled(checked);
+ break;
+ case KEY_DAYS:
+ // TODO: Configure a setting which controls how many days of data the storage manager
+ // should retain.
+ break;
+ }
+ return true;
+ }
+
+ @Override
+ protected int getMetricsCategory() {
+ return MetricsEvent.STORAGE_MANAGER_SETTINGS;
+ }
+
+ @Override
+ public boolean onPreferenceClick(Preference preference) {
+ if (KEY_DELETION_HELPER.equals(preference.getKey())) {
+ startFragment(this, DeletionHelperFragment.class.getCanonicalName(),
+ R.string.deletion_helper_title, 0, null);
+ }
+ return true;
+ }
+}
diff --git a/src/com/android/settings/deletionhelper/ConfirmDeletionDialog.java b/src/com/android/settings/deletionhelper/ConfirmDeletionDialog.java
new file mode 100644
index 0000000..fc6033e
--- /dev/null
+++ b/src/com/android/settings/deletionhelper/ConfirmDeletionDialog.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.deletionhelper;
+
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.app.DialogFragment;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.os.Bundle;
+import android.text.format.Formatter;
+import com.android.settings.R;
+
+/**
+ * Fragment used to confirm that the user wishes to delete a certain amount of data.
+ */
+public class ConfirmDeletionDialog extends DialogFragment implements
+ DialogInterface.OnClickListener {
+ public static final String TAG = "ConfirmDeletionDialog";
+ private static final String ARG_TOTAL_SPACE = "total_freeable";
+
+ public static ConfirmDeletionDialog newInstance(long freeableBytes) {
+ Bundle args = new Bundle(1);
+ args.putLong(ARG_TOTAL_SPACE, freeableBytes);
+
+ ConfirmDeletionDialog dialog = new ConfirmDeletionDialog();
+ dialog.setArguments(args);
+
+ return dialog;
+ }
+
+ @Override
+ public Dialog onCreateDialog(Bundle savedInstanceState) {
+ final Bundle args = getArguments();
+ long totalFreeableSpace = args.getLong(ARG_TOTAL_SPACE);
+
+ final Context context = getContext();
+ return new AlertDialog.Builder(context)
+ .setMessage(context.getString(R.string.deletion_helper_clear_dialog_message,
+ Formatter.formatFileSize(context, totalFreeableSpace)))
+ .setPositiveButton(R.string.deletion_helper_clear_dialog_remove, this)
+ .setNegativeButton(android.R.string.cancel, null)
+ .create();
+ }
+
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ ((DeletionHelperFragment) getTargetFragment()).clearData();
+ }
+}
diff --git a/src/com/android/settings/deletionhelper/DeletionHelperFragment.java b/src/com/android/settings/deletionhelper/DeletionHelperFragment.java
new file mode 100644
index 0000000..85c1035
--- /dev/null
+++ b/src/com/android/settings/deletionhelper/DeletionHelperFragment.java
@@ -0,0 +1,414 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.deletionhelper;
+
+import android.app.Activity;
+import android.app.Application;
+import android.content.Intent;
+import android.os.Bundle;
+import android.support.v7.preference.Preference;
+import android.text.format.Formatter;
+import android.util.ArraySet;
+import android.util.Log;
+import android.view.View;
+import android.widget.Button;
+import com.android.settings.CollapsibleCheckboxPreferenceGroup;
+import com.android.settings.PhotosDeletionPreference;
+import com.android.settings.SettingsPreferenceFragment;
+import com.android.settings.R;
+import com.android.internal.logging.MetricsProto.MetricsEvent;
+import com.android.settings.applications.AppStateBaseBridge;
+import com.android.settings.overlay.DeletionHelperFeatureProvider;
+import com.android.settings.overlay.FeatureFactory;
+import com.android.settingslib.applications.ApplicationsState;
+import com.android.settingslib.applications.ApplicationsState.AppEntry;
+import com.android.settingslib.applications.ApplicationsState.Callbacks;
+import com.android.settingslib.applications.ApplicationsState.Session;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+
+/**
+ * Settings screen for the deletion helper, which manually removes data which is not recently used.
+ */
+public class DeletionHelperFragment extends SettingsPreferenceFragment implements
+ ApplicationsState.Callbacks, AppStateBaseBridge.Callback,
+ Preference.OnPreferenceChangeListener, DeletionType.FreeableChangedListener,
+ View.OnClickListener {
+ public static final int CLEAR_DATA_RESULT = 1;
+ public static final String FREED_BYTES_KEY = "freed";
+
+ private static final String TAG = "DeletionHelperFragment";
+
+ private static final String EXTRA_HAS_BRIDGE = "hasBridge";
+ private static final String EXTRA_HAS_SIZES = "hasSizes";
+ private static final String EXTRA_CHECKED_SET = "checkedSet";
+
+ private static final String KEY_APPS_GROUP = "apps_group";
+ private static final String KEY_PHOTOS_VIDEOS_PREFERENCE = "delete_photos";
+ private static final String KEY_DOWNLOADS_PREFERENCE = "delete_downloads";
+
+ private static final int DOWNLOADS_LOADER_ID = 1;
+
+ private Button mCancel, mFree;
+ private CollapsibleCheckboxPreferenceGroup mApps;
+ private PhotosDeletionPreference mPhotoPreference;
+ private DownloadsDeletionPreferenceGroup mDownloadsPreference;
+
+ private ApplicationsState mState;
+ private Session mSession;
+ private HashSet<String> mCheckedApplications;
+ private AppStateUsageStatsBridge mDataUsageBridge;
+ private ArrayList<AppEntry> mAppEntries;
+ private boolean mHasReceivedAppEntries, mHasReceivedBridgeCallback, mFinishedLoading;
+ private DeletionHelperFeatureProvider mProvider;
+ private DeletionType mPhotoVideoDeletion;
+ private DownloadsDeletionType mDownloadsDeletion;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setAnimationAllowed(true);
+ Application app = getActivity().getApplication();
+ mState = ApplicationsState.getInstance(app);
+ mSession = mState.newSession(this);
+ mCheckedApplications = new HashSet<>();
+ mDataUsageBridge = new AppStateUsageStatsBridge(getActivity(), mState, this);
+
+ addPreferencesFromResource(R.xml.deletion_helper_list);
+ mApps = (CollapsibleCheckboxPreferenceGroup) findPreference(KEY_APPS_GROUP);
+ mPhotoPreference = (PhotosDeletionPreference) findPreference(KEY_PHOTOS_VIDEOS_PREFERENCE);
+ mDownloadsPreference =
+ (DownloadsDeletionPreferenceGroup) findPreference(KEY_DOWNLOADS_PREFERENCE);
+ mProvider =
+ FeatureFactory.getFactory(app).getDeletionHelperFeatureProvider();
+ if (mProvider != null) {
+ mPhotoVideoDeletion = mProvider.createPhotoVideoDeletionType(getContext());
+ }
+ mDownloadsDeletion = new DownloadsDeletionType(getActivity());
+
+ if (savedInstanceState != null) {
+ mHasReceivedAppEntries =
+ savedInstanceState.getBoolean(EXTRA_HAS_SIZES, false);
+ mHasReceivedBridgeCallback =
+ savedInstanceState.getBoolean(EXTRA_HAS_BRIDGE, false);
+ mCheckedApplications =
+ (HashSet<String>) savedInstanceState.getSerializable(EXTRA_CHECKED_SET);
+ }
+ }
+
+ private void initializeButtons(View v) {
+ mCancel = (Button) v.findViewById(R.id.skip_button);
+ mCancel.setText(R.string.cancel);
+ mCancel.setOnClickListener(this);
+ mCancel.setVisibility(View.VISIBLE);
+
+ mFree = (Button) v.findViewById(R.id.next_button);
+ mFree.setText(R.string.storage_menu_free);
+ mFree.setOnClickListener(this);
+
+ Button back = (Button) v.findViewById(R.id.back_button);
+ back.setVisibility(View.GONE);
+ }
+
+ private void initializeDeletionPreferences() {
+ if (mProvider == null) {
+ getPreferenceScreen().removePreference(mPhotoPreference);
+ mPhotoPreference = null;
+ } else {
+ mPhotoPreference.registerFreeableChangedListener(this);
+ mPhotoPreference.registerDeletionService(mPhotoVideoDeletion);
+ }
+
+ mDownloadsPreference.registerFreeableChangedListener(this);
+ mDownloadsPreference.registerDeletionService(mDownloadsDeletion);
+ mApps.setOnPreferenceChangeListener(this);
+ }
+
+ @Override
+ public void onViewCreated(View v, Bundle savedInstanceState) {
+ super.onViewCreated(v, savedInstanceState);
+ initializeButtons(v);
+ initializeDeletionPreferences();
+ setLoading(true, false);
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ mSession.resume();
+ mDataUsageBridge.resume();
+ mDownloadsDeletion.onResume();
+ getLoaderManager().initLoader(DOWNLOADS_LOADER_ID, new Bundle(), mDownloadsDeletion);
+
+ if (mPhotoVideoDeletion != null) {
+ mPhotoVideoDeletion.onResume();
+ }
+ }
+
+
+ @Override
+ public void onSaveInstanceState(Bundle outState) {
+ super.onSaveInstanceState(outState);
+ outState.putBoolean(EXTRA_HAS_SIZES, mHasReceivedAppEntries);
+ outState.putBoolean(EXTRA_HAS_BRIDGE, mHasReceivedBridgeCallback);
+ outState.putSerializable(EXTRA_CHECKED_SET, mCheckedApplications);
+ }
+
+
+ @Override
+ public void onPause() {
+ super.onPause();
+ mDataUsageBridge.pause();
+ mSession.pause();
+ mDownloadsDeletion.onPause();
+
+ if (mPhotoVideoDeletion != null) {
+ mPhotoVideoDeletion.onPause();
+ }
+ }
+
+ private void rebuild() {
+ // Only rebuild if we have the packages and their usage stats.
+ if (!mHasReceivedBridgeCallback || !mHasReceivedAppEntries) {
+ return;
+ }
+
+ final ArrayList<AppEntry> apps =
+ mSession.rebuild(AppStateUsageStatsBridge.FILTER_USAGE_STATS,
+ ApplicationsState.SIZE_COMPARATOR);
+ if (apps == null) return;
+ mAppEntries = apps;
+ refreshAppGroup(apps);
+
+ // All applications should be filled in if we've received the sizes.
+ // setLoading being called multiple times causes flickering, so we only do it once.
+ if (mHasReceivedAppEntries && !mFinishedLoading) {
+ mFinishedLoading = true;
+ setLoading(false, true);
+ getButtonBar().setVisibility(View.VISIBLE);
+ }
+ updateFreeButtonText();
+ }
+
+ private void updateFreeButtonText() {
+ mFree.setText(String.format(getActivity().getString(R.string.deletion_helper_free_button),
+ Formatter.formatFileSize(getActivity(), getTotalFreeableSpace())));
+ }
+
+ @Override
+ public void onRunningStateChanged(boolean running) {
+ // No-op.
+ }
+
+ @Override
+ public void onPackageListChanged() {
+ rebuild();
+ }
+
+ @Override
+ public void onRebuildComplete(ArrayList<AppEntry> apps) {
+ }
+
+ @Override
+ public void onPackageIconChanged() {
+ }
+
+ @Override
+ public void onPackageSizeChanged(String packageName) {
+ rebuild();
+ }
+
+ @Override
+ public void onAllSizesComputed() {
+ rebuild();
+ }
+
+ @Override
+ public void onLauncherInfoChanged() {
+ }
+
+ @Override
+ public void onLoadEntriesCompleted() {
+ mHasReceivedAppEntries = true;
+ rebuild();
+ }
+
+ @Override
+ public void onExtraInfoUpdated() {
+ mHasReceivedBridgeCallback = true;
+ rebuild();
+ }
+
+ @Override
+ protected int getMetricsCategory() {
+ return MetricsEvent.DEVICEINFO_STORAGE;
+ }
+
+ @Override
+ public boolean onPreferenceChange(Preference preference, Object newValue) {
+ boolean checked = (boolean) newValue;
+ if (preference.getKey().equals(mApps.getKey())) {
+ return toggleAllApps(checked);
+ }
+
+ String packageName = ((AppDeletionPreference) preference).getPackageName();
+ if (checked) {
+ mCheckedApplications.add(packageName);
+ } else {
+ mCheckedApplications.remove(packageName);
+
+ // We remove the preference change listener to avoid toggling every app on and off.
+ mApps.setOnPreferenceChangeListener(null);
+ mApps.setChecked(false);
+ mApps.setOnPreferenceChangeListener(this);
+ }
+ updateFreeButtonText();
+ return true;
+ }
+
+ @Override
+ public void onFreeableChanged(int numItems, long freeableBytes) {
+ updateFreeButtonText();
+ }
+
+ @Override
+ public void onClick(View v) {
+ if (v.getId() == mFree.getId()) {
+ ConfirmDeletionDialog dialog =
+ ConfirmDeletionDialog.newInstance(getTotalFreeableSpace());
+ // The 0 is a placeholder for an optional result code.
+ dialog.setTargetFragment(this, 0);
+ dialog.show(getFragmentManager(), ConfirmDeletionDialog.TAG);
+ } else {
+ finishFragment();
+ }
+ }
+
+ /**
+ * Clears out the selected apps and data from the device and closes the fragment.
+ */
+ protected void clearData() {
+ // This should be fine as long as there is only one extra deletion feature.
+ // In the future, this should be done in an async queue in order to not
+ // interfere with the simultaneous PackageDeletionTask.
+ if (mPhotoPreference != null && mPhotoPreference.isChecked()) {
+ mPhotoVideoDeletion.clearFreeableData();
+ }
+ mDownloadsDeletion.clearFreeableData();
+
+ ArraySet<String> apps = new ArraySet<>();
+ for (AppEntry entry : mAppEntries) {
+ if (mCheckedApplications.contains(entry.label)) {
+ synchronized (entry) {
+ apps.add(entry.info.packageName);
+ }
+ }
+ }
+ // TODO: If needed, add an action on the callback.
+ PackageDeletionTask task = new PackageDeletionTask(getActivity().getPackageManager(), apps,
+ new PackageDeletionTask.Callback() {
+ @Override
+ public void onSuccess() {
+ }
+
+ @Override
+ public void onError() {
+ Log.e(TAG, "An error occurred while uninstalling packages.");
+ }
+ });
+ Intent data = new Intent();
+ data.putExtra(FREED_BYTES_KEY, getTotalFreeableSpace());
+ getActivity().setResult(CLEAR_DATA_RESULT, data);
+
+ task.run();
+ finishFragment();
+ }
+
+ private long getTotalFreeableSpace() {
+ long freeableSpace = 0;
+ freeableSpace += getTotalAppsFreeableSpace(false);
+ if (mPhotoPreference != null) {
+ freeableSpace += mPhotoPreference.getFreeableBytes();
+ }
+ freeableSpace += mDownloadsDeletion.getFreeableBytes();
+ return freeableSpace;
+ }
+
+ private void refreshAppGroup(ArrayList<AppEntry> apps) {
+ int entryCount = apps.size();
+ cacheRemoveAllPrefs(mApps);
+ for (int i = 0; i < entryCount; i++) {
+ AppEntry entry = apps.get(i);
+ final String packageName = entry.label;
+ AppDeletionPreference preference =
+ (AppDeletionPreference) getCachedPreference(entry.label);
+ if (preference == null) {
+ preference = new AppDeletionPreference(getActivity(), entry, mState);
+ preference.setKey(packageName);
+ preference.setOnPreferenceChangeListener(this);
+ mApps.addPreference(preference);
+ }
+ preference.setChecked(mCheckedApplications.contains(packageName));
+ preference.setOrder(i);
+ }
+ removeCachedPrefs(mApps);
+ updateAppsGroupText();
+ }
+
+ private long getTotalAppsFreeableSpace(boolean countUnchecked) {
+ long freeableSpace = 0;
+ if (mAppEntries != null) {
+ for (int i = 0; i < mAppEntries.size(); i++) {
+ final AppEntry entry = mAppEntries.get(i);
+ long entrySize = mAppEntries.get(i).size;
+ // If the entrySize is negative, it is either an unknown size or an error occurred.
+ if ((countUnchecked ||
+ mCheckedApplications.contains(entry.label)) && entrySize > 0) {
+ freeableSpace += entrySize;
+ }
+ }
+ }
+
+ return freeableSpace;
+ }
+
+ private void updateAppsGroupText() {
+ if (mAppEntries != null) {
+ Activity app = getActivity();
+ mApps.setTitle(app.getString(R.string.deletion_helper_apps_group_title,
+ mAppEntries.size()));
+ mApps.setSummary(app.getString(R.string.deletion_helper_apps_group_summary,
+ Formatter.formatFileSize(app,
+ getTotalAppsFreeableSpace(true))));
+ }
+ }
+
+ private boolean toggleAllApps(boolean checked) {
+ for (AppEntry entry : mAppEntries) {
+ final String packageName = entry.label;
+ if (checked) {
+ mCheckedApplications.add(packageName);
+ } else {
+ mCheckedApplications.remove(packageName);
+ }
+ }
+ refreshAppGroup(mAppEntries);
+ updateFreeButtonText();
+ return true;
+ }
+}
\ No newline at end of file
diff --git a/src/com/android/settings/deletionhelper/DeletionType.java b/src/com/android/settings/deletionhelper/DeletionType.java
new file mode 100644
index 0000000..ee1e0f7
--- /dev/null
+++ b/src/com/android/settings/deletionhelper/DeletionType.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.deletionhelper;
+
+import android.content.Context;
+import android.support.v7.preference.PreferenceGroup;
+import android.support.v7.preference.Preference;
+
+/**
+ * Helper for the Deletion Helper which can query, clear out, and visualize deletable data.
+ * This could represent a helper for deleting photos, downloads, movies, etc.
+ */
+public interface DeletionType {
+ /**
+ * Registers a callback to call when the amount of freeable space is updated.
+ * @param listener A callback.
+ */
+ void registerFreeableChangedListener(FreeableChangedListener listener);
+
+ /**
+ * Resumes an operation, intended to be called when the deletion fragment resumes.
+ */
+ void onResume();
+
+ /**
+ * Pauses the feature's operations, intended to be called when the deletion fragment is paused.
+ */
+ void onPause();
+
+ /**
+ * Asynchronously free up the freeable information for the feature.
+ */
+ void clearFreeableData();
+
+ /**
+ * Callback interface to listen for when a deletion feature's amount of freeable space updates.
+ */
+ interface FreeableChangedListener {
+ void onFreeableChanged(int numItems, long bytesFreeable);
+ }
+}
diff --git a/src/com/android/settings/deletionhelper/DownloadsDeletionPreferenceGroup.java b/src/com/android/settings/deletionhelper/DownloadsDeletionPreferenceGroup.java
new file mode 100644
index 0000000..440b962
--- /dev/null
+++ b/src/com/android/settings/deletionhelper/DownloadsDeletionPreferenceGroup.java
@@ -0,0 +1,157 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.deletionhelper;
+
+import android.content.Context;
+import android.support.v7.preference.Preference;
+import android.text.format.DateUtils;
+import android.text.format.Formatter;
+import android.util.ArrayMap;
+import android.util.AttributeSet;
+import com.android.settings.CollapsibleCheckboxPreferenceGroup;
+import com.android.settings.R;
+
+import java.io.File;
+import java.util.Set;
+
+/**
+ * DownloadsDeletionPreferenceGroup defines a checkable preference group which contains
+ * downloads file deletion preferences.
+ */
+public class DownloadsDeletionPreferenceGroup extends CollapsibleCheckboxPreferenceGroup
+ implements DeletionType.FreeableChangedListener, Preference.OnPreferenceChangeListener {
+ private DownloadsDeletionType mDeletionType;
+ private DeletionType.FreeableChangedListener mListener;
+
+ public DownloadsDeletionPreferenceGroup(Context context) {
+ this(context, null);
+ }
+
+ public DownloadsDeletionPreferenceGroup(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ setOrderingAsAdded(false);
+ setOnPreferenceChangeListener(this);
+ }
+
+ /**
+ * Set up a deletion type to get info for the preference group.
+ * @param type A {@link DownloadsDeletionType}.
+ */
+ public void registerDeletionService(DownloadsDeletionType type) {
+ mDeletionType = type;
+ mDeletionType.registerFreeableChangedListener(this);
+ }
+
+ /**
+ * Registers a callback to be called when the amount of freeable space updates.
+ * @param listener The callback listener.
+ */
+ public void registerFreeableChangedListener(DeletionType.FreeableChangedListener listener) {
+ mListener = listener;
+ }
+
+ @Override
+ public void onFreeableChanged(int numItems, long freeableBytes) {
+ updatePreferenceText(numItems, freeableBytes, mDeletionType.getMostRecentLastModified());
+ maybeUpdateListener(numItems, freeableBytes);
+ updateFiles();
+ }
+
+ @Override
+ public boolean onPreferenceChange(Preference preference, Object newValue) {
+ boolean checked = (boolean) newValue;
+ if (!checked) {
+ // Temporarily stop listening to avoid propagating the checked change to children.
+ setOnPreferenceChangeListener(null);
+ setChecked(false);
+ setOnPreferenceChangeListener(this);
+ }
+
+ // If the group checkbox changed, we need to toggle every child preference.
+ if (preference == this) {
+ for (int i = 0; i < getPreferenceCount(); i++) {
+ DownloadsFilePreference p = (DownloadsFilePreference) getPreference(i);
+ p.setOnPreferenceChangeListener(null);
+ mDeletionType.toggleFile(p.getFile(), checked);
+ p.setChecked(checked);
+ p.setOnPreferenceChangeListener(this);
+ }
+ maybeUpdateListener(mDeletionType.getFiles().size(), mDeletionType.getFreeableBytes());
+ return true;
+ }
+
+ // If a single DownloadFilePreference changed, we need to toggle just itself.
+ DownloadsFilePreference p = (DownloadsFilePreference) preference;
+ mDeletionType.toggleFile(p.getFile(), checked);
+ maybeUpdateListener(mDeletionType.getFiles().size(), mDeletionType.getFreeableBytes());
+ return true;
+ }
+
+
+ private void updatePreferenceText(int itemCount, long bytes, long mostRecent) {
+ Context context = getContext();
+ setTitle(context.getString(R.string.deletion_helper_downloads_title, itemCount));
+ // If there are no files to clear, show the empty text instead.
+ if (itemCount != 0) {
+ setSummary(context.getString(R.string.deletion_helper_downloads_summary,
+ Formatter.formatFileSize(context, bytes),
+ DateUtils.getRelativeTimeSpanString(mostRecent,
+ System.currentTimeMillis(),
+ DateUtils.DAY_IN_MILLIS,
+ DateUtils.FORMAT_ABBREV_RELATIVE)));
+ } else {
+ setSummary(context.getString(R.string.deletion_helper_downloads_summary_empty,
+ Formatter.formatFileSize(context, bytes)));
+ }
+ }
+
+ private void maybeUpdateListener(int numItems, long bytesFreeable) {
+ if (mListener != null) {
+ mListener.onFreeableChanged(numItems, bytesFreeable);
+ }
+ }
+
+ private void updateFiles() {
+ // TODO: Remove impl overlap with the cached preferences methods in
+ // SettingsPreferenceFragment.
+
+ // Cache the existing file preferences.
+ ArrayMap<String, Preference> cachedPreferences = new ArrayMap<>();
+ for (int i = 0; i < getPreferenceCount(); i++) {
+ Preference p = getPreference(i);
+ cachedPreferences.put(p.getKey(), p);
+ }
+
+ // Iterate over all of the files and re-use the old file preference, if it exists.
+ Set<File> files = mDeletionType.getFiles();
+ for (File file : files) {
+ DownloadsFilePreference filePreference =
+ (DownloadsFilePreference) cachedPreferences.remove(file.getPath());
+ if (filePreference == null) {
+ filePreference = new DownloadsFilePreference(getContext(), file);
+ filePreference.setChecked(isChecked());
+ filePreference.setOnPreferenceChangeListener(this);
+ }
+ addPreference(filePreference);
+ }
+
+ // Remove all of the unused preferences.
+ for (Preference p : cachedPreferences.values()) {
+ removePreference(p);
+ }
+ }
+}
diff --git a/src/com/android/settings/deletionhelper/DownloadsDeletionType.java b/src/com/android/settings/deletionhelper/DownloadsDeletionType.java
new file mode 100644
index 0000000..3a251eb
--- /dev/null
+++ b/src/com/android/settings/deletionhelper/DownloadsDeletionType.java
@@ -0,0 +1,149 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.deletionhelper;
+
+import android.app.LoaderManager.LoaderCallbacks;
+import android.content.Context;
+import android.content.Loader;
+import android.os.AsyncTask;
+import android.os.Bundle;
+import android.os.Environment;
+import android.util.ArrayMap;
+import android.util.ArraySet;
+import com.android.settings.deletionhelper.FetchDownloadsLoader.DownloadsResult;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * The DownloadsDeletionType provides stale download file information to the
+ * {@link DownloadsDeletionPreferenceGroup}.
+ */
+public class DownloadsDeletionType implements DeletionType, LoaderCallbacks<DownloadsResult> {
+ private long mBytes;
+ private long mMostRecent;
+ private FreeableChangedListener mListener;
+ private Context mContext;
+ private ArrayMap<File, Boolean> mFiles;
+
+ public DownloadsDeletionType(Context context) {
+ mContext = context;
+ mFiles = new ArrayMap<>();
+ }
+
+ @Override
+ public void registerFreeableChangedListener(FreeableChangedListener listener) {
+ mListener = listener;
+ if (mFiles != null) {
+ maybeUpdateListener();
+ }
+ }
+
+ @Override
+ public void onResume() {
+ }
+
+ @Override
+ public void onPause() {
+ }
+
+ @Override
+ public void clearFreeableData() {
+ if (mFiles != null) {
+ AsyncTask.execute(new Runnable() {
+ @Override
+ public void run() {
+ for (Map.Entry<File, Boolean> entry : mFiles.entrySet()) {
+ if (entry.getValue()) {
+ entry.getKey().delete();
+ }
+ }
+ }
+ });
+ }
+ }
+
+ @Override
+ public Loader<DownloadsResult> onCreateLoader(int id, Bundle args) {
+ return new FetchDownloadsLoader(mContext,
+ Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS));
+ }
+
+ @Override
+ public void onLoadFinished(Loader<DownloadsResult> loader, DownloadsResult data) {
+ mMostRecent = data.youngestLastModified;
+ for (File file : data.files) {
+ if (mFiles.containsKey(file)) {
+ continue;
+ }
+ mFiles.put(file, false);
+ }
+ mBytes = data.totalSize;
+ maybeUpdateListener();
+ }
+
+ @Override
+ public void onLoaderReset(Loader<DownloadsResult> loader) {
+ }
+
+ /**
+ * Returns the most recent last modified time for any clearable file.
+ * @return The last modified time.
+ */
+ public long getMostRecentLastModified() {
+ return mMostRecent;
+ }
+
+ /**
+ * Returns the files in the Downloads folder after the loader task finishes.
+ */
+ public Set<File> getFiles() {
+ if (mFiles == null) {
+ return null;
+ }
+ return mFiles.keySet();
+ }
+
+ /**
+ * Toggle if a file should be deleted when the service is asked to clear files.
+ */
+ public void toggleFile(File file, boolean checked) {
+ mFiles.put(file, checked);
+ }
+
+ /**
+ * Returns the number of bytes that would be cleared if the deletion tasks runs.
+ */
+ public long getFreeableBytes() {
+ long freedBytes = 0;
+ for (Map.Entry<File, Boolean> entry : mFiles.entrySet()) {
+ if (entry.getValue()) {
+ freedBytes += entry.getKey().length();
+ }
+ }
+ return freedBytes;
+ }
+
+ private void maybeUpdateListener() {
+ if (mListener != null) {
+ mListener.onFreeableChanged(mFiles.size(), mBytes);
+ }
+ }
+}
diff --git a/src/com/android/settings/deletionhelper/DownloadsFilePreference.java b/src/com/android/settings/deletionhelper/DownloadsFilePreference.java
new file mode 100644
index 0000000..af8f6b6
--- /dev/null
+++ b/src/com/android/settings/deletionhelper/DownloadsFilePreference.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.deletionhelper;
+
+import android.content.Context;
+import android.support.v7.preference.Preference;
+import android.support.v7.preference.CheckBoxPreference;
+import android.text.format.DateUtils;
+import android.text.format.Formatter;
+import com.android.settings.R;
+
+import java.io.File;
+
+/**
+ * DownloadsFilePreference is a preference representing a file in the Downloads folder
+ * with a checkbox that represents if the file should be deleted.
+ */
+public class DownloadsFilePreference extends CheckBoxPreference {
+ private File mFile;
+
+ public DownloadsFilePreference(Context context, File file) {
+ super(context);
+ mFile = file;
+ setKey(mFile.getPath());
+ setTitle(file.getName());
+ setSummary(context.getString(R.string.deletion_helper_downloads_summary,
+ Formatter.formatFileSize(getContext(), file.length()),
+ DateUtils.getRelativeTimeSpanString(mFile.lastModified(),
+ System.currentTimeMillis(),
+ DateUtils.DAY_IN_MILLIS,
+ DateUtils.FORMAT_ABBREV_RELATIVE)));
+ }
+
+ public File getFile() {
+ return mFile;
+ }
+
+ @Override
+ public int compareTo(Preference other) {
+ if (other == null) {
+ return 1;
+ }
+
+ if (other instanceof DownloadsFilePreference) {
+ DownloadsFilePreference preference = (DownloadsFilePreference) other;
+ return Long.compare(getFile().length(), preference.getFile().length());
+ } else {
+ // If a non-DownloadsFilePreference appears, consider ourselves to be greater.
+ // This means if a non-DownloadsFilePreference sneaks into a DownloadsPreferenceGroup
+ // then the DownloadsFilePreference will appear higher.
+ return 1;
+ }
+ }
+}
diff --git a/src/com/android/settings/deletionhelper/FetchDownloadsLoader.java b/src/com/android/settings/deletionhelper/FetchDownloadsLoader.java
new file mode 100644
index 0000000..86352c9
--- /dev/null
+++ b/src/com/android/settings/deletionhelper/FetchDownloadsLoader.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.deletionhelper;
+
+import android.content.Context;
+import android.support.annotation.VisibleForTesting;
+import com.android.settings.utils.AsyncLoader;
+
+import java.io.File;
+import java.util.ArrayList;
+
+/**
+ * FetchDownloadsLoader is an asynchronous task which returns files in the Downloads
+ * directory which have not been modified in longer than 90 days.
+ */
+public class FetchDownloadsLoader extends
+ AsyncLoader<FetchDownloadsLoader.DownloadsResult> {
+ private File mDirectory;
+
+ /**
+ * Sets up a FetchDownloadsLoader in any directory.
+ * @param directory The directory to look into.
+ */
+ public FetchDownloadsLoader(Context context, File directory) {
+ super(context);
+ mDirectory = directory;
+ }
+
+ @Override
+ protected void onDiscardResult(DownloadsResult result) {}
+
+ @Override
+ public DownloadsResult loadInBackground() {
+ return collectFiles(mDirectory);
+ }
+
+ @VisibleForTesting
+ static DownloadsResult collectFiles(File dir) {
+ return collectFiles(dir, new DownloadsResult());
+ }
+
+ private static DownloadsResult collectFiles(File dir, DownloadsResult result) {
+ File downloadFiles[] = dir.listFiles();
+ if (downloadFiles == null) {
+ }
+ if (downloadFiles != null && downloadFiles.length > 0) {
+ for (File currentFile : downloadFiles) {
+ if (currentFile.isDirectory()) {
+ collectFiles(currentFile, result);
+ } else {
+ if (currentFile.lastModified() < result.youngestLastModified) {
+ result.youngestLastModified = currentFile.lastModified();
+ }
+ result.files.add(currentFile);
+ result.totalSize += currentFile.length();
+ }
+ }
+ }
+
+ return result;
+ }
+
+ /**
+ * The DownloadsResult is the result of a {@link FetchDownloadsLoader} with the files
+ * and the amount of space they use.
+ */
+ public static class DownloadsResult {
+ public long totalSize;
+ public long youngestLastModified;
+ public ArrayList<File> files;
+
+ public DownloadsResult() {
+ this(0, Long.MAX_VALUE, new ArrayList<File>());
+ }
+
+ public DownloadsResult(long totalSize, long youngestLastModified, ArrayList<File> files) {
+ this.totalSize = totalSize;
+ this.youngestLastModified = youngestLastModified;
+ this.files = files;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/com/android/settings/deletionhelper/PackageDeletionTask.java b/src/com/android/settings/deletionhelper/PackageDeletionTask.java
new file mode 100644
index 0000000..69e6a6c
--- /dev/null
+++ b/src/com/android/settings/deletionhelper/PackageDeletionTask.java
@@ -0,0 +1,58 @@
+package com.android.settings.deletionhelper;
+
+import android.content.pm.IPackageDeleteObserver;
+import android.content.pm.PackageManager;
+import android.os.UserHandle;
+
+import java.util.Set;
+import java.util.concurrent.atomic.AtomicInteger;
+
+/**
+ * Deletes a specified set of apps as a specified user and calls back once done.
+ */
+public class PackageDeletionTask {
+ private Set<String> mPackages;
+ private Callback mCallback;
+ private PackageManager mPm;
+ private UserHandle mUser;
+
+ public PackageDeletionTask(PackageManager pm, Set<String> packageNames, Callback callback) {
+ mPackages = packageNames;
+ mCallback = callback;
+ mPm = pm;
+ mUser = android.os.Process.myUserHandle();
+ }
+
+ public void run() {
+ PackageDeletionObserver observer = new PackageDeletionObserver(mPackages.size());
+ for (String packageName : mPackages) {
+ mPm.deletePackageAsUser(packageName, observer, 0, mUser.getIdentifier());
+ }
+ }
+
+ private class PackageDeletionObserver extends IPackageDeleteObserver.Stub {
+ private final AtomicInteger mPackagesRemaining = new AtomicInteger(0);
+
+ public PackageDeletionObserver(int packages) {
+ mPackagesRemaining.set(packages);
+ }
+
+ @Override
+ public void packageDeleted(String packageName, int returnCode) {
+ if (returnCode != PackageManager.DELETE_SUCCEEDED) {
+ mCallback.onError();
+ return;
+ }
+
+ int remaining = mPackagesRemaining.decrementAndGet();
+ if (remaining == 0) {
+ mCallback.onSuccess();
+ }
+ }
+ }
+
+ public static abstract class Callback {
+ public abstract void onSuccess();
+ public abstract void onError();
+ }
+}
diff --git a/src/com/android/settings/deletionhelper/StorageManagerUpsellDialog.java b/src/com/android/settings/deletionhelper/StorageManagerUpsellDialog.java
new file mode 100644
index 0000000..e72933a
--- /dev/null
+++ b/src/com/android/settings/deletionhelper/StorageManagerUpsellDialog.java
@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+package com.android.settings.deletionhelper;
+
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.app.DialogFragment;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.SharedPreferences;
+import android.os.Bundle;
+import android.text.format.Formatter;
+import com.android.settings.R;
+import android.util.Log;
+
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Fragment for activating the storage manager after a manual clear.
+ */
+public class StorageManagerUpsellDialog extends DialogFragment
+ implements DialogInterface.OnClickListener, DialogInterface.OnDismissListener {
+ public static final String TAG = "StorageManagerUpsellDialog";
+ private static final String SHARED_PREFERENCES_NAME = "StorageManagerUpsellDialog";
+ private static final String NEXT_SHOW_TIME = "next_show_time";
+ private static final String DISMISSED_COUNT = "dismissed_count";
+ private static final String NO_THANKS_COUNT = "no_thanks_count";
+
+ private static final String ARGS_FREED_BYTES = "freed_bytes";
+
+ private static final long NEVER = -1;
+ private static final long DISMISS_SHORT_DELAY = TimeUnit.DAYS.toMillis(14);
+ private static final long DISMISS_LONG_DELAY = TimeUnit.DAYS.toMillis(90);
+ private static final int DISMISS_LONG_THRESHOLD = 9;
+ private static final long NO_THANKS_SHORT_DELAY = TimeUnit.DAYS.toMillis(90);
+ private static final long NO_THANKS_LONG_DELAY = NEVER;
+ private static final int NO_THANKS_LONG_THRESHOLD = 3;
+
+ public static StorageManagerUpsellDialog newInstance(long freedBytes) {
+ StorageManagerUpsellDialog dialog = new StorageManagerUpsellDialog();
+ Bundle args = new Bundle(1);
+ args.putLong(ARGS_FREED_BYTES, freedBytes);
+ dialog.setArguments(args);
+ return dialog;
+ }
+
+ @Override
+ public Dialog onCreateDialog(Bundle savedInstanceState) {
+ final Bundle args = getArguments();
+ long freedBytes = args.getLong(ARGS_FREED_BYTES);
+
+ final Context context = getContext();
+ return new AlertDialog.Builder(context)
+ .setTitle(context.getString(R.string.deletion_helper_upsell_title,
+ Formatter.formatFileSize(context, freedBytes)))
+ .setMessage(context.getString(R.string.deletion_helper_upsell_summary))
+ .setPositiveButton(R.string.deletion_helper_upsell_activate, this)
+ .setNegativeButton(R.string.deletion_helper_upsell_cancel, this)
+ .create();
+ }
+
+ @Override
+ public void onClick(DialogInterface dialog, int buttonId) {
+ if (buttonId == DialogInterface.BUTTON_POSITIVE) {
+ // TODO: Activate the storage manager once the storage manager is landed.
+ } else {
+ SharedPreferences sp = getSharedPreferences(getContext());
+ int noThanksCount = sp.getInt(NO_THANKS_COUNT, 0) + 1;
+ SharedPreferences.Editor editor = sp.edit();
+ editor.putInt(NO_THANKS_COUNT, noThanksCount);
+ editor.putLong(NEXT_SHOW_TIME,
+ System.currentTimeMillis() + getNoThanksDelay(noThanksCount));
+ editor.apply();
+ }
+ }
+
+ @Override
+ public void onCancel(DialogInterface dialog) {
+ SharedPreferences sp = getSharedPreferences(getContext());
+ int dismissCount = sp.getInt(DISMISSED_COUNT, 0) + 1;
+ SharedPreferences.Editor editor = sp.edit();
+ editor.putInt(DISMISSED_COUNT, dismissCount);
+ editor.putLong(NEXT_SHOW_TIME,
+ System.currentTimeMillis() + getDismissDelay(dismissCount));
+ editor.apply();
+ }
+
+ /**
+ * Returns if the dialog should be shown, given the delays between when it is shown.
+ * @param context Context to get shared preferences for determining the next show time.
+ */
+ public static boolean shouldShow(Context context) {
+ // TODO: If the Storage Manager is enabled, return false.
+ long nextTimeToShow = getSharedPreferences(context).getLong(NEXT_SHOW_TIME, 0);
+
+ if (nextTimeToShow == NEVER) {
+ return false;
+ }
+
+ return System.currentTimeMillis() > nextTimeToShow;
+ }
+
+ private static SharedPreferences getSharedPreferences(Context context) {
+ return context.getSharedPreferences(SHARED_PREFERENCES_NAME, Context.MODE_PRIVATE);
+ }
+
+ private static long getNoThanksDelay(int noThanksCount) {
+ return (noThanksCount > NO_THANKS_LONG_THRESHOLD)
+ ? NO_THANKS_LONG_DELAY : NO_THANKS_SHORT_DELAY;
+ }
+
+ private static long getDismissDelay(int dismissCount) {
+ return (dismissCount > DISMISS_LONG_THRESHOLD)
+ ? DISMISS_LONG_DELAY : DISMISS_SHORT_DELAY;
+ }
+}
diff --git a/src/com/android/settings/deviceinfo/PrivateVolumeSettings.java b/src/com/android/settings/deviceinfo/PrivateVolumeSettings.java
index c9a1fb7..c262806 100644
--- a/src/com/android/settings/deviceinfo/PrivateVolumeSettings.java
+++ b/src/com/android/settings/deviceinfo/PrivateVolumeSettings.java
@@ -58,6 +58,9 @@
import com.android.settings.SettingsPreferenceFragment;
import com.android.settings.Utils;
import com.android.settings.applications.ManageApplications;
+import com.android.settings.deletionhelper.DeletionHelperFragment;
+import com.android.settings.deletionhelper.AutomaticStorageManagerSettings;
+import com.android.settings.deletionhelper.StorageManagerUpsellDialog;
import com.android.settings.deviceinfo.StorageSettings.MountTask;
import com.android.settingslib.deviceinfo.StorageMeasurement;
import com.android.settingslib.deviceinfo.StorageMeasurement.MeasurementDetails;
@@ -98,6 +101,9 @@
R.string.storage_detail_other
};
+ private static final int DELETION_HELPER_SETTINGS = 1;
+ private static final int DELETION_HELPER_CLEAR = 1;
+
private StorageManager mStorageManager;
private UserManager mUserManager;
@@ -116,6 +122,7 @@
private int mItemPoolIndex;
private Preference mExplore;
+ private Preference mAutomaticStorageManagement;
private boolean mNeedsUpdate;
@@ -163,6 +170,7 @@
mCurrentUser = mUserManager.getUserInfo(UserHandle.myUserId());
mExplore = buildAction(R.string.storage_menu_explore);
+ mAutomaticStorageManagement = buildAction(R.string.storage_menu_manage);
mNeedsUpdate = true;
@@ -189,6 +197,9 @@
screen.removeAll();
+ if (getResources().getBoolean(R.bool.config_has_storage_manager)) {
+ addPreference(screen, mAutomaticStorageManagement);
+ }
addPreference(screen, mSummary);
List<UserInfo> allUsers = mUserManager.getUsers();
@@ -355,6 +366,7 @@
final MenuItem unmount = menu.findItem(R.id.storage_unmount);
final MenuItem format = menu.findItem(R.id.storage_format);
final MenuItem migrate = menu.findItem(R.id.storage_migrate);
+ final MenuItem manage = menu.findItem(R.id.storage_free);
// Actions live in menu for non-internal private volumes; they're shown
// as preference items for public volumes.
@@ -363,11 +375,13 @@
mount.setVisible(false);
unmount.setVisible(false);
format.setVisible(false);
+ manage.setVisible(true);
} else {
rename.setVisible(mVolume.getType() == VolumeInfo.TYPE_PRIVATE);
mount.setVisible(mVolume.getState() == VolumeInfo.STATE_UNMOUNTED);
unmount.setVisible(mVolume.isMountedReadable());
format.setVisible(true);
+ manage.setVisible(false);
}
format.setTitle(R.string.storage_menu_format_public);
@@ -406,6 +420,10 @@
intent.putExtra(VolumeInfo.EXTRA_VOLUME_ID, mVolume.getId());
startActivity(intent);
return true;
+ case R.id.storage_free:
+ startFragment(this, DeletionHelperFragment.class.getCanonicalName(),
+ R.string.deletion_helper_title, DELETION_HELPER_SETTINGS, args);
+ return true;
}
return super.onOptionsItemSelected(item);
}
@@ -467,6 +485,11 @@
case R.string.storage_menu_explore: {
intent = mSharedVolume.buildBrowseIntent();
} break;
+ case R.string.storage_menu_manage: {
+ startFragment(this, AutomaticStorageManagerSettings.class.getCanonicalName(),
+ R.string.automatic_storage_manager_settings, 0, null);
+ return true;
+ }
case 0: {
UserInfoFragment.show(this, pref.getTitle(), pref.getSummary());
return true;
@@ -488,6 +511,18 @@
return super.onPreferenceTreeClick(pref);
}
+ @Override
+ public void onActivityResult(int requestCode, int resultCode, Intent data) {
+ super.onActivityResult(requestCode, resultCode, data);
+ if (requestCode == DELETION_HELPER_SETTINGS && resultCode == DELETION_HELPER_CLEAR &&
+ StorageManagerUpsellDialog.shouldShow(getActivity())) {
+ long freedBytes = data.getLongExtra(DeletionHelperFragment.FREED_BYTES_KEY, 0);
+ StorageManagerUpsellDialog dialog =
+ StorageManagerUpsellDialog.newInstance(freedBytes);
+ dialog.show(getFragmentManager(), StorageManagerUpsellDialog.TAG);
+ }
+ }
+
private final MeasurementReceiver mReceiver = new MeasurementReceiver() {
@Override
public void onDetailsChanged(MeasurementDetails details) {
diff --git a/src/com/android/settings/fingerprint/FingerprintEnrollBase.java b/src/com/android/settings/fingerprint/FingerprintEnrollBase.java
index 150a01a..2aef37b 100644
--- a/src/com/android/settings/fingerprint/FingerprintEnrollBase.java
+++ b/src/com/android/settings/fingerprint/FingerprintEnrollBase.java
@@ -23,15 +23,13 @@
import android.os.UserHandle;
import android.text.TextUtils;
import android.view.View;
-import android.view.WindowManager;
import android.widget.Button;
import android.widget.TextView;
import com.android.settings.ChooseLockSettingsHelper;
import com.android.settings.InstrumentedActivity;
import com.android.settings.R;
-import com.android.setupwizardlib.SetupWizardLayout;
-import com.android.setupwizardlib.view.NavigationBar;
+import com.android.setupwizardlib.GlifLayout;
/**
* Base activity for all fingerprint enrollment steps.
@@ -71,38 +69,26 @@
}
protected void initViews() {
- getWindow().addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS |
- WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN |
- WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR);
-
- getWindow().getDecorView().setSystemUiVisibility(
- View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
-
getWindow().setStatusBarColor(Color.TRANSPARENT);
- getNavigationBar().setVisibility(View.GONE);
Button nextButton = getNextButton();
if (nextButton != null) {
nextButton.setOnClickListener(this);
}
}
- protected NavigationBar getNavigationBar() {
- return (NavigationBar) findViewById(R.id.suw_layout_navigation_bar);
- }
-
- protected SetupWizardLayout getSetupWizardLayout() {
- return (SetupWizardLayout) findViewById(R.id.setup_wizard_layout);
+ protected GlifLayout getLayout() {
+ return (GlifLayout) findViewById(R.id.setup_wizard_layout);
}
protected void setHeaderText(int resId, boolean force) {
- TextView layoutTitle = getSetupWizardLayout().getHeaderTextView();
+ TextView layoutTitle = getLayout().getHeaderTextView();
CharSequence previousTitle = layoutTitle.getText();
CharSequence title = getText(resId);
if (previousTitle != title || force) {
if (!TextUtils.isEmpty(previousTitle)) {
layoutTitle.setAccessibilityLiveRegion(View.ACCESSIBILITY_LIVE_REGION_POLITE);
}
- getSetupWizardLayout().setHeaderText(title);
+ getLayout().setHeaderText(title);
setTitle(title);
}
}
diff --git a/src/com/android/settings/fingerprint/FingerprintEnrollIntroduction.java b/src/com/android/settings/fingerprint/FingerprintEnrollIntroduction.java
index d1bd3f7..48d0884 100644
--- a/src/com/android/settings/fingerprint/FingerprintEnrollIntroduction.java
+++ b/src/com/android/settings/fingerprint/FingerprintEnrollIntroduction.java
@@ -18,36 +18,31 @@
import android.app.admin.DevicePolicyManager;
import android.content.ActivityNotFoundException;
-import android.content.Context;
import android.content.Intent;
-import android.graphics.Typeface;
import android.hardware.fingerprint.FingerprintManager;
import android.os.Bundle;
import android.os.UserHandle;
import android.os.UserManager;
-import android.text.Annotation;
-import android.text.SpannableString;
-import android.text.SpannableStringBuilder;
-import android.text.TextPaint;
-import android.text.style.URLSpan;
import android.util.Log;
-import android.view.View;
import com.android.internal.logging.MetricsProto.MetricsEvent;
import com.android.settings.ChooseLockGeneric;
import com.android.settings.ChooseLockSettingsHelper;
-import com.android.settingslib.HelpUtils;
import com.android.settings.R;
-import com.android.setupwizardlib.SetupWizardRecyclerLayout;
+import com.android.settingslib.HelpUtils;
+import com.android.setupwizardlib.GlifRecyclerLayout;
import com.android.setupwizardlib.items.IItem;
import com.android.setupwizardlib.items.Item;
import com.android.setupwizardlib.items.RecyclerItemAdapter;
+import com.android.setupwizardlib.span.LinkSpan;
/**
* Onboarding activity for fingerprint enrollment.
*/
public class FingerprintEnrollIntroduction extends FingerprintEnrollBase
- implements RecyclerItemAdapter.OnItemSelectedListener {
+ implements RecyclerItemAdapter.OnItemSelectedListener, LinkSpan.OnClickListener {
+
+ private static final String TAG = "FingerprintIntro";
protected static final int CHOOSE_LOCK_GENERIC_REQUEST = 1;
protected static final int FINGERPRINT_FIND_SENSOR_REQUEST = 2;
@@ -61,19 +56,12 @@
super.onCreate(savedInstanceState);
setContentView(R.layout.fingerprint_enroll_introduction);
setHeaderText(R.string.security_settings_fingerprint_enroll_introduction_title);
- final SetupWizardRecyclerLayout layout =
- (SetupWizardRecyclerLayout) findViewById(R.id.setup_wizard_layout);
+ final GlifRecyclerLayout layout = (GlifRecyclerLayout) getLayout();
mUserManager = UserManager.get(this);
final RecyclerItemAdapter adapter = (RecyclerItemAdapter) layout.getAdapter();
adapter.setOnItemSelectedListener(this);
Item item = (Item) adapter.findItemById(R.id.fingerprint_introduction_message);
- item.setTitle(LearnMoreSpan.linkify(
- getText(R.string.security_settings_fingerprint_enroll_introduction_message),
- getString(R.string.help_url_fingerprint)));
- // setupwizard library automatically sets the divider inset to
- // R.dimen.suw_items_icon_divider_inset. We adjust this back to 0 as we do not want
- // an inset within settings.
- layout.setDividerInset(0);
+ item.setTitle(getText(R.string.security_settings_fingerprint_enroll_introduction_message));
updatePasswordQuality();
}
@@ -125,8 +113,7 @@
}
protected Intent getFindSensorIntent() {
- Intent intent = new Intent(this, FingerprintEnrollFindSensor.class);
- return intent;
+ return new Intent(this, FingerprintEnrollFindSensor.class);
}
@Override
@@ -147,6 +134,8 @@
launchFindSensor(token);
return;
}
+ } else if (requestCode == LEARN_MORE_REQUEST) {
+ overridePendingTransition(R.anim.suw_slide_back_in, R.anim.suw_slide_back_out);
}
super.onActivityResult(requestCode, resultCode, data);
}
@@ -172,47 +161,22 @@
finish();
}
- private static class LearnMoreSpan extends URLSpan {
- private static final String TAG = "LearnMoreSpan";
- private static final Typeface TYPEFACE_MEDIUM =
- Typeface.create("sans-serif-medium", Typeface.NORMAL);
-
- private LearnMoreSpan(String url) {
- super(url);
- }
-
- @Override
- public void onClick(View widget) {
- Context ctx = widget.getContext();
- Intent intent = HelpUtils.getHelpIntent(ctx, getURL(), ctx.getClass().getName());
+ @Override
+ public void onClick(LinkSpan span) {
+ if ("url".equals(span.getId())) {
+ String url = getString(R.string.help_url_fingerprint);
+ Intent intent = HelpUtils.getHelpIntent(this, url, getClass().getName());
+ if (intent == null) {
+ Log.w(TAG, "Null help intent.");
+ return;
+ }
try {
// This needs to be startActivityForResult even though we do not care about the
// actual result because the help app needs to know about who invoked it.
- widget.startActivityForResult(intent, LEARN_MORE_REQUEST);
+ startActivityForResult(intent, LEARN_MORE_REQUEST);
} catch (ActivityNotFoundException e) {
- Log.w(LearnMoreSpan.TAG,
- "Actvity was not found for intent, " + intent.toString());
+ Log.w(TAG, "Activity was not found for intent, " + e);
}
}
-
- @Override
- public void updateDrawState(TextPaint ds) {
- super.updateDrawState(ds);
- ds.setUnderlineText(false);
- ds.setTypeface(TYPEFACE_MEDIUM);
- }
-
- public static CharSequence linkify(CharSequence rawText, String uri) {
- SpannableString msg = new SpannableString(rawText);
- Annotation[] spans = msg.getSpans(0, msg.length(), Annotation.class);
- SpannableStringBuilder builder = new SpannableStringBuilder(msg);
- for (Annotation annotation : spans) {
- int start = msg.getSpanStart(annotation);
- int end = msg.getSpanEnd(annotation);
- LearnMoreSpan link = new LearnMoreSpan(uri);
- builder.setSpan(link, start, end, msg.getSpanFlags(link));
- }
- return builder;
- }
}
}
diff --git a/src/com/android/settings/fingerprint/SetupFingerprintEnrollEnrolling.java b/src/com/android/settings/fingerprint/SetupFingerprintEnrollEnrolling.java
index b037c2b..8bd495e 100644
--- a/src/com/android/settings/fingerprint/SetupFingerprintEnrollEnrolling.java
+++ b/src/com/android/settings/fingerprint/SetupFingerprintEnrollEnrolling.java
@@ -31,11 +31,8 @@
import com.android.internal.logging.MetricsProto.MetricsEvent;
import com.android.settings.R;
import com.android.settings.SetupWizardUtils;
-import com.android.setupwizardlib.util.SystemBarHelper;
-import com.android.setupwizardlib.view.NavigationBar;
-public class SetupFingerprintEnrollEnrolling extends FingerprintEnrollEnrolling
- implements NavigationBar.NavigationBarListener {
+public class SetupFingerprintEnrollEnrolling extends FingerprintEnrollEnrolling {
private static final String TAG_DIALOG = "dialog";
@@ -54,32 +51,21 @@
@Override
protected void initViews() {
- SetupWizardUtils.setImmersiveMode(this);
+ super.initViews();
+ final Button skipButton = (Button) findViewById(R.id.skip_button);
+ skipButton.setVisibility(View.VISIBLE);
+ skipButton.setOnClickListener(this);
+ }
- final View buttonBar = findViewById(R.id.button_bar);
- if (buttonBar != null) {
- buttonBar.setVisibility(View.GONE);
+ @Override
+ public void onClick(View v) {
+ switch (v.getId()) {
+ case R.id.skip_button:
+ new SkipDialog().show(getFragmentManager(), TAG_DIALOG);
+ break;
+ default:
+ super.onClick(v);
}
-
- final NavigationBar navigationBar = getNavigationBar();
- navigationBar.setNavigationBarListener(this);
- navigationBar.getNextButton().setText(R.string.skip_label);
- navigationBar.getBackButton().setVisibility(View.GONE);
- }
-
- @Override
- protected Button getNextButton() {
- return getNavigationBar().getNextButton();
- }
-
- @Override
- public void onNavigateBack() {
- onBackPressed();
- }
-
- @Override
- public void onNavigateNext() {
- new SkipDialog().show(getFragmentManager(), TAG_DIALOG);
}
@Override
@@ -102,7 +88,7 @@
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
- final AlertDialog dialog = new AlertDialog.Builder(getActivity())
+ return new AlertDialog.Builder(getActivity())
.setTitle(R.string.setup_fingerprint_enroll_enrolling_skip_title)
.setMessage(R.string.setup_fingerprint_enroll_enrolling_skip_message)
.setCancelable(false)
@@ -124,8 +110,6 @@
}
})
.create();
- SystemBarHelper.hideSystemBars(dialog);
- return dialog;
}
}
}
diff --git a/src/com/android/settings/fingerprint/SetupFingerprintEnrollFindSensor.java b/src/com/android/settings/fingerprint/SetupFingerprintEnrollFindSensor.java
index 9cf5369..bb78477 100644
--- a/src/com/android/settings/fingerprint/SetupFingerprintEnrollFindSensor.java
+++ b/src/com/android/settings/fingerprint/SetupFingerprintEnrollFindSensor.java
@@ -19,17 +19,13 @@
import android.content.Intent;
import android.content.res.Resources;
import android.os.UserHandle;
-import android.view.View;
-import android.widget.Button;
import com.android.internal.logging.MetricsProto.MetricsEvent;
import com.android.settings.ChooseLockSettingsHelper;
import com.android.settings.R;
import com.android.settings.SetupWizardUtils;
-import com.android.setupwizardlib.view.NavigationBar;
-public class SetupFingerprintEnrollFindSensor extends FingerprintEnrollFindSensor
- implements NavigationBar.NavigationBarListener {
+public class SetupFingerprintEnrollFindSensor extends FingerprintEnrollFindSensor {
@Override
protected int getContentView() {
@@ -54,34 +50,6 @@
}
@Override
- protected void initViews() {
- SetupWizardUtils.setImmersiveMode(this);
-
- final View nextButton = findViewById(R.id.next_button);
- if (nextButton != null) {
- nextButton.setVisibility(View.GONE);
- }
-
- getNavigationBar().setNavigationBarListener(this);
- getNavigationBar().getBackButton().setVisibility(View.GONE);
- }
-
- @Override
- protected Button getNextButton() {
- return getNavigationBar().getNextButton();
- }
-
- @Override
- public void onNavigateBack() {
- onBackPressed();
- }
-
- @Override
- public void onNavigateNext() {
- onNextButtonClick();
- }
-
- @Override
protected int getMetricsCategory() {
return MetricsEvent.FINGERPRINT_FIND_SENSOR_SETUP;
}
diff --git a/src/com/android/settings/fingerprint/SetupFingerprintEnrollFinish.java b/src/com/android/settings/fingerprint/SetupFingerprintEnrollFinish.java
index b17ed09..f6602f3 100644
--- a/src/com/android/settings/fingerprint/SetupFingerprintEnrollFinish.java
+++ b/src/com/android/settings/fingerprint/SetupFingerprintEnrollFinish.java
@@ -20,17 +20,14 @@
import android.content.res.Resources;
import android.os.UserHandle;
import android.view.View;
-import android.widget.Button;
import android.widget.TextView;
import com.android.internal.logging.MetricsProto.MetricsEvent;
import com.android.settings.ChooseLockSettingsHelper;
import com.android.settings.R;
import com.android.settings.SetupWizardUtils;
-import com.android.setupwizardlib.view.NavigationBar;
-public class SetupFingerprintEnrollFinish extends FingerprintEnrollFinish
- implements NavigationBar.NavigationBarListener {
+public class SetupFingerprintEnrollFinish extends FingerprintEnrollFinish {
@Override
protected Intent getEnrollingIntent() {
@@ -51,16 +48,7 @@
@Override
protected void initViews() {
- SetupWizardUtils.setImmersiveMode(this);
-
- final View nextButton = findViewById(R.id.next_button);
- if (nextButton != null) {
- nextButton.setVisibility(View.GONE);
- }
-
- final NavigationBar navigationBar = getNavigationBar();
- navigationBar.setNavigationBarListener(this);
- navigationBar.getBackButton().setVisibility(View.GONE);
+ super.initViews();
final TextView message = (TextView) findViewById(R.id.message);
message.setText(R.string.setup_fingerprint_enroll_finish_message);
@@ -70,21 +58,6 @@
}
@Override
- protected Button getNextButton() {
- return getNavigationBar().getNextButton();
- }
-
- @Override
- public void onNavigateBack() {
- onBackPressed();
- }
-
- @Override
- public void onNavigateNext() {
- onNextButtonClick();
- }
-
- @Override
protected int getMetricsCategory() {
return MetricsEvent.FINGERPRINT_ENROLL_FINISH_SETUP;
}
diff --git a/src/com/android/settings/fingerprint/SetupFingerprintEnrollIntroduction.java b/src/com/android/settings/fingerprint/SetupFingerprintEnrollIntroduction.java
index f816682..aac2057 100644
--- a/src/com/android/settings/fingerprint/SetupFingerprintEnrollIntroduction.java
+++ b/src/com/android/settings/fingerprint/SetupFingerprintEnrollIntroduction.java
@@ -19,20 +19,17 @@
import android.content.Intent;
import android.content.res.Resources;
import android.os.UserHandle;
-import android.widget.Button;
import com.android.internal.logging.MetricsProto.MetricsEvent;
import com.android.internal.widget.LockPatternUtils;
import com.android.settings.R;
import com.android.settings.SetupChooseLockGeneric;
import com.android.settings.SetupWizardUtils;
-import com.android.setupwizardlib.SetupWizardRecyclerLayout;
+import com.android.setupwizardlib.GlifRecyclerLayout;
import com.android.setupwizardlib.items.Item;
import com.android.setupwizardlib.items.RecyclerItemAdapter;
-import com.android.setupwizardlib.view.NavigationBar;
-public class SetupFingerprintEnrollIntroduction extends FingerprintEnrollIntroduction
- implements NavigationBar.NavigationBarListener {
+public class SetupFingerprintEnrollIntroduction extends FingerprintEnrollIntroduction {
@Override
protected Intent getChooseLockIntent() {
@@ -56,8 +53,7 @@
@Override
protected void initViews() {
- final SetupWizardRecyclerLayout layout =
- (SetupWizardRecyclerLayout) findViewById(R.id.setup_wizard_layout);
+ GlifRecyclerLayout layout = (GlifRecyclerLayout) getLayout();
final RecyclerItemAdapter adapter = (RecyclerItemAdapter) layout.getAdapter();
final Item nextItem = (Item) adapter.findItemById(R.id.next_button);
nextItem.setTitle(
@@ -66,14 +62,6 @@
final Item cancelItem = (Item) adapter.findItemById(R.id.cancel_button);
cancelItem.setTitle(
getText(R.string.security_settings_fingerprint_enroll_introduction_cancel_setup));
-
- SetupWizardUtils.setImmersiveMode(this);
- getNavigationBar().setNavigationBarListener(this);
- Button nextButton = getNavigationBar().getNextButton();
- nextButton.setText(null);
- nextButton.setEnabled(false);
- layout.setDividerInset(getResources().getDimensionPixelSize(
- R.dimen.suw_items_icon_divider_inset));
}
@Override
@@ -98,16 +86,6 @@
}
@Override
- public void onNavigateBack() {
- onBackPressed();
- }
-
- @Override
- public void onNavigateNext() {
- // next is handled via the onNextButtonClick method in FingerprintEnrollIntroduction
- }
-
- @Override
protected int getMetricsCategory() {
return MetricsEvent.FINGERPRINT_ENROLL_INTRO_SETUP;
}
diff --git a/src/com/android/settings/fingerprint/SetupSkipDialog.java b/src/com/android/settings/fingerprint/SetupSkipDialog.java
index 11e6936..c6e04d7 100644
--- a/src/com/android/settings/fingerprint/SetupSkipDialog.java
+++ b/src/com/android/settings/fingerprint/SetupSkipDialog.java
@@ -22,17 +22,10 @@
import android.app.DialogFragment;
import android.app.FragmentManager;
import android.content.DialogInterface;
-import android.os.Build.VERSION;
-import android.os.Build.VERSION_CODES;
import android.os.Bundle;
-import android.os.Handler;
import android.support.annotation.NonNull;
-import android.view.View;
-import android.view.Window;
-import android.view.WindowManager;
import com.android.settings.R;
-import com.android.setupwizardlib.util.SystemBarHelper;
public class SetupSkipDialog extends DialogFragment implements DialogInterface.OnClickListener {
@@ -52,10 +45,7 @@
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
- final AlertDialog dialog = onCreateDialogBuilder().create();
- // hide system status bar.
- SystemBarHelper.hideSystemBars(dialog);
- return dialog;
+ return onCreateDialogBuilder().create();
}
@NonNull
diff --git a/src/com/android/settings/overlay/DeletionHelperFeatureProvider.java b/src/com/android/settings/overlay/DeletionHelperFeatureProvider.java
new file mode 100644
index 0000000..15b5896
--- /dev/null
+++ b/src/com/android/settings/overlay/DeletionHelperFeatureProvider.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.overlay;
+
+import android.content.Context;
+import android.support.v7.preference.PreferenceGroup;
+import com.android.settings.deletionhelper.DeletionType;
+
+/**
+ * Feature provider for the manual deletion helper Settings page.
+ */
+public interface DeletionHelperFeatureProvider {
+ /**
+ * Creates a {@link DeletionType} for clearing out stored photos and videos on the device.
+ */
+ DeletionType createPhotoVideoDeletionType(Context context);
+}
diff --git a/src/com/android/settings/overlay/FeatureFactory.java b/src/com/android/settings/overlay/FeatureFactory.java
new file mode 100644
index 0000000..3b307e5
--- /dev/null
+++ b/src/com/android/settings/overlay/FeatureFactory.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.overlay;
+
+import android.content.Context;
+import android.text.TextUtils;
+import android.util.Log;
+
+import com.android.settings.R;
+
+/**
+ * Abstract class for creating feature controllers. Allows OEM implementations to define their own
+ * factories with their own controllers containing whatever code is needed to implement
+ * the features. To provide a factory implementation, implementors should override
+ * {@link R.string#config_featureFactory} in their override.
+ */
+public abstract class FeatureFactory {
+ private static final String LOG_TAG = "FeatureFactory";
+ private static final boolean DEBUG = false;
+
+ private static FeatureFactory sFactory;
+
+ /**
+ * Returns a factory for creating feature controllers. Creates the factory if it does not
+ * already exist. Uses the value of {@link R.string#config_featureFactory} to instantiate
+ * a factory implementation.
+ */
+ public static FeatureFactory getFactory(Context context) {
+ if (sFactory != null) {
+ return sFactory;
+ }
+
+ if (DEBUG) Log.d(LOG_TAG, "getFactory");
+ final String clsName = context.getString(R.string.config_featureFactory);
+ if (TextUtils.isEmpty(clsName)) {
+ throw new UnsupportedOperationException("No feature factory configured");
+ }
+ try {
+ sFactory = (FeatureFactory) context.getClassLoader().loadClass(clsName).newInstance();
+ } catch (InstantiationException | IllegalAccessException | ClassNotFoundException e) {
+ throw new FactoryNotFoundException(e);
+ }
+
+ if (DEBUG) Log.d(LOG_TAG, "started " + sFactory.getClass().getSimpleName());
+ return sFactory;
+ }
+
+ public abstract SupportFeatureProvider getSupportFeatureProvider(Context context);
+
+ /**
+ * Return a provider which adds additional deletion services to the Deletion Helper.
+ */
+ public abstract DeletionHelperFeatureProvider getDeletionHelperFeatureProvider();
+
+ public static final class FactoryNotFoundException extends RuntimeException {
+ public FactoryNotFoundException(Throwable throwable) {
+ super("Unable to create factory. Did you misconfigure Proguard?", throwable);
+ }
+ }
+}
diff --git a/src/com/android/settings/overlay/FeatureFactoryImpl.java b/src/com/android/settings/overlay/FeatureFactoryImpl.java
new file mode 100644
index 0000000..425320a
--- /dev/null
+++ b/src/com/android/settings/overlay/FeatureFactoryImpl.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.overlay;
+
+import android.content.Context;
+
+/**
+ * {@link FeatureFactory} implementation for AOSP Settings.
+ */
+public final class FeatureFactoryImpl extends FeatureFactory {
+
+ @Override
+ public SupportFeatureProvider getSupportFeatureProvider(Context context) {
+ return null;
+ }
+
+ @Override
+ public DeletionHelperFeatureProvider getDeletionHelperFeatureProvider() {
+ return null;
+ }
+
+}
diff --git a/src/com/android/settings/overlay/SupportFeatureProvider.java b/src/com/android/settings/overlay/SupportFeatureProvider.java
new file mode 100644
index 0000000..e95a928
--- /dev/null
+++ b/src/com/android/settings/overlay/SupportFeatureProvider.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.overlay;
+
+import android.accounts.Account;
+import android.annotation.IntDef;
+import android.app.Activity;
+import android.content.Context;
+import android.content.Intent;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Feature provider for support tab.
+ */
+public interface SupportFeatureProvider {
+
+ @IntDef({SupportType.EMAIL, SupportType.PHONE, SupportType.CHAT})
+ @Retention(RetentionPolicy.SOURCE)
+ @interface SupportType {
+ int EMAIL = 1;
+ int PHONE = 2;
+ int CHAT = 3;
+ }
+
+ /**
+ * Returns a intent that will open help forum.
+ */
+ Intent getForumIntent();
+
+ /**
+ * Returns a intent that will open help & feedback.
+ */
+ Intent getHelpIntent(Context context);
+
+ /**
+ * Whether or not a support type is enabled.
+ */
+ boolean isSupportTypeEnabled(Context context, @SupportType int type);
+
+ /**
+ * Returns a localized string indicating estimated wait time for a support time.
+ */
+ String getEstimatedWaitTime(Context context, @SupportType int type);
+
+ /**
+ * Whether or not a disclaimer dialog should be displayed.
+ */
+ boolean shouldShowDisclaimerDialog(Context context);
+
+ /**
+ * Returns an {@link Account} that's eligible for support options.
+ */
+ Account getSupportEligibleAccount(Context context);
+
+ /**
+ * Starts support activity of specified type
+ *
+ * @param activity Calling activity
+ * @param account A account returned by {@link #getSupportEligibleAccount}
+ * @param type The type of support account needs.
+ */
+ void startSupport(Activity activity, Account account, @SupportType int type);
+
+ /**
+ * Returns an {@link Intent} that opens help and allow user get help on sign in.
+ */
+ Intent getSignInHelpIntent(Context context);
+
+ /**
+ * Returns an intent that will start the add account UI.
+ */
+ Intent getAccountLoginIntent();
+
+ /**
+ * Returns an intent that will launch the tips and tricks UI.
+ */
+ Intent getTipsAndTricksIntent(Context context);
+}
diff --git a/src/com/android/settings/support/SupportDisclaimerDialogFragment.java b/src/com/android/settings/support/SupportDisclaimerDialogFragment.java
new file mode 100644
index 0000000..98f34bc
--- /dev/null
+++ b/src/com/android/settings/support/SupportDisclaimerDialogFragment.java
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.support;
+
+import android.accounts.Account;
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.app.DialogFragment;
+import android.content.DialogInterface;
+import android.os.Bundle;
+import android.text.Spannable;
+import android.text.TextPaint;
+import android.text.method.LinkMovementMethod;
+import android.text.style.URLSpan;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.TextView;
+
+import com.android.settings.R;
+import com.android.settings.overlay.FeatureFactory;
+import com.android.settings.overlay.SupportFeatureProvider;
+
+/**
+ * {@link DialogFragment} for support disclaimer.
+ */
+public final class SupportDisclaimerDialogFragment extends DialogFragment implements
+ DialogInterface.OnClickListener {
+
+ public static final String TAG = "SupportDisclaimerDialog";
+ private static final String EXTRA_TYPE = "extra_type";
+ private static final String EXTRA_ACCOUNT = "extra_account";
+
+ public static SupportDisclaimerDialogFragment newInstance(Account account,
+ @SupportFeatureProvider.SupportType int type) {
+ final SupportDisclaimerDialogFragment fragment = new SupportDisclaimerDialogFragment();
+ final Bundle bundle = new Bundle(2);
+ bundle.putParcelable(SupportDisclaimerDialogFragment.EXTRA_ACCOUNT, account);
+ bundle.putInt(SupportDisclaimerDialogFragment.EXTRA_TYPE, type);
+ fragment.setArguments(bundle);
+ return fragment;
+ }
+
+ @Override
+ public Dialog onCreateDialog(Bundle savedInstanceState) {
+ final AlertDialog.Builder builder = new AlertDialog.Builder(getActivity())
+ .setTitle(R.string.support_disclaimer_title)
+ .setPositiveButton(android.R.string.ok, this)
+ .setNegativeButton(android.R.string.cancel, null);
+ final View content = LayoutInflater.from(builder.getContext())
+ .inflate(R.layout.support_disclaimer_content, null);
+ final TextView disclaimer = (TextView) content.findViewById(R.id.support_disclaimer_text);
+ disclaimer.setMovementMethod(LinkMovementMethod.getInstance());
+ stripUnderlines((Spannable) disclaimer.getText());
+ return builder
+ .setView(content)
+ .create();
+ }
+
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ final Activity activity = getActivity();
+ final SupportFeatureProvider supportFeatureProvider =
+ FeatureFactory.getFactory(activity).getSupportFeatureProvider(activity);
+ final Bundle bundle = getArguments();
+ supportFeatureProvider.startSupport(getActivity(),
+ (Account) bundle.getParcelable(EXTRA_ACCOUNT), bundle.getInt(EXTRA_TYPE));
+ }
+
+ /**
+ * Removes the underlines of {@link android.text.style.URLSpan}s.
+ */
+ private static void stripUnderlines(Spannable input) {
+ final URLSpan[] urls = input.getSpans(0, input.length(), URLSpan.class);
+
+ for (URLSpan span : urls) {
+ final int start = input.getSpanStart(span);
+ final int end = input.getSpanEnd(span);
+ input.removeSpan(span);
+ input.setSpan(new NoUnderlineUrlSpan(span.getURL()), start, end,
+ Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
+ }
+ }
+
+ /**
+ * A {@link URLSpan} that doesn't decorate the link with underline.
+ */
+ public static class NoUnderlineUrlSpan extends URLSpan {
+
+ public NoUnderlineUrlSpan(String url) {
+ super(url);
+ }
+
+ @Override
+ public void updateDrawState(TextPaint ds) {
+ super.updateDrawState(ds);
+ ds.setUnderlineText(false);
+ }
+ }
+}
diff --git a/src/com/android/settings/utils/AsyncLoader.java b/src/com/android/settings/utils/AsyncLoader.java
new file mode 100644
index 0000000..76c99fa
--- /dev/null
+++ b/src/com/android/settings/utils/AsyncLoader.java
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2016 Google Inc.
+ * Licensed to 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.AsyncTaskLoader;
+import android.content.Context;
+
+/**
+ * This class fills in some boilerplate for AsyncTaskLoader to actually load things.
+ *
+ * Subclasses need to implement {@link AsyncLoader#loadInBackground()} to perform the actual
+ * background task, and {@link AsyncLoader#onDiscardResult(T)} to clean up previously loaded
+ * results.
+ *
+ * This loader is based on the MailAsyncTaskLoader from the AOSP EmailUnified repo.
+ */
+public abstract class AsyncLoader<T> extends AsyncTaskLoader<T> {
+ private T mResult;
+
+ public AsyncLoader(final Context context) {
+ super(context);
+ }
+
+ @Override
+ protected void onStartLoading() {
+ if (mResult != null) {
+ deliverResult(mResult);
+ }
+
+ if (takeContentChanged() || mResult == null) {
+ forceLoad();
+ }
+ }
+
+ @Override
+ protected void onStopLoading() {
+ cancelLoad();
+ }
+
+ @Override
+ public void deliverResult(final T data) {
+ if (isReset()) {
+ if (data != null) {
+ onDiscardResult(data);
+ }
+ return;
+ }
+
+ final T oldResult = mResult;
+ mResult = data;
+
+ if (isStarted()) {
+ super.deliverResult(data);
+ }
+
+ if (oldResult != null && oldResult != mResult) {
+ onDiscardResult(oldResult);
+ }
+ }
+
+ @Override
+ protected void onReset() {
+ super.onReset();
+
+ onStopLoading();
+
+ if (mResult != null) {
+ onDiscardResult(mResult);
+ }
+ mResult = null;
+ }
+
+ @Override
+ public void onCanceled(final T data) {
+ super.onCanceled(data);
+
+ if (data != null) {
+ onDiscardResult(data);
+ }
+ }
+
+ /**
+ * Called when discarding the load results so subclasses can take care of clean-up or
+ * recycling tasks. This is not called if the same result (by way of pointer equality) is
+ * returned again by a subsequent call to loadInBackground, or if result is null.
+ *
+ * Note that this may be called concurrently with loadInBackground(), and in some circumstances
+ * may be called more than once for a given object.
+ *
+ * @param result The value returned from {@link AsyncLoader#loadInBackground()} which
+ * is to be discarded.
+ */
+ protected abstract void onDiscardResult(final T result);
+}
diff --git a/src/com/android/settings/utils/SettingsDividerItemDecoration.java b/src/com/android/settings/utils/SettingsDividerItemDecoration.java
new file mode 100644
index 0000000..451d532
--- /dev/null
+++ b/src/com/android/settings/utils/SettingsDividerItemDecoration.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.utils;
+
+import android.content.Context;
+import android.support.v7.preference.PreferenceViewHolder;
+import android.support.v7.widget.RecyclerView;
+
+import com.android.setupwizardlib.DividerItemDecoration;
+
+public class SettingsDividerItemDecoration extends DividerItemDecoration {
+
+ public SettingsDividerItemDecoration(Context context) {
+ super(context);
+ }
+
+ @Override
+ protected boolean isDividerAllowedAbove(RecyclerView.ViewHolder viewHolder) {
+ if (viewHolder instanceof PreferenceViewHolder) {
+ return ((PreferenceViewHolder) viewHolder).isDividerAllowedAbove();
+ }
+ return super.isDividerAllowedAbove(viewHolder);
+ }
+
+ @Override
+ protected boolean isDividerAllowedBelow(RecyclerView.ViewHolder viewHolder) {
+ if (viewHolder instanceof PreferenceViewHolder) {
+ return ((PreferenceViewHolder) viewHolder).isDividerAllowedBelow();
+ }
+ return super.isDividerAllowedBelow(viewHolder);
+ }
+}
diff --git a/src/com/android/settings/widget/SlidingTabLayout.java b/src/com/android/settings/widget/SlidingTabLayout.java
new file mode 100644
index 0000000..219d37b
--- /dev/null
+++ b/src/com/android/settings/widget/SlidingTabLayout.java
@@ -0,0 +1,166 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.widget;
+
+import android.content.Context;
+import android.support.v4.view.PagerAdapter;
+import android.support.v4.view.ViewPager;
+import android.util.AttributeSet;
+import android.view.Gravity;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.FrameLayout;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+import com.android.settings.R;
+
+/**
+ * To be used with ViewPager to provide a tab indicator component which give constant feedback as
+ * to the user's scroll progress.
+ */
+public final class SlidingTabLayout extends FrameLayout implements View.OnClickListener {
+
+ private final LinearLayout mTitleView;
+ private final View mIndicatorView;
+ private final LayoutInflater mLayoutInflater;
+
+ private ViewPager mViewPager;
+ private int mSelectedPosition;
+ private float mSelectionOffset;
+
+ public SlidingTabLayout(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ mLayoutInflater = LayoutInflater.from(context);
+ mTitleView = new LinearLayout(context);
+ mTitleView.setGravity(Gravity.CENTER_HORIZONTAL);
+ mIndicatorView = mLayoutInflater.inflate(R.layout.sliding_tab_indicator_view, this, false);
+
+ addView(mTitleView, LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
+ addView(mIndicatorView, mIndicatorView.getLayoutParams());
+ }
+
+ /**
+ * Sets the associated view pager. Note that the assumption here is that the pager content
+ * (number of tabs and tab titles) does not change after this call has been made.
+ */
+ public void setViewPager(ViewPager viewPager) {
+ mTitleView.removeAllViews();
+
+ mViewPager = viewPager;
+ if (viewPager != null) {
+ viewPager.addOnPageChangeListener(new InternalViewPagerListener());
+ populateTabStrip();
+ }
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+ final int titleCount = mTitleView.getChildCount();
+ if (titleCount > 0) {
+ final int width = MeasureSpec.makeMeasureSpec(
+ mTitleView.getMeasuredWidth() / titleCount, MeasureSpec.EXACTLY);
+ final int height = MeasureSpec.makeMeasureSpec(
+ mIndicatorView.getMeasuredHeight(), MeasureSpec.EXACTLY);
+ mIndicatorView.measure(width, height);
+ }
+ }
+
+ @Override
+ protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+ if (mTitleView.getChildCount() > 0) {
+ mTitleView.layout(0, 0, mTitleView.getMeasuredWidth(), mTitleView.getMeasuredHeight());
+ final int indicatorBottom = getMeasuredHeight();
+ final int indicatorHeight = mIndicatorView.getMeasuredHeight();
+ mIndicatorView.layout(0, indicatorBottom - indicatorHeight,
+ mIndicatorView.getMeasuredWidth(), indicatorBottom);
+ }
+ }
+
+ @Override
+ public void onClick(View v) {
+ final int titleCount = mTitleView.getChildCount();
+ for (int i = 0; i < titleCount; i++) {
+ if (v == mTitleView.getChildAt(i)) {
+ mViewPager.setCurrentItem(i);
+ return;
+ }
+ }
+ }
+
+ private void onViewPagerPageChanged(int position, float positionOffset) {
+ mSelectedPosition = position;
+ mSelectionOffset = positionOffset;
+ mIndicatorView.setTranslationX(getIndicatorLeft());
+ }
+
+ private void populateTabStrip() {
+ final PagerAdapter adapter = mViewPager.getAdapter();
+
+ for (int i = 0; i < adapter.getCount(); i++) {
+ final TextView tabTitleView = (TextView) mLayoutInflater.inflate(
+ R.layout.sliding_tab_title_view, mTitleView, false);
+
+ tabTitleView.setText(adapter.getPageTitle(i));
+ tabTitleView.setOnClickListener(this);
+
+ mTitleView.addView(tabTitleView);
+ tabTitleView.setSelected(i == mViewPager.getCurrentItem());
+ }
+ }
+
+ private int getIndicatorLeft() {
+ View selectedTitle = mTitleView.getChildAt(mSelectedPosition);
+ int left = selectedTitle.getLeft();
+ if (mSelectionOffset > 0f && mSelectedPosition < (getChildCount() - 1)) {
+ View nextTitle = mTitleView.getChildAt(mSelectedPosition + 1);
+ left = (int) (mSelectionOffset * nextTitle.getLeft()
+ + (1.0f - mSelectionOffset) * left);
+ }
+ return left;
+ }
+
+ private final class InternalViewPagerListener implements ViewPager.OnPageChangeListener {
+ private int mScrollState;
+
+ @Override
+ public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
+ final int titleCount = mTitleView.getChildCount();
+ if ((titleCount == 0) || (position < 0) || (position >= titleCount)) {
+ return;
+ }
+ onViewPagerPageChanged(position, positionOffset);
+ }
+
+ @Override
+ public void onPageScrollStateChanged(int state) {
+ mScrollState = state;
+ }
+
+ @Override
+ public void onPageSelected(int position) {
+ if (mScrollState == ViewPager.SCROLL_STATE_IDLE) {
+ onViewPagerPageChanged(position, 0f);
+ }
+ final int titleCount = mTitleView.getChildCount();
+ for (int i = 0; i < titleCount; i++) {
+ mTitleView.getChildAt(i).setSelected(position == i);
+ }
+ }
+ }
+}
diff --git a/tests/unit/src/com/android/settings/deletionhelper/FetchDownloadsLoaderTest.java b/tests/unit/src/com/android/settings/deletionhelper/FetchDownloadsLoaderTest.java
new file mode 100644
index 0000000..52312d1
--- /dev/null
+++ b/tests/unit/src/com/android/settings/deletionhelper/FetchDownloadsLoaderTest.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.deletionhelper;
+
+import com.android.settings.deletionhelper.FetchDownloadsLoader.DownloadsResult;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.rules.TemporaryFolder;
+import org.junit.runners.JUnit4;
+
+import java.io.File;
+import java.io.FileWriter;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertEquals;
+
+@RunWith(JUnit4.class)
+public class FetchDownloadsLoaderTest {
+ @Rule
+ public TemporaryFolder temporaryFolder = new TemporaryFolder();
+
+ @Test
+ public void testEmptyDirectory() throws Exception {
+ DownloadsResult result =
+ FetchDownloadsLoader.collectFiles(temporaryFolder.getRoot());
+ assertNotNull(result);
+ assertEquals(0, result.totalSize);
+ assertEquals(0, result.files.size());
+ }
+
+ @Test
+ public void testFilesInDirectory() throws Exception {
+ temporaryFolder.newFile();
+ temporaryFolder.newFile();
+
+ DownloadsResult result =
+ FetchDownloadsLoader.collectFiles(temporaryFolder.getRoot());
+ assertNotNull(result);
+ assertEquals(0, result.totalSize);
+ assertEquals(2, result.files.size());
+ }
+
+ @Test
+ public void testNestedDirectories() throws Exception {
+ File tempDir = temporaryFolder.newFolder();
+
+ File testFile = File.createTempFile("test", null, tempDir);
+ testFile.deleteOnExit();
+ DownloadsResult result =
+ FetchDownloadsLoader.collectFiles(temporaryFolder.getRoot());
+ assertNotNull(result);
+ assertEquals(0, result.totalSize);
+ assertEquals(1, result.files.size());
+ }
+
+ @Test
+ public void testSumFileSizes() throws Exception {
+ File first = temporaryFolder.newFile();
+ FileWriter fileWriter = new FileWriter(first);
+ fileWriter.write("test");
+ fileWriter.close();
+
+ File second = temporaryFolder.newFile();
+ fileWriter = new FileWriter(second);
+ fileWriter.write("test2");
+ fileWriter.close();
+
+ DownloadsResult result =
+ FetchDownloadsLoader.collectFiles(temporaryFolder.getRoot());
+ assertNotNull(result);
+ assertEquals(9, result.totalSize);
+ assertEquals(2, result.files.size());
+ }
+}
diff --git a/tests/unit/src/com/android/settings/deletionhelper/PackageDeletionTaskTest.java b/tests/unit/src/com/android/settings/deletionhelper/PackageDeletionTaskTest.java
new file mode 100644
index 0000000..10ba585
--- /dev/null
+++ b/tests/unit/src/com/android/settings/deletionhelper/PackageDeletionTaskTest.java
@@ -0,0 +1,120 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.deletionhelper;
+
+import android.test.AndroidTestCase;
+import android.content.pm.IPackageDeleteObserver;
+import android.content.pm.PackageManager;
+import android.os.RemoteException;
+import android.test.mock.MockPackageManager;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import com.android.settings.deletionhelper.PackageDeletionTask;
+import com.android.settings.deletionhelper.PackageDeletionTask.Callback;
+
+import java.util.Set;
+import java.util.HashSet;
+
+public class PackageDeletionTaskTest extends AndroidTestCase {
+ private FakePackageManager mPackageManager;
+ private Set<String> mDeletedApps;
+
+ @Override
+ protected void setUp() throws Exception {
+ mPackageManager = new FakePackageManager();
+ mDeletedApps = new HashSet<String>();
+ }
+
+ @SmallTest
+ public void testDeleteNoApps() throws Exception {
+ runTask(new HashSet<String>(), false);
+ }
+
+ @SmallTest
+ public void testDeleteOneApp() throws Exception {
+ HashSet<String> appsToDelete = new HashSet<String>();
+ appsToDelete.add("app.test1");
+ runTask(appsToDelete, false);
+ }
+
+ @SmallTest
+ public void testDeleteManyApps() throws Exception {
+ HashSet<String> appsToDelete = new HashSet<String>();
+ appsToDelete.add("app.test1");
+ appsToDelete.add("app.test2");
+ runTask(appsToDelete, false);
+ }
+
+ @SmallTest
+ public void testDeleteFails() throws Exception {
+ HashSet<String> appsToDelete = new HashSet<String>();
+ appsToDelete.add("app.test1");
+ mPackageManager.deletionSucceeds = false;
+ runTask(appsToDelete, true);
+ }
+
+ private void runTask(HashSet<String> appsToDelete, boolean shouldFail) {
+ PackageDeletionTask task = new PackageDeletionTask(mPackageManager, appsToDelete,
+ new VerifierCallback(appsToDelete, shouldFail));
+ task.run();
+ }
+
+ class FakePackageManager extends MockPackageManager {
+ public boolean deletionSucceeds = true;
+
+ @Override
+ public void deletePackageAsUser(String packageName, IPackageDeleteObserver observer,
+ int flags, int userId) {
+ int resultCode;
+ if (deletionSucceeds) {
+ resultCode = PackageManager.DELETE_SUCCEEDED;
+ mDeletedApps.add(packageName);
+ } else {
+ resultCode = PackageManager.DELETE_FAILED_INTERNAL_ERROR;
+ }
+
+ try {
+ observer.packageDeleted(packageName, resultCode);
+ } catch (RemoteException e) {
+ fail(e.toString());
+ }
+ }
+ }
+
+ class VerifierCallback extends Callback {
+ private Set<String> mExpectedDeletedApps;
+ private boolean mShouldFail;
+
+ public VerifierCallback(HashSet<String> expectedDeletedApps, boolean shouldFail) {
+ mExpectedDeletedApps = expectedDeletedApps;
+ mShouldFail = shouldFail;
+ }
+
+ @Override
+ public void onSuccess() {
+ System.out.println("lol");
+ assertFalse(mShouldFail);
+ assertEquals(mExpectedDeletedApps, mDeletedApps);
+ }
+
+ @Override
+ public void onError() {
+ assertTrue(mShouldFail);
+ }
+ }
+
+}