Merge "Apply LightActionBar theme to Settings app."
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index f4a972b..010c515 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -453,6 +453,7 @@
<activity android:name="TetherProvisioningActivity"
android:exported="true"
android:permission="android.permission.TETHER_PRIVILEGED"
+ android:excludeFromRecents="true"
android:theme="@style/Theme.ProvisioningActivity">
<intent-filter android:priority="1">
<action android:name="android.settings.TETHER_PROVISIONING_UI" />
@@ -3090,7 +3091,7 @@
</activity-alias>
<activity android:name=".Settings$StorageDashboardActivity"
- android:label="@string/storage_settings"
+ android:label="@string/storage_settings_2"
android:icon="@drawable/ic_settings_storage">
<intent-filter android:priority="5">
<action android:name="com.android.settings.action.SETTINGS" />
@@ -3103,20 +3104,6 @@
android:value="true" />
</activity>
- <activity-alias android:name="InternalStorageDashboardAlias"
- android:targetActivity="Settings$StorageSettingsActivity"
- android:label="@string/storage_internal_title">
- <intent-filter android:priority="5">
- <action android:name="com.android.settings.action.SETTINGS" />
- </intent-filter>
- <meta-data android:name="com.android.settings.category"
- android:value="com.android.settings.category.ia.storage" />
- <meta-data android:name="com.android.settings.FRAGMENT_CLASS"
- android:value="com.android.settings.deviceinfo.StorageSettings" />
- <meta-data android:name="com.android.settings.PRIMARY_PROFILE_CONTROLLED"
- android:value="true" />
- </activity-alias>
-
<activity-alias android:name="SecurityDashboardAlias"
android:targetActivity="Settings$SecuritySettingsActivity">
<intent-filter android:priority="4">
@@ -3466,25 +3453,24 @@
<!-- Quick Settings tiles for Developer Options -->
<service
- android:name=".qstile.DevelopmentTiles$ShowLayout"
- android:label="@string/debug_layout"
- android:icon="@drawable/tile_icon_show_layout"
- android:permission="android.permission.BIND_QUICK_SETTINGS_TILE"
- android:enabled="false">
+ android:name=".qstile.DevelopmentModeTile"
+ android:label="@string/developer_tile"
+ android:icon="@drawable/ic_settings_development"
+ android:permission="android.permission.BIND_QUICK_SETTINGS_TILE"
+ android:enabled="true">
<intent-filter>
<action android:name="android.service.quicksettings.action.QS_TILE" />
</intent-filter>
</service>
- <service
- android:name=".qstile.DevelopmentTiles$GPUProfiling"
- android:label="@string/track_frame_time"
- android:icon="@drawable/tile_icon_graphics"
- android:permission="android.permission.BIND_QUICK_SETTINGS_TILE"
- android:enabled="false">
+ <activity
+ android:name=".qstile.DevelopmentTileConfigActivity"
+ android:excludeFromRecents="true"
+ android:launchMode="singleInstance"
+ android:label="@string/developer_tile">
<intent-filter>
- <action android:name="android.service.quicksettings.action.QS_TILE" />
+ <action android:name="android.service.quicksettings.action.QS_TILE_PREFERENCES" />
</intent-filter>
- </service>
+ </activity>
<activity android:name=".HelpTrampoline"
android:exported="true"
diff --git a/res/drawable/tile_icon_graphics.xml b/res/drawable/tile_icon_graphics.xml
deleted file mode 100644
index 84a0a5a..0000000
--- a/res/drawable/tile_icon_graphics.xml
+++ /dev/null
@@ -1,52 +0,0 @@
-<!--
-Copyright (C) 2015 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="24dp"
- android:height="24dp"
- android:viewportWidth="24.0"
- android:viewportHeight="24.0">
- <path
- android:fillColor="#FFFFFFFF"
- android:pathData="M23,1v22H1V1H23 M24,0H0v24h24V0L24,0z"/>
- <path
- android:strokeColor="#FFFFFFFF"
- android:strokeWidth="0.667"
- android:pathData="M5,19L1,23"/>
- <path
- android:strokeColor="#FFFFFFFF"
- android:strokeWidth="0.667"
- android:pathData="M1,1L5,5"/>
- <path
- android:strokeColor="#FFFFFFFF"
- android:strokeWidth="0.667"
- android:pathData="M19,5L23,1"/>
- <path
- android:strokeColor="#FFFFFFFF"
- android:strokeWidth="0.667"
- android:pathData="M19,19L23,23"/>
- <path
- android:fillColor="#FFFFFFFF"
- android:pathData="M14,3.8l-4,0l-0.2,-0.8l4.4,0z"/>
- <path
- android:fillColor="#FFFFFFFF"
- android:pathData="M18.8,5.2v13.5H5.2V5.2H18.8 M19.5,4.5h-15v15h15V4.5L19.5,4.5z"/>
- <path
- android:fillColor="#FFFFFFFF"
- android:pathData="M6.5,9.5h5v11h-5z"/>
- <path
- android:fillColor="#FFFFFFFF"
- android:pathData="M12.5,16.5h5v5h-5z"/>
-</vector>
diff --git a/res/drawable/tile_icon_show_layout.xml b/res/drawable/tile_icon_show_layout.xml
deleted file mode 100644
index b9b825e..0000000
--- a/res/drawable/tile_icon_show_layout.xml
+++ /dev/null
@@ -1,60 +0,0 @@
-<!--
-Copyright (C) 2015 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="24dp"
- android:height="24dp"
- android:viewportWidth="24.0"
- android:viewportHeight="24.0">
- <path
- android:fillColor="#FFFFFFFF"
- android:pathData="M12,7.2c-3.2,0 -5.9,2 -7,4.8c1.1,2.8 3.8,4.8 7,4.8s5.9,-2 7,-4.8C17.9,9.2 15.2,7.2 12,7.2zM12,15.2c-1.8,0 -3.2,-1.4 -3.2,-3.2s1.4,-3.2 3.2,-3.2s3.2,1.4 3.2,3.2S13.8,15.2 12,15.2zM12,10.1c-1.1,0 -1.9,0.9 -1.9,1.9s0.9,1.9 1.9,1.9s1.9,-0.9 1.9,-1.9S13.1,10.1 12,10.1z"/>
- <path
- android:fillColor="#80FFFFFF"
- android:pathData="M0.0,6.0h1.0v12.0h-1.0z"/>
- <path
- android:fillColor="#80FFFFFF"
- android:pathData="M6.0,0.0h12.0v1.0h-12.0z"/>
- <path
- android:fillColor="#80FFFFFF"
- android:pathData="M23.0,6.0h1.0v12.0h-1.0z"/>
- <path
- android:fillColor="#80FFFFFF"
- android:pathData="M6.0,23.0h12.0v1.0h-12.0z"/>
- <path
- android:fillColor="#FFFFFFFF"
- android:pathData="M1.0,23.0l0.0,-5.0l-1.0,0.0l0.0,6.0l6.0,0.0l0.0,-1.0z"/>
- <path
- android:fillColor="#FFFFFFFF"
- android:pathData="M1.0,1.0l5.0,0.0l0.0,-1.0l-6.0,0.0l0.0,6.0l1.0,0.0z"/>
- <path
- android:fillColor="#FFFFFFFF"
- android:pathData="M18.0,0.0l0.0,1.0l5.0,0.0l0.0,5.0l1.0,0.0l0.0,-6.0z"/>
- <path
- android:fillColor="#FFFFFFFF"
- android:pathData="M23.0,23.0l-5.0,0.0l0.0,1.0l6.0,0.0l0.0,-6.0l-1.0,0.0z"/>
- <path
- android:fillColor="#80FFFFFF"
- android:pathData="M9.5,6.0h5.0v1.0h-5.0z"/>
- <path
- android:fillColor="#80FFFFFF"
- android:pathData="M9.5,17.0h5.0v1.0h-5.0z"/>
- <path
- android:fillColor="#FFFFFFFF"
- android:pathData="M4.5,7.0l5.0,0.0l0.0,-1.0l-6.0,0.0l0.0,6.0l0.0,6.0l6.0,0.0l0.0,-1.0l-5.0,0.0l0.0,-5.0z"/>
- <path
- android:fillColor="#FFFFFFFF"
- android:pathData="M14.5,6.0l0.0,1.0l5.0,0.0l0.0,5.0l0.0,5.0l-5.0,0.0l0.0,1.0l6.0,0.0l0.0,-6.0l0.0,-6.0z"/>
-</vector>
diff --git a/res/layout/development_tile_config_header.xml b/res/layout/development_tile_config_header.xml
new file mode 100644
index 0000000..5169da2
--- /dev/null
+++ b/res/layout/development_tile_config_header.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
+ -->
+
+<TextView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="?android:attr/actionBarSize"
+ android:background="@drawable/switchbar_background"
+ android:text="@string/developer_tile_unavailable"
+ android:paddingStart="8dip"
+ android:paddingEnd="8dip"
+ android:singleLine="true"
+ android:ellipsize="marquee"
+ android:marqueeRepeatLimit ="marquee_forever"
+ android:textSize="16sp"
+ android:fontFamily="sans-serif"
+ android:textColor="?android:attr/textColorPrimary"
+ android:gravity="center" />
diff --git a/res/layout/storage_item_alternate.xml b/res/layout/storage_item_alternate.xml
new file mode 100644
index 0000000..b41c82b
--- /dev/null
+++ b/res/layout/storage_item_alternate.xml
@@ -0,0 +1,56 @@
+<?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:minHeight="?android:attr/listPreferredItemHeightSmall"
+ android:gravity="center_vertical"
+ android:paddingStart="@dimen/preference_no_icon_padding_start"
+ android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
+ android:paddingTop="16dip"
+ android:paddingBottom="16dip"
+ android:background="?android:attr/selectableItemBackground">
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal">
+
+ <TextView
+ android:id="@android:id/title"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:singleLine="true"
+ android:textAppearance="@android:style/TextAppearance.Material.Subhead"
+ android:textAlignment="viewStart"
+ android:ellipsize="marquee"
+ android:fadingEdge="horizontal" />
+
+ <TextView
+ android:id="@android:id/summary"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textAlignment="viewStart"
+ android:textAppearance="@android:style/TextAppearance.Material.Body1"
+ android:textColor="?android:attr/textColorSecondaryNoDisable"
+ android:maxLines="10" />
+
+ </LinearLayout>
+
+</LinearLayout>
diff --git a/res/layout/storage_summary_donut.xml b/res/layout/storage_summary_donut.xml
new file mode 100644
index 0000000..9cffe69
--- /dev/null
+++ b/res/layout/storage_summary_donut.xml
@@ -0,0 +1,60 @@
+<?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.
+-->
+
+<!-- TODO: Update this view to not match the existing storage summary.-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ android:minHeight="?android:attr/listPreferredItemHeightSmall"
+ android:gravity="center_vertical"
+ android:paddingStart="@dimen/preference_no_icon_padding_start"
+ android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
+ android:paddingTop="16dip"
+ android:paddingBottom="16dip"
+ android:background="?android:attr/selectableItemBackground">
+
+ <TextView
+ android:id="@android:id/title"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:singleLine="true"
+ android:textAlignment="viewStart"
+ android:textAppearance="@android:style/TextAppearance.Material.Subhead"
+ android:textColor="?android:attr/colorAccent"
+ android:textSize="36sp"
+ android:ellipsize="marquee"
+ android:fadingEdge="horizontal" />
+
+ <TextView
+ android:id="@android:id/summary"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textAlignment="viewStart"
+ android:textAppearance="@android:style/TextAppearance.Material.Body1"
+ android:maxLines="10" />
+
+ <ProgressBar
+ android:id="@android:id/progress"
+ android:layout_width="match_parent"
+ android:layout_height="8dp"
+ android:layout_marginTop="16dp"
+ android:layout_marginBottom="8dp"
+ android:visibility="gone"
+ android:max="100"
+ style="?android:attr/progressBarStyleHorizontal" />
+
+</LinearLayout>
diff --git a/res/values-nl/strings.xml b/res/values-nl/strings.xml
index d816790..6a8a6cd 100644
--- a/res/values-nl/strings.xml
+++ b/res/values-nl/strings.xml
@@ -425,7 +425,7 @@
<string name="crypt_keeper_failed_title" msgid="7133499413023075961">"Encryptie mislukt"</string>
<string name="crypt_keeper_failed_summary" product="tablet" msgid="8219375738445017266">"Het versleutelen is onderbroken en kan niet worden voltooid. Als gevolg hiervan zijn de gegevens op je telefoon niet meer toegankelijk. \n\nAls je je tablet weer wilt gebruiken, moet je de fabrieksinstellingen herstellen. Wanneer je de tablet instelt na het herstel, krijg je de mogelijkheid gegevens waarvan je een back-up hebt gemaakt in je Google-account, terug te zetten."</string>
<string name="crypt_keeper_failed_summary" product="default" msgid="3270131542549577953">"Het versleutelen is onderbroken en kan niet worden voltooid. Daardoor zijn de gegevens op je telefoon niet meer toegankelijk. \n\nAls je je telefoon weer wilt gebruiken, moet je de fabrieksinstellingen herstellen. Wanneer je de telefoon instelt na het herstel, krijg je de mogelijkheid gegevens terug te zetten waarvan je een back-up hebt gemaakt in je Google-account."</string>
- <string name="crypt_keeper_data_corrupt_title" msgid="8759119849089795751">"Decodering mislukt"</string>
+ <string name="crypt_keeper_data_corrupt_title" msgid="8759119849089795751">"Ontsleutelen mislukt"</string>
<string name="crypt_keeper_data_corrupt_summary" product="tablet" msgid="840107296925798402">"Het wachtwoord dat je hebt opgegeven, is correct, maar je gegevens zijn beschadigd. \n\nAls je je tablet weer wilt gebruiken, moet je deze terugzetten naar de fabrieksinstellingen. Wanneer je je tablet configureert na het terugzetten, heb je de mogelijkheid gegevens waarvan je een back-up in je Google-account hebt gemaakt, te herstellen."</string>
<string name="crypt_keeper_data_corrupt_summary" product="default" msgid="8843311420059663824">"Het wachtwoord dat je hebt opgegeven, is correct, maar je gegevens zijn beschadigd. \n\nAls je je telefoon weer wilt gebruiken, moet je deze terugzetten naar de fabrieksinstellingen. Wanneer je je telefoon configureert na het terugzetten, heb je de mogelijkheid gegevens waarvan je een back-up in je Google-account hebt gemaakt, te herstellen."</string>
<string name="crypt_keeper_switch_input_method" msgid="4168332125223483198">"Invoermethode schakelen"</string>
diff --git a/res/values-sv/strings.xml b/res/values-sv/strings.xml
index 8b1f3ed..b88f762 100644
--- a/res/values-sv/strings.xml
+++ b/res/values-sv/strings.xml
@@ -321,7 +321,7 @@
<string name="owner_info_settings_title" msgid="5530285568897386122">"Låsskärmsmeddelande"</string>
<string name="security_enable_widgets_title" msgid="2754833397070967846">"Aktivera widgetar"</string>
<string name="security_enable_widgets_disabled_summary" msgid="1557090442377855233">"Har inaktiverats av administratören"</string>
- <string name="owner_info_settings_summary" msgid="7472393443779227052">"Ingen"</string>
+ <string name="owner_info_settings_summary" msgid="7472393443779227052">"Inget"</string>
<string name="owner_info_settings_status" msgid="120407527726476378">"<xliff:g id="COUNT_0">%1$d</xliff:g>/<xliff:g id="COUNT_1">%2$d</xliff:g>"</string>
<string name="owner_info_settings_edit_text_hint" msgid="7591869574491036360">"T.ex. Jockes Android."</string>
<string name="user_info_settings_title" msgid="1195015434996724736">"Användarinfo"</string>
diff --git a/res/values/colors.xml b/res/values/colors.xml
index 3be4038..a8d35dc 100644
--- a/res/values/colors.xml
+++ b/res/values/colors.xml
@@ -111,4 +111,6 @@
<!-- Gestures settings -->
<color name="gestures_setting_background_color">#f5f5f5</color>
+ <!-- TODO: revert it after the SettingsShadowResources is globally finalized -->
+ <color name="status_bar_color">#3c3c3c</color>
</resources>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 955b8cc..68728c8 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -1554,7 +1554,7 @@
<!-- Used in the Android Beam sharing preferences screen. This phrase is a trademark. [CHAR LIMIT=32] -->
<string name="android_beam_label">Android Beam</string>
<!-- Explanation of the Android Beam feature in the Android Beam settings panel. The use of "beam" here is as a verb and not considered trademarked. [CHAR LIMIT=NONE] -->
- <string name="android_beam_explained">When this feature is turned on, you can beam app content to another NFC-capable device by holding the devices close together. For example, you can beam Browser pages, YouTube videos, People contacts, and more.\n\nJust bring the devices together (typically back to back) and then tap your screen. The app determines what gets beamed.</string>
+ <string name="android_beam_explained">When this feature is turned on, you can beam app content to another NFC-capable device by holding the devices close together. For example, you can beam web pages, YouTube videos, contacts, and more.\n\nJust bring the devices together (typically back to back) and then tap your screen. The app determines what gets beamed.</string>
<!-- Wi-Fi Settings --> <skip />
<!-- Used in the 1st-level settings screen to turn on Wi-Fi -->
@@ -7680,6 +7680,12 @@
<!-- Title of developer options to set the smallest width of the screen [CHAR LIMIT=60]-->
<string name="developer_smallest_width">Smallest width</string>
+ <!-- Title of developer options time [CHAR LIMIT=60]-->
+ <string name="developer_tile">Development mode</string>
+
+ <!-- Message shown when there is no active state for development mode [CHAR LIMIT=NONE]-->
+ <string name="developer_tile_unavailable">No active state selected</string>
+
<!-- Message shown when there are no premium SMS apps [CHAR LIMIT=NONE] -->
<string name="premium_sms_none">No installed apps have requested Premium SMS access</string>
@@ -7996,4 +8002,23 @@
<string name="enterprise_privacy_security_logs">Your most recent security log</string>
<!-- Label indicating that the date at which the admin last took a particular action was "never" (i.e. the admin never took the action so far). -->
<string name="enterprise_privacy_never">Never</string>
+
+ <!-- Preference label for the Photos & Videos storage section. [CHAR LIMIT=50] -->
+ <string name="storage_photos_videos">Photos & Videos</string>
+
+ <!-- Preference label for the Music & Audio storage section. [CHAR LIMIT=50] -->
+ <string name="storage_music_audio">Music & Audio</string>
+
+ <!-- Preference label for the Games storage section. [CHAR LIMIT=50] -->
+ <string name="storage_games">Games</string>
+
+ <!-- Preference label for the Other apps storage section. [CHAR LIMIT=50] -->
+ <string name="storage_other_apps">Other apps</string>
+
+ <!-- Preference label for the Files storage section. [CHAR LIMIT=50] -->
+ <string name="storage_files">Files</string>
+
+ <!-- Main settings screen item's title to go into the storage settings screen [CHAR LIMIT=25] -->
+ <string name="storage_settings_2" >Phone Storage</string>
+
</resources>
diff --git a/res/values/themes.xml b/res/values/themes.xml
index abbe3a7..f1cca37 100644
--- a/res/values/themes.xml
+++ b/res/values/themes.xml
@@ -155,7 +155,7 @@
<item name="*android:successColor">@color/lock_pattern_view_success_color</item>
<item name="*android:errorColor">@color/lock_pattern_view_error_color</item>
- <item name="android:statusBarColor">@*android:color/secondary_device_default_settings</item>
+ <item name="android:statusBarColor">@color/status_bar_color</item>
</style>
<style name="Theme.SubSettings" parent="Theme.Settings">
diff --git a/res/xml/development_tile_prefs.xml b/res/xml/development_tile_prefs.xml
new file mode 100644
index 0000000..26f1c24
--- /dev/null
+++ b/res/xml/development_tile_prefs.xml
@@ -0,0 +1,114 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2017 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" >
+
+ <PreferenceCategory
+ android:key="debug_input_category"
+ android:title="@string/debug_input_category">
+
+ <SwitchPreference
+ android:key="show_touches"
+ android:title="@string/show_touches"
+ android:summary="@string/show_touches_summary"/>
+
+ <SwitchPreference
+ android:key="pointer_location"
+ android:title="@string/pointer_location"
+ android:summary="@string/pointer_location_summary"/>
+
+ </PreferenceCategory>
+
+ <PreferenceCategory
+ android:key="debug_drawing_category"
+ android:title="@string/debug_drawing_category">
+
+ <SwitchPreference
+ android:key="debug_layout"
+ android:title="@string/debug_layout"
+ android:summary="@string/debug_layout_summary"/>
+
+ <SwitchPreference
+ android:key="force_rtl_layout_all_locales"
+ android:title="@string/force_rtl_layout_all_locales"
+ android:summary="@string/force_rtl_layout_all_locales_summary"/>
+
+ <ListPreference
+ android:key="window_animation_scale"
+ android:defaultValue="1"
+ android:summary="%s"
+ android:title="@string/window_animation_scale_title"
+ android:entries="@array/window_animation_scale_entries"
+ android:entryValues="@array/window_animation_scale_values" />
+
+ <ListPreference
+ android:key="transition_animation_scale"
+ android:defaultValue="1"
+ android:summary="%s"
+ android:title="@string/transition_animation_scale_title"
+ android:entries="@array/transition_animation_scale_entries"
+ android:entryValues="@array/transition_animation_scale_values" />
+
+ <ListPreference
+ android:key="animator_duration_scale"
+ android:defaultValue="1"
+ android:summary="%s"
+ android:title="@string/animator_duration_scale_title"
+ android:entries="@array/animator_duration_scale_entries"
+ android:entryValues="@array/animator_duration_scale_values" />
+
+ </PreferenceCategory>
+
+ <PreferenceCategory
+ android:key="debug_hw_drawing_category"
+ android:title="@string/debug_hw_drawing_category">
+
+ <SwitchPreference
+ android:key="show_hw_screen_udpates"
+ android:title="@string/show_hw_screen_updates"
+ android:summary="@string/show_hw_screen_updates_summary"/>
+
+ <SwitchPreference
+ android:key="show_hw_layers_udpates"
+ android:title="@string/show_hw_layers_updates"
+ android:summary="@string/show_hw_layers_updates_summary"/>
+
+ <ListPreference
+ android:key="debug_hw_overdraw"
+ android:defaultValue="false"
+ android:summary="%s"
+ android:title="@string/debug_hw_overdraw"
+ android:entries="@array/debug_hw_overdraw_entries"
+ android:entryValues="@array/debug_hw_overdraw_values" />
+
+ </PreferenceCategory>
+
+ <PreferenceCategory
+ android:key="debug_monitoring_category"
+ android:title="@string/debug_monitoring_category">
+
+ <ListPreference
+ android:key="track_frame_time"
+ android:defaultValue="false"
+ android:summary="%s"
+ android:title="@string/track_frame_time"
+ android:entries="@array/track_frame_time_entries"
+ android:entryValues="@array/track_frame_time_values" />
+
+ </PreferenceCategory>
+
+</PreferenceScreen>
diff --git a/res/xml/storage_dashboard_fragment.xml b/res/xml/storage_dashboard_fragment.xml
index 92e3ddb..d577267 100644
--- a/res/xml/storage_dashboard_fragment.xml
+++ b/res/xml/storage_dashboard_fragment.xml
@@ -17,9 +17,36 @@
<PreferenceScreen
xmlns:android="http://schemas.android.com/apk/res/android"
android:title="@string/storage_settings">
- <Preference
- android:key="pref_manage_storage"
- android:title="@string/storage_menu_manage"
+ <com.android.settings.deviceinfo.storage.StorageSummaryDonutPreference
+ android:key="pref_summary" />
+ <com.android.settings.deviceinfo.storage.StorageItemPreferenceAlternate
+ android:key="pref_photos_videos"
+ android:title="@string/storage_photos_videos"
android:fragment="com.android.settings.deletionhelper.AutomaticStorageManagerSettings">
- </Preference>
+ </com.android.settings.deviceinfo.storage.StorageItemPreferenceAlternate>
+ <com.android.settings.deviceinfo.storage.StorageItemPreferenceAlternate
+ android:key="pref_music_audio"
+ android:title="@string/storage_music_audio"
+ android:fragment="com.android.settings.deletionhelper.AutomaticStorageManagerSettings">
+ </com.android.settings.deviceinfo.storage.StorageItemPreferenceAlternate>
+ <com.android.settings.deviceinfo.storage.StorageItemPreferenceAlternate
+ android:key="pref_games"
+ android:title="@string/storage_games"
+ android:fragment="com.android.settings.deletionhelper.AutomaticStorageManagerSettings">
+ </com.android.settings.deviceinfo.storage.StorageItemPreferenceAlternate>
+ <com.android.settings.deviceinfo.storage.StorageItemPreferenceAlternate
+ android:key="pref_other_apps"
+ android:title="@string/storage_other_apps"
+ android:fragment="com.android.settings.deletionhelper.AutomaticStorageManagerSettings">
+ </com.android.settings.deviceinfo.storage.StorageItemPreferenceAlternate>
+ <com.android.settings.deviceinfo.storage.StorageItemPreferenceAlternate
+ android:key="pref_system"
+ android:title="@string/storage_detail_system"
+ android:fragment="com.android.settings.deletionhelper.AutomaticStorageManagerSettings">
+ </com.android.settings.deviceinfo.storage.StorageItemPreferenceAlternate>
+ <com.android.settings.deviceinfo.storage.StorageItemPreferenceAlternate
+ android:key="pref_files"
+ android:title="@string/storage_files"
+ android:fragment="com.android.settings.deletionhelper.AutomaticStorageManagerSettings">
+ </com.android.settings.deviceinfo.storage.StorageItemPreferenceAlternate>
</PreferenceScreen>
\ No newline at end of file
diff --git a/src/com/android/settings/SecuritySettings.java b/src/com/android/settings/SecuritySettings.java
index 46e7fe5..b092857 100644
--- a/src/com/android/settings/SecuritySettings.java
+++ b/src/com/android/settings/SecuritySettings.java
@@ -62,10 +62,13 @@
import com.android.settings.search.Index;
import com.android.settings.search.Indexable;
import com.android.settings.search.SearchIndexableRaw;
+import com.android.settings.security.SecurityFeatureProvider;
import com.android.settingslib.RestrictedLockUtils;
import com.android.settingslib.RestrictedPreference;
import com.android.settingslib.RestrictedSwitchPreference;
import com.android.settingslib.drawer.CategoryKey;
+import com.android.settingslib.drawer.DashboardCategory;
+import com.android.settingslib.drawer.Tile;
import java.util.ArrayList;
import java.util.List;
@@ -130,6 +133,7 @@
private DashboardFeatureProvider mDashboardFeatureProvider;
private DevicePolicyManager mDPM;
+ private SecurityFeatureProvider mSecurityFeatureProvider;
private SubscriptionManager mSubscriptionManager;
private UserManager mUm;
@@ -183,6 +187,8 @@
mDashboardFeatureProvider = FeatureFactory.getFactory(activity)
.getDashboardFeatureProvider(activity);
+ mSecurityFeatureProvider = FeatureFactory.getFactory(activity).getSecurityFeatureProvider();
+
if (savedInstanceState != null
&& savedInstanceState.containsKey(TRUST_AGENT_CLICK_INTENT)) {
mTrustAgentClickIntent = savedInstanceState.getParcelable(TRUST_AGENT_CLICK_INTENT);
@@ -416,6 +422,11 @@
}
}
+ // Update preference data with tile data. Security feature provider only updates the data
+ // if it actually needs to be changed.
+ mSecurityFeatureProvider.updatePreferences(getActivity(), root,
+ mDashboardFeatureProvider.getTilesForCategory(CategoryKey.CATEGORY_SECURITY));
+
for (int i = 0; i < SWITCH_PREFERENCE_KEYS.length; i++) {
final Preference pref = findPreference(SWITCH_PREFERENCE_KEYS[i]);
if (pref != null) pref.setOnPreferenceChangeListener(this);
diff --git a/src/com/android/settings/SettingsActivity.java b/src/com/android/settings/SettingsActivity.java
index b9be118..179e352 100644
--- a/src/com/android/settings/SettingsActivity.java
+++ b/src/com/android/settings/SettingsActivity.java
@@ -61,7 +61,7 @@
import com.android.settings.dashboard.DashboardSummary;
import com.android.settings.dashboard.SearchResultsSummary;
import com.android.settings.overlay.FeatureFactory;
-import com.android.settings.qstile.DevelopmentTiles;
+import com.android.settings.qstile.DevelopmentModeTile;
import com.android.settings.search.DynamicIndexableContentMonitor;
import com.android.settings.search.Index;
import com.android.settings.search2.SearchFeatureProvider;
@@ -994,7 +994,7 @@
showDev, isAdmin, pm);
// Reveal development-only quick settings tiles
- DevelopmentTiles.setTilesEnabled(this, showDev);
+ setTileEnabled(new ComponentName(this, DevelopmentModeTile.class), showDev);
if (UserHandle.MU_ENABLED && !isAdmin) {
// When on restricted users, disable all extra categories (but only the settings ones).
diff --git a/src/com/android/settings/bluetooth/BluetoothSettings.java b/src/com/android/settings/bluetooth/BluetoothSettings.java
index 2a1341e..d709726 100644
--- a/src/com/android/settings/bluetooth/BluetoothSettings.java
+++ b/src/com/android/settings/bluetooth/BluetoothSettings.java
@@ -428,10 +428,7 @@
});
}
getPreferenceScreen().removeAll();
- Spannable boldSpan = (Spannable) emptyView.getText();
- boldSpan.setSpan(
- new TextAppearanceSpan(getActivity(), android.R.style.TextAppearance_Medium), 0,
- briefText.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
+ setTextSpan(emptyView.getText(), briefText);
}
@Override
@@ -461,6 +458,16 @@
updateContent(mLocalAdapter.getBluetoothState());
}
+ @VisibleForTesting
+ void setTextSpan(CharSequence text, CharSequence briefText) {
+ if (text instanceof Spannable) {
+ Spannable boldSpan = (Spannable) text;
+ boldSpan.setSpan(
+ new TextAppearanceSpan(getActivity(), android.R.style.TextAppearance_Medium), 0,
+ briefText.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
+ }
+ }
+
private final View.OnClickListener mDeviceProfilesListener = new View.OnClickListener() {
@Override
public void onClick(View v) {
diff --git a/src/com/android/settings/deviceinfo/ManageStoragePreferenceController.java b/src/com/android/settings/deviceinfo/ManageStoragePreferenceController.java
index f4dd14e..3170a87 100644
--- a/src/com/android/settings/deviceinfo/ManageStoragePreferenceController.java
+++ b/src/com/android/settings/deviceinfo/ManageStoragePreferenceController.java
@@ -23,7 +23,7 @@
public class ManageStoragePreferenceController extends PreferenceController {
- public static final String KEY_MANAGE_STORAGE = "pref_manage_storage";
+ public static final String KEY_MANAGE_STORAGE = "footer_preference";
public ManageStoragePreferenceController(Context context) {
super(context);
diff --git a/src/com/android/settings/deviceinfo/StorageDashboardFragment.java b/src/com/android/settings/deviceinfo/StorageDashboardFragment.java
index 8992830..5d1ac4a 100644
--- a/src/com/android/settings/deviceinfo/StorageDashboardFragment.java
+++ b/src/com/android/settings/deviceinfo/StorageDashboardFragment.java
@@ -17,15 +17,24 @@
package com.android.settings.deviceinfo;
import android.content.Context;
+import android.os.Bundle;
+import android.os.storage.StorageManager;
+import android.os.storage.VolumeInfo;
import android.provider.SearchIndexableResource;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
import com.android.internal.logging.nano.MetricsProto;
import com.android.settings.R;
import com.android.settings.core.PreferenceController;
import com.android.settings.dashboard.DashboardFragment;
+import com.android.settings.deviceinfo.storage.StorageItemPreferenceController;
+import com.android.settings.deviceinfo.storage.StorageSummaryDonutPreferenceController;
import com.android.settings.overlay.FeatureFactory;
import com.android.settings.search.BaseSearchIndexProvider;
import com.android.settings.search.Indexable;
+import com.android.settings.widget.FooterPreference;
import com.android.settingslib.drawer.CategoryKey;
import java.util.ArrayList;
@@ -33,9 +42,53 @@
import java.util.List;
public class StorageDashboardFragment extends DashboardFragment {
-
private static final String TAG = "StorageDashboardFrag";
+ private VolumeInfo mVolume;
+ private long mTotalSize;
+
+ private StorageSummaryDonutPreferenceController mSummaryController;
+
+ private boolean isVolumeValid() {
+ return (mVolume != null) && (mVolume.getType() == VolumeInfo.TYPE_PRIVATE)
+ && mVolume.isMountedReadable();
+ }
+
+ @Override
+ public void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+ final Context context = getActivity();
+
+ // Initialize the storage sizes that we can quickly calc.
+ StorageManager sm = context.getSystemService(StorageManager.class);
+ mVolume = sm.findVolumeById(VolumeInfo.ID_PRIVATE_INTERNAL);
+ if (!isVolumeValid()) {
+ getActivity().finish();
+ return;
+ }
+
+ final long sharedDataSize = mVolume.getPath().getTotalSpace();
+ mTotalSize = sm.getPrimaryStorageSize();
+ long systemSize = mTotalSize - sharedDataSize;
+
+ if (mTotalSize <= 0) {
+ mTotalSize = sharedDataSize;
+ systemSize = 0;
+ }
+
+ final long usedBytes = mTotalSize - mVolume.getPath().getFreeSpace();
+ mSummaryController.updateBytes(usedBytes, mTotalSize);
+
+ // Initialize the footer preference to go to the smart storage management.
+ final FooterPreference pref = mFooterPreferenceMixin.createFooterPreference();
+ pref.setTitle(R.string.storage_menu_manage);
+ pref.setFragment("com.android.settings.deletionhelper.AutomaticStorageManagerSettings");
+ pref.setIcon(R.drawable.ic_settings_storage);
+ pref.setEnabled(true);
+
+
+ }
+
@Override
public int getMetricsCategory() {
return MetricsProto.MetricsEvent.SETTINGS_STORAGE_CATEGORY;
@@ -59,10 +112,25 @@
@Override
protected List<PreferenceController> getPreferenceControllers(Context context) {
final List<PreferenceController> controllers = new ArrayList<>();
+ mSummaryController = new StorageSummaryDonutPreferenceController(context);
+ controllers.add(mSummaryController);
controllers.add(new ManageStoragePreferenceController(context));
+ controllers.add(new StorageItemPreferenceController(context, "pref_photos_videos"));
+ controllers.add(new StorageItemPreferenceController(context, "pref_music_audio"));
+ controllers.add(new StorageItemPreferenceController(context, "pref_games"));
+ controllers.add(new StorageItemPreferenceController(context, "pref_other_apps"));
+ controllers.add(new StorageItemPreferenceController(context, "pref_system"));
+ controllers.add(new StorageItemPreferenceController(context, "pref_files"));
return controllers;
}
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ View root = super.onCreateView(inflater, container, savedInstanceState);
+ // TODO: Add loader to load the storage sizes for the StorageItemPreferenceControllers.
+ return root;
+ }
/**
* For Search.
*/
diff --git a/src/com/android/settings/deviceinfo/storage/StorageItemPreferenceAlternate.java b/src/com/android/settings/deviceinfo/storage/StorageItemPreferenceAlternate.java
new file mode 100644
index 0000000..932a779
--- /dev/null
+++ b/src/com/android/settings/deviceinfo/storage/StorageItemPreferenceAlternate.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.deviceinfo.storage;
+
+import android.content.Context;
+import android.support.v7.preference.Preference;
+import android.support.v7.preference.PreferenceViewHolder;
+import android.text.format.Formatter;
+import android.util.AttributeSet;
+import android.view.View;
+
+import com.android.settings.R;
+
+public class StorageItemPreferenceAlternate extends Preference {
+ public StorageItemPreferenceAlternate(Context context) {
+ this(context, null);
+ }
+
+ public StorageItemPreferenceAlternate(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ setLayoutResource(R.layout.storage_item_alternate);
+ setSummary(R.string.memory_calculating_size);
+ }
+
+ public void setStorageSize(long size) {
+ setSummary(size == 0
+ ? String.valueOf(0)
+ : Formatter.formatFileSize(getContext(), size));
+ }
+}
\ No newline at end of file
diff --git a/src/com/android/settings/deviceinfo/storage/StorageItemPreferenceController.java b/src/com/android/settings/deviceinfo/storage/StorageItemPreferenceController.java
new file mode 100644
index 0000000..6a61072
--- /dev/null
+++ b/src/com/android/settings/deviceinfo/storage/StorageItemPreferenceController.java
@@ -0,0 +1,69 @@
+/*
+ * 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.deviceinfo.storage;
+
+import android.content.Context;
+import android.support.v7.preference.Preference;
+
+import com.android.settings.core.PreferenceController;
+
+/**
+ * StorageItemPreferenceController handles the updating of a single storage preference line item.
+ */
+public class StorageItemPreferenceController extends PreferenceController {
+ private static final long NOT_YET_SET = -1;
+ private final String mKey;
+ private long mStorageSize;
+
+ public StorageItemPreferenceController(Context context, String key) {
+ super(context);
+ mKey = key;
+ mStorageSize = NOT_YET_SET;
+ }
+
+ @Override
+ public boolean isAvailable() {
+ return true;
+ }
+
+ @Override
+ public boolean handlePreferenceTreeClick(Preference preference) {
+ return false;
+ }
+
+ @Override
+ public String getPreferenceKey() {
+ return mKey;
+ }
+
+ @Override
+ public void updateState(Preference preference) {
+ if (preference == null || mStorageSize == NOT_YET_SET) {
+ return;
+ }
+
+ StorageItemPreferenceAlternate summary = (StorageItemPreferenceAlternate) preference;
+ summary.setStorageSize(mStorageSize);
+ }
+
+ /**
+ * Sets the amount of bytes used by this storage item.
+ */
+ public void setStorageSize(long size) {
+ mStorageSize = size;
+ }
+}
diff --git a/src/com/android/settings/deviceinfo/storage/StorageSummaryDonutPreference.java b/src/com/android/settings/deviceinfo/storage/StorageSummaryDonutPreference.java
new file mode 100644
index 0000000..d6fd354
--- /dev/null
+++ b/src/com/android/settings/deviceinfo/storage/StorageSummaryDonutPreference.java
@@ -0,0 +1,71 @@
+/*
+ * 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.deviceinfo.storage;
+
+import android.content.Context;
+import android.support.v7.preference.Preference;
+import android.support.v7.preference.PreferenceViewHolder;
+import android.util.AttributeSet;
+import android.util.MathUtils;
+import android.view.View;
+import android.widget.ProgressBar;
+
+import com.android.settings.R;
+
+/**
+ * StorageSummaryDonutPreference is a preference which summarizes the used and remaining storage left
+ * on a given storage volume. It is visualized with a donut graphing the % used.
+ */
+public class StorageSummaryDonutPreference extends Preference {
+ private int mPercent = -1;
+
+ public StorageSummaryDonutPreference(Context context) {
+ this(context, null);
+ }
+
+ public StorageSummaryDonutPreference(Context context, AttributeSet attrs) {
+ super(context, attrs);
+
+ setLayoutResource(R.layout.storage_summary_donut);
+ setEnabled(false);
+ }
+
+ public void setPercent(long usedBytes, long totalBytes) {
+ if (totalBytes == 0) {
+ return;
+ }
+
+ mPercent = MathUtils.constrain((int) ((usedBytes * 100) / totalBytes),
+ (usedBytes > 0) ? 1 : 0, 100);
+ }
+
+ @Override
+ public void onBindViewHolder(PreferenceViewHolder view) {
+ // TODO: Replace the progress bar with a donut.
+ final ProgressBar progress = (ProgressBar) view.findViewById(android.R.id.progress);
+ if (mPercent != -1) {
+ progress.setVisibility(View.VISIBLE);
+ progress.setProgress(mPercent);
+ progress.setScaleY(7f);
+ } else {
+ progress.setVisibility(View.GONE);
+ }
+
+ super.onBindViewHolder(view);
+ }
+
+}
diff --git a/src/com/android/settings/deviceinfo/storage/StorageSummaryDonutPreferenceController.java b/src/com/android/settings/deviceinfo/storage/StorageSummaryDonutPreferenceController.java
new file mode 100644
index 0000000..45a81e8
--- /dev/null
+++ b/src/com/android/settings/deviceinfo/storage/StorageSummaryDonutPreferenceController.java
@@ -0,0 +1,73 @@
+package com.android.settings.deviceinfo.storage;
+
+import android.content.Context;
+import android.support.v7.preference.Preference;
+import android.support.v7.preference.PreferenceGroup;
+import android.support.v7.preference.PreferenceScreen;
+import android.text.TextUtils;
+import android.text.format.Formatter;
+import android.util.Log;
+import android.widget.TextView;
+
+import com.android.settings.core.PreferenceController;
+import com.android.settings.R;
+
+/**
+ * StorgaeSummaryPreferenceController updates the donut storage summary preference to have the
+ * correct sizes showing.
+ */
+public class StorageSummaryDonutPreferenceController extends PreferenceController {
+ private long mUsedBytes;
+ private long mTotalBytes;
+
+ public StorageSummaryDonutPreferenceController(Context context) {
+ super(context);
+ }
+
+ @Override
+ public void displayPreference(PreferenceScreen screen) {
+ Log.d("dhnishi", "Preference displayed!");
+ StorageSummaryDonutPreference summary = (StorageSummaryDonutPreference)
+ screen.findPreference("pref_summary");
+ summary.setEnabled(true);
+ }
+
+ @Override
+ public void updateState(Preference preference) {
+ super.updateState(preference);
+ StorageSummaryDonutPreference summary = (StorageSummaryDonutPreference) preference;
+ final Formatter.BytesResult result = Formatter.formatBytes(mContext.getResources(),
+ mUsedBytes, 0);
+ summary.setTitle(TextUtils.expandTemplate(mContext.getText(R.string.storage_size_large),
+ result.value, result.units));
+ summary.setSummary(mContext.getString(R.string.storage_volume_used,
+ Formatter.formatFileSize(mContext, mTotalBytes)));
+ summary.setEnabled(true);
+ summary.setPercent(mUsedBytes, mTotalBytes);
+ }
+
+ @Override
+ public boolean isAvailable() {
+ return true;
+ }
+
+ @Override
+ public boolean handlePreferenceTreeClick(Preference preference) {
+ return false;
+ }
+
+ @Override
+ public String getPreferenceKey() {
+ return "pref_summary";
+ }
+
+ /**
+ * Updates the state of the donut preference for the next update.
+ * @param used Total number of used bytes on the summarized volume.
+ * @param total Total number of bytes on the summarized volume.
+ */
+ public void updateBytes(long used, long total) {
+ mUsedBytes = used;
+ mTotalBytes = total;
+ }
+}
diff --git a/src/com/android/settings/overlay/FeatureFactory.java b/src/com/android/settings/overlay/FeatureFactory.java
index 0b8ee8e..8b6c3b1 100644
--- a/src/com/android/settings/overlay/FeatureFactory.java
+++ b/src/com/android/settings/overlay/FeatureFactory.java
@@ -27,6 +27,7 @@
import com.android.settings.enterprise.EnterprisePrivacyFeatureProvider;
import com.android.settings.fuelgauge.PowerUsageFeatureProvider;
import com.android.settings.localepicker.LocaleFeatureProvider;
+import com.android.settings.security.SecurityFeatureProvider;
import com.android.settings.search2.SearchFeatureProvider;
/**
@@ -85,6 +86,8 @@
public abstract SurveyFeatureProvider getSurveyFeatureProvider(Context context);
+ public abstract SecurityFeatureProvider getSecurityFeatureProvider();
+
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
index c2d5d79..eb5d065 100644
--- a/src/com/android/settings/overlay/FeatureFactoryImpl.java
+++ b/src/com/android/settings/overlay/FeatureFactoryImpl.java
@@ -33,6 +33,8 @@
import com.android.settings.fuelgauge.PowerUsageFeatureProvider;
import com.android.settings.localepicker.LocaleFeatureProvider;
import com.android.settings.localepicker.LocaleFeatureProviderImpl;
+import com.android.settings.security.SecurityFeatureProvider;
+import com.android.settings.security.SecurityFeatureProviderImpl;
import com.android.settings.search2.SearchFeatureProvider;
import com.android.settings.search2.SearchFeatureProviderImpl;
@@ -48,6 +50,7 @@
private LocaleFeatureProvider mLocaleFeatureProvider;
private EnterprisePrivacyFeatureProvider mEnterprisePrivacyFeatureProvider;
private SearchFeatureProvider mSearchFeatureProvider;
+ private SecurityFeatureProvider mSecurityFeatureProvider;
@Override
public SupportFeatureProvider getSupportFeatureProvider(Context context) {
@@ -115,4 +118,12 @@
public SurveyFeatureProvider getSurveyFeatureProvider(Context context) {
return null;
}
+
+ @Override
+ public SecurityFeatureProvider getSecurityFeatureProvider() {
+ if (mSecurityFeatureProvider == null) {
+ mSecurityFeatureProvider = new SecurityFeatureProviderImpl();
+ }
+ return mSecurityFeatureProvider;
+ }
}
diff --git a/src/com/android/settings/qstile/DevelopmentModeTile.java b/src/com/android/settings/qstile/DevelopmentModeTile.java
new file mode 100644
index 0000000..578ffd8
--- /dev/null
+++ b/src/com/android/settings/qstile/DevelopmentModeTile.java
@@ -0,0 +1,205 @@
+/*
+ * 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.qstile;
+
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.Intent;
+import android.os.RemoteException;
+import android.os.SystemProperties;
+import android.provider.Settings;
+import android.service.quicksettings.Tile;
+import android.service.quicksettings.TileService;
+import android.view.IWindowManager;
+import android.view.ThreadedRenderer;
+import android.view.View;
+
+import android.view.WindowManagerGlobal;
+import com.android.internal.app.LocalePicker;
+import com.android.settings.DevelopmentSettings;
+
+import java.util.Map;
+
+public class DevelopmentModeTile extends TileService {
+
+ static final String SHARED_PREFERENCES_NAME = "development_mode_tile_settings";
+
+ private static final String SHOW_TOUCHES_KEY = "show_touches";
+ private static final String POINTER_LOCATION_KEY = "pointer_location";
+ private static final String DEBUG_LAYOUT_KEY = "debug_layout";
+ private static final String FORCE_RTL_LAYOUT_KEY = "force_rtl_layout_all_locales";
+ private static final String WINDOW_ANIMATION_SCALE_KEY = "window_animation_scale";
+ private static final String TRANSITION_ANIMATION_SCALE_KEY = "transition_animation_scale";
+ private static final String ANIMATOR_DURATION_SCALE_KEY = "animator_duration_scale";
+ private static final String SHOW_HW_SCREEN_UPDATES_KEY = "show_hw_screen_udpates";
+ private static final String SHOW_HW_LAYERS_UPDATES_KEY = "show_hw_layers_udpates";
+ private static final String DEBUG_HW_OVERDRAW_KEY = "debug_hw_overdraw";
+ private static final String TRACK_FRAME_TIME_KEY = "track_frame_time";
+
+ private DevModeProperties mProps = new DevModeProperties();
+
+ @Override
+ public void onStartListening() {
+ super.onStartListening();
+ refresh();
+ }
+
+ public void refresh() {
+ mProps.refreshState(this);
+ getQsTile().setState(mProps.isSet ? (mProps.allMatch
+ ? Tile.STATE_ACTIVE : Tile.STATE_INACTIVE) : Tile.STATE_UNAVAILABLE);
+ getQsTile().updateTile();
+ }
+
+ @Override
+ public void onClick() {
+ if (getQsTile().getState() == Tile.STATE_UNAVAILABLE) {
+ startActivityAndCollapse(new Intent(this, DevelopmentTileConfigActivity.class));
+ return;
+ }
+
+ boolean active = getQsTile().getState() == Tile.STATE_INACTIVE;
+ Map<String, ?> values =
+ getSharedPreferences(SHARED_PREFERENCES_NAME, MODE_PRIVATE).getAll();
+ ContentResolver cr = getContentResolver();
+ for (Property prop : mProps.mSysProps) {
+ Object expected = values.get(prop.prefKey);
+ String value = active && !prop.isDefault(expected) ? expected.toString() : "false";
+ SystemProperties.set(prop.key, value);
+ }
+ for (Property prop : mProps.mSysSettings) {
+ boolean expectedTrue = active && !prop.isDefault(values.get(prop.prefKey));
+ Settings.System.putInt(cr, prop.key, expectedTrue ? 1 : 0);
+ }
+
+ boolean expectedGlobPropTrue = active &&
+ !mProps.mGlobProp.isDefault(values.get(mProps.mGlobProp.prefKey));
+ Settings.Global.putInt(cr, mProps.mGlobProp.key, expectedGlobPropTrue ? 1 : 0);
+ SystemProperties.set(mProps.mGlobProp.key, expectedGlobPropTrue ? "1" : "0");
+ LocalePicker.updateLocales(getResources().getConfiguration().getLocales());
+
+ IWindowManager wm = WindowManagerGlobal.getWindowManagerService();
+ try {
+ // Update the various animation scale values to expected values or 1. mProps.mAnimScales
+ // is an ordered array, where the index corresponds to the individual property.
+ for (int i = 0; i < mProps.mAnimScales.length; i++) {
+ Object expected = values.get(mProps.mAnimScales[i]);
+ float expectedFloat = active && expected != null ?
+ Float.parseFloat(expected.toString()) : 1;
+ wm.setAnimationScale(i, expectedFloat);
+ }
+ } catch (RemoteException e) { }
+
+ new DevelopmentSettings.SystemPropPoker().execute(); // Settings app magic
+ refresh();
+ }
+
+ static class DevModeProperties {
+
+ private final Property[] mSysProps = new Property[] {
+ new Property(View.DEBUG_LAYOUT_PROPERTY, DEBUG_LAYOUT_KEY),
+ new Property(ThreadedRenderer.DEBUG_DIRTY_REGIONS_PROPERTY,
+ SHOW_HW_SCREEN_UPDATES_KEY),
+ new Property(ThreadedRenderer.DEBUG_SHOW_LAYERS_UPDATES_PROPERTY,
+ SHOW_HW_LAYERS_UPDATES_KEY),
+ new Property(ThreadedRenderer.DEBUG_OVERDRAW_PROPERTY, DEBUG_HW_OVERDRAW_KEY),
+ new Property(ThreadedRenderer.PROFILE_PROPERTY, TRACK_FRAME_TIME_KEY),
+ };
+
+ private final Property[] mSysSettings = new Property[] {
+ new Property(Settings.System.SHOW_TOUCHES, SHOW_TOUCHES_KEY),
+ new Property(Settings.System.POINTER_LOCATION, POINTER_LOCATION_KEY),
+ };
+
+ private final Property mGlobProp =
+ new Property(Settings.Global.DEVELOPMENT_FORCE_RTL, FORCE_RTL_LAYOUT_KEY);
+
+ private final String[] mAnimScales = new String[] {
+ WINDOW_ANIMATION_SCALE_KEY,
+ TRANSITION_ANIMATION_SCALE_KEY,
+ ANIMATOR_DURATION_SCALE_KEY
+ };
+
+ /**
+ * True is the values of all the properties corresponds to the expected values. Updated when
+ * {@link #refreshState(Context)} is called.
+ */
+ public boolean allMatch;
+ /**
+ * True is at least one property has a non-default expected value. Updated when
+ * {@link #refreshState(Context)} is called. Not that if all properties have default
+ * expected value, then active and non-active state will be the same.
+ */
+ public boolean isSet;
+
+ public void refreshState(Context context) {
+ Map<String, ?> values =
+ context.getSharedPreferences(SHARED_PREFERENCES_NAME, MODE_PRIVATE).getAll();
+ allMatch = true;
+ // True if there is at least one non-default value.
+ isSet = false;
+
+ for (Property prop : mSysProps) {
+ Object expected = values.get(prop.prefKey);
+ String actual = SystemProperties.get(prop.key);
+ allMatch &= prop.isDefault(expected)
+ ? prop.isDefault(actual) : expected.toString().equals(actual);
+ isSet |= !prop.isDefault(expected);
+ }
+
+ ContentResolver cr = context.getContentResolver();
+ for (Property prop : mSysSettings) {
+ boolean expectedTrue = !prop.isDefault(values.get(prop.prefKey));
+ isSet |= expectedTrue;
+ allMatch &= expectedTrue == (Settings.System.getInt(cr, prop.key, 0) != 0);
+ }
+
+ boolean expectedGlopPropTrue = !mGlobProp.isDefault(values.get(mGlobProp.prefKey));
+ isSet |= expectedGlopPropTrue;
+ allMatch &= expectedGlopPropTrue == (Settings.Global.getInt(cr, mGlobProp.key, 0) != 0);
+
+ IWindowManager wm = WindowManagerGlobal.getWindowManagerService();
+ try {
+ for (int i = 0; i < mAnimScales.length; i++) {
+ Object expected = values.get(mAnimScales[i]);
+ float expectedFloat = expected == null
+ ? 1 : Float.parseFloat(expected.toString());
+ isSet |= expectedFloat != 1;
+ allMatch &= expectedFloat == wm.getAnimationScale(i);
+ }
+ } catch (RemoteException e) { }
+ }
+ }
+
+ private static class Property {
+ final String key;
+ final String prefKey;
+
+ Property(String key, String prefKey) {
+ this.key = key;
+ this.prefKey = prefKey;
+ }
+
+ boolean isDefault(Object value) {
+ if (value == null) {
+ return true;
+ }
+ String str = value.toString();
+ return str.equals("") || str.equals("false");
+ }
+ }
+}
diff --git a/src/com/android/settings/qstile/DevelopmentTileConfigActivity.java b/src/com/android/settings/qstile/DevelopmentTileConfigActivity.java
new file mode 100644
index 0000000..cc63026
--- /dev/null
+++ b/src/com/android/settings/qstile/DevelopmentTileConfigActivity.java
@@ -0,0 +1,115 @@
+/*
+ * 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.qstile;
+
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.os.Bundle;
+import android.view.View;
+
+import com.android.settings.R;
+import com.android.settings.SettingsActivity;
+import com.android.settings.SettingsPreferenceFragment;
+import com.android.settings.core.instrumentation.Instrumentable;
+import com.android.settings.widget.SwitchBar;
+
+public class DevelopmentTileConfigActivity extends SettingsActivity {
+
+ @Override
+ public Intent getIntent() {
+ Intent modIntent = new Intent(super.getIntent())
+ .putExtra(EXTRA_SHOW_FRAGMENT, DevelopmentTileConfigFragment.class.getName())
+ .putExtra(EXTRA_HIDE_DRAWER, true);
+ return modIntent;
+ }
+
+ @Override
+ protected boolean isValidFragment(String fragmentName) {
+ return (DevelopmentTileConfigFragment.class.getName().equals(fragmentName));
+ }
+
+ public static class DevelopmentTileConfigFragment extends SettingsPreferenceFragment implements
+ SharedPreferences.OnSharedPreferenceChangeListener {
+
+ private DevelopmentModeTile.DevModeProperties mProps =
+ new DevelopmentModeTile.DevModeProperties();
+
+ private SwitchBar mSwitchBar;
+ private View mDisabledMessage;
+
+ @Override
+ public void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+ getPreferenceManager()
+ .setSharedPreferencesName(DevelopmentModeTile.SHARED_PREFERENCES_NAME);
+ addPreferencesFromResource(R.xml.development_tile_prefs);
+ }
+
+ @Override
+ public void onViewCreated(View view, Bundle savedInstanceState) {
+ super.onViewCreated(view, savedInstanceState);
+ mDisabledMessage = setPinnedHeaderView(R.layout.development_tile_config_header);
+ refreshHeader();
+ }
+
+ @Override
+ public void onActivityCreated(Bundle savedInstanceState) {
+ super.onActivityCreated(savedInstanceState);
+ mSwitchBar = ((SettingsActivity) getActivity()).getSwitchBar();
+ mSwitchBar.setEnabled(false);
+ }
+
+ @Override
+ public int getMetricsCategory() {
+ return Instrumentable.METRICS_CATEGORY_UNKNOWN;
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ refreshHeader();
+ getPreferenceManager().getSharedPreferences()
+ .registerOnSharedPreferenceChangeListener(this);
+ }
+
+ @Override
+ public void onPause() {
+ super.onPause();
+ getPreferenceManager().getSharedPreferences()
+ .unregisterOnSharedPreferenceChangeListener(this);
+ }
+
+ @Override
+ public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
+ refreshHeader();
+ }
+
+ private void refreshHeader() {
+ if (mSwitchBar != null && mDisabledMessage != null) {
+ mProps.refreshState(getActivity());
+ if (mProps.isSet) {
+ mSwitchBar.show();
+ mDisabledMessage.setVisibility(View.GONE);
+ } else {
+ mSwitchBar.hide();
+ mDisabledMessage.setVisibility(View.VISIBLE);
+ }
+ mSwitchBar.setChecked(mProps.allMatch);
+ }
+ }
+ }
+}
diff --git a/src/com/android/settings/qstile/DevelopmentTiles.java b/src/com/android/settings/qstile/DevelopmentTiles.java
deleted file mode 100644
index 0d8e7db..0000000
--- a/src/com/android/settings/qstile/DevelopmentTiles.java
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- * 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.qstile;
-
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.pm.PackageManager;
-import android.os.SystemProperties;
-import android.service.quicksettings.Tile;
-import android.service.quicksettings.TileService;
-import android.view.ThreadedRenderer;
-import android.view.View;
-import com.android.settings.DevelopmentSettings;
-
-public class DevelopmentTiles {
- // List of components that need to be enabled when developer tools are turned on
- static final Class[] TILE_CLASSES = new Class[] {
- ShowLayout.class,
- GPUProfiling.class,
- };
- public static void setTilesEnabled(Context context, boolean enable) {
- final PackageManager pm = context.getPackageManager();
- for (Class cls : TILE_CLASSES) {
- pm.setComponentEnabledSetting(new ComponentName(context, cls),
- enable ? PackageManager.COMPONENT_ENABLED_STATE_ENABLED
- : PackageManager.COMPONENT_ENABLED_STATE_DEFAULT,
- PackageManager.DONT_KILL_APP);
- }
- }
-
- /**
- * Tile to control the "Show layout bounds" developer setting
- */
- public static class ShowLayout extends TileService {
- @Override
- public void onStartListening() {
- super.onStartListening();
- refresh();
- }
-
- public void refresh() {
- final boolean enabled = SystemProperties.getBoolean(View.DEBUG_LAYOUT_PROPERTY, false);
- getQsTile().setState(enabled ? Tile.STATE_ACTIVE : Tile.STATE_INACTIVE);
- getQsTile().updateTile();
- }
-
- @Override
- public void onClick() {
- SystemProperties.set(View.DEBUG_LAYOUT_PROPERTY,
- getQsTile().getState() == Tile.STATE_INACTIVE ? "true" : "false");
- new DevelopmentSettings.SystemPropPoker().execute(); // Settings app magic
- refresh();
- }
- }
-
- /**
- * Tile to control the "GPU profiling" developer setting
- */
- public static class GPUProfiling extends TileService {
- @Override
- public void onStartListening() {
- super.onStartListening();
- refresh();
- }
-
- public void refresh() {
- final String value = SystemProperties.get(ThreadedRenderer.PROFILE_PROPERTY);
- getQsTile().setState(value.equals("visual_bars")
- ? Tile.STATE_ACTIVE : Tile.STATE_INACTIVE);
- getQsTile().updateTile();
- }
-
- @Override
- public void onClick() {
- SystemProperties.set(ThreadedRenderer.PROFILE_PROPERTY,
- getQsTile().getState() == Tile.STATE_INACTIVE ? "visual_bars" : "");
- new DevelopmentSettings.SystemPropPoker().execute(); // Settings app magic
- refresh();
- }
- }
-}
\ No newline at end of file
diff --git a/src/com/android/settings/security/SecurityFeatureProvider.java b/src/com/android/settings/security/SecurityFeatureProvider.java
new file mode 100644
index 0000000..5cf6fc9
--- /dev/null
+++ b/src/com/android/settings/security/SecurityFeatureProvider.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.security;
+
+import android.content.Context;
+import android.support.v7.preference.PreferenceScreen;
+
+import com.android.settingslib.drawer.DashboardCategory;
+
+
+/** FeatureProvider for security. */
+public interface SecurityFeatureProvider {
+
+ /** Update preferences with data from associated tiles. */
+ void updatePreferences(Context context, PreferenceScreen preferenceScreen,
+ DashboardCategory dashboardCategory);
+}
diff --git a/src/com/android/settings/security/SecurityFeatureProviderImpl.java b/src/com/android/settings/security/SecurityFeatureProviderImpl.java
new file mode 100644
index 0000000..91659fd
--- /dev/null
+++ b/src/com/android/settings/security/SecurityFeatureProviderImpl.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.security;
+
+import android.content.Context;
+import android.content.Intent;
+import android.content.IContentProvider;
+import android.content.pm.PackageManager;
+import android.content.res.Resources;
+import android.graphics.drawable.Drawable;
+import com.android.settingslib.drawer.DashboardCategory;
+import android.support.v4.content.ContextCompat;
+import android.support.v7.preference.Preference;
+import android.support.v7.preference.PreferenceScreen;
+import android.text.TextUtils;
+import android.util.ArrayMap;
+
+import com.android.settingslib.drawer.Tile;
+import com.android.settingslib.drawer.TileUtils;
+
+import java.util.Map;
+
+/** Implementation for {@code SecurityFeatureProvider}. */
+public class SecurityFeatureProviderImpl implements SecurityFeatureProvider {
+
+ /** Update preferences with data from associated tiles. */
+ public void updatePreferences(Context context, PreferenceScreen preferenceScreen,
+ DashboardCategory dashboardCategory) {
+ if (preferenceScreen == null) {
+ return;
+ }
+ int tilesCount = (dashboardCategory != null) ? dashboardCategory.getTilesCount() : 0;
+ if (tilesCount == 0) {
+ return;
+ }
+ Map<String, IContentProvider> providerMap = new ArrayMap<>();
+ for (int i = 0; i < tilesCount; i++) {
+ Tile tile = dashboardCategory.getTile(i);
+ // If the tile does not have a key or appropriate meta data, skip it.
+ if (TextUtils.isEmpty(tile.key) || (tile.metaData == null)) {
+ continue;
+ }
+ Preference matchingPref = preferenceScreen.findPreference(tile.key);
+ // If the tile does not have a matching preference, skip it.
+ if (matchingPref == null) {
+ continue;
+ }
+ // Check if the tile has content providers for dynamically updatable content.
+ String iconUri = tile.metaData.getString(TileUtils.META_DATA_PREFERENCE_ICON_URI, null);
+ String summaryUri =
+ tile.metaData.getString(TileUtils.META_DATA_PREFERENCE_SUMMARY_URI, null);
+ if (!TextUtils.isEmpty(iconUri)) {
+ int icon = TileUtils.getIconFromUri(context, iconUri, providerMap);
+ boolean updateIcon = true;
+ String packageName = null;
+ // Dynamic icon has to come from the same package that the preference launches.
+ if (tile.intent != null) {
+ Intent intent = tile.intent;
+ if (!TextUtils.isEmpty(intent.getPackage())) {
+ packageName = intent.getPackage();
+ } else if (intent.getComponent() != null) {
+ packageName = intent.getComponent().getPackageName();
+ }
+ }
+ if (TextUtils.isEmpty(packageName)) {
+ updateIcon = false;
+ } else {
+ if (tile.icon == null) {
+ // If the tile does not have an icon already, only update if the suggested
+ // icon is non-zero.
+ updateIcon = (icon != 0);
+ } else {
+ // If the existing icon has the same resource package and resource id, the
+ // icon does not need to be updated.
+ updateIcon = !(packageName.equals(tile.icon.getResPackage())
+ && (icon == tile.icon.getResId()));
+ }
+ }
+ if (updateIcon) {
+ try {
+ matchingPref.setIcon(context.getPackageManager()
+ .getResourcesForApplication(packageName)
+ .getDrawable(icon, context.getTheme()));
+ } catch (PackageManager.NameNotFoundException | Resources.NotFoundException e) {
+ // Intentionally ignored. If icon resources cannot be found, do not update.
+ }
+ }
+ }
+ if (!TextUtils.isEmpty(summaryUri)) {
+ String summary = TileUtils.getTextFromUri(context, summaryUri, providerMap,
+ TileUtils.META_DATA_PREFERENCE_SUMMARY);
+ // Only update the summary if it has actually changed.
+ if (summary == null) {
+ if (matchingPref.getSummary() != null) {
+ matchingPref.setSummary(summary);
+ }
+ } else if (!summary.equals(matchingPref.getSummary())) {
+ matchingPref.setSummary(summary);
+ }
+ }
+ }
+ }
+}
diff --git a/tests/robotests/assets/grandfather_not_implementing_indexable b/tests/robotests/assets/grandfather_not_implementing_indexable
index 0c539d8..81adf8b 100644
--- a/tests/robotests/assets/grandfather_not_implementing_indexable
+++ b/tests/robotests/assets/grandfather_not_implementing_indexable
@@ -88,4 +88,5 @@
com.android.settings.notification.ZenModeSettings
com.android.settings.accessibility.ToggleDaltonizerPreferenceFragment
com.android.settings.applications.ConvertToFbe
-com.android.settings.localepicker.LocaleListEditor
\ No newline at end of file
+com.android.settings.localepicker.LocaleListEditor
+com.android.settings.qstile.DevelopmentTileConfigActivity$DevelopmentTileConfigFragment
\ No newline at end of file
diff --git a/tests/robotests/src/com/android/settings/bluetooth/BluetoothSettingsTest.java b/tests/robotests/src/com/android/settings/bluetooth/BluetoothSettingsTest.java
new file mode 100644
index 0000000..9e90fdf
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/bluetooth/BluetoothSettingsTest.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2017 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.bluetooth;
+
+import com.android.settings.SettingsRobolectricTestRunner;
+import com.android.settings.TestConfig;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.annotation.Config;
+
+@RunWith(SettingsRobolectricTestRunner.class)
+@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
+public class BluetoothSettingsTest {
+
+ @Test
+ public void setTextSpan_notSpannable_shouldNotCrash() {
+ final String str = "test";
+ final BluetoothSettings settings = new BluetoothSettings();
+ settings.setTextSpan(str, "hello");
+ }
+
+}
diff --git a/tests/robotests/src/com/android/settings/deviceinfo/StorageDashboardFragmentTest.java b/tests/robotests/src/com/android/settings/deviceinfo/StorageDashboardFragmentTest.java
new file mode 100644
index 0000000..5775aeb
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/deviceinfo/StorageDashboardFragmentTest.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.deviceinfo;
+
+import android.content.Context;
+import android.provider.SearchIndexableResource;
+
+import com.android.settings.SettingsRobolectricTestRunner;
+import com.android.settings.TestConfig;
+import com.android.settings.testutils.FakeFeatureFactory;
+import com.android.settingslib.drawer.CategoryKey;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Answers;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.annotation.Config;
+import org.robolectric.shadows.ShadowApplication;
+
+import java.util.List;
+
+import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.Mockito.when;
+
+@RunWith(SettingsRobolectricTestRunner.class)
+@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
+public class StorageDashboardFragmentTest {
+
+ @Mock(answer = Answers.RETURNS_DEEP_STUBS)
+ private Context mContext;
+
+ private StorageDashboardFragment mFragment;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ FakeFeatureFactory.setupForTest(mContext);
+ final FakeFeatureFactory factory =
+ (FakeFeatureFactory) FakeFeatureFactory.getFactory(mContext);
+ when(factory.dashboardFeatureProvider.isEnabled()).thenReturn(true);
+ mFragment = new StorageDashboardFragment();
+ }
+
+ @Test
+ public void testCategory_isConnectedDevice() {
+ assertThat(mFragment.getCategoryKey()).isEqualTo(CategoryKey.CATEGORY_STORAGE);
+ }
+
+ @Test
+ public void testSearchIndexProvider_shouldIndexResource() {
+ final List<SearchIndexableResource> indexRes =
+ StorageDashboardFragment.SEARCH_INDEX_DATA_PROVIDER.getXmlResourcesToIndex(
+ ShadowApplication.getInstance().getApplicationContext(),
+ true /* enabled */);
+
+ assertThat(indexRes).isNotNull();
+ assertThat(indexRes.get(0).xmlResId).isEqualTo(mFragment.getPreferenceScreenResId());
+ }
+}
\ No newline at end of file
diff --git a/tests/robotests/src/com/android/settings/deviceinfo/storage/StorageItemPreferenceAlternateTest.java b/tests/robotests/src/com/android/settings/deviceinfo/storage/StorageItemPreferenceAlternateTest.java
new file mode 100644
index 0000000..d2fc504
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/deviceinfo/storage/StorageItemPreferenceAlternateTest.java
@@ -0,0 +1,56 @@
+/*
+ * 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.deviceinfo.storage;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.content.Context;
+
+import com.android.settings.R;
+import com.android.settings.SettingsRobolectricTestRunner;
+import com.android.settings.TestConfig;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.Config;
+
+
+@RunWith(SettingsRobolectricTestRunner.class)
+@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
+public class StorageItemPreferenceAlternateTest {
+ private Context mContext;
+
+ @Before
+ public void setUp() throws Exception {
+ mContext = RuntimeEnvironment.application;
+ }
+
+ @Test
+ public void testBeforeLoad() {
+ StorageItemPreferenceAlternate pref = new StorageItemPreferenceAlternate(mContext);
+ assertThat(((String) pref.getSummary())).isEqualTo(
+ mContext.getString(R.string.memory_calculating_size));
+ }
+
+ @Test
+ public void testAfterLoad() {
+ StorageItemPreferenceAlternate pref = new StorageItemPreferenceAlternate(mContext);
+ pref.setStorageSize(1024L);
+ assertThat(((String) pref.getSummary())).isEqualTo("1.00KB");
+ }
+}
\ No newline at end of file
diff --git a/tests/robotests/src/com/android/settings/deviceinfo/storage/StorageItemPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/deviceinfo/storage/StorageItemPreferenceControllerTest.java
new file mode 100644
index 0000000..1862dd0
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/deviceinfo/storage/StorageItemPreferenceControllerTest.java
@@ -0,0 +1,79 @@
+/*
+ * 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.deviceinfo.storage;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.content.Context;
+import android.support.v7.preference.Preference;
+import android.support.v7.preference.PreferenceViewHolder;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.LinearLayout;
+
+import com.android.settings.SettingsRobolectricTestRunner;
+import com.android.settings.TestConfig;
+import com.android.settings.deviceinfo.StorageItemPreference;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mockito;
+import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.Config;
+
+@RunWith(SettingsRobolectricTestRunner.class)
+@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
+public class StorageItemPreferenceControllerTest {
+ private static final String KEY = "pref";
+ private Context mContext;
+ private StorageItemPreferenceController mController;
+ private PreferenceViewHolder mHolder;
+ private StorageItemPreferenceAlternate mPreference;
+
+ @Before
+ public void setUp() throws Exception {
+ mContext = RuntimeEnvironment.application;
+ mController = new StorageItemPreferenceController(mContext, KEY);
+ mPreference = new StorageItemPreferenceAlternate(mContext);
+
+ // Inflate the preference and the widget.
+ LayoutInflater inflater = LayoutInflater.from(mContext);
+ final View view = inflater.inflate(mPreference.getLayoutResource(),
+ new LinearLayout(mContext), false);
+
+ mHolder = new PreferenceViewHolder(view);
+ }
+
+ @Test
+ public void testGetKey() {
+ assertThat(mController.getPreferenceKey()).isEqualTo(KEY);
+ }
+
+ @Test
+ public void testUpdateStateWithInitialState() {
+ mController.updateState(mPreference);
+ assertThat(mPreference.getSummary().toString()).isEqualTo("Calculating…");
+ }
+
+ @Test
+ public void testPreferenceShouldUpdateAfterPopulatingData() {
+ mController.setStorageSize(1024L);
+ mController.updateState(mPreference);
+ assertThat(mPreference.getSummary().toString()).isEqualTo("1.00KB");
+
+ }
+}
\ No newline at end of file
diff --git a/tests/robotests/src/com/android/settings/qstile/DevelopmentModeTileTest.java b/tests/robotests/src/com/android/settings/qstile/DevelopmentModeTileTest.java
new file mode 100644
index 0000000..a30bd47
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/qstile/DevelopmentModeTileTest.java
@@ -0,0 +1,75 @@
+package com.android.settings.qstile;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.Intent;
+import android.service.quicksettings.Tile;
+
+import com.android.settings.SettingsRobolectricTestRunner;
+import com.android.settings.TestConfig;
+import com.android.settings.testutils.shadow.ShadowTileService;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.Robolectric;
+import org.robolectric.annotation.Config;
+import org.robolectric.internal.ShadowExtractor;
+import org.robolectric.util.ReflectionHelpers;
+
+@RunWith(SettingsRobolectricTestRunner.class)
+@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION,
+ shadows = ShadowTileService.class)
+public class DevelopmentModeTileTest {
+
+ @Mock private Tile mTile;
+ @Mock private DevelopmentModeTile.DevModeProperties mProps;
+
+ private DevelopmentModeTile mDevelopmentModeTile;
+ private ShadowTileService mShadowTileService;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ mDevelopmentModeTile = Robolectric.buildService(DevelopmentModeTile.class).get();
+
+ ReflectionHelpers.setField(mDevelopmentModeTile, "mProps", mProps);
+ mShadowTileService = (ShadowTileService) ShadowExtractor.extract(mDevelopmentModeTile);
+ mShadowTileService.setTile(mTile);
+ }
+
+ @Test
+ public void refresh() {
+ verifyRefreshState(false, true, Tile.STATE_UNAVAILABLE);
+ verifyRefreshState(false, false, Tile.STATE_UNAVAILABLE);
+ verifyRefreshState(true, false, Tile.STATE_INACTIVE);
+ verifyRefreshState(true, true, Tile.STATE_ACTIVE);
+ }
+
+ @Test
+ public void onClick_startSetting() {
+ when(mTile.getState()).thenReturn(Tile.STATE_UNAVAILABLE);
+ mDevelopmentModeTile.onClick();
+
+ Intent intent = mShadowTileService.getNextStartedActivity();
+ assertEquals(DevelopmentTileConfigActivity.class.getName(),
+ intent.getComponent().getClassName());
+ }
+
+ private void verifyRefreshState(boolean isSet, boolean allMatch, int expectedState) {
+ reset(mProps, mTile);
+
+ mProps.isSet = isSet;
+ mProps.allMatch = allMatch;
+ mDevelopmentModeTile.refresh();
+
+ verify(mProps).refreshState(eq(mDevelopmentModeTile));
+ verify(mTile).setState(eq(expectedState));
+ }
+}
diff --git a/tests/robotests/src/com/android/settings/security/SecurityFeatureProviderImplTest.java b/tests/robotests/src/com/android/settings/security/SecurityFeatureProviderImplTest.java
new file mode 100644
index 0000000..7df9af7
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/security/SecurityFeatureProviderImplTest.java
@@ -0,0 +1,186 @@
+/*
+ * 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.security;
+
+import android.content.IContentProvider;
+import android.content.Intent;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.content.res.Resources;
+import android.graphics.Color;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.PaintDrawable;
+import android.os.Bundle;
+import android.support.v7.preference.Preference;
+import android.support.v7.preference.PreferenceScreen;
+
+import com.android.settings.SettingsRobolectricTestRunner;
+import com.android.settings.TestConfig;
+import com.android.settingslib.drawer.DashboardCategory;
+import com.android.settingslib.drawer.Tile;
+import com.android.settingslib.drawer.TileUtils;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.Config;
+import org.robolectric.annotation.Implementation;
+import org.robolectric.annotation.Implements;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Mockito.eq;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.when;
+
+@RunWith(SettingsRobolectricTestRunner.class)
+@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
+public class SecurityFeatureProviderImplTest {
+
+ private static final String MOCK_KEY = "key";
+ private static final String MOCK_SUMMARY = "summary";
+ private static final String URI_GET_SUMMARY = "content://package/text/summary";
+ private static final String URI_GET_ICON = "content://package/icon/my_icon";
+
+ private static final Drawable MOCK_DRAWABLE = new PaintDrawable(Color.BLUE);
+
+ @Mock
+ private Context mContext;
+ @Mock
+ private PackageManager mPackageManager;
+ @Mock
+ private Resources mResources;
+
+ private SecurityFeatureProviderImpl mImpl;
+
+ @Implements(com.android.settingslib.drawer.TileUtils.class)
+ public static class TileUtilsMock {
+ @Implementation
+ public static int getIconFromUri(Context context, String uriString,
+ Map<String, IContentProvider> providerMap) {
+ return 161803;
+ }
+
+ @Implementation
+ public static String getTextFromUri(Context context, String uriString,
+ Map<String, IContentProvider> providerMap, String key) {
+ return MOCK_SUMMARY;
+ }
+ }
+
+ @Before
+ public void setUp() throws PackageManager.NameNotFoundException {
+ MockitoAnnotations.initMocks(this);
+ mContext = spy(RuntimeEnvironment.application);
+ mImpl = new SecurityFeatureProviderImpl();
+ when(mContext.getPackageManager()).thenReturn(mPackageManager);
+ when(mPackageManager.getResourcesForApplication(anyString())).thenReturn(mResources);
+ when(mResources.getDrawable(anyInt(), any())).thenReturn(MOCK_DRAWABLE);
+ }
+
+ @Test
+ public void updateTilesData_shouldNotProcessEmptyScreenOrTiles() {
+ mImpl.updatePreferences(mContext, null, null);
+ mImpl.updatePreferences(mContext, new PreferenceScreen(mContext, null), null);
+ verifyNoMoreInteractions(mPackageManager);
+ }
+
+ @Test
+ public void updateTilesData_shouldNotProcessNonMatchingPreference() {
+ DashboardCategory dashboardCategory = new DashboardCategory();
+ dashboardCategory.addTile(new Tile());
+ mImpl.updatePreferences(mContext, getPreferenceScreen(), dashboardCategory);
+ verifyNoMoreInteractions(mPackageManager);
+ }
+
+ @Test
+ public void updateTilesData_shouldNotProcessMatchingPreferenceWithNoData() {
+ mImpl.updatePreferences(mContext, getPreferenceScreen(), getDashboardCategory());
+ verifyNoMoreInteractions(mPackageManager);
+ }
+
+ @Test
+ @Config(shadows = {
+ TileUtilsMock.class,
+ })
+ public void updateTilesData_shouldUpdateMatchingPreference() {
+ Bundle bundle = new Bundle();
+ bundle.putString(TileUtils.META_DATA_PREFERENCE_ICON_URI, URI_GET_ICON);
+ bundle.putString(TileUtils.META_DATA_PREFERENCE_SUMMARY_URI, URI_GET_SUMMARY);
+
+ PreferenceScreen screen = getPreferenceScreen();
+ DashboardCategory dashboardCategory = getDashboardCategory();
+ dashboardCategory.getTile(0).intent = new Intent().setPackage("package");
+ dashboardCategory.getTile(0).metaData = bundle;
+
+ mImpl.updatePreferences(mContext, getPreferenceScreen(), dashboardCategory);
+ assertThat(screen.findPreference(MOCK_KEY).getIcon()).isEqualTo(MOCK_DRAWABLE);
+ assertThat(screen.findPreference(MOCK_KEY).getSummary()).isEqualTo(MOCK_SUMMARY);
+ }
+
+ @Test
+ @Config(shadows = {
+ TileUtilsMock.class,
+ })
+ public void updateTilesData_shouldNotUpdateAlreadyUpdatedPreference() {
+ Bundle bundle = new Bundle();
+ bundle.putString(TileUtils.META_DATA_PREFERENCE_ICON_URI, URI_GET_ICON);
+ bundle.putString(TileUtils.META_DATA_PREFERENCE_SUMMARY_URI, URI_GET_SUMMARY);
+
+ PreferenceScreen screen = getPreferenceScreen();
+ screen.findPreference(MOCK_KEY).setIcon(MOCK_DRAWABLE);
+ screen.findPreference(MOCK_KEY).setSummary(MOCK_SUMMARY);
+
+ DashboardCategory dashboardCategory = getDashboardCategory();
+ dashboardCategory.getTile(0).intent = new Intent().setPackage("package");
+ dashboardCategory.getTile(0).metaData = bundle;
+
+ mImpl.updatePreferences(mContext, screen, dashboardCategory);
+ verify(screen.findPreference(MOCK_KEY), times(0)).setIcon(any());
+ verify(screen.findPreference(MOCK_KEY), times(0)).setSummary(anyString());
+ assertThat(screen.findPreference(MOCK_KEY).getIcon()).isEqualTo(MOCK_DRAWABLE);
+ assertThat(screen.findPreference(MOCK_KEY).getSummary()).isEqualTo(MOCK_SUMMARY);
+ }
+
+ private PreferenceScreen getPreferenceScreen() {
+ PreferenceScreen screen = new PreferenceScreen(mContext, null);
+ Preference preference = spy(new Preference(mContext));
+ preference.setKey(MOCK_KEY);
+ screen.addPreference(preference);
+ return screen;
+ }
+
+ private static DashboardCategory getDashboardCategory() {
+ DashboardCategory dashboardCategory = new DashboardCategory();
+ Tile tile = new Tile();
+ tile.key = MOCK_KEY;
+ dashboardCategory.addTile(tile);
+ return dashboardCategory;
+ }
+}
diff --git a/tests/robotests/src/com/android/settings/testutils/FakeFeatureFactory.java b/tests/robotests/src/com/android/settings/testutils/FakeFeatureFactory.java
index 1625f35..bc0894c 100644
--- a/tests/robotests/src/com/android/settings/testutils/FakeFeatureFactory.java
+++ b/tests/robotests/src/com/android/settings/testutils/FakeFeatureFactory.java
@@ -25,6 +25,7 @@
import com.android.settings.localepicker.LocaleFeatureProvider;
import com.android.settings.overlay.FeatureFactory;
import com.android.settings.overlay.SupportFeatureProvider;
+import com.android.settings.security.SecurityFeatureProvider;
import com.android.settings.search2.SearchFeatureProvider;
import com.android.settings.overlay.SurveyFeatureProvider;
@@ -47,6 +48,7 @@
public final EnterprisePrivacyFeatureProvider enterprisePrivacyFeatureProvider;
public final SearchFeatureProvider searchFeatureProvider;
public final SurveyFeatureProvider surveyFeatureProvider;
+ public final SecurityFeatureProvider securityFeatureProvider;
/**
* Call this in {@code @Before} method of the test class to use fake factory.
@@ -78,6 +80,7 @@
enterprisePrivacyFeatureProvider = mock(EnterprisePrivacyFeatureProvider.class);
searchFeatureProvider = mock(SearchFeatureProvider.class);
surveyFeatureProvider = mock(SurveyFeatureProvider.class);
+ securityFeatureProvider = mock(SecurityFeatureProvider.class);
}
@Override
@@ -124,4 +127,9 @@
public SurveyFeatureProvider getSurveyFeatureProvider(Context context) {
return surveyFeatureProvider;
}
+
+ @Override
+ public SecurityFeatureProvider getSecurityFeatureProvider() {
+ return securityFeatureProvider;
+ }
}
diff --git a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowTileService.java b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowTileService.java
new file mode 100644
index 0000000..2270ff3
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowTileService.java
@@ -0,0 +1,38 @@
+package com.android.settings.testutils.shadow;
+
+import android.content.Intent;
+import android.service.quicksettings.Tile;
+import android.service.quicksettings.TileService;
+
+import org.robolectric.annotation.Implementation;
+import org.robolectric.annotation.Implements;
+import org.robolectric.annotation.RealObject;
+import org.robolectric.shadows.ShadowService;
+
+/**
+ * Shadow for {@link TileService}.
+ */
+@Implements(TileService.class)
+public class ShadowTileService extends ShadowService {
+
+ @RealObject TileService realService;
+
+ private Tile mTile;
+
+ public void __constructor__() { }
+
+ @Implementation
+ public final Tile getQsTile() {
+ return mTile;
+ }
+
+ @Implementation
+ public final void startActivityAndCollapse(Intent intent) {
+ realService.startActivity(intent);
+ }
+
+ // Non-Android setter.
+ public void setTile(Tile tile) {
+ mTile = tile;
+ }
+}