Merge "Add EID into SIM status dialog"
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 9e4dc39..fc5b830 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -1004,6 +1004,34 @@
android:value="true" />
</activity>
+
+ <activity android:name="Settings$MeCardActivity"
+ android:label="@string/device_info_settings"
+ android:icon="@drawable/ic_settings_about"
+ android:taskAffinity="com.android.settings"
+ android:parentActivityName="Settings">
+ <intent-filter android:priority="1">
+ <action android:name="android.settings.DEVICE_INFO_SETTINGS" />
+ <category android:name="android.intent.category.DEFAULT" />
+ </intent-filter>
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.DEFAULT" />
+ <category android:name="android.intent.category.VOICE_LAUNCH" />
+ </intent-filter>
+ <intent-filter android:priority="10">
+ <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.system" />
+ <meta-data android:name="com.android.settings.title"
+ android:resource="@string/about_settings" />
+ <meta-data android:name="com.android.settings.FRAGMENT_CLASS"
+ android:value="com.android.settings.deviceinfo.aboutphone.MyDeviceInfoFragment" />
+ <meta-data android:name="com.android.settings.PRIMARY_PROFILE_CONTROLLED"
+ android:value="true" />
+ </activity>
+
<activity android:name="SettingsLicenseActivity"
android:label="@string/settings_license_activity_title"
android:theme="@android:style/Theme.DeviceDefault.Light.Panel"
@@ -2200,12 +2228,15 @@
android:label="@string/power_usage_summary_title"
android:icon="@drawable/ic_settings_battery"
android:enabled="false">
- <!-- TODO(b/69867246): add priority for this intent-filter -->
- <intent-filter>
+ <intent-filter android:priority="1">
<action android:name="android.intent.action.POWER_USAGE_SUMMARY" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
- <!-- TODO(b/69867246): add shortcut intent-filter -->
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.DEFAULT" />
+ <category android:name="com.android.settings.SHORTCUT" />
+ </intent-filter>
<intent-filter android:priority="8">
<action android:name="com.android.settings.action.SETTINGS" />
</intent-filter>
@@ -2227,15 +2258,10 @@
<activity android:name=".Settings$PowerUsageSummaryLegacyActivity"
android:label="@string/power_usage_summary_title"
android:icon="@drawable/ic_settings_battery">
- <intent-filter android:priority="1">
+ <intent-filter>
<action android:name="android.intent.action.POWER_USAGE_SUMMARY" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
- <intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="com.android.settings.SHORTCUT" />
- </intent-filter>
<intent-filter android:priority="8">
<action android:name="com.android.settings.action.SETTINGS" />
</intent-filter>
@@ -2686,10 +2712,6 @@
<!-- Show channel group-level notification settings (group passed in as extras) -->
<activity android:name="Settings$ChannelGroupNotificationSettingsActivity"
android:exported="true">
- <intent-filter android:priority="1">
- <action android:name="android.settings.CHANNEL_GROUP_NOTIFICATION_SETTINGS" />
- <category android:name="android.intent.category.DEFAULT" />
- </intent-filter>
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.DEFAULT" />
@@ -3200,99 +3222,6 @@
android:permission="android.permission.DUMP"
android:enabled="@bool/config_has_help" />
-
- <!-- Activities for moves/gestures suggestions -->
- <activity
- android:name=".Settings$DoubleTapPowerSuggestionActivity"
- android:label="@string/double_tap_power_for_camera_title"
- android:icon="@drawable/ic_settings_gestures">
- <intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.settings.suggested.category.GESTURE" />
- </intent-filter>
- <meta-data android:name="com.android.settings.dismiss"
- android:value="4,8,30" />
- <meta-data android:name="com.android.settings.FRAGMENT_CLASS"
- android:value="com.android.settings.gestures.DoubleTapPowerSettings"/>
- <meta-data android:name="com.android.settings.title"
- android:resource="@string/double_tap_power_for_camera_suggestion_title" />
- <meta-data android:name="com.android.settings.summary"
- android:resource="@string/double_tap_power_for_camera_suggestion_summary" />
- </activity>
-
- <activity
- android:name=".Settings$DoubleTwistSuggestionActivity"
- android:label="@string/double_twist_for_camera_mode_title"
- android:icon="@drawable/ic_settings_gestures">
- <intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.settings.suggested.category.GESTURE" />
- </intent-filter>
- <meta-data android:name="com.android.settings.dismiss"
- android:value="4,8,30" />
- <meta-data android:name="com.android.settings.FRAGMENT_CLASS"
- android:value="com.android.settings.gestures.DoubleTwistGestureSettings"/>
- <meta-data android:name="com.android.settings.title"
- android:resource="@string/double_twist_for_camera_suggestion_title" />
- <meta-data android:name="com.android.settings.summary"
- android:resource="@string/double_twist_for_camera_suggestion_summary" />
- </activity>
-
- <activity
- android:name=".Settings$AmbientDisplaySuggestionActivity"
- android:label="@string/ambient_display_title"
- android:icon="@drawable/ic_settings_gestures">
- <intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.settings.suggested.category.GESTURE" />
- </intent-filter>
- <meta-data android:name="com.android.settings.dismiss"
- android:value="9,13,30" />
- <meta-data android:name="com.android.settings.FRAGMENT_CLASS"
- android:value="com.android.settings.gestures.DoubleTapScreenSettings"/>
- <meta-data android:name="com.android.settings.title"
- android:resource="@string/ambient_display_title" />
- <meta-data android:name="com.android.settings.summary"
- android:resource="@string/ambient_display_suggestion_summary" />
- </activity>
-
- <activity
- android:name=".Settings$AmbientDisplayPickupSuggestionActivity"
- android:label="@string/ambient_display_pickup_title"
- android:icon="@drawable/ic_settings_gestures">
- <intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.settings.suggested.category.GESTURE" />
- </intent-filter>
- <meta-data android:name="com.android.settings.dismiss"
- android:value="9,13,30" />
- <meta-data android:name="com.android.settings.FRAGMENT_CLASS"
- android:value="com.android.settings.gestures.PickupGestureSettings"/>
- <meta-data android:name="com.android.settings.title"
- android:resource="@string/ambient_display_pickup_title" />
- <meta-data android:name="com.android.settings.summary"
- android:resource="@string/ambient_display_pickup_suggestion_summary" />
- </activity>
-
- <activity
- android:name=".Settings$SwipeToNotificationSuggestionActivity"
- android:label="@string/fingerprint_swipe_for_notifications_title"
- android:icon="@drawable/ic_settings_gestures">
- <intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.settings.suggested.category.GESTURE" />
- </intent-filter>
- <meta-data android:name="com.android.settings.dismiss"
- android:value="9,13,30" />
- <meta-data android:name="com.android.settings.FRAGMENT_CLASS"
- android:value="com.android.settings.gestures.SwipeToNotificationSettings"/>
- <meta-data android:name="com.android.settings.title"
- android:resource="@string/fingerprint_swipe_for_notifications_suggestion_title" />
- <meta-data android:name="com.android.settings.summary"
- android:resource="@string/fingerprint_swipe_for_notifications_suggestion_summary" />
- </activity>
- <!-- End activities for moves/gestures suggestions -->
-
<activity android:name=".applications.autofill.AutofillPickerActivity"
android:excludeFromRecents="true"
android:launchMode="singleInstance"
@@ -3311,6 +3240,36 @@
</intent-filter>
</activity>
+ <activity android:name="Settings$AdvancedConnectedDeviceActivity"
+ android:label="@string/connected_device_connections_title"
+ android:taskAffinity="com.android.settings"
+ android:parentActivityName="Settings$ConnectedDeviceDashboardActivity"
+ android:enabled="false">
+ <intent-filter android:priority="1">
+ <action android:name="com.android.settings.ADVANCED_CONNECTED_DEVICE_SETTINGS" />
+ <category android:name="android.intent.category.DEFAULT" />
+ </intent-filter>
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.DEFAULT" />
+ </intent-filter>
+ <meta-data android:name="com.android.settings.FRAGMENT_CLASS"
+ android:value="com.android.settings.connecteddevice.AdvancedConnectedDeviceDashboardFragment" />
+ <meta-data android:name="com.android.settings.PRIMARY_PROFILE_CONTROLLED"
+ android:value="true" />
+ </activity>
+
+ <activity android:name="Settings$DirectoryAccessSettingsActivity"
+ android:label="@string/directory_access"
+ android:taskAffinity="">
+ <intent-filter>
+ <action android:name="android.settings.STORAGE_VOLUME_ACCESS_SETTINGS" />
+ <category android:name="android.intent.category.DEFAULT" />
+ </intent-filter>
+ <meta-data android:name="com.android.settings.FRAGMENT_CLASS"
+ android:value="com.android.settings.applications.manageapplications.ManageApplications" />
+ </activity>
+
<provider android:name=".slices.SettingsSliceProvider"
android:authorities="com.android.settings.slices"
android:exported="true">
diff --git a/res/layout/master_clear.xml b/res/layout/master_clear.xml
index 779e504..d328478 100644
--- a/res/layout/master_clear.xml
+++ b/res/layout/master_clear.xml
@@ -93,7 +93,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
- android:paddingEnd="8dp"
+ android:paddingEnd="@dimen/reset_checkbox_padding_end"
android:focusable="false"
android:clickable="false"
android:duplicateParentState="true" />
@@ -104,17 +104,21 @@
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:paddingTop="12dp"
- android:textSize="18sp"
+ android:paddingTop="@dimen/reset_checkbox_title_padding_top"
+ android:textSize="@dimen/reset_checkbox_title_text_size"
android:text="@string/erase_external_storage" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:paddingTop="4sp"
- android:textSize="14sp"
+ android:paddingTop="@dimen/reset_checkbox_summary_padding_top"
+ android:textSize="@dimen/reset_checkbox_summary_text_size"
android:text="@string/erase_external_storage_description" />
</LinearLayout>
</LinearLayout>
+ <include layout="@layout/reset_esim_checkbox"
+ android:id="@+id/erase_esim_container"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content" />
</LinearLayout>
</ScrollView>
<Button
diff --git a/res/layout/reset_esim_checkbox.xml b/res/layout/reset_esim_checkbox.xml
new file mode 100644
index 0000000..d830bf4
--- /dev/null
+++ b/res/layout/reset_esim_checkbox.xml
@@ -0,0 +1,55 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2018 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="horizontal"
+ android:focusable="true"
+ android:clickable="true"
+ android:visibility="gone">
+
+ <CheckBox
+ android:id="@+id/erase_esim"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical"
+ android:paddingEnd="@dimen/reset_checkbox_padding_end"
+ android:focusable="false"
+ android:clickable="false"
+ android:duplicateParentState="true" />
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical"
+ android:orientation="vertical">
+
+ <TextView
+ android:id="@+id/erase_esim_title"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:paddingTop="@dimen/reset_checkbox_title_padding_top"
+ android:textSize="@dimen/reset_checkbox_title_text_size" />
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:paddingTop="@dimen/reset_checkbox_summary_padding_top"
+ android:textSize="@dimen/reset_checkbox_summary_text_size"
+ android:text="@string/reset_esim_desc" />
+ </LinearLayout>
+</LinearLayout>
diff --git a/res/layout/reset_network.xml b/res/layout/reset_network.xml
index be966dd..1850bb2 100644
--- a/res/layout/reset_network.xml
+++ b/res/layout/reset_network.xml
@@ -14,7 +14,8 @@
limitations under the License.
-->
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
@@ -27,7 +28,8 @@
android:layout_marginTop="12dp"
android:layout_weight="1">
- <LinearLayout android:layout_width="match_parent"
+ <LinearLayout
+ android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
@@ -38,6 +40,11 @@
android:textDirection="locale"
android:text="@string/reset_network_desc" />
+ <include layout="@layout/reset_esim_checkbox"
+ android:id="@+id/erase_esim_container"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content" />
+
</LinearLayout>
</ScrollView>
diff --git a/res/layout/zen_mode_settings_button.xml b/res/layout/zen_mode_settings_button.xml
index 82989fc..4fe522d7 100644
--- a/res/layout/zen_mode_settings_button.xml
+++ b/res/layout/zen_mode_settings_button.xml
@@ -30,7 +30,7 @@
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content"
- android:layout_gravity="center"
+ android:layout_gravity="left"
android:text="@string/zen_mode_button_turn_on"
android:paddingEnd="8dp" />
@@ -40,7 +40,7 @@
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content"
- android:layout_gravity="center"
+ android:layout_gravity="left"
android:text="@string/zen_mode_button_turn_off"
android:paddingEnd="8dp" />
diff --git a/res/values/arrays.xml b/res/values/arrays.xml
index 7ab9afb..cb6f9be 100644
--- a/res/values/arrays.xml
+++ b/res/values/arrays.xml
@@ -266,14 +266,16 @@
<item>PWD</item>
</string-array>
- <!-- Wi-Fi AP band settings. Either 2.4GHz or 5GHz. -->
+ <!-- Wi-Fi AP band settings. Either Auto, 2.4GHz or 5GHz. -->
<!-- Note that adding/removing/moving the items will need wifi settings code change. -->
<string-array name="wifi_ap_band_config_full">
+ <item>@string/wifi_ap_choose_auto</item>
<item>@string/wifi_ap_choose_2G</item>
<item>@string/wifi_ap_choose_5G</item>
</string-array>
<string-array name="wifi_ap_band_config_2G_only">
+ <item>@string/wifi_ap_choose_auto</item>
<item>@string/wifi_ap_choose_2G</item>
</string-array>
diff --git a/res/values/bools.xml b/res/values/bools.xml
index e4a57ab..ab8a6fd 100644
--- a/res/values/bools.xml
+++ b/res/values/bools.xml
@@ -155,4 +155,7 @@
<!-- Whether assist_and_voice_input should be shown or not. -->
<bool name="config_show_assist_and_voice_input">true</bool>
+
+ <!-- Whether system_update_settings should be shown or not. -->
+ <bool name="config_show_system_update_settings">true</bool>
</resources>
diff --git a/res/values/config.xml b/res/values/config.xml
index 097350b..ce61164 100755
--- a/res/values/config.xml
+++ b/res/values/config.xml
@@ -44,6 +44,10 @@
<!-- Whether to show Camera laser sensor switch in Developer Options -->
<bool name="config_show_camera_laser_sensor">false</bool>
+ <!-- Whether to show Connected MAC Randomization in Developer Options
+ as not all devices can support dynamic MAC address change. -->
+ <bool name="config_wifi_support_connected_mac_randomization">false</bool>
+
<!-- Fully-qualified class name for the implementation of the FeatureFactory to be instantiated. -->
<string name="config_featureFactory" translatable="false">com.android.settings.overlay.FeatureFactoryImpl</string>
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index 339eaf2..16ac128 100755
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -106,13 +106,9 @@
<!-- Dashboard tile image margin start / end -->
<dimen name="dashboard_tile_image_margin">24dp</dimen>
- <!-- SwitchBar margin start / end -->
- <dimen name="switchbar_margin_start">16dp</dimen>
- <dimen name="switchbar_margin_end">16dp</dimen>
-
<!-- SwitchBar sub settings margin start / end -->
<dimen name="switchbar_subsettings_margin_start">72dp</dimen>
- <dimen name="switchbar_subsettings_margin_end">24dp</dimen>
+ <dimen name="switchbar_subsettings_margin_end">16dp</dimen>
<!-- The following two margins need to match, with the caveat that
the second should be negative. The second one ensures that the icons and text
@@ -311,4 +307,11 @@
<dimen name="suggestion_card_title_padding_bottom_one_card">6dp</dimen>
<dimen name="suggestion_card_title_padding_bottom_multiple_cards">8dp</dimen>
+ <!-- Padding for the reset screens -->
+ <dimen name="reset_checkbox_padding_end">8dp</dimen>
+ <dimen name="reset_checkbox_title_padding_top">12dp</dimen>
+ <dimen name="reset_checkbox_summary_padding_top">4dp</dimen>
+ <dimen name="reset_checkbox_title_text_size">18sp</dimen>
+ <dimen name="reset_checkbox_summary_text_size">14sp</dimen>
+
</resources>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 68bc0ee..800113e 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -788,6 +788,10 @@
<string name="security_enable_widgets_title">Enable widgets</string>
<!-- Summary for settings checkbox to disable widgets when the setting has been disabled by an installed device admin [CHAR LIMIT=50] -->
<string name="security_enable_widgets_disabled_summary">Disabled by admin</string>
+ <!-- Text shown for the title of the lockdown option -->
+ <string name="lockdown_settings_title">Show lockdown option</string>
+ <!-- Text shown for the description of the lockdown option -->
+ <string name="lockdown_settings_summary">Display power button option that turns off extended access and fingerprint unlocking.</string>
<!-- Text shown for summary of owner info setting (if none set) [CHAR LIMIT=40]-->
<string name="owner_info_settings_summary">None</string>
<!-- Description of how many characters are used in owner info [CHAR LIMIT=40]-->
@@ -1116,14 +1120,18 @@
<!-- Security Picker --><skip />
- <!-- Title for suggested actions for screen lock -->
- <string name="suggested_lock_settings_title">Set screen lock</string>
+ <!-- Title for suggested actions for screen lock [CHAR LIMIT=34] -->
+ <string name="suggested_lock_settings_title">Set screen lock for security</string>
- <!-- Summary for suggested actions for screen lock -->
- <string name="suggested_lock_settings_summary">Protect your device</string>
+ <!-- Summary for suggested actions for screen lock (tablet) -->
+ <string name="suggested_lock_settings_summary" product="tablet">Prevent others from using your tablet</string>
+ <!-- Summary for suggested actions for screen lock (device) -->
+ <string name="suggested_lock_settings_summary" product="device">Prevent others from using your device</string>
+ <!-- Summary for suggested actions for screen lock (phone) -->
+ <string name="suggested_lock_settings_summary" product="default">Prevent others from using your phone</string>
- <!-- Title for suggested actions for settings up a fingerprint lock -->
- <string name="suggested_fingerprint_lock_settings_title">Use fingerprint</string>
+ <!-- Title for suggested actions for settings up a fingerprint lock [CHAR LIMIT=34] -->
+ <string name="suggested_fingerprint_lock_settings_title">Unlock with fingerprint</string>
<!-- Summary for suggested actions for settings up a fingerprint lock -->
<string name="suggested_fingerprint_lock_settings_summary">Unlock with your fingerprint</string>
@@ -1941,6 +1949,8 @@
<string name="wifi_show_password">Show password</string>
<!-- Label for the RadioGroup to choose wifi ap band -->
<string name="wifi_ap_band_config">Select AP Band</string>
+ <!-- Label for the radio button to choose wifi ap channel automatically-->
+ <string name="wifi_ap_choose_auto">Auto</string>
<!-- Label for the radio button to choose wifi ap 2.4 GHz band -->
<string name="wifi_ap_choose_2G">2.4 GHz Band</string>
<!-- Label for the radio button to choose wifi ap 5GHz band -->
@@ -2247,7 +2257,7 @@
<!-- Title of suggestion to turn on wifi calling [CHAR LIMIT=30] -->
<string name="wifi_calling_suggestion_title">Turn on Wi-Fi Calling</string>
<!-- Summary of suggestion to turn on wifi calling [CHAR LIMIT=60] -->
- <string name="wifi_calling_suggestion_summary">Use Wi-Fi instead of mobile network</string>
+ <string name="wifi_calling_suggestion_summary">Extend coverage by calling over Wi-Fi</string>
<!-- Title of WFC preference item [CHAR LIMIT=30] -->
<string name="wifi_calling_mode_title">Calling preference</string>
<!-- Title of WFC preference selection dialog [CHAR LIMIT=30] -->
@@ -3215,6 +3225,10 @@
<string name="reset_network_title">Reset Wi-Fi, mobile & Bluetooth</string>
<!-- SD card & phone storage settings screen, message on screen after user selects Reset network settings [CHAR LIMIT=NONE] -->
<string name="reset_network_desc">This will reset all network settings, including:\n\n<li>Wi\u2011Fi</li>\n<li>Mobile data</li>\n<li>Bluetooth</li>"</string>
+ <!-- SD card & phone storage settings screen, title for the checkbox to let user decide whether erase eSIM data together [CHAR LIMIT=NONE] -->
+ <string name="reset_esim_title">Also reset eSIMs</string>
+ <!-- SD card & phone storage settings screen, message for the checkbox to let user decide whether erase eSIM data together [CHAR LIMIT=NONE] -->
+ <string name="reset_esim_desc">Erase all eSIMs on the phone. You\u2019ll have to contract your carrier to redownload your eSIMs. This will not cancel your mobile service plan.</string>
<!-- SD card & phone storage settings screen, button on screen after user selects Reset network settings -->
<string name="reset_network_button_text">Reset settings</string>
<!-- SD card & phone storage settings screen, message on screen after user selects Reset settings button -->
@@ -3227,6 +3241,10 @@
<string name="network_reset_not_available">Network reset is not available for this user</string>
<!-- Reset settings complete toast text [CHAR LIMIT=75] -->
<string name="reset_network_complete_toast">Network settings have been reset</string>
+ <!-- Title of the error message shown when error happens during erase eSIM data [CHAR LIMIT=NONE] -->
+ <string name="reset_esim_error_title">Cant\u2019t reset eSIMs</string>
+ <!-- Message of the error message shown when error happens during erase eSIM data [CHAR LIMIT=NONE] -->
+ <string name="reset_esim_error_msg">The eSIMs can\u2019tt be reset due to an error.</string>
<!-- Master Clear -->
<!-- Button title to factory data reset the entire device -->
@@ -3242,7 +3260,7 @@
<!-- SD card & phone storage settings screen, list of items in user data storage (USB storage or SD card) that will be erased during this operation [CHAR LIMIT=NONE] -->
<string name="master_clear_desc_also_erases_external">"<li>Music</li>\n<li>Photos</li>\n<li>Other user data</li>"</string>
<!-- SD card & phone storage settings screen, list of items on an eSIM (embedded SIM) that will be erased during this operation [CHAR LIMIT=NONE] -->
- <string name="master_clear_desc_also_erases_esim">"<li>Carriers on eSIM</li>"</string>
+ <string name="master_clear_desc_also_erases_esim">"<li>eSIMs</li>"</string>
<!-- SD card & phone storage settings screen, notification if there are eSIM (embedded SIM) profiles present that the user's mobile service plan will not be canceled [CHAR LIMIT=NONE] -->
<string name="master_clear_desc_no_cancel_mobile_plan">"\n\nThis will not cancel your mobile service plan.</string>
<!-- SD card & phone storage settings screen, instructions about whether to also erase the external storage (SD card) when erasing the internal storage [CHAR LIMIT=NONE] -->
@@ -4713,7 +4731,7 @@
<string name="power_charge_remaining"><xliff:g id="until_charged">%1$s</xliff:g> to charge</string>
<!-- Title for the background activity setting, which allows a user to control whether an app can run in the background [CHAR_LIMIT=40] -->
- <string name="background_activity_title">Background activity</string>
+ <string name="background_activity_title">Restricted</string>
<!-- Summary for the background activity [CHAR_LIMIT=120] -->
<string name="background_activity_summary">Allow the app to run in the background</string>
<!-- Summary for the background activity when it is on [CHAR_LIMIT=120] -->
@@ -5582,10 +5600,12 @@
<string name="add_account_label">Add account</string>
<!-- Label for the state of the work profile [CHAR LIMIT=80] -->
<string name="managed_profile_not_available_label">Work profile isn\u2019t available yet</string>
- <!-- Account Settings. The preference title for enabling work mode -->
- <string name="work_mode_label">Work mode</string>
- <!-- Account Settings. The preference summary for enabling work mode -->
- <string name="work_mode_summary">Allow work profile to function, including apps, background sync, and related features</string>
+ <!-- This string is the title of a setting. If a user taps the setting, they can turn their work profile on or off. The work profile is a section of their phone that's managed by their employer. "Work" is an adjective. -->
+ <string name="work_mode_label">Work profile</string>
+ <!-- This string is located under a setting and describes what the setting does. It's letting a user know whether their work profile is on or off, and they can use the setting to turn it on or off. The work profile is a section of their phone that's managed by their employer. "Work" is an adjective.-->
+ <string name="work_mode_on_summary">Managed by your organization</string>
+ <!-- This string is located under a setting and describes what the setting does. It's letting a user know whether their work profile is on or off, and they can use the setting to turn it on or off. The work profile is a section of their phone that's managed by their employer. "Work" is an adjective.-->
+ <string name="work_mode_off_summary">Apps and notifications are off</string>
<!-- Button label to remove the work profile [CHAR LIMIT=35] -->
<string name="remove_managed_profile_label">Remove work profile</string>
<!-- Data synchronization settings screen, title of setting that controls whether background data should be used [CHAR LIMIT=30] -->
@@ -6431,6 +6451,7 @@
<string name="help_uri_process_stats_summary" translatable="false"></string>
<string name="help_uri_process_stats_apps" translatable="false"></string>
<string name="help_uri_private_dns" translatable="false"></string>
+ <string name="help_uri_about_phone_v2" translatable="false"></string>
<!-- User account title [CHAR LIMIT=30] -->
<string name="user_account_title">Account for content</string>
@@ -6839,6 +6860,9 @@
<!-- Sound: Title for the Do not Disturb option and associated settings page. [CHAR LIMIT=50]-->
<string name="zen_mode_settings_title">Do Not Disturb</string>
+ <!-- Do not disturb: Title for the Do not Disturb dialog to turn on Do not disturb. [CHAR LIMIT=50]-->
+ <string name="zen_mode_settings_turn_on_dialog_title">Turn on Do Not Disturb</string>
+
<!-- Do not disturb: Title for the behaviors option and associated settings page. [CHAR LIMIT=30] -->
<string name="zen_mode_behavior_settings_title">Behavior</string>
@@ -6866,11 +6890,11 @@
<!-- Do not disturb: Title for a specific zen mode automatic rule in settings. [CHAR LIMIT=30] -->
<string name="zen_mode_automatic_rule_settings_page_title">Automatic rule</string>
- <!-- Do not disturb: Title for the zen mode automation option Suggestion. [CHAR LIMIT=50] -->
- <string name="zen_mode_automation_suggestion_title">Set Do Not Disturb rules</string>
+ <!-- Do not disturb: Title for the zen mode automation option Suggestion. [CHAR LIMIT=34] -->
+ <string name="zen_mode_automation_suggestion_title">Silence phone at certain times</string>
<!-- Do not disturb: Summary for the zen mode automation option Suggestion. [CHAR LIMIT=NONE] -->
- <string name="zen_mode_automation_suggestion_summary">Limit sounds & vibrations at certain times</string>
+ <string name="zen_mode_automation_suggestion_summary">Set Do Not Disturb rules</string>
<!-- Do not disturb: Switch toggle to toggle whether to use an automatic dnd rule or not [CHAR LIMIT=40] -->
<string name="zen_mode_use_automatic_rule">Use rule</string>
@@ -6896,6 +6920,9 @@
<!-- Do not disturb: Button to add new automatic rule to DND. [CHAR LIMIT=30] -->
<string name="zen_mode_add">Add</string>
+ <!-- Do not disturb: Label for button in enable zen dialog that will turn on zen mode. [CHAR LIMIT=30] -->
+ <string name="zen_mode_enable_dialog_turn_on">Turn on</string>
+
<!-- Do not disturb: Label for button that will turn on zen mode. [CHAR LIMIT=30] -->
<string name="zen_mode_button_turn_on">Turn on now</string>
@@ -6914,6 +6941,12 @@
<!-- [CHAR LIMIT=110] Zen mode settings footer: Footer how DND was triggered by an app -->
<string name="zen_mode_settings_dnd_automatic_rule_app">Do Not Disturb was automatically turned on by an app (<xliff:g id="app_name" example="Android Services">%s</xliff:g>)</string>
+ <!--[CHAR LIMIT=40] Zen Interruption level: Priority. -->
+ <string name="zen_interruption_level_priority">Priority only</string>
+
+ <!-- [CHAR LIMIT=20] Accessibility string for current zen mode and selected exit condition. A template that simply concatenates existing mode string and the current condition description. -->
+ <string name="zen_mode_and_condition"><xliff:g id="zen_mode" example="Priority interruptions only">%1$s</xliff:g>. <xliff:g id="exit_condition" example="For one hour">%2$s</xliff:g></string>
+
<!-- Work Sounds: Work sound settings section header. [CHAR LIMIT=50] -->
<string name="sound_work_settings">Work profile sounds</string>
@@ -6959,6 +6992,9 @@
<!-- Configure Notifications Settings title. [CHAR LIMIT=30] -->
<string name="configure_notification_settings">Notifications</string>
+ <!-- notification header - apps that have recently sent notifications -->
+ <string name="recent_notifications">Recently sent</string>
+
<!-- Configure Notifications: Advanced section header [CHAR LIMIT=30] -->
<string name="advanced_section_header">Advanced</string>
@@ -7596,6 +7632,11 @@
<!-- Button label to say no to the question of whether to require PIN/password/pattern to start your device. [CHAR LIMIT=20] -->
<string name="encryption_interstitial_no">No</string>
+ <!-- Label to say yes to the question of whether app is restricted. [CHAR LIMIT=20] -->
+ <string name="restricted_true_label">Yes</string>
+ <!-- Label to say no to the question of whether app is restricted. [CHAR LIMIT=20] -->
+ <string name="restricted_false_label">No</string>
+
<!-- Title for encryption dialog that disables TalkBack. [CHAR_LIMIT=25] -->
<string name="encrypt_talkback_dialog_require_pin">Require PIN?</string>
@@ -8329,6 +8370,8 @@
<string name="disabled_by_policy_title_camera">Camera not allowed</string>
<!-- Title for dialog displayed to tell user that screenshots are disabled by an admin [CHAR LIMIT=50] -->
<string name="disabled_by_policy_title_screen_capture">Screenshot not allowed</string>
+ <!-- Title for dialog displayed to tell user that turning off backups is disallowed by an admin [CHAR LIMIT=50] -->
+ <string name="disabled_by_policy_title_turn_off_backups">Can\'t turn off backups</string>
<!-- Shown when the user tries to change a settings locked by an admin [CHAR LIMIT=200] -->
<string name="default_admin_support_msg">This action is disabled. To learn more, contact your
organization\'s admin.</string>
@@ -8402,7 +8445,7 @@
<string name="night_display_suggestion_title">Set Night Light schedule</string>
<!-- Night display: Summary for the night display option Suggestion (renamed "Night Light" with title caps). [CHAR LIMIT=NONE] -->
- <string name="night_display_suggestion_summary">Tint screen amber to help you fall asleep</string>
+ <string name="night_display_suggestion_summary">Automatically tint screen every night</string>
<!-- Title of condition that night display is on (renamed "Night Light" with title caps). [CHAR LIMIT=30] -->
<string name="condition_night_display_title">Night Light is on</string>
@@ -8683,7 +8726,10 @@
<string name="notification_log_details_ranking_none">Ranking object doesn\'t contain this key.</string>
<!-- [CHAR_LIMIT=NONE] Developer Settings: Title of the setting which turns on emulation of a display cutout. -->
- <string name="display_cutout_emulation">Emulate a display with a cutout</string>
+ <string name="display_cutout_emulation">Simulate a display with a cutout</string>
+
+ <!-- [CHAR_LIMIT=NONE] Developer Settings: Label for the option that turns off display cutout emulation. -->
+ <string name="display_cutout_emulation_none">None</string>
<!-- [CHAR_LIMIT=60] Label for special access screen -->
<string name="special_access">Special app access</string>
@@ -8821,9 +8867,6 @@
<!-- Title for settings suggestion for double tap power for camera [CHAR LIMIT=60] -->
<string name="double_tap_power_for_camera_suggestion_title">Open camera quickly</string>
- <!-- Summary for settings suggestion for double tap power for camera [CHAR LIMIT=60] -->
- <string name="double_tap_power_for_camera_suggestion_summary">Press power button twice to open camera</string>
-
<!-- Title text for double twist for camera mode [CHAR LIMIT=60]-->
<string name="double_twist_for_camera_mode_title">Flip camera</string>
@@ -8833,13 +8876,6 @@
<!-- Title for settings suggestion for double twist for camera [CHAR LIMIT=60] -->
<string name="double_twist_for_camera_suggestion_title">Take selfies faster</string>
- <!-- Summary for settings suggestion for double twist for camera (phone) [CHAR LIMIT=60] -->
- <string name="double_twist_for_camera_suggestion_summary" product="default">Double-twist phone for selfie mode</string>
- <!-- Summary for settings suggestion for double twist for camera (tablet) [CHAR LIMIT=60] -->
- <string name="double_twist_for_camera_suggestion_summary" product="tablet">Double-twist tablet for selfie mode</string>
- <!-- Summary for settings suggestion for double twist for camera (device) [CHAR LIMIT=60] -->
- <string name="double_twist_for_camera_suggestion_summary" product="device">Double-twist device for selfie mode</string>
-
<!-- Preference and settings suggestion title text for ambient display double tap (phone) [CHAR LIMIT=60]-->
<string name="ambient_display_title" product="default">Double-tap to check phone</string>
<!-- Preference and settings suggestion title text for ambient display double tap (tablet) [CHAR LIMIT=60]-->
@@ -8850,9 +8886,6 @@
<!-- Summary text for ambient display double tap [CHAR LIMIT=NONE]-->
<string name="ambient_display_summary">To check time, notification icons, and other info, double-tap your screen.</string>
- <!-- Summary for settings suggestion for double tap power for camera [CHAR LIMIT=60] -->
- <string name="ambient_display_suggestion_summary">Check notifications when screen is off</string>
-
<!-- Preference and settings suggestion title text for ambient display pick up (phone) [CHAR LIMIT=60]-->
<string name="ambient_display_pickup_title" product="default">Lift to check phone</string>
<!-- Preference and settings suggestion title text for ambient display pick up (tablet) [CHAR LIMIT=60]-->
@@ -8867,9 +8900,6 @@
<!-- Summary text for ambient display (device) [CHAR LIMIT=NONE]-->
<string name="ambient_display_pickup_summary" product="device">To check time, notification icons, and other info, pick up your device.</string>
- <!-- Summary for settings suggestion for ambient display pick up [CHAR LIMIT=60] -->
- <string name="ambient_display_pickup_suggestion_summary">Check notifications when screen is off</string>
-
<!-- Title text for swiping downwards on fingerprint sensor for notifications [CHAR LIMIT=80]-->
<string name="fingerprint_swipe_for_notifications_title">Swipe fingerprint for notifications</string>
<!-- Title text for fingerprint gesture preference screen [CHAR LIMIT=25] -->
@@ -8885,9 +8915,6 @@
<!-- Title for settings suggestion for fingerprint swipe for notifications [CHAR LIMIT=60] -->
<string name="fingerprint_swipe_for_notifications_suggestion_title">See notifications quickly</string>
- <!-- Summary for settings suggestion for fingerprint swipe for notifications [CHAR LIMIT=60] -->
- <string name="fingerprint_swipe_for_notifications_suggestion_summary">Swipe down on the fingerprint sensor</string>
-
<!-- Title text for the assist gesture [CHAR LIMIT=60] DO NOT TRANSLATE -->
<string name="assist_gesture_title" translatable="false"></string>
@@ -9210,4 +9237,15 @@
[DO NOT TRANSLATE] -->
<string name="account_confirmation_package"></string>
+ <!-- Title for the new About Phone screen [CHAR LIMIT=40] -->
+ <string name="my_device_info_title" product="default">My Phone</string>
+ <!-- Title for the new About Phone screen [CHAR LIMIT=40] -->
+ <string name="my_device_info_title" product="tablet">My Tablet</string>
+ <!-- Title for the new About Phone screen [CHAR LIMIT=40] -->
+ <string name="my_device_info_title" product="device">My Device</string>
+ <!-- Title for preference showing the primary account on the device [CHAR LIMIT=60]-->
+ <string name="my_device_info_account_preference_title">Account</string>
+ <!-- Title for preference showing the name of the device. [CHAR LIMIT=60]-->
+ <string name="my_device_info_device_name_preference_title">Device name</string>
+
</resources>
diff --git a/res/xml/configure_notification_settings.xml b/res/xml/configure_notification_settings.xml
index 21904e6..520ebaa 100644
--- a/res/xml/configure_notification_settings.xml
+++ b/res/xml/configure_notification_settings.xml
@@ -19,8 +19,28 @@
android:key="configure_notification_settings">
<PreferenceCategory
- android:key="dashboard_tile_placeholder"
- android:order="1"/>
+ android:key="recent_notifications_category"
+ android:title="@string/recent_notifications"
+ android:order="-200">
+ <!-- Placeholder for a list of recent apps -->
+
+ <!-- See all apps button -->
+ <Preference
+ android:title="@string/notifications_title"
+ android:key="all_notifications"
+ android:order="20">
+ <intent
+ android:action="android.intent.action.MAIN"
+ android:targetPackage="com.android.settings"
+ android:targetClass="com.android.settings.Settings$NotificationAppListActivity">
+ </intent>
+ </Preference>
+ </PreferenceCategory>
+
+ <!-- Empty category to draw divider -->
+ <PreferenceCategory
+ android:key="all_notifications_divider"
+ android:order="-190"/>
<!-- When device is locked -->
<com.android.settings.notification.RestrictedDropDownPreference
diff --git a/res/xml/development_settings.xml b/res/xml/development_settings.xml
index 9d85ec9..04644f5 100644
--- a/res/xml/development_settings.xml
+++ b/res/xml/development_settings.xml
@@ -203,6 +203,11 @@
android:summary="@string/wifi_verbose_logging_summary"/>
<SwitchPreference
+ android:key="wifi_connected_mac_randomization"
+ android:title="@string/wifi_connected_mac_randomization"
+ android:summary="@string/wifi_connected_mac_randomization_summary"/>
+
+ <SwitchPreference
android:key="mobile_data_always_on"
android:title="@string/mobile_data_always_on"
android:summary="@string/mobile_data_always_on_summary"/>
@@ -346,7 +351,7 @@
android:key="density"
android:title="@string/developer_smallest_width" />
- <SwitchPreference
+ <ListPreference
android:key="display_cutout_emulation"
android:title="@string/display_cutout_emulation" />
diff --git a/res/xml/directory_access_details.xml b/res/xml/directory_access_details.xml
new file mode 100644
index 0000000..4448ba6
--- /dev/null
+++ b/res/xml/directory_access_details.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2018 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:settings="http://schemas.android.com/apk/res-auto"
+ android:key="directory_access_details"
+ android:title="@string/directory_access"/>
diff --git a/res/xml/managed_profile_settings.xml b/res/xml/managed_profile_settings.xml
index 58fcd88..c283e13 100644
--- a/res/xml/managed_profile_settings.xml
+++ b/res/xml/managed_profile_settings.xml
@@ -20,14 +20,13 @@
<SwitchPreference
android:key="work_mode"
- android:summary="@string/work_mode_summary"
- android:title="@string/work_mode_label"/>
+ android:title="@string/work_mode_label"
+ android:summary="@string/summary_placeholder"/>
<com.android.settingslib.RestrictedSwitchPreference
android:key="contacts_search"
android:summary="@string/managed_profile_contact_search_summary"
android:title="@string/managed_profile_contact_search_title"
- settings:useAdditionalSummary="true"
- />
+ settings:useAdditionalSummary="true"/>
</PreferenceScreen>
\ No newline at end of file
diff --git a/res/xml/my_device_info.xml b/res/xml/my_device_info.xml
new file mode 100644
index 0000000..673b2a5
--- /dev/null
+++ b/res/xml/my_device_info.xml
@@ -0,0 +1,167 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2018 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<PreferenceScreen
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:settings="http://schemas.android.com/apk/res-auto"
+ android:key="my_device_info_pref_screen"
+ android:title="@string/my_device_info_title"
+ settings:initialExpandedChildrenCount="4">
+
+ <com.android.settings.applications.LayoutPreference
+ android:key="my_device_info_header"
+ android:order="0"
+ android:layout="@layout/settings_entity_header"
+ android:selectable="false"/>
+
+ <!-- Account name -->
+ <Preference
+ android:key="account"
+ android:order="1"
+ android:title="@string/my_device_info_account_preference_title"
+ android:summary="@string/summary_placeholder"/>
+
+ <!-- Phone number -->
+ <Preference
+ android:key="phone_number"
+ android:order="2"
+ android:title="@string/status_number"
+ android:summary="@string/summary_placeholder"/>
+
+ <!-- Device name -->
+ <Preference
+ android:key="device_name"
+ android:order="3"
+ android:title="@string/my_device_info_device_name_preference_title"
+ android:summary="@string/summary_placeholder"/>
+
+ <!-- SIM status -->
+ <Preference
+ android:key="sim_status"
+ android:order="4"
+ android:title="@string/sim_status_title"
+ settings:keywords="@string/keywords_sim_status"
+ android:summary="@string/summary_placeholder"/>
+
+ <!-- Model & hardware -->
+ <Preference
+ android:key="device_model"
+ android:order="21"
+ android:title="@string/hardware_info"
+ settings:keywords="@string/keywords_model_and_hardware"
+ android:summary="@string/summary_placeholder"/>
+
+ <!-- IMEI -->
+ <Preference
+ android:key="imei_info"
+ android:order="22"
+ android:title="@string/status_imei"
+ settings:keywords="@string/keywords_imei_info"
+ android:summary="@string/summary_placeholder"/>
+
+ <!-- Android version -->
+ <Preference
+ android:key="firmware_version"
+ android:order="32"
+ android:title="@string/firmware_version"
+ settings:keywords="@string/keywords_android_version"
+ android:summary="@string/summary_placeholder"/>
+
+ <!-- IMS registration -->
+ <Preference
+ android:key="ims_reg_state"
+ android:order="33"
+ android:title="@string/ims_reg_title"
+ android:summary="@string/summary_placeholder"/>
+
+ <!--IP address -->
+ <Preference
+ android:key="wifi_ip_address"
+ android:order="34"
+ android:title="@string/wifi_ip_address"
+ android:summary="@string/summary_placeholder"
+ settings:allowDividerAbove="true"/>
+
+ <!-- Wi-Fi MAC address -->
+ <Preference
+ android:key="wifi_mac_address"
+ android:order="35"
+ android:title="@string/status_wifi_mac_address"
+ android:summary="@string/summary_placeholder"/>
+
+ <!-- Bluetooth address -->
+ <Preference
+ android:key="bt_address"
+ android:order="36"
+ android:title="@string/status_bt_address"
+ android:summary="@string/summary_placeholder"/>
+
+
+ <!-- Legal information -->
+ <Preference
+ android:key="legal_container"
+ android:order="37"
+ android:title="@string/legal_information"
+ android:fragment="com.android.settings.LegalSettings"
+ settings:allowDividerAbove="true"/>
+
+ <!-- Regulatory labels -->
+ <Preference
+ android:key="regulatory_info"
+ android:order="38"
+ android:title="@string/regulatory_labels">
+ <intent android:action="android.settings.SHOW_REGULATORY_INFO"/>
+ </Preference>
+
+ <!-- Safety & regulatory manual -->
+ <Preference
+ android:key="safety_info"
+ android:order="39"
+ android:title="@string/safety_and_regulatory_info">
+ <intent android:action="android.settings.SHOW_SAFETY_AND_REGULATORY_INFO"/>
+ </Preference>
+
+ <!-- Manual -->
+ <Preference
+ android:key="manual"
+ android:order="40"
+ android:title="@string/manual">
+ <intent android:action="android.settings.SHOW_MANUAL"/>
+ </Preference>
+
+ <!-- Feedback on the device -->
+ <Preference
+ android:key="device_feedback"
+ android:order="41"
+ android:title="@string/device_feedback"/>
+
+ <!-- Device FCC equipment id -->
+ <Preference
+ android:key="fcc_equipment_id"
+ android:order="42"
+ android:title="@string/fcc_equipment_id"
+ android:summary="@string/summary_placeholder"/>
+
+ <!-- Build number -->
+ <Preference
+ android:key="build_number"
+ android:order="43"
+ android:title="@string/build_number"
+ android:summary="@string/summary_placeholder"
+ settings:allowDividerAbove="true"/>
+
+</PreferenceScreen>
\ No newline at end of file
diff --git a/res/xml/power_usage_detail.xml b/res/xml/power_usage_detail.xml
index acd6367..acc62b6 100644
--- a/res/xml/power_usage_detail.xml
+++ b/res/xml/power_usage_detail.xml
@@ -27,6 +27,22 @@
android:key="action_buttons"
android:order="-9999"/>
+ <PreferenceCategory
+ android:title="@string/battery_detail_manage_title">
+
+ <Preference
+ android:key="background_activity"
+ android:title="@string/background_activity_title"
+ android:selectable="true"/>
+
+ <Preference
+ android:key="battery_optimization"
+ android:title="@string/high_power_apps"
+ android:summary="@string/high_power_off"
+ android:selectable="true"/>
+
+ </PreferenceCategory>
+
<Preference
android:key="high_usage"
android:icon="@drawable/ic_battery_alert_24dp"
@@ -52,20 +68,4 @@
</PreferenceCategory>
- <PreferenceCategory
- android:title="@string/battery_detail_manage_title">
-
- <SwitchPreference
- android:key="background_activity"
- android:title="@string/background_activity_title"
- android:selectable="true"/>
-
- <Preference
- android:key="battery_optimization"
- android:title="@string/high_power_apps"
- android:summary="@string/high_power_off"
- android:selectable="true"/>
-
- </PreferenceCategory>
-
</PreferenceScreen>
\ No newline at end of file
diff --git a/res/xml/security_lockscreen_settings.xml b/res/xml/security_lockscreen_settings.xml
index 7a45bec..6faedd7 100644
--- a/res/xml/security_lockscreen_settings.xml
+++ b/res/xml/security_lockscreen_settings.xml
@@ -33,6 +33,11 @@
android:title="@string/owner_info_settings_title"
android:summary="@string/owner_info_settings_summary" />
+ <SwitchPreference
+ android:key="security_setting_lockdown_enabled"
+ android:title="@string/lockdown_settings_title"
+ android:summary="@string/lockdown_settings_summary" />
+
<PreferenceCategory
android:key="security_setting_lock_screen_notif_work_header"
android:title="@string/profile_section_header">
diff --git a/res/xml/special_access.xml b/res/xml/special_access.xml
index 0843b79..7205eaf 100644
--- a/res/xml/special_access.xml
+++ b/res/xml/special_access.xml
@@ -111,7 +111,6 @@
android:value="com.android.settings.Settings$VrListenersSettingsActivity" />
</Preference>
-<!-- TODO(b/63720392): add when ready
<Preference
android:key="special_app_directory_access"
android:title="@string/directory_access"
@@ -119,8 +118,7 @@
settings:keywords="@string/keywords_directory_access">
<extra
android:name="classname"
- android:value="com.android.settings.Settings$DirectoryeAccessSettingsActivity" />
+ android:value="com.android.settings.Settings$DirectoryAccessSettingsActivity" />
</Preference>
- -->
</PreferenceScreen>
diff --git a/src/com/android/settings/AirplaneModeEnabler.java b/src/com/android/settings/AirplaneModeEnabler.java
index 5f93589..4fc205d 100644
--- a/src/com/android/settings/AirplaneModeEnabler.java
+++ b/src/com/android/settings/AirplaneModeEnabler.java
@@ -30,8 +30,8 @@
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.internal.telephony.PhoneStateIntentReceiver;
import com.android.internal.telephony.TelephonyProperties;
+import com.android.settings.core.instrumentation.MetricsFeatureProvider;
import com.android.settingslib.WirelessUtils;
-import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
public class AirplaneModeEnabler implements Preference.OnPreferenceChangeListener {
diff --git a/src/com/android/settings/ApnPreference.java b/src/com/android/settings/ApnPreference.java
index 4e89efc..9a6eeaf 100755
--- a/src/com/android/settings/ApnPreference.java
+++ b/src/com/android/settings/ApnPreference.java
@@ -16,6 +16,7 @@
package com.android.settings;
+import static android.provider.Telephony.Carriers.CONTENT_URI;
import static android.provider.Telephony.Carriers.FILTERED_URI;
import android.content.ContentUris;
@@ -36,6 +37,7 @@
public class ApnPreference extends Preference implements
CompoundButton.OnCheckedChangeListener, OnClickListener {
final static String TAG = "ApnPreference";
+ private boolean mDpcEnforced = false;
private int mSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
@@ -119,7 +121,8 @@
Context context = getContext();
if (context != null) {
int pos = Integer.parseInt(getKey());
- Uri url = ContentUris.withAppendedId(FILTERED_URI, pos);
+ Uri url = ContentUris.withAppendedId(
+ mDpcEnforced ? FILTERED_URI : CONTENT_URI, pos);
Intent editIntent = new Intent(Intent.ACTION_EDIT, url);
editIntent.putExtra(ApnSettings.SUB_ID, mSubId);
context.startActivity(editIntent);
@@ -138,4 +141,8 @@
public void setSubId(int subId) {
mSubId = subId;
}
+
+ public void setDpcEnforced(boolean enforced) {
+ mDpcEnforced = enforced;
+ }
}
diff --git a/src/com/android/settings/ApnSettings.java b/src/com/android/settings/ApnSettings.java
index 3628121..2c22a79 100755
--- a/src/com/android/settings/ApnSettings.java
+++ b/src/com/android/settings/ApnSettings.java
@@ -16,6 +16,7 @@
package com.android.settings;
+import static android.provider.Telephony.Carriers.CONTENT_URI;
import static android.provider.Telephony.Carriers.ENFORCE_MANAGED_URI;
import static android.provider.Telephony.Carriers.FILTERED_URI;
@@ -291,6 +292,7 @@
mSelectedKey = getSelectedApnKey();
cursor.moveToFirst();
+ boolean enforced = isDpcApnEnforced();
while (!cursor.isAfterLast()) {
String name = cursor.getString(NAME_INDEX);
String apn = cursor.getString(APN_INDEX);
@@ -307,6 +309,7 @@
pref.setPersistent(false);
pref.setOnPreferenceChangeListener(this);
pref.setSubId(subId);
+ pref.setDpcEnforced(enforced);
boolean selectable = ((type == null) || !type.equals("mms"));
pref.setSelectable(selectable);
@@ -398,7 +401,7 @@
@Override
public boolean onPreferenceTreeClick(Preference preference) {
int pos = Integer.parseInt(preference.getKey());
- Uri url = ContentUris.withAppendedId(FILTERED_URI, pos);
+ Uri url = ContentUris.withAppendedId(isDpcApnEnforced() ? FILTERED_URI : CONTENT_URI, pos);
startActivity(new Intent(Intent.ACTION_EDIT, url));
return true;
}
diff --git a/src/com/android/settings/DeviceAdminSettings.java b/src/com/android/settings/DeviceAdminSettings.java
index bb53018..9391439 100644
--- a/src/com/android/settings/DeviceAdminSettings.java
+++ b/src/com/android/settings/DeviceAdminSettings.java
@@ -49,9 +49,8 @@
import android.widget.TextView;
import com.android.internal.logging.nano.MetricsProto;
-import com.android.settings.overlay.FeatureFactory;
-import com.android.settingslib.core.instrumentation.Instrumentable;
-import com.android.settingslib.core.instrumentation.VisibilityLoggerMixin;
+import com.android.settings.core.instrumentation.Instrumentable;
+import com.android.settings.core.instrumentation.VisibilityLoggerMixin;
import org.xmlpull.v1.XmlPullParserException;
@@ -64,7 +63,8 @@
public class DeviceAdminSettings extends ListFragment implements Instrumentable {
static final String TAG = "DeviceAdminSettings";
- private VisibilityLoggerMixin mVisibilityLoggerMixin;
+ private final VisibilityLoggerMixin mVisibilityLoggerMixin =
+ new VisibilityLoggerMixin(getMetricsCategory());
private DevicePolicyManager mDPM;
private UserManager mUm;
@@ -85,6 +85,12 @@
}
}
+ @Override
+ public void onAttach(Context context) {
+ super.onAttach(context);
+ mVisibilityLoggerMixin.onAttach(context);
+ }
+
/**
* Internal collection of device admin info objects for all profiles associated with the current
* user.
@@ -115,8 +121,6 @@
@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
- mVisibilityLoggerMixin = new VisibilityLoggerMixin(getMetricsCategory(),
- FeatureFactory.getFactory(getContext()).getMetricsFeatureProvider());
}
@Override
diff --git a/src/com/android/settings/MasterClear.java b/src/com/android/settings/MasterClear.java
index 3cc722b..b7fb694 100644
--- a/src/com/android/settings/MasterClear.java
+++ b/src/com/android/settings/MasterClear.java
@@ -75,8 +75,11 @@
public class MasterClear extends InstrumentedPreferenceFragment {
private static final String TAG = "MasterClear";
- private static final int KEYGUARD_REQUEST = 55;
- private static final int CREDENTIAL_CONFIRM_REQUEST = 56;
+ @VisibleForTesting static final int KEYGUARD_REQUEST = 55;
+ @VisibleForTesting static final int CREDENTIAL_CONFIRM_REQUEST = 56;
+
+ private static final String KEY_SHOW_ESIM_RESET_CHECKBOX
+ = "masterclear.allow_retain_esim_profiles_after_fdr";
static final String ERASE_EXTERNAL_EXTRA = "erase_sd";
static final String ERASE_ESIMS_EXTRA = "erase_esim";
@@ -85,6 +88,8 @@
private Button mInitiateButton;
private View mExternalStorageContainer;
@VisibleForTesting CheckBox mExternalStorage;
+ private View mEsimStorageContainer;
+ @VisibleForTesting CheckBox mEsimStorage;
private ScrollView mScrollView;
private final OnGlobalLayoutListener mOnGlobalLayoutListener = new OnGlobalLayoutListener() {
@@ -113,11 +118,16 @@
request, res.getText(R.string.master_clear_title));
}
+ @VisibleForTesting
+ boolean isValidRequestCode(int requestCode) {
+ return !((requestCode != KEYGUARD_REQUEST) && (requestCode != CREDENTIAL_CONFIRM_REQUEST));
+ }
+
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
- if (requestCode != KEYGUARD_REQUEST || requestCode != CREDENTIAL_CONFIRM_REQUEST) {
+ if (!isValidRequestCode(requestCode)) {
return;
}
@@ -134,8 +144,7 @@
void showFinalConfirmation() {
Bundle args = new Bundle();
args.putBoolean(ERASE_EXTERNAL_EXTRA, mExternalStorage.isChecked());
- // TODO: Offer the user a choice to wipe eSIMs when it is technically feasible to do so.
- args.putBoolean(ERASE_ESIMS_EXTRA, true);
+ args.putBoolean(ERASE_ESIMS_EXTRA, mEsimStorage.isChecked());
((SettingsActivity) getActivity()).startPreferencePanel(
this, MasterClearConfirm.class.getName(),
args, R.string.master_clear_confirm_title, null, null, 0);
@@ -157,9 +166,12 @@
.setAction("android.accounts.action.PRE_FACTORY_RESET");
// Check to make sure that the intent is supported.
final PackageManager pm = context.getPackageManager();
- final List<ResolveInfo> resolutions =
- pm.queryIntentActivities(requestAccountConfirmation, 0);
- if (resolutions != null && resolutions.size() > 0) {
+ final ResolveInfo resolution = pm.resolveActivity(requestAccountConfirmation, 0);
+ if (resolution != null
+ && resolution.activityInfo != null
+ && packageName.equals(resolution.activityInfo.packageName)) {
+ // Note that we need to check the packagename to make sure that an Activity resolver
+ // wasn't returned.
getActivity().startActivityForResult(
requestAccountConfirmation, CREDENTIAL_CONFIRM_REQUEST);
return true;
@@ -214,6 +226,8 @@
mInitiateButton.setOnClickListener(mInitiateListener);
mExternalStorageContainer = mContentView.findViewById(R.id.erase_external_container);
mExternalStorage = (CheckBox) mContentView.findViewById(R.id.erase_external);
+ mEsimStorageContainer = mContentView.findViewById(R.id.erase_esim_container);
+ mEsimStorage = (CheckBox) mContentView.findViewById(R.id.erase_esim);
mScrollView = (ScrollView) mContentView.findViewById(R.id.master_clear_scrollview);
/*
@@ -248,11 +262,25 @@
}
if (showWipeEuicc()) {
- final View esimAlsoErased = mContentView.findViewById(R.id.also_erases_esim);
- esimAlsoErased.setVisibility(View.VISIBLE);
+ if (showWipeEuiccCheckbox()) {
+ TextView title = mContentView.findViewById(R.id.erase_esim_title);
+ title.setText(R.string.erase_esim_storage);
+ mEsimStorageContainer.setVisibility(View.VISIBLE);
+ mEsimStorageContainer.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ mEsimStorage.toggle();
+ }
+ });
+ } else {
+ final View esimAlsoErased = mContentView.findViewById(R.id.also_erases_esim);
+ esimAlsoErased.setVisibility(View.VISIBLE);
- final View noCancelMobilePlan = mContentView.findViewById(R.id.no_cancel_mobile_plan);
- noCancelMobilePlan.setVisibility(View.VISIBLE);
+ final View noCancelMobilePlan = mContentView.findViewById(
+ R.id.no_cancel_mobile_plan);
+ noCancelMobilePlan.setVisibility(View.VISIBLE);
+ mEsimStorage.setChecked(true /* checked */);
+ }
}
final UserManager um = (UserManager) getActivity().getSystemService(Context.USER_SERVICE);
@@ -294,6 +322,12 @@
}
@VisibleForTesting
+ boolean showWipeEuiccCheckbox() {
+ return SystemProperties
+ .getBoolean(KEY_SHOW_ESIM_RESET_CHECKBOX, false /* def */);
+ }
+
+ @VisibleForTesting
protected boolean isEuiccEnabled(Context context) {
EuiccManager euiccManager = (EuiccManager) context.getSystemService(Context.EUICC_SERVICE);
return euiccManager.isEnabled();
diff --git a/src/com/android/settings/ResetNetwork.java b/src/com/android/settings/ResetNetwork.java
index 0f08c26..f64f6dc 100644
--- a/src/com/android/settings/ResetNetwork.java
+++ b/src/com/android/settings/ResetNetwork.java
@@ -18,20 +18,28 @@
import android.annotation.Nullable;
import android.app.Activity;
+import android.content.ContentResolver;
+import android.content.Context;
import android.content.Intent;
import android.content.res.Resources;
import android.os.Bundle;
import android.os.UserHandle;
import android.os.UserManager;
+import android.provider.Settings;
+import android.provider.Settings.Global;
import android.telephony.SubscriptionInfo;
import android.telephony.SubscriptionManager;
+import android.telephony.euicc.EuiccManager;
import android.text.TextUtils;
import android.view.LayoutInflater;
import android.view.View;
+import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.Button;
+import android.widget.CheckBox;
import android.widget.Spinner;
+import android.widget.TextView;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.internal.telephony.PhoneConstants;
@@ -64,6 +72,8 @@
private View mContentView;
private Spinner mSubscriptionSpinner;
private Button mInitiateButton;
+ private View mEsimContainer;
+ private CheckBox mEsimCheckbox;
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
@@ -107,6 +117,7 @@
SubscriptionInfo subscription = mSubscriptions.get(selectedIndex);
args.putInt(PhoneConstants.SUBSCRIPTION_KEY, subscription.getSubscriptionId());
}
+ args.putBoolean(MasterClear.ERASE_ESIMS_EXTRA, mEsimCheckbox.isChecked());
((SettingsActivity) getActivity()).startPreferencePanel(
this, ResetNetworkConfirm.class.getName(),
args, R.string.reset_network_confirm_title, null, null, 0);
@@ -141,6 +152,8 @@
*/
private void establishInitialState() {
mSubscriptionSpinner = (Spinner) mContentView.findViewById(R.id.reset_network_subscription);
+ mEsimContainer = mContentView.findViewById(R.id.erase_esim_container);
+ mEsimCheckbox = mContentView.findViewById(R.id.erase_esim);
mSubscriptions = SubscriptionManager.from(getActivity()).getActiveSubscriptionInfoList();
if (mSubscriptions != null && mSubscriptions.size() > 0) {
@@ -192,6 +205,30 @@
}
mInitiateButton = (Button) mContentView.findViewById(R.id.initiate_reset_network);
mInitiateButton.setOnClickListener(mInitiateListener);
+ if (showEuiccSettings(getContext())) {
+ mEsimContainer.setVisibility(View.VISIBLE);
+ TextView title = mContentView.findViewById(R.id.erase_esim_title);
+ title.setText(R.string.reset_esim_title);
+ mEsimContainer.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ mEsimCheckbox.toggle();
+ }
+ });
+ } else {
+ mEsimCheckbox.setChecked(false /* checked */);
+ }
+ }
+
+ private boolean showEuiccSettings(Context context) {
+ EuiccManager euiccManager =
+ (EuiccManager) context.getSystemService(Context.EUICC_SERVICE);
+ if (!euiccManager.isEnabled()) {
+ return false;
+ }
+ ContentResolver resolver = context.getContentResolver();
+ return Settings.Global.getInt(resolver, Global.EUICC_PROVISIONED, 0) != 0
+ || Settings.Global.getInt(resolver, Global.DEVELOPMENT_SETTINGS_ENABLED, 0) != 0;
}
@Override
diff --git a/src/com/android/settings/ResetNetworkConfirm.java b/src/com/android/settings/ResetNetworkConfirm.java
index 58b8289..bc0fa77 100644
--- a/src/com/android/settings/ResetNetworkConfirm.java
+++ b/src/com/android/settings/ResetNetworkConfirm.java
@@ -16,6 +16,7 @@
package com.android.settings;
+import android.app.AlertDialog;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothManager;
import android.content.ContentResolver;
@@ -24,9 +25,12 @@
import android.net.NetworkPolicyManager;
import android.net.Uri;
import android.net.wifi.WifiManager;
+import android.os.AsyncTask;
import android.os.Bundle;
+import android.os.RecoverySystem;
import android.os.UserHandle;
import android.os.UserManager;
+import android.support.annotation.VisibleForTesting;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
import android.view.LayoutInflater;
@@ -39,6 +43,7 @@
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.internal.telephony.PhoneConstants;
import com.android.settings.core.InstrumentedPreferenceFragment;
+import com.android.settings.wrapper.RecoverySystemWrapper;
import com.android.settingslib.RestrictedLockUtils;
import static com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
@@ -57,6 +62,42 @@
private View mContentView;
private int mSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
+ @VisibleForTesting boolean mEraseEsim;
+ @VisibleForTesting EraseEsimAsyncTask mEraseEsimTask;
+ @VisibleForTesting static RecoverySystemWrapper mRecoverySystem;
+
+ /**
+ * Async task used to erase all the eSIM profiles from the phone. If error happens during
+ * erasing eSIM profiles or timeout, an error msg is shown.
+ */
+ private static class EraseEsimAsyncTask extends AsyncTask<Void, Void, Boolean> {
+ private final Context mContext;
+ private final String mPackageName;
+
+ EraseEsimAsyncTask(Context context, String packageName) {
+ mContext = context;
+ mPackageName = packageName;
+ }
+
+ @Override
+ protected Boolean doInBackground(Void... params) {
+ return mRecoverySystem.wipeEuiccData(mContext, mPackageName);
+ }
+
+ @Override
+ protected void onPostExecute(Boolean succeeded) {
+ if (succeeded) {
+ Toast.makeText(mContext, R.string.reset_network_complete_toast, Toast.LENGTH_SHORT)
+ .show();
+ } else {
+ new AlertDialog.Builder(mContext)
+ .setTitle(R.string.reset_esim_error_title)
+ .setMessage(R.string.reset_esim_error_msg)
+ .setPositiveButton(android.R.string.ok, null /* listener */)
+ .show();
+ }
+ }
+ }
/**
* The user has gone through the multiple confirmation, so now we go ahead
@@ -69,7 +110,8 @@
if (Utils.isMonkeyRunning()) {
return;
}
- // TODO maybe show a progress dialog if this ends up taking a while
+ // TODO maybe show a progress screen if this ends up taking a while and won't let user
+ // go back until the tasks finished.
Context context = getActivity();
ConnectivityManager connectivityManager = (ConnectivityManager)
@@ -108,11 +150,20 @@
ImsManager.factoryReset(context);
restoreDefaultApn(context);
+ esimFactoryReset(context, context.getPackageName());
+ }
+ };
+ @VisibleForTesting
+ void esimFactoryReset(Context context, String packageName) {
+ if (mEraseEsim) {
+ mEraseEsimTask = new EraseEsimAsyncTask(context, packageName);
+ mEraseEsimTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
+ } else {
Toast.makeText(context, R.string.reset_network_complete_toast, Toast.LENGTH_SHORT)
.show();
}
- };
+ }
/**
* Restore APN settings to default.
@@ -163,6 +214,16 @@
if (args != null) {
mSubId = args.getInt(PhoneConstants.SUBSCRIPTION_KEY,
SubscriptionManager.INVALID_SUBSCRIPTION_ID);
+ mEraseEsim = args.getBoolean(MasterClear.ERASE_ESIMS_EXTRA);
+ }
+ mRecoverySystem = new RecoverySystemWrapper();
+ }
+
+ @Override
+ public void onDestroy() {
+ if (mEraseEsimTask != null) {
+ mEraseEsimTask.cancel(true /* mayInterruptIfRunning */);
+ mEraseEsimTask = null;
}
}
diff --git a/src/com/android/settings/Settings.java b/src/com/android/settings/Settings.java
index 5e815bc..dcf7ed5 100644
--- a/src/com/android/settings/Settings.java
+++ b/src/com/android/settings/Settings.java
@@ -16,7 +16,6 @@
package com.android.settings;
-import static com.android.settings.core.FeatureFlags.BATTERY_SETTINGS_V2;
import static com.android.settings.core.FeatureFlags.CONNECTED_DEVICE_V2;
import android.os.Bundle;
@@ -55,6 +54,7 @@
public static class NightDisplaySettingsActivity extends SettingsActivity { /* empty */ }
public static class NightDisplaySuggestionActivity extends NightDisplaySettingsActivity { /* empty */ }
public static class DeviceInfoSettingsActivity extends SettingsActivity { /* empty */ }
+ public static class MeCardActivity extends SettingsActivity { /* empty */ }
public static class ApplicationSettingsActivity extends SettingsActivity { /* empty */ }
public static class ManageApplicationsActivity extends SettingsActivity { /* empty */ }
public static class ManageAssistActivity extends SettingsActivity { /* empty */ }
@@ -133,16 +133,8 @@
public static class AppWriteSettingsActivity extends SettingsActivity { /* empty */ }
public static class AdvancedAppsActivity extends SettingsActivity { /* empty */ }
- public static class ManageExternalSourcesActivity extends SettingsActivity {
- /* empty */ }
+ public static class ManageExternalSourcesActivity extends SettingsActivity {/* empty */ }
public static class ManageAppExternalSourcesActivity extends SettingsActivity { /* empty */ }
- public static class DoubleTapPowerSuggestionActivity extends SettingsActivity { /* empty */ }
- public static class DoubleTwistSuggestionActivity extends SettingsActivity { /* empty */ }
- public static class AmbientDisplaySuggestionActivity extends SettingsActivity { /* empty */ }
- public static class AmbientDisplayPickupSuggestionActivity extends SettingsActivity {
- /* empty */ }
- public static class SwipeToNotificationSuggestionActivity extends SettingsActivity {
- /* empty */ }
public static class WallpaperSettingsActivity extends SettingsActivity { /* empty */ }
public static class ManagedProfileSettingsActivity extends SettingsActivity { /* empty */ }
public static class DeletionHelperActivity extends SettingsActivity { /* empty */ }
@@ -178,5 +170,10 @@
public static class StorageDashboardActivity extends SettingsActivity {}
public static class UserAndAccountDashboardActivity extends SettingsActivity {}
public static class SystemDashboardActivity extends SettingsActivity {}
+ public static class AdvancedConnectedDeviceActivity extends SettingsActivity {
+ public static final boolean isEnabled() {
+ return FeatureFlagUtils.isEnabled(null /* context */, CONNECTED_DEVICE_V2);
+ }
+ }
}
diff --git a/src/com/android/settings/SettingsActivity.java b/src/com/android/settings/SettingsActivity.java
index 5cb7c06..3ac268a 100644
--- a/src/com/android/settings/SettingsActivity.java
+++ b/src/com/android/settings/SettingsActivity.java
@@ -56,13 +56,13 @@
import com.android.settings.applications.manageapplications.ManageApplications;
import com.android.settings.backup.BackupSettingsActivity;
import com.android.settings.core.gateway.SettingsGateway;
+import com.android.settings.core.instrumentation.MetricsFeatureProvider;
+import com.android.settings.core.instrumentation.SharedPreferencesLogger;
import com.android.settings.dashboard.DashboardFeatureProvider;
import com.android.settings.dashboard.DashboardSummary;
import com.android.settings.overlay.FeatureFactory;
import com.android.settings.wfd.WifiDisplaySettings;
import com.android.settings.widget.SwitchBar;
-import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
-import com.android.settingslib.core.instrumentation.SharedPreferencesLogger;
import com.android.settingslib.development.DevelopmentSettingsEnabler;
import com.android.settingslib.drawer.DashboardCategory;
import com.android.settingslib.drawer.SettingsDrawerActivity;
@@ -93,6 +93,11 @@
public static final String EXTRA_SHOW_FRAGMENT = ":settings:show_fragment";
/**
+ * The metrics category constant for logging source when a setting fragment is opened.
+ */
+ public static final String EXTRA_SOURCE_METRICS_CATEGORY = ":settings:source_metrics";
+
+ /**
* When starting this activity and using {@link #EXTRA_SHOW_FRAGMENT},
* this extra can also be specified to supply a Bundle of arguments to pass
* to that fragment when it is instantiated during the initial creation
@@ -215,8 +220,7 @@
@Override
public SharedPreferences getSharedPreferences(String name, int mode) {
if (name.equals(getPackageName() + "_preferences")) {
- return new SharedPreferencesLogger(this, getMetricsTag(),
- FeatureFactory.getFactory(this).getMetricsFeatureProvider());
+ return new SharedPreferencesLogger(this, getMetricsTag());
}
return super.getSharedPreferences(name, mode);
}
@@ -873,6 +877,19 @@
WifiDisplaySettings.isAvailable(this), isAdmin)
|| somethingChanged;
+ // Enable/disable the Me Card page.
+ final boolean isMeCardEnabled = featureFactory
+ .getAccountFeatureProvider()
+ .isMeCardEnabled(this);
+ somethingChanged = setTileEnabled(new ComponentName(packageName,
+ Settings.MeCardActivity.class.getName()),
+ isMeCardEnabled, isAdmin)
+ || somethingChanged;
+ somethingChanged = setTileEnabled(new ComponentName(packageName,
+ Settings.DeviceInfoSettingsActivity.class.getName()),
+ !isMeCardEnabled, isAdmin)
+ || somethingChanged;
+
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/SettingsPreferenceFragment.java b/src/com/android/settings/SettingsPreferenceFragment.java
index c5d477a..d9e264b 100644
--- a/src/com/android/settings/SettingsPreferenceFragment.java
+++ b/src/com/android/settings/SettingsPreferenceFragment.java
@@ -45,6 +45,7 @@
import com.android.settings.applications.LayoutPreference;
import com.android.settings.core.InstrumentedPreferenceFragment;
+import com.android.settings.core.instrumentation.Instrumentable;
import com.android.settings.core.instrumentation.InstrumentedDialogFragment;
import com.android.settings.search.actionbar.SearchMenuController;
import com.android.settings.support.actionbar.HelpMenuController;
@@ -52,7 +53,6 @@
import com.android.settings.widget.LoadingViewController;
import com.android.settingslib.CustomDialogPreference;
import com.android.settingslib.CustomEditTextPreference;
-import com.android.settingslib.core.instrumentation.Instrumentable;
import com.android.settingslib.widget.FooterPreferenceMixin;
import java.util.UUID;
diff --git a/src/com/android/settings/ShowAdminSupportDetailsDialog.java b/src/com/android/settings/ShowAdminSupportDetailsDialog.java
index c1cd6f5..321f93d 100644
--- a/src/com/android/settings/ShowAdminSupportDetailsDialog.java
+++ b/src/com/android/settings/ShowAdminSupportDetailsDialog.java
@@ -150,6 +150,9 @@
case DevicePolicyManager.POLICY_DISABLE_SCREEN_CAPTURE:
titleView.setText(R.string.disabled_by_policy_title_screen_capture);
break;
+ case DevicePolicyManager.POLICY_MANDATORY_BACKUPS:
+ titleView.setText(R.string.disabled_by_policy_title_turn_off_backups);
+ break;
default:
// Use general text if no specialized title applies
titleView.setText(R.string.disabled_by_policy_title);
diff --git a/src/com/android/settings/Utils.java b/src/com/android/settings/Utils.java
index 1c674b6..ae10ffe 100644
--- a/src/com/android/settings/Utils.java
+++ b/src/com/android/settings/Utils.java
@@ -110,7 +110,6 @@
import com.android.settings.password.ChooseLockSettingsHelper;
import com.android.settings.wrapper.DevicePolicyManagerWrapper;
import com.android.settings.wrapper.FingerprintManagerWrapper;
-import com.android.settingslib.core.instrumentation.VisibilityLoggerMixin;
import java.net.InetAddress;
import java.util.ArrayList;
@@ -515,7 +514,8 @@
Fragment resultTo, int resultRequestCode, String titleResPackageName, int titleResId,
CharSequence title, boolean isShortcut, int metricsCategory) {
startWithFragment(context, fragmentName, args, resultTo, resultRequestCode,
- titleResPackageName, titleResId, title, isShortcut, metricsCategory, 0);
+ titleResPackageName, titleResId, title, isShortcut, metricsCategory,
+ Intent.FLAG_ACTIVITY_NEW_TASK);
}
@@ -577,7 +577,7 @@
intent.putExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT_TITLE_RESID, titleResId);
intent.putExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT_TITLE, title);
intent.putExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT_AS_SHORTCUT, isShortcut);
- intent.putExtra(VisibilityLoggerMixin.EXTRA_SOURCE_METRICS_CATEGORY, sourceMetricsCategory);
+ intent.putExtra(SettingsActivity.EXTRA_SOURCE_METRICS_CATEGORY, sourceMetricsCategory);
return intent;
}
diff --git a/src/com/android/settings/accounts/AccountFeatureProvider.java b/src/com/android/settings/accounts/AccountFeatureProvider.java
new file mode 100644
index 0000000..bbfc48a
--- /dev/null
+++ b/src/com/android/settings/accounts/AccountFeatureProvider.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2018 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.accounts;
+
+import android.accounts.Account;
+import android.content.Context;
+import android.util.FeatureFlagUtils;
+
+import com.android.settings.core.FeatureFlags;
+
+public interface AccountFeatureProvider {
+ String getAccountType();
+ Account[] getAccounts(Context context);
+ /**
+ * Checks whether or not to display the new About Phone page.
+ */
+ default boolean isMeCardEnabled(Context context) {
+ return FeatureFlagUtils.isEnabled(context, FeatureFlags.ABOUT_PHONE_V2);
+ }
+}
diff --git a/src/com/android/settings/accounts/AccountFeatureProviderImpl.java b/src/com/android/settings/accounts/AccountFeatureProviderImpl.java
new file mode 100644
index 0000000..90b581b
--- /dev/null
+++ b/src/com/android/settings/accounts/AccountFeatureProviderImpl.java
@@ -0,0 +1,16 @@
+package com.android.settings.accounts;
+
+import android.accounts.Account;
+import android.content.Context;
+
+public class AccountFeatureProviderImpl implements AccountFeatureProvider {
+ @Override
+ public String getAccountType() {
+ return null;
+ }
+
+ @Override
+ public Account[] getAccounts(Context context) {
+ return new Account[0];
+ }
+}
diff --git a/src/com/android/settings/accounts/AccountPreferenceController.java b/src/com/android/settings/accounts/AccountPreferenceController.java
index 6127ab9..c0bf7d2 100644
--- a/src/com/android/settings/accounts/AccountPreferenceController.java
+++ b/src/com/android/settings/accounts/AccountPreferenceController.java
@@ -51,12 +51,12 @@
import com.android.settings.SettingsPreferenceFragment;
import com.android.settings.Utils;
import com.android.settings.core.PreferenceControllerMixin;
+import com.android.settings.core.instrumentation.MetricsFeatureProvider;
import com.android.settings.overlay.FeatureFactory;
import com.android.settings.search.SearchIndexableRaw;
import com.android.settingslib.RestrictedPreference;
import com.android.settingslib.accounts.AuthenticatorHelper;
import com.android.settingslib.core.AbstractPreferenceController;
-import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
import com.android.settingslib.core.lifecycle.LifecycleObserver;
import com.android.settingslib.core.lifecycle.events.OnPause;
import com.android.settingslib.core.lifecycle.events.OnResume;
diff --git a/src/com/android/settings/accounts/ManagedProfileSettings.java b/src/com/android/settings/accounts/ManagedProfileSettings.java
index 3ea7cf7..0933042 100644
--- a/src/com/android/settings/accounts/ManagedProfileSettings.java
+++ b/src/com/android/settings/accounts/ManagedProfileSettings.java
@@ -104,8 +104,7 @@
private void loadDataAndPopulateUi() {
if (mWorkModePreference != null) {
- mWorkModePreference.setChecked(
- !mUserManager.isQuietModeEnabled(mManagedUser));
+ updateWorkModePreference();
}
if (mContactPrefrence != null) {
@@ -124,6 +123,14 @@
return MetricsProto.MetricsEvent.ACCOUNTS_WORK_PROFILE_SETTINGS;
}
+ private void updateWorkModePreference() {
+ boolean isWorkModeOn = !mUserManager.isQuietModeEnabled(mManagedUser);
+ mWorkModePreference.setChecked(isWorkModeOn);
+ mWorkModePreference.setSummary(isWorkModeOn
+ ? R.string.work_mode_on_summary
+ : R.string.work_mode_off_summary);
+ }
+
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
@@ -159,8 +166,7 @@
|| action.equals(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE)) {
if (intent.getIntExtra(Intent.EXTRA_USER_HANDLE,
UserHandle.USER_NULL) == mManagedUser.getIdentifier()) {
- mWorkModePreference.setChecked(
- !mUserManager.isQuietModeEnabled(mManagedUser));
+ updateWorkModePreference();
}
return;
}
diff --git a/src/com/android/settings/applications/AppStateDirectoryAccessBridge.java b/src/com/android/settings/applications/AppStateDirectoryAccessBridge.java
index 8cd4444..1c2a0af 100644
--- a/src/com/android/settings/applications/AppStateDirectoryAccessBridge.java
+++ b/src/com/android/settings/applications/AppStateDirectoryAccessBridge.java
@@ -33,11 +33,15 @@
import java.util.Set;
-// TODO(b/63720392): add unit tests
+// TODO(b/72055774): add unit tests
public class AppStateDirectoryAccessBridge extends AppStateBaseBridge {
private static final String TAG = "DirectoryAccessBridge";
+ // TODO(b/72055774): set to false once feature is ready (or use Log.isLoggable)
+ static final boolean DEBUG = true;
+ static final boolean VERBOSE = true;
+
public AppStateDirectoryAccessBridge(ApplicationsState appState, Callback callback) {
super(appState, callback);
}
@@ -59,27 +63,34 @@
@Override
public void init(Context context) {
- try (Cursor cursor = context.getContentResolver().query(
- new Uri.Builder().scheme(ContentResolver.SCHEME_CONTENT)
- .authority(AUTHORITY).appendPath(TABLE_PACKAGES).appendPath("*")
- .build(), TABLE_PACKAGES_COLUMNS, null, null)) {
+ mPackages = null;
+ final Uri providerUri = new Uri.Builder().scheme(ContentResolver.SCHEME_CONTENT)
+ .authority(AUTHORITY).appendPath(TABLE_PACKAGES).appendPath("*")
+ .build();
+ try (Cursor cursor = context.getContentResolver().query(providerUri,
+ TABLE_PACKAGES_COLUMNS, null, null)) {
if (cursor == null) {
- Log.w(TAG, "didn't get cursor");
+ Log.w(TAG, "Didn't get cursor for " + providerUri);
return;
}
final int count = cursor.getCount();
if (count == 0) {
- Log.d(TAG, "no packages");
+ if (DEBUG) {
+ Log.d(TAG, "No packages anymore (was " + mPackages + ")");
+ }
return;
}
mPackages = new ArraySet<>(count);
while (cursor.moveToNext()) {
mPackages.add(cursor.getString(TABLE_PACKAGES_COL_PACKAGE));
}
- Log.v(TAG, "init(): " + mPackages);
+ if (DEBUG) {
+ Log.d(TAG, "init(): " + mPackages);
+ }
}
}
+
@Override
public boolean filterApp(AppEntry info) {
return mPackages != null && mPackages.contains(info.info.packageName);
diff --git a/src/com/android/settings/applications/DirectoryAccessDetails.java b/src/com/android/settings/applications/DirectoryAccessDetails.java
index 1f7a81a..43422d0 100644
--- a/src/com/android/settings/applications/DirectoryAccessDetails.java
+++ b/src/com/android/settings/applications/DirectoryAccessDetails.java
@@ -17,84 +17,236 @@
package com.android.settings.applications;
import static android.os.storage.StorageVolume.ScopedAccessProviderContract.AUTHORITY;
+import static android.os.storage.StorageVolume.ScopedAccessProviderContract.COL_DIRECTORY;
+import static android.os.storage.StorageVolume.ScopedAccessProviderContract.COL_GRANTED;
+import static android.os.storage.StorageVolume.ScopedAccessProviderContract.COL_PACKAGE;
+import static android.os.storage.StorageVolume.ScopedAccessProviderContract.COL_VOLUME_UUID;
import static android.os.storage.StorageVolume.ScopedAccessProviderContract.TABLE_PERMISSIONS;
import static android.os.storage.StorageVolume.ScopedAccessProviderContract.TABLE_PERMISSIONS_COLUMNS;
import static android.os.storage.StorageVolume.ScopedAccessProviderContract.TABLE_PERMISSIONS_COL_DIRECTORY;
-import static android.os.storage.StorageVolume.ScopedAccessProviderContract.TABLE_PERMISSIONS_COL_GRANTED;
import static android.os.storage.StorageVolume.ScopedAccessProviderContract.TABLE_PERMISSIONS_COL_PACKAGE;
import static android.os.storage.StorageVolume.ScopedAccessProviderContract.TABLE_PERMISSIONS_COL_VOLUME_UUID;
+import static com.android.settings.applications.AppStateDirectoryAccessBridge.DEBUG;
+import static com.android.settings.applications.AppStateDirectoryAccessBridge.VERBOSE;
+
+import android.annotation.Nullable;
+import android.app.Activity;
import android.app.AlertDialog;
import android.content.ContentResolver;
+import android.content.ContentValues;
+import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
+import android.os.storage.StorageManager;
+import android.os.storage.VolumeInfo;
+import android.support.v14.preference.SwitchPreference;
import android.support.v7.preference.Preference;
import android.support.v7.preference.Preference.OnPreferenceChangeListener;
import android.support.v7.preference.Preference.OnPreferenceClickListener;
+import android.text.TextUtils;
+import android.support.v7.preference.PreferenceManager;
+import android.support.v7.preference.PreferenceScreen;
+import android.util.ArrayMap;
+import android.util.ArraySet;
+import android.util.IconDrawableFactory;
import android.util.Log;
+import android.util.Pair;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.settings.R;
+import com.android.settings.widget.EntityHeaderController;
+import com.android.settings.widget.EntityHeaderController.ActionType;
+import com.android.settingslib.applications.AppUtils;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
/**
* Detailed settings for an app's directory access permissions (A.K.A Scoped Directory Access).
+ *
+ * <p>Currently, it shows the entry for which the user denied access with the "Do not ask again"
+ * flag checked on: the user than can use the settings toggle to reset that deniel.
+ *
+ * <p>This fragments dynamically lists all such permissions, starting with one preference per
+ * directory in the primary storage, then adding additional entries for the external volumes (one
+ * entry for the whole volume).
*/
-// TODO(b/63720392): explain its layout
-// TODO(b/63720392): add unit tests
-public class DirectoryAccessDetails extends AppInfoWithHeader implements OnPreferenceChangeListener,
- OnPreferenceClickListener {
- private static final String MY_TAG = "DirectoryAccessDetails";
+// TODO(b/72055774): add unit tests
+public class DirectoryAccessDetails extends AppInfoBase {
+
+ @SuppressWarnings("hiding")
+ private static final String TAG = "DirectoryAccessDetails";
+
+ private boolean mCreated;
+
+ @Override
+ public void onActivityCreated(Bundle savedInstanceState) {
+ super.onActivityCreated(savedInstanceState);
+
+ if (mCreated) {
+ Log.w(TAG, "onActivityCreated(): ignoring duplicate call");
+ return;
+ }
+ mCreated = true;
+ if (mPackageInfo == null) {
+ Log.w(TAG, "onActivityCreated(): no package info");
+ return;
+ }
+ final Activity activity = getActivity();
+ final Preference pref = EntityHeaderController
+ .newInstance(activity, this, /* header= */ null )
+ .setRecyclerView(getListView(), getLifecycle())
+ .setIcon(IconDrawableFactory.newInstance(getPrefContext())
+ .getBadgedIcon(mPackageInfo.applicationInfo))
+ .setLabel(mPackageInfo.applicationInfo.loadLabel(mPm))
+ .setIsInstantApp(AppUtils.isInstant(mPackageInfo.applicationInfo))
+ .setPackageName(mPackageName)
+ .setUid(mPackageInfo.applicationInfo.uid)
+ .setHasAppInfoLink(false)
+ .setButtonActions(ActionType.ACTION_NONE, ActionType.ACTION_NONE)
+ .done(activity, getPrefContext());
+ getPreferenceScreen().addPreference(pref);
+ }
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- if (true) {
- // TODO(b/63720392): temporarily hack so the screen doesn't crash..
- addPreferencesFromResource(R.xml.app_ops_permissions_details);
- // ... we need to dynamically create the preferences by calling the provider instead:
- try (Cursor cursor = getContentResolver().query(
- new Uri.Builder().scheme(ContentResolver.SCHEME_CONTENT)
- .authority(AUTHORITY).appendPath(TABLE_PERMISSIONS).appendPath("*")
- .build(),
- TABLE_PERMISSIONS_COLUMNS, null, null)) {
- if (cursor == null) {
- Log.w(TAG, "didn't get cursor");
- return;
+ final Context context = getPrefContext();
+ addPreferencesFromResource(R.xml.directory_access_details);
+ final PreferenceScreen prefsGroup = getPreferenceScreen();
+
+ // Set external directory UUIDs.
+ ArraySet<String> externalDirectoryUuids = null;
+
+ final Uri providerUri = new Uri.Builder().scheme(ContentResolver.SCHEME_CONTENT)
+ .authority(AUTHORITY).appendPath(TABLE_PERMISSIONS).appendPath("*")
+ .build();
+ // Query provider for entries.
+ try (Cursor cursor = context.getContentResolver().query(providerUri,
+ TABLE_PERMISSIONS_COLUMNS, null, new String[] { mPackageName }, null)) {
+ if (cursor == null) {
+ Log.w(TAG, "Didn't get cursor for " + mPackageName);
+ return;
+ }
+ final int count = cursor.getCount();
+ if (count == 0) {
+ if (DEBUG) {
+ Log.d(TAG, "No permissions for " + mPackageName);
}
- final int count = cursor.getCount();
- if (count == 0) {
- Log.d(TAG, "no permissions");
- return;
+ // TODO(b/72055774): display empty message
+ return;
+ }
+
+ while (cursor.moveToNext()) {
+ final String pkg = cursor.getString(TABLE_PERMISSIONS_COL_PACKAGE);
+ final String uuid = cursor.getString(TABLE_PERMISSIONS_COL_VOLUME_UUID);
+ final String dir = cursor.getString(TABLE_PERMISSIONS_COL_DIRECTORY);
+ if (VERBOSE) {
+ Log.v(TAG, "Pkg:" + pkg + " uuid: " + uuid + " dir: " + dir);
}
- while (cursor.moveToNext()) {
- final String pkg = cursor.getString(TABLE_PERMISSIONS_COL_PACKAGE);
- final String uuid = cursor.getString(TABLE_PERMISSIONS_COL_VOLUME_UUID);
- final String dir = cursor.getString(TABLE_PERMISSIONS_COL_DIRECTORY);
- final boolean granted = cursor.getInt(TABLE_PERMISSIONS_COL_GRANTED) == 1;
- Log.v(MY_TAG, "pkg:" + pkg + " uuid: " + uuid + " dir: " + dir + "> "
- + granted);
+
+ if (!mPackageName.equals(pkg)) {
+ // Sanity check, shouldn't happen
+ Log.w(TAG, "Ignoring " + uuid + "/" + dir + " due to package mismatch: "
+ + "expected " + mPackageName + ", got " + pkg);
+ continue;
+ }
+
+ if (uuid == null) {
+ // Primary storage entry: add right away
+ prefsGroup.addPreference(
+ newPreference(context, dir, providerUri, /* uuid= */ null, dir));
+ } else {
+ // External volume entry: save it for later.
+ if (externalDirectoryUuids == null) {
+ externalDirectoryUuids = new ArraySet<>(1);
+ }
+ externalDirectoryUuids.add(uuid);
}
}
}
+
+ // Add entries from external volumes
+ if (externalDirectoryUuids != null) {
+ if (VERBOSE) {
+ Log.v(TAG, "adding external directories: " + externalDirectoryUuids);
+ }
+
+ // Query StorageManager to get the user-friendly volume names.
+ final StorageManager sm = context.getSystemService(StorageManager.class);
+ final List<VolumeInfo> volumes = sm.getVolumes();
+ if (volumes.isEmpty()) {
+ Log.w(TAG, "StorageManager returned no secondary volumes");
+ return;
+ }
+ final Map<String, String> volumeNames = new HashMap<>(volumes.size());
+ for (VolumeInfo volume : volumes) {
+ final String uuid = volume.getFsUuid();
+ if (uuid == null) continue; // Primary storage; not used.
+
+ String name = sm.getBestVolumeDescription(volume);
+ if (name == null) {
+ Log.w(TAG, "No description for " + volume + "; using uuid instead: " + uuid);
+ name = uuid;
+ }
+ volumeNames.put(uuid, name);
+ }
+ if (VERBOSE) {
+ Log.v(TAG, "UUID -> name mapping: " + volumeNames);
+ }
+
+ externalDirectoryUuids.forEach((uuid) ->{
+ final String name = volumeNames.get(uuid);
+ // TODO(b/72055774): add separator
+ prefsGroup.addPreference(
+ newPreference(context, name, providerUri, uuid, /* dir= */ null));
+ });
+ }
+ return;
+ }
+
+
+ private SwitchPreference newPreference(Context context, String title, Uri providerUri,
+ String uuid, String dir) {
+ final SwitchPreference pref = new SwitchPreference(context);
+ pref.setKey(String.format("%s:%s", uuid, dir));
+ pref.setTitle(title);
+ pref.setChecked(false);
+ pref.setOnPreferenceChangeListener((unused, value) -> {
+ resetDoNotAskAgain(context, value, providerUri, uuid, dir);
+ return true;
+ });
+ return pref;
+ }
+
+ private void resetDoNotAskAgain(Context context, Object value, Uri providerUri,
+ @Nullable String uuid, @Nullable String directory) {
+ if (!Boolean.class.isInstance(value)) {
+ // Sanity check
+ Log.wtf(TAG, "Invalid value from switch: " + value);
+ return;
+ }
+ final boolean newValue = ((Boolean) value).booleanValue();
+ if (DEBUG) {
+ Log.d(TAG, "Asking " + providerUri + " to update " + uuid + "/" + directory + " to "
+ + newValue);
+ }
+ final ContentValues values = new ContentValues(1);
+ values.put(COL_GRANTED, newValue);
+ final int updated = context.getContentResolver().update(providerUri, values,
+ null, new String[] { mPackageName, uuid, directory });
+ if (DEBUG) {
+ Log.d(TAG, "Updated " + updated + " entries for " + uuid + "/" + directory);
+ }
}
@Override
- public boolean onPreferenceClick(Preference preference) {
- // TODO(b/63720392): implement or remove listener
- return false;
- }
-
- @Override
- public boolean onPreferenceChange(Preference preference, Object newValue) {
- // TODO(b/63720392): implement or remove listener
- return false;
- }
-
- @Override
protected boolean refreshUi() {
- // TODO(b/63720392): implement
return true;
}
diff --git a/src/com/android/settings/applications/UsageAccessDetails.java b/src/com/android/settings/applications/UsageAccessDetails.java
index c172137..c10fb55 100644
--- a/src/com/android/settings/applications/UsageAccessDetails.java
+++ b/src/com/android/settings/applications/UsageAccessDetails.java
@@ -37,8 +37,8 @@
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.settings.R;
import com.android.settings.applications.AppStateUsageBridge.UsageState;
+import com.android.settings.core.instrumentation.MetricsFeatureProvider;
import com.android.settings.overlay.FeatureFactory;
-import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
public class UsageAccessDetails extends AppInfoWithHeader implements OnPreferenceChangeListener,
OnPreferenceClickListener {
diff --git a/src/com/android/settings/bluetooth/BluetoothDevicePreference.java b/src/com/android/settings/bluetooth/BluetoothDevicePreference.java
index 3fd7ced..a0ce733 100644
--- a/src/com/android/settings/bluetooth/BluetoothDevicePreference.java
+++ b/src/com/android/settings/bluetooth/BluetoothDevicePreference.java
@@ -33,10 +33,10 @@
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.settings.R;
+import com.android.settings.core.instrumentation.MetricsFeatureProvider;
import com.android.settings.overlay.FeatureFactory;
import com.android.settings.widget.GearPreference;
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
-import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
import static android.os.UserManager.DISALLOW_CONFIG_BLUETOOTH;
diff --git a/src/com/android/settings/bluetooth/BluetoothDeviceRenamePreferenceController.java b/src/com/android/settings/bluetooth/BluetoothDeviceRenamePreferenceController.java
index cea0147..a12d1a8 100644
--- a/src/com/android/settings/bluetooth/BluetoothDeviceRenamePreferenceController.java
+++ b/src/com/android/settings/bluetooth/BluetoothDeviceRenamePreferenceController.java
@@ -23,9 +23,9 @@
import android.text.TextUtils;
import com.android.internal.logging.nano.MetricsProto;
+import com.android.settings.core.instrumentation.MetricsFeatureProvider;
import com.android.settings.overlay.FeatureFactory;
import com.android.settingslib.bluetooth.LocalBluetoothAdapter;
-import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
import com.android.settingslib.core.lifecycle.Lifecycle;
public class BluetoothDeviceRenamePreferenceController extends
diff --git a/src/com/android/settings/bluetooth/BluetoothDeviceUpdater.java b/src/com/android/settings/bluetooth/BluetoothDeviceUpdater.java
index 127730b..2862083 100644
--- a/src/com/android/settings/bluetooth/BluetoothDeviceUpdater.java
+++ b/src/com/android/settings/bluetooth/BluetoothDeviceUpdater.java
@@ -27,14 +27,19 @@
import com.android.settings.dashboard.DashboardFragment;
import com.android.settings.connecteddevice.DevicePreferenceCallback;
import com.android.settings.widget.GearPreference;
+import com.android.settingslib.bluetooth.A2dpProfile;
import com.android.settingslib.bluetooth.BluetoothCallback;
import com.android.settingslib.bluetooth.BluetoothDeviceFilter;
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
+import com.android.settingslib.bluetooth.HeadsetProfile;
import com.android.settingslib.bluetooth.LocalBluetoothManager;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
+import java.util.Objects;
+
+import android.util.Log;
/**
* Update the bluetooth devices. It gets bluetooth event from {@link LocalBluetoothManager} using
@@ -45,6 +50,7 @@
* whether the {@link CachedBluetoothDevice} is relevant.
*/
public abstract class BluetoothDeviceUpdater implements BluetoothCallback {
+ private static final String TAG = "BluetoothDeviceUpdater";
private static final String BLUETOOTH_SHOW_DEVICES_WITHOUT_NAMES_PROPERTY =
"persist.bluetooth.showdeviceswithoutnames";
@@ -55,6 +61,7 @@
private final boolean mShowDeviceWithoutNames;
private DashboardFragment mFragment;
+ private Preference.OnPreferenceClickListener mDevicePreferenceClickListener = null;
@VisibleForTesting
final GearPreference.OnGearClickListener mDeviceProfilesListener = pref -> {
@@ -73,6 +80,38 @@
};
+ private class PreferenceClickListener implements
+ Preference.OnPreferenceClickListener {
+ @Override
+ public boolean onPreferenceClick(Preference preference) {
+ final CachedBluetoothDevice device =
+ ((BluetoothDevicePreference) preference).getBluetoothDevice();
+ if (device == null) {
+ return false;
+ }
+
+ // Set the device as active per profile only if the device supports that profile
+ // TODO: The active device selector location might change in the future
+ Log.i(TAG, "OnPreferenceClickListener: device=" + device);
+ boolean result = false;
+ A2dpProfile a2dpProfile = mLocalManager.getProfileManager().getA2dpProfile();
+ if ((a2dpProfile != null) && device.isConnectedProfile(a2dpProfile)) {
+ if (a2dpProfile.setActiveDevice(device.getDevice())) {
+ Log.i(TAG, "OnPreferenceClickListener: A2DP active device=" + device);
+ result = true;
+ }
+ }
+ HeadsetProfile headsetProfile = mLocalManager.getProfileManager().getHeadsetProfile();
+ if ((headsetProfile != null) && device.isConnectedProfile(headsetProfile)) {
+ if (headsetProfile.setActiveDevice(device.getDevice())) {
+ Log.i(TAG, "OnPreferenceClickListener: Headset active device=" + device);
+ result = true;
+ }
+ }
+ return result;
+ }
+ }
+
public BluetoothDeviceUpdater(DashboardFragment fragment,
DevicePreferenceCallback devicePreferenceCallback) {
this(fragment, devicePreferenceCallback, Utils.getLocalBtManager(fragment.getContext()));
@@ -87,6 +126,7 @@
BLUETOOTH_SHOW_DEVICES_WITHOUT_NAMES_PROPERTY, false);
mPreferenceMap = new HashMap<>();
mLocalManager = localManager;
+ mDevicePreferenceClickListener = new PreferenceClickListener();
}
/**
@@ -141,6 +181,18 @@
@Override
public void onConnectionStateChanged(CachedBluetoothDevice cachedDevice, int state) {}
+ @Override
+ public void onActiveDeviceChanged(CachedBluetoothDevice activeDevice, int bluetoothProfile) {
+ Collection<CachedBluetoothDevice> cachedDevices =
+ mLocalManager.getCachedDeviceManager().getCachedDevicesCopy();
+ // TODO: The state update of the Cached Bluetooth Devices should be
+ // moved to the device manager: b/72316092
+ for (CachedBluetoothDevice cachedBluetoothDevice : cachedDevices) {
+ boolean isActive = Objects.equals(cachedBluetoothDevice, activeDevice);
+ cachedBluetoothDevice.setActiveDevice(isActive, bluetoothProfile);
+ }
+ }
+
/**
* Set the context to generate the {@link Preference}, so it could get the correct theme.
*/
@@ -176,6 +228,7 @@
new BluetoothDevicePreference(mPrefContext, cachedDevice,
mShowDeviceWithoutNames);
btPreference.setOnGearClickListener(mDeviceProfilesListener);
+ btPreference.setOnPreferenceClickListener(mDevicePreferenceClickListener);
mPreferenceMap.put(device, btPreference);
mDevicePreferenceCallback.onDeviceAdded(btPreference);
}
diff --git a/src/com/android/settings/bluetooth/BluetoothEnabler.java b/src/com/android/settings/bluetooth/BluetoothEnabler.java
index 0f294bd..87fa43d 100644
--- a/src/com/android/settings/bluetooth/BluetoothEnabler.java
+++ b/src/com/android/settings/bluetooth/BluetoothEnabler.java
@@ -27,12 +27,12 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.settings.R;
+import com.android.settings.core.instrumentation.MetricsFeatureProvider;
import com.android.settings.widget.SwitchWidgetController;
import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
import com.android.settingslib.WirelessUtils;
import com.android.settingslib.bluetooth.LocalBluetoothAdapter;
import com.android.settingslib.bluetooth.LocalBluetoothManager;
-import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
/**
* BluetoothEnabler is a helper to manage the Bluetooth on/off checkbox
diff --git a/src/com/android/settings/bluetooth/BluetoothFilesPreferenceController.java b/src/com/android/settings/bluetooth/BluetoothFilesPreferenceController.java
index 1ecfed4..450c7b2 100644
--- a/src/com/android/settings/bluetooth/BluetoothFilesPreferenceController.java
+++ b/src/com/android/settings/bluetooth/BluetoothFilesPreferenceController.java
@@ -23,9 +23,9 @@
import com.android.internal.logging.nano.MetricsProto;
import com.android.settings.core.PreferenceControllerMixin;
+import com.android.settings.core.instrumentation.MetricsFeatureProvider;
import com.android.settings.overlay.FeatureFactory;
import com.android.settingslib.core.AbstractPreferenceController;
-import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
/**
* Controller that shows received files
diff --git a/src/com/android/settings/bluetooth/BluetoothSummaryUpdater.java b/src/com/android/settings/bluetooth/BluetoothSummaryUpdater.java
index 662cd70..43d25e7 100644
--- a/src/com/android/settings/bluetooth/BluetoothSummaryUpdater.java
+++ b/src/com/android/settings/bluetooth/BluetoothSummaryUpdater.java
@@ -77,6 +77,10 @@
}
@Override
+ public void onActiveDeviceChanged(CachedBluetoothDevice activeDevice, int bluetoothProfile) {
+ }
+
+ @Override
public void register(boolean listening) {
if (mBluetoothAdapter == null) {
return;
diff --git a/src/com/android/settings/bluetooth/DeviceListPreferenceFragment.java b/src/com/android/settings/bluetooth/DeviceListPreferenceFragment.java
index 0a90edc..207a4b0 100644
--- a/src/com/android/settings/bluetooth/DeviceListPreferenceFragment.java
+++ b/src/com/android/settings/bluetooth/DeviceListPreferenceFragment.java
@@ -277,6 +277,9 @@
public void onConnectionStateChanged(CachedBluetoothDevice cachedDevice, int state) { }
+ @Override
+ public void onActiveDeviceChanged(CachedBluetoothDevice activeDevice, int bluetoothProfile) { }
+
/**
* Return the key of the {@link PreferenceGroup} that contains the bluetooth devices
*/
diff --git a/src/com/android/settings/core/FeatureFlags.java b/src/com/android/settings/core/FeatureFlags.java
index 4b5ce78..4b8ccd1 100644
--- a/src/com/android/settings/core/FeatureFlags.java
+++ b/src/com/android/settings/core/FeatureFlags.java
@@ -27,4 +27,5 @@
public static final String SECURITY_SETTINGS_V2 = "settings_security_settings_v2";
public static final String ZONE_PICKER_V2 = "settings_zone_picker_v2";
public static final String SUGGESTION_UI_V2 = "settings_suggestion_ui_v2";
+ public static final String ABOUT_PHONE_V2 = "settings_about_phone_v2";
}
diff --git a/src/com/android/settings/core/InstrumentedActivity.java b/src/com/android/settings/core/InstrumentedActivity.java
index 294de2c..9b24756 100644
--- a/src/com/android/settings/core/InstrumentedActivity.java
+++ b/src/com/android/settings/core/InstrumentedActivity.java
@@ -16,9 +16,8 @@
package com.android.settings.core;
-import com.android.settings.overlay.FeatureFactory;
-import com.android.settingslib.core.instrumentation.Instrumentable;
-import com.android.settingslib.core.instrumentation.VisibilityLoggerMixin;
+import com.android.settings.core.instrumentation.Instrumentable;
+import com.android.settings.core.instrumentation.VisibilityLoggerMixin;
import com.android.settingslib.core.lifecycle.ObservableActivity;
/**
@@ -28,8 +27,7 @@
public InstrumentedActivity() {
// Mixin that logs visibility change for activity.
- getLifecycle().addObserver(new VisibilityLoggerMixin(getMetricsCategory(),
- FeatureFactory.getFactory(this).getMetricsFeatureProvider()));
+ getLifecycle().addObserver(new VisibilityLoggerMixin(getMetricsCategory()));
}
}
diff --git a/src/com/android/settings/core/InstrumentedFragment.java b/src/com/android/settings/core/InstrumentedFragment.java
index b1215b9..45db836 100644
--- a/src/com/android/settings/core/InstrumentedFragment.java
+++ b/src/com/android/settings/core/InstrumentedFragment.java
@@ -18,28 +18,30 @@
import android.content.Context;
+import com.android.settings.core.instrumentation.Instrumentable;
+import com.android.settings.core.instrumentation.MetricsFeatureProvider;
+import com.android.settings.core.instrumentation.VisibilityLoggerMixin;
import com.android.settings.overlay.FeatureFactory;
import com.android.settings.survey.SurveyMixin;
-import com.android.settingslib.core.instrumentation.Instrumentable;
-import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
-import com.android.settingslib.core.instrumentation.VisibilityLoggerMixin;
import com.android.settingslib.core.lifecycle.ObservableFragment;
public abstract class InstrumentedFragment extends ObservableFragment implements Instrumentable {
protected MetricsFeatureProvider mMetricsFeatureProvider;
- private VisibilityLoggerMixin mVisibilityLoggerMixin;
+ private final VisibilityLoggerMixin mVisibilityLoggerMixin;
+
+ public InstrumentedFragment() {
+ // Mixin that logs visibility change for activity.
+ mVisibilityLoggerMixin = new VisibilityLoggerMixin(getMetricsCategory());
+ getLifecycle().addObserver(mVisibilityLoggerMixin);
+ getLifecycle().addObserver(new SurveyMixin(this, getClass().getSimpleName()));
+ }
@Override
public void onAttach(Context context) {
- mMetricsFeatureProvider = FeatureFactory.getFactory(context).getMetricsFeatureProvider();
- mVisibilityLoggerMixin = new VisibilityLoggerMixin(getMetricsCategory(),
- mMetricsFeatureProvider);
- // Mixin that logs visibility change for activity.
- getLifecycle().addObserver(mVisibilityLoggerMixin);
- getLifecycle().addObserver(new SurveyMixin(this, getClass().getSimpleName()));
super.onAttach(context);
+ mMetricsFeatureProvider = FeatureFactory.getFactory(context).getMetricsFeatureProvider();
}
@Override
diff --git a/src/com/android/settings/core/InstrumentedPreferenceFragment.java b/src/com/android/settings/core/InstrumentedPreferenceFragment.java
index 278676c..7e37115 100644
--- a/src/com/android/settings/core/InstrumentedPreferenceFragment.java
+++ b/src/com/android/settings/core/InstrumentedPreferenceFragment.java
@@ -23,11 +23,11 @@
import android.text.TextUtils;
import android.util.Log;
+import com.android.settings.core.instrumentation.Instrumentable;
+import com.android.settings.core.instrumentation.MetricsFeatureProvider;
+import com.android.settings.core.instrumentation.VisibilityLoggerMixin;
import com.android.settings.overlay.FeatureFactory;
import com.android.settings.survey.SurveyMixin;
-import com.android.settingslib.core.instrumentation.Instrumentable;
-import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
-import com.android.settingslib.core.instrumentation.VisibilityLoggerMixin;
import com.android.settingslib.core.lifecycle.ObservablePreferenceFragment;
/**
@@ -44,17 +44,19 @@
// metrics placeholder value. Only use this for development.
protected final int PLACEHOLDER_METRIC = 10000;
- private VisibilityLoggerMixin mVisibilityLoggerMixin;
+ private final VisibilityLoggerMixin mVisibilityLoggerMixin;
+
+ public InstrumentedPreferenceFragment() {
+ // Mixin that logs visibility change for activity.
+ mVisibilityLoggerMixin = new VisibilityLoggerMixin(getMetricsCategory());
+ getLifecycle().addObserver(mVisibilityLoggerMixin);
+ getLifecycle().addObserver(new SurveyMixin(this, getClass().getSimpleName()));
+ }
@Override
public void onAttach(Context context) {
- mMetricsFeatureProvider = FeatureFactory.getFactory(context).getMetricsFeatureProvider();
- // Mixin that logs visibility change for activity.
- mVisibilityLoggerMixin = new VisibilityLoggerMixin(getMetricsCategory(),
- mMetricsFeatureProvider);
- getLifecycle().addObserver(mVisibilityLoggerMixin);
- getLifecycle().addObserver(new SurveyMixin(this, getClass().getSimpleName()));
super.onAttach(context);
+ mMetricsFeatureProvider = FeatureFactory.getFactory(context).getMetricsFeatureProvider();
}
@Override
diff --git a/src/com/android/settings/core/gateway/SettingsGateway.java b/src/com/android/settings/core/gateway/SettingsGateway.java
index 0a4b1f2..2cb1cbf 100644
--- a/src/com/android/settings/core/gateway/SettingsGateway.java
+++ b/src/com/android/settings/core/gateway/SettingsGateway.java
@@ -57,6 +57,7 @@
import com.android.settings.applications.manageapplications.ManageApplications;
import com.android.settings.bluetooth.BluetoothDeviceDetailsFragment;
import com.android.settings.bluetooth.BluetoothSettings;
+import com.android.settings.connecteddevice.AdvancedConnectedDeviceDashboardFragment;
import com.android.settings.connecteddevice.ConnectedDeviceDashboardFragment;
import com.android.settings.connecteddevice.ConnectedDeviceDashboardFragmentOld;
import com.android.settings.datausage.DataPlanUsageSummary;
@@ -254,7 +255,8 @@
LockscreenDashboardFragment.class.getName(),
BluetoothDeviceDetailsFragment.class.getName(),
DataUsageList.class.getName(),
- DirectoryAccessDetails.class.getName()
+ DirectoryAccessDetails.class.getName(),
+ AdvancedConnectedDeviceDashboardFragment.class.getName()
};
public static final String[] SETTINGS_FOR_RESTRICTED = {
@@ -296,5 +298,6 @@
Settings.DateTimeSettingsActivity.class.getName(),
Settings.DeviceInfoSettingsActivity.class.getName(),
Settings.EnterprisePrivacySettingsActivity.class.getName(),
+ Settings.MeCardActivity.class.getName(),
};
}
diff --git a/src/com/android/settings/core/instrumentation/EventLogWriter.java b/src/com/android/settings/core/instrumentation/EventLogWriter.java
new file mode 100644
index 0000000..3196f76
--- /dev/null
+++ b/src/com/android/settings/core/instrumentation/EventLogWriter.java
@@ -0,0 +1,110 @@
+/*
+ * 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.core.instrumentation;
+
+import android.content.Context;
+import android.metrics.LogMaker;
+import android.util.Log;
+import android.util.Pair;
+
+import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.nano.MetricsProto;
+
+/**
+ * {@link LogWriter} that writes data to eventlog.
+ */
+public class EventLogWriter implements LogWriter {
+
+ private final MetricsLogger mMetricsLogger = new MetricsLogger();
+
+ public void visible(Context context, int source, int category) {
+ final LogMaker logMaker = new LogMaker(category)
+ .setType(MetricsProto.MetricsEvent.TYPE_OPEN)
+ .addTaggedData(MetricsProto.MetricsEvent.FIELD_CONTEXT, source);
+ MetricsLogger.action(logMaker);
+ }
+
+ public void hidden(Context context, int category) {
+ MetricsLogger.hidden(context, category);
+ }
+
+ public void action(int category, int value, Pair<Integer, Object>... taggedData) {
+ if (taggedData == null || taggedData.length == 0) {
+ mMetricsLogger.action(category, value);
+ } else {
+ final LogMaker logMaker = new LogMaker(category)
+ .setType(MetricsProto.MetricsEvent.TYPE_ACTION)
+ .setSubtype(value);
+ for (Pair<Integer, Object> pair : taggedData) {
+ logMaker.addTaggedData(pair.first, pair.second);
+ }
+ mMetricsLogger.write(logMaker);
+ }
+ }
+
+ public void action(int category, boolean value, Pair<Integer, Object>... taggedData) {
+ action(category, value ? 1 : 0, taggedData);
+ }
+
+ public void action(Context context, int category, Pair<Integer, Object>... taggedData) {
+ action(context, category, "", taggedData);
+ }
+
+ public void actionWithSource(Context context, int source, int category) {
+ final LogMaker logMaker = new LogMaker(category)
+ .setType(MetricsProto.MetricsEvent.TYPE_ACTION);
+ if (source != MetricsProto.MetricsEvent.VIEW_UNKNOWN) {
+ logMaker.addTaggedData(MetricsProto.MetricsEvent.FIELD_CONTEXT, source);
+ }
+ MetricsLogger.action(logMaker);
+ }
+
+ /** @deprecated use {@link #action(int, int, Pair[])} */
+ @Deprecated
+ public void action(Context context, int category, int value) {
+ MetricsLogger.action(context, category, value);
+ }
+
+ /** @deprecated use {@link #action(int, boolean, Pair[])} */
+ @Deprecated
+ public void action(Context context, int category, boolean value) {
+ MetricsLogger.action(context, category, value);
+ }
+
+ public void action(Context context, int category, String pkg,
+ Pair<Integer, Object>... taggedData) {
+ if (taggedData == null || taggedData.length == 0) {
+ MetricsLogger.action(context, category, pkg);
+ } else {
+ final LogMaker logMaker = new LogMaker(category)
+ .setType(MetricsProto.MetricsEvent.TYPE_ACTION)
+ .setPackageName(pkg);
+ for (Pair<Integer, Object> pair : taggedData) {
+ logMaker.addTaggedData(pair.first, pair.second);
+ }
+ MetricsLogger.action(logMaker);
+ }
+ }
+
+ public void count(Context context, String name, int value) {
+ MetricsLogger.count(context, name, value);
+ }
+
+ public void histogram(Context context, String name, int bucket) {
+ MetricsLogger.histogram(context, name, bucket);
+ }
+}
diff --git a/src/com/android/settings/core/instrumentation/Instrumentable.java b/src/com/android/settings/core/instrumentation/Instrumentable.java
new file mode 100644
index 0000000..f58e140
--- /dev/null
+++ b/src/com/android/settings/core/instrumentation/Instrumentable.java
@@ -0,0 +1,28 @@
+/*
+ * 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.core.instrumentation;
+
+public interface Instrumentable {
+
+ int METRICS_CATEGORY_UNKNOWN = 0;
+
+ /**
+ * Instrumented name for a view as defined in
+ * {@link com.android.internal.logging.nano.MetricsProto.MetricsEvent}.
+ */
+ int getMetricsCategory();
+}
diff --git a/src/com/android/settings/core/instrumentation/InstrumentedDialogFragment.java b/src/com/android/settings/core/instrumentation/InstrumentedDialogFragment.java
index 0a214f1..5a9ab56 100644
--- a/src/com/android/settings/core/instrumentation/InstrumentedDialogFragment.java
+++ b/src/com/android/settings/core/instrumentation/InstrumentedDialogFragment.java
@@ -19,9 +19,6 @@
import com.android.settings.DialogCreatable;
import com.android.settings.overlay.FeatureFactory;
-import com.android.settingslib.core.instrumentation.Instrumentable;
-import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
-import com.android.settingslib.core.instrumentation.VisibilityLoggerMixin;
import com.android.settingslib.core.lifecycle.ObservableDialogFragment;
public abstract class InstrumentedDialogFragment extends ObservableDialogFragment
@@ -41,15 +38,13 @@
public InstrumentedDialogFragment(DialogCreatable dialogCreatable, int dialogId) {
mDialogCreatable = dialogCreatable;
mDialogId = dialogId;
+ mLifecycle.addObserver(new VisibilityLoggerMixin(getMetricsCategory()));
}
+
@Override
public void onAttach(Context context) {
super.onAttach(context);
- mMetricsFeatureProvider = FeatureFactory.getFactory(context)
- .getMetricsFeatureProvider();
- mLifecycle.addObserver(new VisibilityLoggerMixin(getMetricsCategory(),
- mMetricsFeatureProvider));
- mLifecycle.onAttach(context);
+ mMetricsFeatureProvider = FeatureFactory.getFactory(context).getMetricsFeatureProvider();
}
}
diff --git a/src/com/android/settings/core/instrumentation/LogWriter.java b/src/com/android/settings/core/instrumentation/LogWriter.java
new file mode 100644
index 0000000..062d46f
--- /dev/null
+++ b/src/com/android/settings/core/instrumentation/LogWriter.java
@@ -0,0 +1,84 @@
+/*
+ * 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.core.instrumentation;
+
+import android.content.Context;
+import android.util.Pair;
+
+/**
+ * Generic log writer interface.
+ */
+public interface LogWriter {
+
+ /**
+ * Logs a visibility event when view becomes visible.
+ */
+ void visible(Context context, int source, int category);
+
+ /**
+ * Logs a visibility event when view becomes hidden.
+ */
+ void hidden(Context context, int category);
+
+ /**
+ * Logs a user action.
+ */
+ void action(int category, int value, Pair<Integer, Object>... taggedData);
+
+ /**
+ * Logs a user action.
+ */
+ void action(int category, boolean value, Pair<Integer, Object>... taggedData);
+
+ /**
+ * Logs an user action.
+ */
+ void action(Context context, int category, Pair<Integer, Object>... taggedData);
+
+ /**
+ * Logs an user action.
+ */
+ void actionWithSource(Context context, int source, int category);
+
+ /**
+ * Logs an user action.
+ * @deprecated use {@link #action(int, int, Pair[])}
+ */
+ @Deprecated
+ void action(Context context, int category, int value);
+
+ /**
+ * Logs an user action.
+ * @deprecated use {@link #action(int, boolean, Pair[])}
+ */
+ @Deprecated
+ void action(Context context, int category, boolean value);
+
+ /**
+ * Logs an user action.
+ */
+ void action(Context context, int category, String pkg, Pair<Integer, Object>... taggedData);
+
+ /**
+ * Logs a count.
+ */
+ void count(Context context, String name, int value);
+
+ /**
+ * Logs a histogram event.
+ */
+ void histogram(Context context, String name, int bucket);
+}
diff --git a/src/com/android/settings/core/instrumentation/MetricsFeatureProvider.java b/src/com/android/settings/core/instrumentation/MetricsFeatureProvider.java
new file mode 100644
index 0000000..166cbb8
--- /dev/null
+++ b/src/com/android/settings/core/instrumentation/MetricsFeatureProvider.java
@@ -0,0 +1,159 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.settings.core.instrumentation;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.text.TextUtils;
+import android.util.Pair;
+
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * FeatureProvider for metrics.
+ */
+public class MetricsFeatureProvider {
+ private List<LogWriter> mLoggerWriters;
+
+ public MetricsFeatureProvider() {
+ mLoggerWriters = new ArrayList<>();
+ installLogWriters();
+ }
+
+ protected void installLogWriters() {
+ mLoggerWriters.add(new EventLogWriter());
+ }
+
+ public void visible(Context context, int source, int category) {
+ for (LogWriter writer : mLoggerWriters) {
+ writer.visible(context, source, category);
+ }
+ }
+
+ public void hidden(Context context, int category) {
+ for (LogWriter writer : mLoggerWriters) {
+ writer.hidden(context, category);
+ }
+ }
+
+ public void actionWithSource(Context context, int source, int category) {
+ for (LogWriter writer : mLoggerWriters) {
+ writer.actionWithSource(context, source, category);
+ }
+ }
+
+ /**
+ * Logs a user action. Includes the elapsed time since the containing
+ * fragment has been visible.
+ */
+ public void action(VisibilityLoggerMixin visibilityLogger, int category, int value) {
+ for (LogWriter writer : mLoggerWriters) {
+ writer.action(category, value,
+ sinceVisibleTaggedData(visibilityLogger.elapsedTimeSinceVisible()));
+ }
+ }
+
+ /**
+ * Logs a user action. Includes the elapsed time since the containing
+ * fragment has been visible.
+ */
+ public void action(VisibilityLoggerMixin visibilityLogger, int category, boolean value) {
+ for (LogWriter writer : mLoggerWriters) {
+ writer.action(category, value,
+ sinceVisibleTaggedData(visibilityLogger.elapsedTimeSinceVisible()));
+ }
+ }
+
+ public void action(Context context, int category, Pair<Integer, Object>... taggedData) {
+ for (LogWriter writer : mLoggerWriters) {
+ writer.action(context, category, taggedData);
+ }
+ }
+
+ /** @deprecated use {@link #action(VisibilityLoggerMixin, int, int)} */
+ @Deprecated
+ public void action(Context context, int category, int value) {
+ for (LogWriter writer : mLoggerWriters) {
+ writer.action(context, category, value);
+ }
+ }
+
+ /** @deprecated use {@link #action(VisibilityLoggerMixin, int, boolean)} */
+ @Deprecated
+ public void action(Context context, int category, boolean value) {
+ for (LogWriter writer : mLoggerWriters) {
+ writer.action(context, category, value);
+ }
+ }
+
+ public void action(Context context, int category, String pkg,
+ Pair<Integer, Object>... taggedData) {
+ for (LogWriter writer : mLoggerWriters) {
+ writer.action(context, category, pkg, taggedData);
+ }
+ }
+
+ public void count(Context context, String name, int value) {
+ for (LogWriter writer : mLoggerWriters) {
+ writer.count(context, name, value);
+ }
+ }
+
+ public void histogram(Context context, String name, int bucket) {
+ for (LogWriter writer : mLoggerWriters) {
+ writer.histogram(context, name, bucket);
+ }
+ }
+
+ public int getMetricsCategory(Object object) {
+ if (object == null || !(object instanceof Instrumentable)) {
+ return MetricsEvent.VIEW_UNKNOWN;
+ }
+ return ((Instrumentable) object).getMetricsCategory();
+ }
+
+ public void logDashboardStartIntent(Context context, Intent intent,
+ int sourceMetricsCategory) {
+ if (intent == null) {
+ return;
+ }
+ final ComponentName cn = intent.getComponent();
+ if (cn == null) {
+ final String action = intent.getAction();
+ if (TextUtils.isEmpty(action)) {
+ // Not loggable
+ return;
+ }
+ action(context, MetricsEvent.ACTION_SETTINGS_TILE_CLICK, action,
+ Pair.create(MetricsEvent.FIELD_CONTEXT, sourceMetricsCategory));
+ return;
+ } else if (TextUtils.equals(cn.getPackageName(), context.getPackageName())) {
+ // Going to a Setting internal page, skip click logging in favor of page's own
+ // visibility logging.
+ return;
+ }
+ action(context, MetricsEvent.ACTION_SETTINGS_TILE_CLICK, cn.flattenToString(),
+ Pair.create(MetricsEvent.FIELD_CONTEXT, sourceMetricsCategory));
+ }
+
+ private Pair<Integer, Object> sinceVisibleTaggedData(long timestamp) {
+ return Pair.create(MetricsEvent.NOTIFICATION_SINCE_VISIBLE_MILLIS, timestamp);
+ }
+}
diff --git a/src/com/android/settings/core/instrumentation/SharedPreferencesLogger.java b/src/com/android/settings/core/instrumentation/SharedPreferencesLogger.java
new file mode 100644
index 0000000..dee40c0
--- /dev/null
+++ b/src/com/android/settings/core/instrumentation/SharedPreferencesLogger.java
@@ -0,0 +1,259 @@
+/*
+ * 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.core.instrumentation;
+
+import android.annotation.Nullable;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.content.pm.PackageManager;
+import android.os.AsyncTask;
+import android.support.annotation.VisibleForTesting;
+import android.text.TextUtils;
+import android.util.Log;
+import android.util.Pair;
+
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+import com.android.settings.overlay.FeatureFactory;
+
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentSkipListSet;
+
+public class SharedPreferencesLogger implements SharedPreferences {
+
+ private static final String LOG_TAG = "SharedPreferencesLogger";
+
+ private final String mTag;
+ private final Context mContext;
+ private final MetricsFeatureProvider mMetricsFeature;
+ private final Set<String> mPreferenceKeySet;
+
+ public SharedPreferencesLogger(Context context, String tag) {
+ mContext = context;
+ mTag = tag;
+ mMetricsFeature = FeatureFactory.getFactory(context).getMetricsFeatureProvider();
+ mPreferenceKeySet = new ConcurrentSkipListSet<>();
+ }
+
+ @Override
+ public Map<String, ?> getAll() {
+ return null;
+ }
+
+ @Override
+ public String getString(String key, @Nullable String defValue) {
+ return defValue;
+ }
+
+ @Override
+ public Set<String> getStringSet(String key, @Nullable Set<String> defValues) {
+ return defValues;
+ }
+
+ @Override
+ public int getInt(String key, int defValue) {
+ return defValue;
+ }
+
+ @Override
+ public long getLong(String key, long defValue) {
+ return defValue;
+ }
+
+ @Override
+ public float getFloat(String key, float defValue) {
+ return defValue;
+ }
+
+ @Override
+ public boolean getBoolean(String key, boolean defValue) {
+ return defValue;
+ }
+
+ @Override
+ public boolean contains(String key) {
+ return false;
+ }
+
+ @Override
+ public Editor edit() {
+ return new EditorLogger();
+ }
+
+ @Override
+ public void registerOnSharedPreferenceChangeListener(
+ OnSharedPreferenceChangeListener listener) {
+ }
+
+ @Override
+ public void unregisterOnSharedPreferenceChangeListener(
+ OnSharedPreferenceChangeListener listener) {
+ }
+
+ private void logValue(String key, Object value) {
+ logValue(key, value, false /* forceLog */);
+ }
+
+ private void logValue(String key, Object value, boolean forceLog) {
+ final String prefKey = buildPrefKey(mTag, key);
+ if (!forceLog && !mPreferenceKeySet.contains(prefKey)) {
+ // Pref key doesn't exist in set, this is initial display so we skip metrics but
+ // keeps track of this key.
+ mPreferenceKeySet.add(prefKey);
+ return;
+ }
+ // TODO: Remove count logging to save some resource.
+ mMetricsFeature.count(mContext, buildCountName(prefKey, value), 1);
+
+ final Pair<Integer, Object> valueData;
+ if (value instanceof Long) {
+ final Long longVal = (Long) value;
+ final int intVal;
+ if (longVal > Integer.MAX_VALUE) {
+ intVal = Integer.MAX_VALUE;
+ } else if (longVal < Integer.MIN_VALUE) {
+ intVal = Integer.MIN_VALUE;
+ } else {
+ intVal = longVal.intValue();
+ }
+ valueData = Pair.create(MetricsEvent.FIELD_SETTINGS_PREFERENCE_CHANGE_INT_VALUE,
+ intVal);
+ } else if (value instanceof Integer) {
+ valueData = Pair.create(MetricsEvent.FIELD_SETTINGS_PREFERENCE_CHANGE_INT_VALUE,
+ value);
+ } else if (value instanceof Boolean) {
+ valueData = Pair.create(MetricsEvent.FIELD_SETTINGS_PREFERENCE_CHANGE_INT_VALUE,
+ (Boolean) value ? 1 : 0);
+ } else if (value instanceof Float) {
+ valueData = Pair.create(MetricsEvent.FIELD_SETTINGS_PREFERENCE_CHANGE_FLOAT_VALUE,
+ value);
+ } else if (value instanceof String) {
+ Log.d(LOG_TAG, "Tried to log string preference " + prefKey + " = " + value);
+ valueData = null;
+ } else {
+ Log.w(LOG_TAG, "Tried to log unloggable object" + value);
+ valueData = null;
+ }
+ if (valueData != null) {
+ // Pref key exists in set, log it's change in metrics.
+ mMetricsFeature.action(mContext, MetricsEvent.ACTION_SETTINGS_PREFERENCE_CHANGE,
+ Pair.create(MetricsEvent.FIELD_SETTINGS_PREFERENCE_CHANGE_NAME, prefKey),
+ valueData);
+ }
+ }
+
+ @VisibleForTesting
+ void logPackageName(String key, String value) {
+ final String prefKey = mTag + "/" + key;
+ mMetricsFeature.action(mContext, MetricsEvent.ACTION_SETTINGS_PREFERENCE_CHANGE, value,
+ Pair.create(MetricsEvent.FIELD_SETTINGS_PREFERENCE_CHANGE_NAME, prefKey));
+ }
+
+ private void safeLogValue(String key, String value) {
+ new AsyncPackageCheck().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, key, value);
+ }
+
+ public static String buildCountName(String prefKey, Object value) {
+ return prefKey + "|" + value;
+ }
+
+ public static String buildPrefKey(String tag, String key) {
+ return tag + "/" + key;
+ }
+
+ private class AsyncPackageCheck extends AsyncTask<String, Void, Void> {
+ @Override
+ protected Void doInBackground(String... params) {
+ String key = params[0];
+ String value = params[1];
+ PackageManager pm = mContext.getPackageManager();
+ try {
+ // Check if this might be a component.
+ ComponentName name = ComponentName.unflattenFromString(value);
+ if (value != null) {
+ value = name.getPackageName();
+ }
+ } catch (Exception e) {
+ }
+ try {
+ pm.getPackageInfo(value, PackageManager.MATCH_ANY_USER);
+ logPackageName(key, value);
+ } catch (PackageManager.NameNotFoundException e) {
+ // Clearly not a package, and it's unlikely this preference is in prefSet, so
+ // lets force log it.
+ logValue(key, value, true /* forceLog */);
+ }
+ return null;
+ }
+ }
+
+ public class EditorLogger implements Editor {
+ @Override
+ public Editor putString(String key, @Nullable String value) {
+ safeLogValue(key, value);
+ return this;
+ }
+
+ @Override
+ public Editor putStringSet(String key, @Nullable Set<String> values) {
+ safeLogValue(key, TextUtils.join(",", values));
+ return this;
+ }
+
+ @Override
+ public Editor putInt(String key, int value) {
+ logValue(key, value);
+ return this;
+ }
+
+ @Override
+ public Editor putLong(String key, long value) {
+ logValue(key, value);
+ return this;
+ }
+
+ @Override
+ public Editor putFloat(String key, float value) {
+ logValue(key, value);
+ return this;
+ }
+
+ @Override
+ public Editor putBoolean(String key, boolean value) {
+ logValue(key, value);
+ return this;
+ }
+
+ @Override
+ public Editor remove(String key) {
+ return this;
+ }
+
+ @Override
+ public Editor clear() {
+ return this;
+ }
+
+ @Override
+ public boolean commit() {
+ return true;
+ }
+
+ @Override
+ public void apply() {
+ }
+ }
+}
diff --git a/src/com/android/settings/core/instrumentation/VisibilityLoggerMixin.java b/src/com/android/settings/core/instrumentation/VisibilityLoggerMixin.java
new file mode 100644
index 0000000..2fe2a3b
--- /dev/null
+++ b/src/com/android/settings/core/instrumentation/VisibilityLoggerMixin.java
@@ -0,0 +1,100 @@
+/*
+ * 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.core.instrumentation;
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.Intent;
+
+import android.os.SystemClock;
+import com.android.internal.logging.nano.MetricsProto;
+import com.android.settings.SettingsActivity;
+import com.android.settings.overlay.FeatureFactory;
+import com.android.settingslib.core.lifecycle.LifecycleObserver;
+import com.android.settingslib.core.lifecycle.events.OnAttach;
+import com.android.settingslib.core.lifecycle.events.OnPause;
+import com.android.settingslib.core.lifecycle.events.OnResume;
+
+import static com.android.settings.core.instrumentation.Instrumentable.METRICS_CATEGORY_UNKNOWN;
+
+/**
+ * Logs visibility change of a fragment.
+ */
+public class VisibilityLoggerMixin implements LifecycleObserver, OnResume, OnPause, OnAttach {
+
+ private static final String TAG = "VisibilityLoggerMixin";
+
+ private final int mMetricsCategory;
+
+ private MetricsFeatureProvider mMetricsFeature;
+ private int mSourceMetricsCategory = MetricsProto.MetricsEvent.VIEW_UNKNOWN;
+ private long mVisibleTimestamp;
+
+ public VisibilityLoggerMixin(int metricsCategory) {
+ // MetricsFeature will be set during onAttach.
+ this(metricsCategory, null /* metricsFeature */);
+ }
+
+ public VisibilityLoggerMixin(int metricsCategory, MetricsFeatureProvider metricsFeature) {
+ mMetricsCategory = metricsCategory;
+ mMetricsFeature = metricsFeature;
+ }
+
+ @Override
+ public void onAttach(Context context) {
+ mMetricsFeature = FeatureFactory.getFactory(context).getMetricsFeatureProvider();
+ }
+
+ @Override
+ public void onResume() {
+ mVisibleTimestamp = SystemClock.elapsedRealtime();
+ if (mMetricsFeature != null && mMetricsCategory != METRICS_CATEGORY_UNKNOWN) {
+ mMetricsFeature.visible(null /* context */, mSourceMetricsCategory, mMetricsCategory);
+ }
+ }
+
+ @Override
+ public void onPause() {
+ mVisibleTimestamp = 0;
+ if (mMetricsFeature != null && mMetricsCategory != METRICS_CATEGORY_UNKNOWN) {
+ mMetricsFeature.hidden(null /* context */, mMetricsCategory);
+ }
+ }
+
+ /**
+ * Sets source metrics category for this logger. Source is the caller that opened this UI.
+ */
+ public void setSourceMetricsCategory(Activity activity) {
+ if (mSourceMetricsCategory != MetricsProto.MetricsEvent.VIEW_UNKNOWN || activity == null) {
+ return;
+ }
+ final Intent intent = activity.getIntent();
+ if (intent == null) {
+ return;
+ }
+ mSourceMetricsCategory = intent.getIntExtra(SettingsActivity.EXTRA_SOURCE_METRICS_CATEGORY,
+ MetricsProto.MetricsEvent.VIEW_UNKNOWN);
+ }
+
+ /** Returns elapsed time since onResume() */
+ public long elapsedTimeSinceVisible() {
+ if (mVisibleTimestamp == 0) {
+ return 0;
+ }
+ return SystemClock.elapsedRealtime() - mVisibleTimestamp;
+ }
+}
diff --git a/src/com/android/settings/dashboard/DashboardAdapter.java b/src/com/android/settings/dashboard/DashboardAdapter.java
index 2d35ea7..97eef13 100644
--- a/src/com/android/settings/dashboard/DashboardAdapter.java
+++ b/src/com/android/settings/dashboard/DashboardAdapter.java
@@ -41,6 +41,7 @@
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.settings.R;
import com.android.settings.R.id;
+import com.android.settings.core.instrumentation.MetricsFeatureProvider;
import com.android.settings.dashboard.DashboardData.SuggestionConditionHeaderData;
import com.android.settings.dashboard.conditional.Condition;
import com.android.settings.dashboard.conditional.ConditionAdapter;
@@ -49,7 +50,6 @@
import com.android.settings.dashboard.suggestions.SuggestionDismissController;
import com.android.settings.overlay.FeatureFactory;
import com.android.settingslib.Utils;
-import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
import com.android.settingslib.drawer.DashboardCategory;
import com.android.settingslib.drawer.Tile;
diff --git a/src/com/android/settings/dashboard/DashboardAdapterV2.java b/src/com/android/settings/dashboard/DashboardAdapterV2.java
index ad93e4c..a422ae4 100644
--- a/src/com/android/settings/dashboard/DashboardAdapterV2.java
+++ b/src/com/android/settings/dashboard/DashboardAdapterV2.java
@@ -39,13 +39,13 @@
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.settings.R;
import com.android.settings.R.id;
+import com.android.settings.core.instrumentation.MetricsFeatureProvider;
import com.android.settings.dashboard.DashboardDataV2.ConditionHeaderData;
import com.android.settings.dashboard.conditional.Condition;
import com.android.settings.dashboard.conditional.ConditionAdapterV2;
import com.android.settings.dashboard.suggestions.SuggestionAdapterV2;
import com.android.settings.dashboard.suggestions.SuggestionControllerMixin;
import com.android.settings.overlay.FeatureFactory;
-import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
import com.android.settingslib.core.lifecycle.Lifecycle;
import com.android.settingslib.core.lifecycle.LifecycleObserver;
import com.android.settingslib.core.lifecycle.events.OnSaveInstanceState;
diff --git a/src/com/android/settings/dashboard/DashboardFeatureProviderImpl.java b/src/com/android/settings/dashboard/DashboardFeatureProviderImpl.java
index a14d9e9..a06fee9 100644
--- a/src/com/android/settings/dashboard/DashboardFeatureProviderImpl.java
+++ b/src/com/android/settings/dashboard/DashboardFeatureProviderImpl.java
@@ -41,9 +41,8 @@
import com.android.settings.R;
import com.android.settings.SettingsActivity;
import com.android.settings.core.FeatureFlags;
+import com.android.settings.core.instrumentation.MetricsFeatureProvider;
import com.android.settings.overlay.FeatureFactory;
-import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
-import com.android.settingslib.core.instrumentation.VisibilityLoggerMixin;
import com.android.settingslib.drawer.CategoryManager;
import com.android.settingslib.drawer.DashboardCategory;
import com.android.settingslib.drawer.ProfileSelectDialog;
@@ -160,8 +159,7 @@
pref.setFragment(clsName);
} else if (tile.intent != null) {
final Intent intent = new Intent(tile.intent);
- intent.putExtra(VisibilityLoggerMixin.EXTRA_SOURCE_METRICS_CATEGORY,
- sourceMetricsCategory);
+ intent.putExtra(SettingsActivity.EXTRA_SOURCE_METRICS_CATEGORY, sourceMetricsCategory);
if (action != null) {
intent.setAction(action);
}
@@ -210,7 +208,7 @@
return;
}
final Intent intent = new Intent(tile.intent)
- .putExtra(VisibilityLoggerMixin.EXTRA_SOURCE_METRICS_CATEGORY,
+ .putExtra(SettingsActivity.EXTRA_SOURCE_METRICS_CATEGORY,
MetricsEvent.DASHBOARD_SUMMARY)
.putExtra(SettingsDrawerActivity.EXTRA_SHOW_MENU, true)
.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
diff --git a/src/com/android/settings/dashboard/conditional/Condition.java b/src/com/android/settings/dashboard/conditional/Condition.java
index d66440e..05783bd 100644
--- a/src/com/android/settings/dashboard/conditional/Condition.java
+++ b/src/com/android/settings/dashboard/conditional/Condition.java
@@ -24,8 +24,8 @@
import android.support.annotation.VisibleForTesting;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+import com.android.settings.core.instrumentation.MetricsFeatureProvider;
import com.android.settings.overlay.FeatureFactory;
-import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
public abstract class Condition {
diff --git a/src/com/android/settings/dashboard/conditional/ConditionAdapter.java b/src/com/android/settings/dashboard/conditional/ConditionAdapter.java
index d84aa7c..eb768e5 100644
--- a/src/com/android/settings/dashboard/conditional/ConditionAdapter.java
+++ b/src/com/android/settings/dashboard/conditional/ConditionAdapter.java
@@ -27,13 +27,13 @@
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.settings.R;
+import com.android.settings.core.instrumentation.MetricsFeatureProvider;
import com.android.settings.dashboard.DashboardAdapter;
import com.android.settings.dashboard.DashboardAdapter.DashboardItemHolder;
import com.android.settings.dashboard.DashboardData;
import com.android.settings.dashboard.DashboardData.HeaderMode;
import com.android.settings.overlay.FeatureFactory;
import com.android.settingslib.WirelessUtils;
-import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
import java.util.List;
import java.util.Objects;
diff --git a/src/com/android/settings/dashboard/conditional/ConditionAdapterV2.java b/src/com/android/settings/dashboard/conditional/ConditionAdapterV2.java
index 8db57f7..3f3e5c9 100644
--- a/src/com/android/settings/dashboard/conditional/ConditionAdapterV2.java
+++ b/src/com/android/settings/dashboard/conditional/ConditionAdapterV2.java
@@ -27,10 +27,10 @@
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.settings.R;
+import com.android.settings.core.instrumentation.MetricsFeatureProvider;
import com.android.settings.dashboard.DashboardAdapterV2.DashboardItemHolder;
import com.android.settings.overlay.FeatureFactory;
import com.android.settingslib.WirelessUtils;
-import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
import java.util.List;
import java.util.Objects;
diff --git a/src/com/android/settings/dashboard/suggestions/SuggestionAdapter.java b/src/com/android/settings/dashboard/suggestions/SuggestionAdapter.java
index 2b79a9b..fc11029 100644
--- a/src/com/android/settings/dashboard/suggestions/SuggestionAdapter.java
+++ b/src/com/android/settings/dashboard/suggestions/SuggestionAdapter.java
@@ -27,10 +27,10 @@
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.settings.R;
+import com.android.settings.core.instrumentation.MetricsFeatureProvider;
import com.android.settings.dashboard.DashboardAdapter.DashboardItemHolder;
import com.android.settings.dashboard.DashboardAdapter.IconCache;
import com.android.settings.overlay.FeatureFactory;
-import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
import java.util.List;
import java.util.Objects;
diff --git a/src/com/android/settings/dashboard/suggestions/SuggestionAdapterV2.java b/src/com/android/settings/dashboard/suggestions/SuggestionAdapterV2.java
index e04ae93..afd0e08 100644
--- a/src/com/android/settings/dashboard/suggestions/SuggestionAdapterV2.java
+++ b/src/com/android/settings/dashboard/suggestions/SuggestionAdapterV2.java
@@ -31,10 +31,10 @@
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.settings.R;
+import com.android.settings.core.instrumentation.MetricsFeatureProvider;
import com.android.settings.dashboard.DashboardAdapterV2.DashboardItemHolder;
import com.android.settings.dashboard.DashboardAdapterV2.IconCache;
import com.android.settings.overlay.FeatureFactory;
-import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
import com.android.settingslib.core.lifecycle.Lifecycle;
import com.android.settingslib.core.lifecycle.LifecycleObserver;
import com.android.settingslib.core.lifecycle.events.OnSaveInstanceState;
diff --git a/src/com/android/settings/dashboard/suggestions/SuggestionFeatureProviderImpl.java b/src/com/android/settings/dashboard/suggestions/SuggestionFeatureProviderImpl.java
index 8cd1675..05c1eff 100644
--- a/src/com/android/settings/dashboard/suggestions/SuggestionFeatureProviderImpl.java
+++ b/src/com/android/settings/dashboard/suggestions/SuggestionFeatureProviderImpl.java
@@ -30,25 +30,15 @@
import com.android.internal.logging.nano.MetricsProto;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
-import com.android.settings.Settings.AmbientDisplayPickupSuggestionActivity;
-import com.android.settings.Settings.AmbientDisplaySuggestionActivity;
-import com.android.settings.Settings.DoubleTapPowerSuggestionActivity;
-import com.android.settings.Settings.DoubleTwistSuggestionActivity;
import com.android.settings.Settings.NightDisplaySuggestionActivity;
-import com.android.settings.Settings.SwipeToNotificationSuggestionActivity;
+import com.android.settings.core.instrumentation.MetricsFeatureProvider;
import com.android.settings.fingerprint.FingerprintEnrollSuggestionActivity;
import com.android.settings.fingerprint.FingerprintSuggestionActivity;
-import com.android.settings.gestures.DoubleTapPowerPreferenceController;
-import com.android.settings.gestures.DoubleTapScreenPreferenceController;
-import com.android.settings.gestures.DoubleTwistPreferenceController;
-import com.android.settings.gestures.PickupGesturePreferenceController;
-import com.android.settings.gestures.SwipeToNotificationPreferenceController;
import com.android.settings.overlay.FeatureFactory;
import com.android.settings.password.ScreenLockSuggestionActivity;
import com.android.settings.support.NewDeviceIntroSuggestionActivity;
import com.android.settings.wallpaper.WallpaperSuggestionActivity;
import com.android.settings.wifi.WifiCallingSuggestionActivity;
-import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
import com.android.settingslib.drawer.Tile;
import java.util.List;
@@ -98,21 +88,6 @@
return hasUsedNightDisplay(context);
} else if (className.equals(NewDeviceIntroSuggestionActivity.class.getName())) {
return NewDeviceIntroSuggestionActivity.isSuggestionComplete(context);
- } else if (className.equals(DoubleTapPowerSuggestionActivity.class.getName())) {
- return DoubleTapPowerPreferenceController
- .isSuggestionComplete(context, getSharedPrefs(context));
- } else if (className.equals(DoubleTwistSuggestionActivity.class.getName())) {
- return DoubleTwistPreferenceController
- .isSuggestionComplete(context, getSharedPrefs(context));
- } else if (className.equals(AmbientDisplaySuggestionActivity.class.getName())) {
- return DoubleTapScreenPreferenceController
- .isSuggestionComplete(context, getSharedPrefs(context));
- } else if (className.equals(AmbientDisplayPickupSuggestionActivity.class.getName())) {
- return PickupGesturePreferenceController
- .isSuggestionComplete(context, getSharedPrefs(context));
- } else if (className.equals(SwipeToNotificationSuggestionActivity.class.getName())) {
- return SwipeToNotificationPreferenceController
- .isSuggestionComplete(context, getSharedPrefs(context));
}
return false;
}
diff --git a/src/com/android/settings/datausage/DataSaverBackend.java b/src/com/android/settings/datausage/DataSaverBackend.java
index b59da9d..ff568c7 100644
--- a/src/com/android/settings/datausage/DataSaverBackend.java
+++ b/src/com/android/settings/datausage/DataSaverBackend.java
@@ -25,8 +25,8 @@
import android.util.SparseIntArray;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+import com.android.settings.core.instrumentation.MetricsFeatureProvider;
import com.android.settings.overlay.FeatureFactory;
-import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
import com.android.settingslib.utils.ThreadUtils;
import java.util.ArrayList;
diff --git a/src/com/android/settings/datetime/ZonePicker.java b/src/com/android/settings/datetime/ZonePicker.java
index dc69127..57c340c 100644
--- a/src/com/android/settings/datetime/ZonePicker.java
+++ b/src/com/android/settings/datetime/ZonePicker.java
@@ -35,9 +35,8 @@
import com.android.internal.logging.nano.MetricsProto;
import com.android.settings.R;
-import com.android.settings.overlay.FeatureFactory;
-import com.android.settingslib.core.instrumentation.Instrumentable;
-import com.android.settingslib.core.instrumentation.VisibilityLoggerMixin;
+import com.android.settings.core.instrumentation.Instrumentable;
+import com.android.settings.core.instrumentation.VisibilityLoggerMixin;
import com.android.settingslib.datetime.ZoneGetter;
import java.text.Collator;
@@ -58,7 +57,8 @@
private static final int MENU_TIMEZONE = Menu.FIRST+1;
private static final int MENU_ALPHABETICAL = Menu.FIRST;
- private VisibilityLoggerMixin mVisibilityLoggerMixin;
+ private final VisibilityLoggerMixin mVisibilityLoggerMixin =
+ new VisibilityLoggerMixin(getMetricsCategory());
private boolean mSortedByTimezone;
@@ -145,6 +145,12 @@
}
@Override
+ public void onAttach(Context context) {
+ super.onAttach(context);
+ mVisibilityLoggerMixin.onAttach(context);
+ }
+
+ @Override
public int getMetricsCategory() {
return MetricsProto.MetricsEvent.ZONE_PICKER;
}
@@ -164,13 +170,6 @@
}
@Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- mVisibilityLoggerMixin = new VisibilityLoggerMixin(getMetricsCategory(),
- FeatureFactory.getFactory(getContext()).getMetricsFeatureProvider());
- }
-
- @Override
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
final View view = super.onCreateView(inflater, container, savedInstanceState);
diff --git a/src/com/android/settings/datetime/timezone/ZonePicker.java b/src/com/android/settings/datetime/timezone/ZonePicker.java
index eafbaa2..d0d1720 100644
--- a/src/com/android/settings/datetime/timezone/ZonePicker.java
+++ b/src/com/android/settings/datetime/timezone/ZonePicker.java
@@ -31,6 +31,7 @@
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
+import android.widget.LinearLayout;
import android.widget.Spinner;
import com.android.internal.logging.nano.MetricsProto;
import com.android.settings.R;
@@ -56,11 +57,14 @@
private List<RegionInfo> mRegions;
private Map<String, List<TimeZoneInfo>> mZoneInfos;
private List<TimeZoneInfo> mFixedOffsetTimeZones;
- private TimeZoneAdapter mTimeZoneAdapter;
private String mSelectedTimeZone;
private boolean mSelectByRegion;
private DataLoader mDataLoader;
+ private TimeZoneAdapter mTimeZoneAdapter;
+
private RecyclerView mRecyclerView;
+ private LinearLayout mRegionSpinnerLayout;
+ private Spinner mRegionSpinner;
@Override
public int getMetricsCategory() {
@@ -88,15 +92,17 @@
final ArrayAdapter<RegionInfo> regionAdapter = new ArrayAdapter<>(getContext(),
R.layout.filter_spinner_item, mRegions);
regionAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
- final Spinner spinner = view.findViewById(R.id.tz_region_spinner);
- spinner.setAdapter(regionAdapter);
- spinner.setOnItemSelectedListener(this);
- setupForCurrentTimeZone(spinner);
+
+ mRegionSpinnerLayout = view.findViewById(R.id.tz_region_spinner_layout);
+ mRegionSpinner = view.findViewById(R.id.tz_region_spinner);
+ mRegionSpinner.setAdapter(regionAdapter);
+ mRegionSpinner.setOnItemSelectedListener(this);
+ setupForCurrentTimeZone();
setHasOptionsMenu(true);
return view;
}
- private void setupForCurrentTimeZone(Spinner spinner) {
+ private void setupForCurrentTimeZone() {
final String localeRegionId = mLocale.getCountry().toUpperCase(Locale.ROOT);
final String currentTimeZone = TimeZone.getDefault().getID();
boolean fixedOffset = currentTimeZone.startsWith("Etc/GMT") ||
@@ -105,12 +111,12 @@
for (int regionIndex = 0; regionIndex < mRegions.size(); regionIndex++) {
final RegionInfo region = mRegions.get(regionIndex);
if (localeRegionId.equals(region.getId())) {
- spinner.setSelection(regionIndex);
+ mRegionSpinner.setSelection(regionIndex);
}
if (!fixedOffset) {
for (String timeZoneId: region.getTimeZoneIds()) {
if (TextUtils.equals(timeZoneId, mSelectedTimeZone)) {
- spinner.setSelection(regionIndex);
+ mRegionSpinner.setSelection(regionIndex);
return;
}
}
@@ -179,16 +185,15 @@
private void setSelectByRegion(boolean selectByRegion) {
mSelectByRegion = selectByRegion;
- getView().findViewById(R.id.tz_region_spinner_layout).setVisibility(
+ mRegionSpinnerLayout.setVisibility(
mSelectByRegion ? View.VISIBLE : View.GONE);
List<TimeZoneInfo> tzInfos;
if (selectByRegion) {
- Spinner regionSpinner = getView().findViewById(R.id.tz_region_spinner);
- int selectedRegion = regionSpinner.getSelectedItemPosition();
+ int selectedRegion = mRegionSpinner.getSelectedItemPosition();
if (selectedRegion == -1) {
// Arbitrarily pick the first item if no region was selected above.
selectedRegion = 0;
- regionSpinner.setSelection(selectedRegion);
+ mRegionSpinner.setSelection(selectedRegion);
}
tzInfos = getTimeZoneInfos(mRegions.get(selectedRegion));
} else {
diff --git a/src/com/android/settings/deletionhelper/AutomaticStorageManagerSwitchBarController.java b/src/com/android/settings/deletionhelper/AutomaticStorageManagerSwitchBarController.java
index a20afa1..8ab1a07 100644
--- a/src/com/android/settings/deletionhelper/AutomaticStorageManagerSwitchBarController.java
+++ b/src/com/android/settings/deletionhelper/AutomaticStorageManagerSwitchBarController.java
@@ -23,10 +23,10 @@
import android.support.v7.preference.Preference;
import android.widget.Switch;
-import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.internal.util.Preconditions;
+import com.android.settings.core.instrumentation.MetricsFeatureProvider;
import com.android.settings.widget.SwitchBar;
-import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
/** Handles the logic for flipping the storage management toggle on a {@link SwitchBar}. */
public class AutomaticStorageManagerSwitchBarController
diff --git a/src/com/android/settings/development/DevelopmentSettingsDashboardFragment.java b/src/com/android/settings/development/DevelopmentSettingsDashboardFragment.java
index 0420ecf..ce4b7bf 100644
--- a/src/com/android/settings/development/DevelopmentSettingsDashboardFragment.java
+++ b/src/com/android/settings/development/DevelopmentSettingsDashboardFragment.java
@@ -398,6 +398,7 @@
controllers.add(new CameraLaserSensorPreferenceController(context));
controllers.add(new WifiDisplayCertificationPreferenceController(context));
controllers.add(new WifiVerboseLoggingPreferenceController(context));
+ controllers.add(new WifiConnectedMacRandomizationPreferenceController(context));
controllers.add(new MobileDataAlwaysOnPreferenceController(context));
controllers.add(new TetheringHardwareAccelPreferenceController(context));
controllers.add(new SelectUsbConfigPreferenceController(context, lifecycle));
diff --git a/src/com/android/settings/development/EmulateDisplayCutoutPreferenceController.java b/src/com/android/settings/development/EmulateDisplayCutoutPreferenceController.java
index 1035a1b..d6c74f9 100644
--- a/src/com/android/settings/development/EmulateDisplayCutoutPreferenceController.java
+++ b/src/com/android/settings/development/EmulateDisplayCutoutPreferenceController.java
@@ -16,41 +16,52 @@
package com.android.settings.development;
+import static android.os.UserHandle.USER_SYSTEM;
+
import android.content.Context;
import android.content.om.IOverlayManager;
import android.content.om.OverlayInfo;
+import android.content.pm.PackageManager;
import android.os.RemoteException;
import android.os.ServiceManager;
-import android.os.UserHandle;
import android.support.annotation.VisibleForTesting;
+import android.support.v7.preference.ListPreference;
import android.support.v7.preference.Preference;
import android.support.v7.preference.PreferenceScreen;
-import android.support.v7.preference.TwoStatePreference;
+import android.text.TextUtils;
+import com.android.internal.util.ArrayUtils;
+import com.android.settings.R;
import com.android.settings.core.PreferenceControllerMixin;
import com.android.settingslib.development.DeveloperOptionsPreferenceController;
+import java.util.List;
+
public class EmulateDisplayCutoutPreferenceController extends
DeveloperOptionsPreferenceController implements Preference.OnPreferenceChangeListener,
PreferenceControllerMixin {
- private static final String EMULATION_OVERLAY = "com.android.internal.display.cutout.emulation";
+ public static final String EMULATION_OVERLAY_PREFIX =
+ "com.android.internal.display.cutout.emulation.";
private static final String KEY = "display_cutout_emulation";
private final IOverlayManager mOverlayManager;
private final boolean mAvailable;
- private TwoStatePreference mPreference;
+ private ListPreference mPreference;
+ private PackageManager mPackageManager;
@VisibleForTesting
- EmulateDisplayCutoutPreferenceController(Context context, IOverlayManager overlayManager) {
+ EmulateDisplayCutoutPreferenceController(Context context, PackageManager packageManager,
+ IOverlayManager overlayManager) {
super(context);
mOverlayManager = overlayManager;
- mAvailable = overlayManager != null && getEmulationOverlayInfo() != null;
+ mPackageManager = packageManager;
+ mAvailable = overlayManager != null && getOverlayInfos().length > 0;
}
public EmulateDisplayCutoutPreferenceController(Context context) {
- this(context, IOverlayManager.Stub.asInterface(
+ this(context, context.getPackageManager(), IOverlayManager.Stub.asInterface(
ServiceManager.getService(Context.OVERLAY_SERVICE)));
}
@@ -67,45 +78,95 @@
@Override
public void displayPreference(PreferenceScreen screen) {
super.displayPreference(screen);
- setPreference((TwoStatePreference) screen.findPreference(getPreferenceKey()));
+ setPreference((ListPreference) screen.findPreference(getPreferenceKey()));
}
@VisibleForTesting
- void setPreference(TwoStatePreference preference) {
+ void setPreference(ListPreference preference) {
mPreference = preference;
}
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
- return writeEnabled((boolean) newValue);
+ return setEmulationOverlay((String) newValue);
}
- private boolean writeEnabled(boolean newValue) {
- OverlayInfo current = getEmulationOverlayInfo();
- if (current == null || current.isEnabled() == newValue) {
- return false;
+ private boolean setEmulationOverlay(String packageName) {
+ OverlayInfo[] overlays = getOverlayInfos();
+ CharSequence currentPackageName = null;
+ for (OverlayInfo o : overlays) {
+ if (o.isEnabled()) {
+ currentPackageName = o.packageName;
+ }
}
- try {
- return mOverlayManager.setEnabled(EMULATION_OVERLAY, newValue, UserHandle.USER_SYSTEM);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
+
+ if (TextUtils.isEmpty(packageName) && TextUtils.isEmpty(currentPackageName)
+ || TextUtils.equals(packageName, currentPackageName)) {
+ // Already set.
+ return true;
}
+
+ for (OverlayInfo o : overlays) {
+ boolean isEnabled = o.isEnabled();
+ boolean shouldBeEnabled = TextUtils.equals(o.packageName, packageName);
+ if (isEnabled != shouldBeEnabled) {
+ try {
+ mOverlayManager.setEnabled(o.packageName, shouldBeEnabled, USER_SYSTEM);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+ }
+ updateState(mPreference);
+ return true;
}
@Override
public void updateState(Preference preference) {
- OverlayInfo overlayInfo = getEmulationOverlayInfo();
- mPreference.setChecked(overlayInfo != null && overlayInfo.isEnabled());
+ OverlayInfo[] overlays = getOverlayInfos();
+
+ CharSequence[] pkgs = new CharSequence[overlays.length + 1];
+ CharSequence[] labels = new CharSequence[pkgs.length];
+
+ int current = 0;
+ pkgs[0] = "";
+ labels[0] = mContext.getString(R.string.display_cutout_emulation_none);
+
+ for (int i = 0; i < overlays.length; i++) {
+ OverlayInfo o = overlays[i];
+ pkgs[i+1] = o.packageName;
+ if (o.isEnabled()) {
+ current = i+1;
+ }
+ }
+ for (int i = 1; i < pkgs.length; i++) {
+ try {
+ labels[i] = mPackageManager.getApplicationInfo(pkgs[i].toString(), 0)
+ .loadLabel(mPackageManager);
+ } catch (PackageManager.NameNotFoundException e) {
+ labels[i] = pkgs[i];
+ }
+ }
+
+ mPreference.setEntries(labels);
+ mPreference.setEntryValues(pkgs);
+ mPreference.setValueIndex(current);
+ mPreference.setSummary(labels[current]);
}
- private OverlayInfo getEmulationOverlayInfo() {
- OverlayInfo overlayInfo = null;
+ private OverlayInfo[] getOverlayInfos() {
try {
- overlayInfo = mOverlayManager.getOverlayInfo(EMULATION_OVERLAY, UserHandle.USER_SYSTEM);
+ @SuppressWarnings("unchecked") List<OverlayInfo> overlayInfos =
+ mOverlayManager.getOverlayInfosForTarget("android", USER_SYSTEM);
+ for (int i = overlayInfos.size() - 1; i >= 0; i--) {
+ if (!overlayInfos.get(i).packageName.startsWith(EMULATION_OVERLAY_PREFIX)) {
+ overlayInfos.remove(i);
+ }
+ }
+ return overlayInfos.toArray(new OverlayInfo[overlayInfos.size()]);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
- return overlayInfo;
}
@Override
@@ -115,8 +176,8 @@
@Override
protected void onDeveloperOptionsSwitchDisabled() {
- writeEnabled(false);
- mPreference.setChecked(false);
+ setEmulationOverlay("");
+ updateState(mPreference);
mPreference.setEnabled(false);
}
}
diff --git a/src/com/android/settings/development/WifiConnectedMacRandomizationPreferenceController.java b/src/com/android/settings/development/WifiConnectedMacRandomizationPreferenceController.java
new file mode 100644
index 0000000..eae2355
--- /dev/null
+++ b/src/com/android/settings/development/WifiConnectedMacRandomizationPreferenceController.java
@@ -0,0 +1,93 @@
+/*
+ * 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.development;
+
+import android.content.Context;
+import android.provider.Settings;
+import android.support.annotation.VisibleForTesting;
+import android.support.v14.preference.SwitchPreference;
+import android.support.v7.preference.Preference;
+import android.support.v7.preference.PreferenceScreen;
+
+import com.android.settings.R;
+import com.android.settings.core.PreferenceControllerMixin;
+import com.android.settingslib.development.DeveloperOptionsPreferenceController;
+
+public class WifiConnectedMacRandomizationPreferenceController extends
+ DeveloperOptionsPreferenceController implements Preference.OnPreferenceChangeListener,
+ PreferenceControllerMixin {
+
+ private static final String WIFI_CONNECTED_MAC_RANDOMIZATION_KEY =
+ "wifi_connected_mac_randomization";
+
+ @VisibleForTesting
+ static final int SETTING_VALUE_ON = 1;
+ @VisibleForTesting
+ static final int SETTING_VALUE_OFF = 0;
+
+ private SwitchPreference mPreference;
+
+ public WifiConnectedMacRandomizationPreferenceController(Context context) {
+ super(context);
+ }
+
+ @Override
+ public boolean isAvailable() {
+ return mContext.getResources().getBoolean(
+ R.bool.config_wifi_support_connected_mac_randomization);
+ }
+
+ @Override
+ public String getPreferenceKey() {
+ return WIFI_CONNECTED_MAC_RANDOMIZATION_KEY;
+ }
+
+ @Override
+ public void displayPreference(PreferenceScreen screen) {
+ super.displayPreference(screen);
+ mPreference = (SwitchPreference) screen.findPreference(getPreferenceKey());
+ }
+
+ @Override
+ public boolean onPreferenceChange(Preference preference, Object newValue) {
+ final boolean isEnabled = (Boolean) newValue;
+ Settings.Global.putInt(mContext.getContentResolver(),
+ Settings.Global.WIFI_CONNECTED_MAC_RANDOMIZATION_ENABLED,
+ isEnabled ? SETTING_VALUE_ON : SETTING_VALUE_OFF);
+ return true;
+ }
+
+ @Override
+ public void updateState(Preference preference) {
+ final int enableMode = Settings.Global.getInt(mContext.getContentResolver(),
+ Settings.Global.WIFI_CONNECTED_MAC_RANDOMIZATION_ENABLED, SETTING_VALUE_OFF);
+ mPreference.setChecked(enableMode != SETTING_VALUE_OFF);
+ }
+
+ @Override
+ protected void onDeveloperOptionsSwitchEnabled() {
+ mPreference.setEnabled(true);
+ }
+
+ @Override
+ protected void onDeveloperOptionsSwitchDisabled() {
+ Settings.Global.putInt(mContext.getContentResolver(),
+ Settings.Global.WIFI_CONNECTED_MAC_RANDOMIZATION_ENABLED, SETTING_VALUE_OFF);
+ mPreference.setChecked(false);
+ mPreference.setEnabled(false);
+ }
+}
diff --git a/src/com/android/settings/deviceinfo/BrandedAccountPreferenceController.java b/src/com/android/settings/deviceinfo/BrandedAccountPreferenceController.java
new file mode 100644
index 0000000..5565e3d
--- /dev/null
+++ b/src/com/android/settings/deviceinfo/BrandedAccountPreferenceController.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2018 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.accounts.Account;
+import android.content.Context;
+import android.os.Bundle;
+import android.support.v7.preference.Preference;
+import android.support.v7.preference.PreferenceScreen;
+
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+import com.android.settings.R;
+import com.android.settings.Utils;
+import com.android.settings.accounts.AccountDetailDashboardFragment;
+import com.android.settings.accounts.AccountFeatureProvider;
+import com.android.settings.core.BasePreferenceController;
+import com.android.settings.overlay.FeatureFactory;
+
+public class BrandedAccountPreferenceController extends BasePreferenceController {
+ private static final String KEY_PREFERENCE_TITLE = "account";
+ private final Account[] mAccounts;
+
+ public BrandedAccountPreferenceController(Context context) {
+ super(context, KEY_PREFERENCE_TITLE);
+ final AccountFeatureProvider accountFeatureProvider = FeatureFactory.getFactory(
+ mContext).getAccountFeatureProvider();
+ mAccounts = accountFeatureProvider.getAccounts(mContext);
+ }
+
+ @Override
+ public int getAvailabilityStatus() {
+ if (mAccounts != null && mAccounts.length > 0) {
+ return AVAILABLE;
+ }
+ return DISABLED_FOR_USER;
+ }
+
+ @Override
+ public void displayPreference(PreferenceScreen screen) {
+ super.displayPreference(screen);
+ final AccountFeatureProvider accountFeatureProvider = FeatureFactory.getFactory(
+ mContext).getAccountFeatureProvider();
+ final Preference accountPreference = screen.findPreference(KEY_PREFERENCE_TITLE);
+ if (accountPreference != null && (mAccounts == null || mAccounts.length == 0)) {
+ screen.removePreference(accountPreference);
+ return;
+ }
+
+ accountPreference.setSummary(mAccounts[0].name);
+ accountPreference.setOnPreferenceClickListener(preference -> {
+ final Bundle args = new Bundle();
+ args.putParcelable(AccountDetailDashboardFragment.KEY_ACCOUNT,
+ mAccounts[0]);
+ args.putParcelable(AccountDetailDashboardFragment.KEY_USER_HANDLE,
+ android.os.Process.myUserHandle());
+ args.putString(AccountDetailDashboardFragment.KEY_ACCOUNT_TYPE,
+ accountFeatureProvider.getAccountType());
+ Utils.startWithFragment(mContext, AccountDetailDashboardFragment.class.getName(),
+ args, null, 0,
+ R.string.account_sync_title, null, MetricsEvent.ACCOUNT);
+ return true;
+ });
+ }
+}
diff --git a/src/com/android/settings/deviceinfo/BuildNumberPreferenceController.java b/src/com/android/settings/deviceinfo/BuildNumberPreferenceController.java
index 0f3bfb8..2641f5d 100644
--- a/src/com/android/settings/deviceinfo/BuildNumberPreferenceController.java
+++ b/src/com/android/settings/deviceinfo/BuildNumberPreferenceController.java
@@ -34,11 +34,11 @@
import com.android.settings.R;
import com.android.settings.Utils;
import com.android.settings.core.PreferenceControllerMixin;
+import com.android.settings.core.instrumentation.MetricsFeatureProvider;
import com.android.settings.overlay.FeatureFactory;
import com.android.settings.password.ChooseLockSettingsHelper;
import com.android.settingslib.RestrictedLockUtils;
import com.android.settingslib.core.AbstractPreferenceController;
-import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
import com.android.settingslib.core.lifecycle.Lifecycle;
import com.android.settingslib.core.lifecycle.LifecycleObserver;
import com.android.settingslib.core.lifecycle.events.OnResume;
diff --git a/src/com/android/settings/deviceinfo/SystemUpdatePreferenceController.java b/src/com/android/settings/deviceinfo/SystemUpdatePreferenceController.java
index a061f82..2806275 100644
--- a/src/com/android/settings/deviceinfo/SystemUpdatePreferenceController.java
+++ b/src/com/android/settings/deviceinfo/SystemUpdatePreferenceController.java
@@ -47,7 +47,8 @@
@Override
public int getAvailabilityStatus() {
- return mUm.isAdminUser()
+ return mContext.getResources().getBoolean(R.bool.config_show_system_update_settings)
+ && mUm.isAdminUser()
? AVAILABLE
: DISABLED_UNSUPPORTED;
}
diff --git a/src/com/android/settings/deviceinfo/aboutphone/MyDeviceInfoFragment.java b/src/com/android/settings/deviceinfo/aboutphone/MyDeviceInfoFragment.java
new file mode 100644
index 0000000..a301807
--- /dev/null
+++ b/src/com/android/settings/deviceinfo/aboutphone/MyDeviceInfoFragment.java
@@ -0,0 +1,180 @@
+/*
+ * Copyright (C) 2018 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.aboutphone;
+
+import android.app.Activity;
+import android.app.Fragment;
+import android.content.Context;
+import android.content.pm.UserInfo;
+import android.os.Bundle;
+import android.os.UserManager;
+import android.provider.SearchIndexableResource;
+import android.telephony.TelephonyManager;
+import android.view.View;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+import com.android.settings.R;
+import com.android.settings.SettingsActivity;
+import com.android.settings.Utils;
+import com.android.settings.applications.LayoutPreference;
+import com.android.settings.dashboard.DashboardFragment;
+import com.android.settings.deviceinfo.BluetoothAddressPreferenceController;
+import com.android.settings.deviceinfo.BrandedAccountPreferenceController;
+import com.android.settings.deviceinfo.BuildNumberPreferenceController;
+import com.android.settings.deviceinfo.DeviceModelPreferenceController;
+import com.android.settings.deviceinfo.FccEquipmentIdPreferenceController;
+import com.android.settings.deviceinfo.FeedbackPreferenceController;
+import com.android.settings.deviceinfo.ImsStatusPreferenceController;
+import com.android.settings.deviceinfo.IpAddressPreferenceController;
+import com.android.settings.deviceinfo.ManualPreferenceController;
+import com.android.settings.deviceinfo.PhoneNumberPreferenceController;
+import com.android.settings.deviceinfo.RegulatoryInfoPreferenceController;
+import com.android.settings.deviceinfo.SafetyInfoPreferenceController;
+import com.android.settings.deviceinfo.WifiMacAddressPreferenceController;
+import com.android.settings.deviceinfo.firmwareversion.FirmwareVersionPreferenceController;
+import com.android.settings.deviceinfo.imei.ImeiInfoPreferenceController;
+import com.android.settings.deviceinfo.simstatus.SimStatusPreferenceController;
+import com.android.settings.search.BaseSearchIndexProvider;
+import com.android.settings.search.Indexable;
+import com.android.settings.widget.EntityHeaderController;
+import com.android.settingslib.core.AbstractPreferenceController;
+import com.android.settingslib.core.lifecycle.Lifecycle;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+public class MyDeviceInfoFragment extends DashboardFragment {
+ private static final String LOG_TAG = "MeCardFragment";
+
+ private static final String KEY_MY_DEVICE_INFO_HEADER = "my_device_info_header";
+ private static final String KEY_LEGAL_CONTAINER = "legal_container";
+
+ @Override
+ public int getMetricsCategory() {
+ return MetricsEvent.DEVICEINFO;
+ }
+
+ @Override
+ public int getHelpResource() {
+ return R.string.help_uri_about;
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ initHeader();
+ }
+
+ @Override
+ protected String getLogTag() {
+ return LOG_TAG;
+ }
+
+ @Override
+ protected int getPreferenceScreenResId() {
+ return R.xml.my_device_info;
+ }
+
+ @Override
+ protected List<AbstractPreferenceController> getPreferenceControllers(Context context) {
+ return buildPreferenceControllers(context, getActivity(), this /* fragment */,
+ getLifecycle());
+ }
+
+ private static List<AbstractPreferenceController> buildPreferenceControllers(Context context,
+ Activity activity, Fragment fragment, Lifecycle lifecycle) {
+ final List<AbstractPreferenceController> controllers = new ArrayList<>();
+ controllers.add(new PhoneNumberPreferenceController(context));
+ controllers.add(new BrandedAccountPreferenceController(context));
+ controllers.add(new SimStatusPreferenceController(context, fragment));
+ controllers.add(new DeviceModelPreferenceController(context, fragment));
+ controllers.add(new ImeiInfoPreferenceController(context, fragment));
+ controllers.add(new FirmwareVersionPreferenceController(context, fragment));
+ controllers.add(new ImsStatusPreferenceController(context, lifecycle));
+ controllers.add(new IpAddressPreferenceController(context, lifecycle));
+ controllers.add(new WifiMacAddressPreferenceController(context, lifecycle));
+ controllers.add(new BluetoothAddressPreferenceController(context, lifecycle));
+ controllers.add(new RegulatoryInfoPreferenceController(context));
+ controllers.add(new SafetyInfoPreferenceController(context));
+ controllers.add(new ManualPreferenceController(context));
+ controllers.add(new FeedbackPreferenceController(fragment, context));
+ controllers.add(new FccEquipmentIdPreferenceController(context));
+ controllers.add(
+ new BuildNumberPreferenceController(context, activity, fragment, lifecycle));
+ // TODO: Add preference controller for getting the device name.
+ return controllers;
+ }
+
+ private void initHeader() {
+ // TODO: Migrate into its own controller.
+ final LayoutPreference headerPreference =
+ (LayoutPreference) getPreferenceScreen().findPreference(KEY_MY_DEVICE_INFO_HEADER);
+ final View appSnippet = headerPreference.findViewById(R.id.entity_header);
+ final Activity context = getActivity();
+ final Bundle bundle = getArguments();
+ EntityHeaderController controller = EntityHeaderController
+ .newInstance(context, this, appSnippet)
+ .setRecyclerView(getListView(), getLifecycle())
+ .setButtonActions(EntityHeaderController.ActionType.ACTION_NONE,
+ EntityHeaderController.ActionType.ACTION_NONE);
+
+ // TODO: There may be an avatar setting action we can use here.
+ final int iconId = bundle.getInt("icon_id", 0);
+ if (iconId == 0) {
+ UserManager userManager = (UserManager) getActivity().getSystemService(
+ Context.USER_SERVICE);
+ UserInfo info = Utils.getExistingUser(userManager, android.os.Process.myUserHandle());
+ controller.setLabel(info.name);
+ controller.setIcon(
+ com.android.settingslib.Utils.getUserIcon(getActivity(), userManager, info));
+ }
+
+ controller.done(context, true /* rebindActions */);
+ }
+
+ /**
+ * For Search.
+ */
+ public static final SearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
+ new BaseSearchIndexProvider() {
+
+ @Override
+ public List<SearchIndexableResource> getXmlResourcesToIndex(
+ Context context, boolean enabled) {
+ final SearchIndexableResource sir = new SearchIndexableResource(context);
+ sir.xmlResId = R.xml.my_device_info;
+ return Arrays.asList(sir);
+ }
+
+ @Override
+ public List<AbstractPreferenceController> getPreferenceControllers(
+ Context context) {
+ return buildPreferenceControllers(context, null /*activity */,
+ null /* fragment */, null /* lifecycle */);
+ }
+
+ @Override
+ public List<String> getNonIndexableKeys(Context context) {
+ List<String> keys = super.getNonIndexableKeys(context);
+ // The legal container is duplicated, so we ignore it here.
+ keys.add(KEY_LEGAL_CONTAINER);
+ return keys;
+ }
+ };
+}
diff --git a/src/com/android/settings/deviceinfo/storage/AutomaticStorageManagementSwitchPreferenceController.java b/src/com/android/settings/deviceinfo/storage/AutomaticStorageManagementSwitchPreferenceController.java
index 8ab21b3..717d765 100644
--- a/src/com/android/settings/deviceinfo/storage/AutomaticStorageManagementSwitchPreferenceController.java
+++ b/src/com/android/settings/deviceinfo/storage/AutomaticStorageManagementSwitchPreferenceController.java
@@ -25,12 +25,12 @@
import android.support.v7.preference.PreferenceScreen;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.settings.core.PreferenceControllerMixin;
+import com.android.settings.core.instrumentation.MetricsFeatureProvider;
import com.android.settings.deletionhelper.ActivationWarningFragment;
import com.android.settings.widget.MasterSwitchController;
import com.android.settings.widget.MasterSwitchPreference;
import com.android.settings.widget.SwitchWidgetController;
import com.android.settingslib.core.AbstractPreferenceController;
-import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
import com.android.settingslib.core.lifecycle.LifecycleObserver;
import com.android.settingslib.core.lifecycle.events.OnResume;
diff --git a/src/com/android/settings/deviceinfo/storage/StorageItemPreferenceController.java b/src/com/android/settings/deviceinfo/storage/StorageItemPreferenceController.java
index 3623298..1149b99 100644
--- a/src/com/android/settings/deviceinfo/storage/StorageItemPreferenceController.java
+++ b/src/com/android/settings/deviceinfo/storage/StorageItemPreferenceController.java
@@ -38,11 +38,11 @@
import com.android.settings.Utils;
import com.android.settings.applications.manageapplications.ManageApplications;
import com.android.settings.core.PreferenceControllerMixin;
+import com.android.settings.core.instrumentation.MetricsFeatureProvider;
import com.android.settings.deviceinfo.PrivateVolumeSettings.SystemInfoFragment;
import com.android.settings.deviceinfo.StorageItemPreference;
import com.android.settings.overlay.FeatureFactory;
import com.android.settingslib.core.AbstractPreferenceController;
-import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
import com.android.settingslib.deviceinfo.StorageMeasurement;
import com.android.settingslib.deviceinfo.StorageVolumeProvider;
diff --git a/src/com/android/settings/display/AmbientDisplayNotificationsPreferenceController.java b/src/com/android/settings/display/AmbientDisplayNotificationsPreferenceController.java
index f3d17d5..68a21ce 100644
--- a/src/com/android/settings/display/AmbientDisplayNotificationsPreferenceController.java
+++ b/src/com/android/settings/display/AmbientDisplayNotificationsPreferenceController.java
@@ -27,11 +27,11 @@
import com.android.internal.hardware.AmbientDisplayConfiguration;
import com.android.settings.R;
import com.android.settings.core.PreferenceControllerMixin;
+import com.android.settings.core.instrumentation.MetricsFeatureProvider;
import com.android.settings.search.DatabaseIndexingUtils;
import com.android.settings.search.InlineSwitchPayload;
import com.android.settings.search.ResultPayload;
import com.android.settingslib.core.AbstractPreferenceController;
-import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
public class AmbientDisplayNotificationsPreferenceController extends
AbstractPreferenceController implements PreferenceControllerMixin,
diff --git a/src/com/android/settings/display/AmbientDisplaySettings.java b/src/com/android/settings/display/AmbientDisplaySettings.java
index 187325c..24aede0 100644
--- a/src/com/android/settings/display/AmbientDisplaySettings.java
+++ b/src/com/android/settings/display/AmbientDisplaySettings.java
@@ -23,13 +23,13 @@
import com.android.internal.hardware.AmbientDisplayConfiguration;
import com.android.internal.logging.nano.MetricsProto;
import com.android.settings.R;
+import com.android.settings.core.instrumentation.MetricsFeatureProvider;
import com.android.settings.dashboard.DashboardFragment;
import com.android.settings.gestures.DoubleTapScreenPreferenceController;
import com.android.settings.gestures.PickupGesturePreferenceController;
import com.android.settings.search.BaseSearchIndexProvider;
import com.android.settings.search.Indexable;
import com.android.settingslib.core.AbstractPreferenceController;
-import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
import com.android.settingslib.core.lifecycle.Lifecycle;
import java.util.ArrayList;
diff --git a/src/com/android/settings/display/AutoRotatePreferenceController.java b/src/com/android/settings/display/AutoRotatePreferenceController.java
index 2134b88..c7f6af1 100644
--- a/src/com/android/settings/display/AutoRotatePreferenceController.java
+++ b/src/com/android/settings/display/AutoRotatePreferenceController.java
@@ -20,9 +20,9 @@
import com.android.internal.logging.nano.MetricsProto;
import com.android.internal.view.RotationPolicy;
import com.android.settings.core.PreferenceControllerMixin;
+import com.android.settings.core.instrumentation.MetricsFeatureProvider;
import com.android.settings.overlay.FeatureFactory;
import com.android.settingslib.core.AbstractPreferenceController;
-import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
import com.android.settingslib.core.lifecycle.Lifecycle;
import com.android.settingslib.core.lifecycle.LifecycleObserver;
import com.android.settingslib.core.lifecycle.events.OnPause;
diff --git a/src/com/android/settings/display/ThemePreferenceController.java b/src/com/android/settings/display/ThemePreferenceController.java
index 9c1314e..d1341dd74 100644
--- a/src/com/android/settings/display/ThemePreferenceController.java
+++ b/src/com/android/settings/display/ThemePreferenceController.java
@@ -29,9 +29,9 @@
import com.android.settings.R;
import com.android.settings.core.PreferenceControllerMixin;
+import com.android.settings.core.instrumentation.MetricsFeatureProvider;
import com.android.settings.overlay.FeatureFactory;
import com.android.settingslib.core.AbstractPreferenceController;
-import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
import libcore.util.Objects;
diff --git a/src/com/android/settings/fuelgauge/AdvancedPowerUsageDetail.java b/src/com/android/settings/fuelgauge/AdvancedPowerUsageDetail.java
index 819846a..de027a3 100644
--- a/src/com/android/settings/fuelgauge/AdvancedPowerUsageDetail.java
+++ b/src/com/android/settings/fuelgauge/AdvancedPowerUsageDetail.java
@@ -374,7 +374,7 @@
@Override
public void onLimitBackgroundActivity() {
- mBackgroundActivityPreferenceController.setUnchecked(
+ mBackgroundActivityPreferenceController.setRestricted(
findPreference(mBackgroundActivityPreferenceController.getPreferenceKey()));
}
}
diff --git a/src/com/android/settings/fuelgauge/AppButtonsPreferenceController.java b/src/com/android/settings/fuelgauge/AppButtonsPreferenceController.java
index a52433b..c034746 100644
--- a/src/com/android/settings/fuelgauge/AppButtonsPreferenceController.java
+++ b/src/com/android/settings/fuelgauge/AppButtonsPreferenceController.java
@@ -48,6 +48,7 @@
import com.android.settings.SettingsActivity;
import com.android.settings.Utils;
import com.android.settings.core.PreferenceControllerMixin;
+import com.android.settings.core.instrumentation.MetricsFeatureProvider;
import com.android.settings.overlay.FeatureFactory;
import com.android.settings.widget.ActionButtonPreference;
import com.android.settings.wrapper.DevicePolicyManagerWrapper;
@@ -55,7 +56,6 @@
import com.android.settingslib.applications.AppUtils;
import com.android.settingslib.applications.ApplicationsState;
import com.android.settingslib.core.AbstractPreferenceController;
-import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
import com.android.settingslib.core.lifecycle.Lifecycle;
import com.android.settingslib.core.lifecycle.LifecycleObserver;
import com.android.settingslib.core.lifecycle.events.OnDestroy;
diff --git a/src/com/android/settings/fuelgauge/BackgroundActivityPreferenceController.java b/src/com/android/settings/fuelgauge/BackgroundActivityPreferenceController.java
index 8286774..01e4182 100644
--- a/src/com/android/settings/fuelgauge/BackgroundActivityPreferenceController.java
+++ b/src/com/android/settings/fuelgauge/BackgroundActivityPreferenceController.java
@@ -43,12 +43,12 @@
* Controller to control whether an app can run in the background
*/
public class BackgroundActivityPreferenceController extends AbstractPreferenceController
- implements PreferenceControllerMixin, Preference.OnPreferenceChangeListener {
+ implements PreferenceControllerMixin {
private static final String TAG = "BgActivityPrefContr";
- private static final String KEY_BACKGROUND_ACTIVITY = "background_activity";
+ @VisibleForTesting
+ static final String KEY_BACKGROUND_ACTIVITY = "background_activity";
- private final PackageManager mPackageManager;
private final AppOpsManager mAppOpsManager;
private final UserManager mUserManager;
private final int mUid;
@@ -70,7 +70,6 @@
int uid, String packageName, PowerWhitelistBackend backend) {
super(context);
mPowerWhitelistBackend = backend;
- mPackageManager = context.getPackageManager();
mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
mDpm = new DevicePolicyManagerWrapper(
(DevicePolicyManager) context.getSystemService(Context.DEVICE_POLICY_SERVICE));
@@ -86,11 +85,6 @@
final int mode = mAppOpsManager
.checkOpNoThrow(AppOpsManager.OP_RUN_ANY_IN_BACKGROUND, mUid, mTargetPackage);
final boolean whitelisted = mPowerWhitelistBackend.isWhitelisted(mTargetPackage);
- // Set checked or not before we may set it disabled
- if (mode != AppOpsManager.MODE_ERRORED) {
- final boolean checked = whitelisted || mode != AppOpsManager.MODE_IGNORED;
- ((SwitchPreference) preference).setChecked(checked);
- }
if (whitelisted || mode == AppOpsManager.MODE_ERRORED
|| Utils.isProfileOrDeviceOwner(mUserManager, mDpm, mTargetPackage)) {
preference.setEnabled(false);
@@ -109,9 +103,8 @@
* Called from the warning dialog, if the user decides to go ahead and disable background
* activity for this package
*/
- public void setUnchecked(Preference preference) {
+ public void setRestricted(Preference preference) {
mBatteryUtils.setForceAppStandby(mUid, mTargetPackage, AppOpsManager.MODE_IGNORED);
- ((SwitchPreference) preference).setChecked(false);
updateSummary(preference);
}
@@ -121,17 +114,21 @@
}
@Override
- public boolean onPreferenceChange(Preference preference, Object newValue) {
- final boolean switchOn = (Boolean) newValue;
- if (!switchOn) {
- final WarningDialogFragment dialogFragment = new WarningDialogFragment();
- dialogFragment.setTargetFragment(mFragment, 0);
- dialogFragment.show(mFragment.getFragmentManager(), TAG);
- return false;
+ public boolean handlePreferenceTreeClick(Preference preference) {
+ if (KEY_BACKGROUND_ACTIVITY.equals(preference.getKey())) {
+ final int mode = mAppOpsManager
+ .checkOpNoThrow(AppOpsManager.OP_RUN_ANY_IN_BACKGROUND, mUid, mTargetPackage);
+ final boolean restricted = mode == AppOpsManager.MODE_IGNORED;
+ if (!restricted) {
+ showDialog();
+ return false;
+ }
+ mBatteryUtils.setForceAppStandby(mUid, mTargetPackage, AppOpsManager.MODE_ALLOWED);
+ updateSummary(preference);
+ return true;
}
- mBatteryUtils.setForceAppStandby(mUid, mTargetPackage, AppOpsManager.MODE_ALLOWED);
- updateSummary(preference);
- return true;
+
+ return false;
}
@VisibleForTesting
@@ -146,12 +143,19 @@
if (mode == AppOpsManager.MODE_ERRORED) {
preference.setSummary(R.string.background_activity_summary_disabled);
} else {
- final boolean checked = mode != AppOpsManager.MODE_IGNORED;
- preference.setSummary(checked ? R.string.background_activity_summary_on
- : R.string.background_activity_summary_off);
+ final boolean restricted = mode == AppOpsManager.MODE_IGNORED;
+ preference.setSummary(restricted ? R.string.restricted_true_label
+ : R.string.restricted_false_label);
}
}
+ @VisibleForTesting
+ void showDialog() {
+ final WarningDialogFragment dialogFragment = new WarningDialogFragment();
+ dialogFragment.setTargetFragment(mFragment, 0 /* requestCode */);
+ dialogFragment.show(mFragment.getFragmentManager(), TAG);
+ }
+
interface WarningConfirmationListener {
void onLimitBackgroundActivity();
}
diff --git a/src/com/android/settings/fuelgauge/BatteryAppListPreferenceController.java b/src/com/android/settings/fuelgauge/BatteryAppListPreferenceController.java
index 91f35e2..5d95dd2 100644
--- a/src/com/android/settings/fuelgauge/BatteryAppListPreferenceController.java
+++ b/src/com/android/settings/fuelgauge/BatteryAppListPreferenceController.java
@@ -49,10 +49,10 @@
import com.android.settings.core.FeatureFlags;
import com.android.settings.core.PreferenceControllerMixin;
import com.android.settings.Utils;
+import com.android.settings.core.instrumentation.MetricsFeatureProvider;
import com.android.settings.fuelgauge.anomaly.Anomaly;
import com.android.settings.overlay.FeatureFactory;
import com.android.settingslib.core.AbstractPreferenceController;
-import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
import com.android.settingslib.core.lifecycle.Lifecycle;
import com.android.settingslib.core.lifecycle.LifecycleObserver;
import com.android.settingslib.core.lifecycle.events.OnDestroy;
diff --git a/src/com/android/settings/fuelgauge/BatteryInfo.java b/src/com/android/settings/fuelgauge/BatteryInfo.java
index acd8144..c4c795b 100644
--- a/src/com/android/settings/fuelgauge/BatteryInfo.java
+++ b/src/com/android/settings/fuelgauge/BatteryInfo.java
@@ -272,7 +272,7 @@
void onParsingDone();
}
- private static void parse(BatteryStats stats, BatteryDataParser... parsers) {
+ public static void parse(BatteryStats stats, BatteryDataParser... parsers) {
long startWalltime = 0;
long endWalltime = 0;
long historyStart = 0;
diff --git a/src/com/android/settings/fuelgauge/PowerUsageSummary.java b/src/com/android/settings/fuelgauge/PowerUsageSummary.java
index e0954e5..ec54291 100644
--- a/src/com/android/settings/fuelgauge/PowerUsageSummary.java
+++ b/src/com/android/settings/fuelgauge/PowerUsageSummary.java
@@ -47,6 +47,7 @@
import com.android.settings.Utils;
import com.android.settings.applications.LayoutPreference;
import com.android.settings.applications.manageapplications.ManageApplications;
+import com.android.settings.core.instrumentation.MetricsFeatureProvider;
import com.android.settings.dashboard.SummaryLoader;
import com.android.settings.display.AmbientDisplayPreferenceController;
import com.android.settings.display.AutoBrightnessPreferenceController;
@@ -60,7 +61,6 @@
import com.android.settings.overlay.FeatureFactory;
import com.android.settings.search.BaseSearchIndexProvider;
import com.android.settingslib.core.AbstractPreferenceController;
-import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
import com.android.settingslib.core.lifecycle.Lifecycle;
import java.util.ArrayList;
diff --git a/src/com/android/settings/fuelgauge/PowerUsageSummaryLegacy.java b/src/com/android/settings/fuelgauge/PowerUsageSummaryLegacy.java
index 605591d..c50d580 100644
--- a/src/com/android/settings/fuelgauge/PowerUsageSummaryLegacy.java
+++ b/src/com/android/settings/fuelgauge/PowerUsageSummaryLegacy.java
@@ -54,6 +54,7 @@
import com.android.settings.Utils;
import com.android.settings.applications.LayoutPreference;
import com.android.settings.applications.manageapplications.ManageApplications;
+import com.android.settings.core.instrumentation.MetricsFeatureProvider;
import com.android.settings.dashboard.SummaryLoader;
import com.android.settings.display.AmbientDisplayPreferenceController;
import com.android.settings.display.AutoBrightnessPreferenceController;
@@ -66,7 +67,6 @@
import com.android.settings.fuelgauge.anomaly.AnomalySummaryPreferenceController;
import com.android.settings.fuelgauge.anomaly.AnomalyUtils;
import com.android.settings.overlay.FeatureFactory;
-import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
import com.android.settingslib.core.AbstractPreferenceController;
import java.util.ArrayList;
diff --git a/src/com/android/settings/fuelgauge/RestrictedAppDetails.java b/src/com/android/settings/fuelgauge/RestrictedAppDetails.java
index bdaaa3a..e09a8a3 100644
--- a/src/com/android/settings/fuelgauge/RestrictedAppDetails.java
+++ b/src/com/android/settings/fuelgauge/RestrictedAppDetails.java
@@ -20,11 +20,9 @@
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
-import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.os.UserHandle;
import android.support.v14.preference.PreferenceFragment;
-import android.support.v14.preference.SwitchPreference;
import android.support.v7.preference.CheckBoxPreference;
import android.support.v7.preference.Preference;
import android.support.v7.preference.PreferenceGroup;
@@ -36,9 +34,7 @@
import com.android.settings.SettingsActivity;
import com.android.settings.Utils;
import com.android.settings.dashboard.DashboardFragment;
-import com.android.settings.fuelgauge.anomaly.Anomaly;
-import com.android.settings.fuelgauge.anomaly.AnomalyDialogFragment;
-import com.android.settings.fuelgauge.anomaly.AnomalyPreference;
+import com.android.settings.widget.AppCheckBoxPreference;
import com.android.settingslib.core.AbstractPreferenceController;
import java.util.List;
@@ -120,7 +116,7 @@
final Context context = getPrefContext();
for (int i = 0, size = mPackageOpsList.size(); i < size; i++) {
- final CheckBoxPreference checkBoxPreference = new CheckBoxPreference(context);
+ final CheckBoxPreference checkBoxPreference = new AppCheckBoxPreference(context);
final AppOpsManager.PackageOps packageOps = mPackageOpsList.get(i);
try {
final ApplicationInfo applicationInfo = mPackageManager.getApplicationInfo(
@@ -128,6 +124,10 @@
checkBoxPreference.setChecked(true);
checkBoxPreference.setTitle(mPackageManager.getApplicationLabel(applicationInfo));
checkBoxPreference.setKey(packageOps.getPackageName());
+ checkBoxPreference.setIcon(
+ Utils.getBadgedIcon(mIconDrawableFactory, mPackageManager,
+ packageOps.getPackageName(),
+ UserHandle.getUserId(packageOps.getUid())));
checkBoxPreference.setOnPreferenceChangeListener((pref, value) -> {
// change the toggle
final int mode = (Boolean) value ? AppOpsManager.MODE_IGNORED
diff --git a/src/com/android/settings/fuelgauge/anomaly/AnomalyUtils.java b/src/com/android/settings/fuelgauge/anomaly/AnomalyUtils.java
index 3dde95e..39d51dc0 100644
--- a/src/com/android/settings/fuelgauge/anomaly/AnomalyUtils.java
+++ b/src/com/android/settings/fuelgauge/anomaly/AnomalyUtils.java
@@ -24,6 +24,7 @@
import com.android.internal.logging.nano.MetricsProto;
import com.android.internal.os.BatteryStatsHelper;
+import com.android.settings.core.instrumentation.MetricsFeatureProvider;
import com.android.settings.fuelgauge.anomaly.action.AnomalyAction;
import com.android.settings.fuelgauge.anomaly.action.ForceStopAction;
import com.android.settings.fuelgauge.anomaly.action.LocationCheckAction;
@@ -32,7 +33,6 @@
import com.android.settings.fuelgauge.anomaly.checker.BluetoothScanAnomalyDetector;
import com.android.settings.fuelgauge.anomaly.checker.WakeLockAnomalyDetector;
import com.android.settings.fuelgauge.anomaly.checker.WakeupAlarmAnomalyDetector;
-import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
import java.util.ArrayList;
import java.util.List;
diff --git a/src/com/android/settings/fuelgauge/anomaly/action/AnomalyAction.java b/src/com/android/settings/fuelgauge/anomaly/action/AnomalyAction.java
index d7de5a7..3ee89d1 100644
--- a/src/com/android/settings/fuelgauge/anomaly/action/AnomalyAction.java
+++ b/src/com/android/settings/fuelgauge/anomaly/action/AnomalyAction.java
@@ -20,9 +20,9 @@
import android.util.Pair;
import com.android.internal.logging.nano.MetricsProto;
+import com.android.settings.core.instrumentation.MetricsFeatureProvider;
import com.android.settings.fuelgauge.anomaly.Anomaly;
import com.android.settings.overlay.FeatureFactory;
-import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
/**
* Abstract class for anomaly action, which is triggered if we need to handle the anomaly
diff --git a/src/com/android/settings/fuelgauge/batterytip/BatteryTipPolicy.java b/src/com/android/settings/fuelgauge/batterytip/BatteryTipPolicy.java
index 6af859b..a580db1 100644
--- a/src/com/android/settings/fuelgauge/batterytip/BatteryTipPolicy.java
+++ b/src/com/android/settings/fuelgauge/batterytip/BatteryTipPolicy.java
@@ -19,9 +19,12 @@
import android.content.Context;
import android.provider.Settings;
import android.support.annotation.VisibleForTesting;
+import android.text.format.DateUtils;
import android.util.KeyValueListParser;
import android.util.Log;
+import java.time.Duration;
+
/**
* Class to store the policy for battery tips, which comes from
* {@link Settings.Global}
@@ -34,6 +37,8 @@
private static final String KEY_BATTERY_SAVER_TIP_ENABLED = "battery_saver_tip_enabled";
private static final String KEY_HIGH_USAGE_ENABLED = "high_usage_enabled";
private static final String KEY_HIGH_USAGE_APP_COUNT = "high_usage_app_count";
+ private static final String KEY_HIGH_USAGE_PERIOD_MS = "high_usage_period_ms";
+ private static final String KEY_HIGH_USAGE_BATTERY_DRAINING = "high_usage_battery_draining";
private static final String KEY_APP_RESTRICTION_ENABLED = "app_restriction_enabled";
private static final String KEY_REDUCED_BATTERY_ENABLED = "reduced_battery_enabled";
private static final String KEY_REDUCED_BATTERY_PERCENT = "reduced_battery_percent";
@@ -81,6 +86,24 @@
public final int highUsageAppCount;
/**
+ * The size of the window(milliseconds) for checking if the device is being heavily used
+ *
+ * @see Settings.Global#BATTERY_TIP_CONSTANTS
+ * @see #KEY_HIGH_USAGE_PERIOD_MS
+ */
+ public final long highUsagePeriodMs;
+
+ /**
+ * The battery draining threshold to detect whether device is heavily used.
+ * If battery drains more than {@link #highUsageBatteryDraining} in last {@link
+ * #highUsagePeriodMs}, treat device as heavily used.
+ *
+ * @see Settings.Global#BATTERY_TIP_CONSTANTS
+ * @see #KEY_HIGH_USAGE_BATTERY_DRAINING
+ */
+ public final int highUsageBatteryDraining;
+
+ /**
* {@code true} if app restriction tip is enabled
*
* @see Settings.Global#BATTERY_TIP_CONSTANTS
@@ -143,6 +166,9 @@
batterySaverTipEnabled = mParser.getBoolean(KEY_BATTERY_SAVER_TIP_ENABLED, true);
highUsageEnabled = mParser.getBoolean(KEY_HIGH_USAGE_ENABLED, true);
highUsageAppCount = mParser.getInt(KEY_HIGH_USAGE_APP_COUNT, 3);
+ highUsagePeriodMs = mParser.getLong(KEY_HIGH_USAGE_PERIOD_MS,
+ Duration.ofHours(2).toMillis());
+ highUsageBatteryDraining = mParser.getInt(KEY_HIGH_USAGE_BATTERY_DRAINING, 25);
appRestrictionEnabled = mParser.getBoolean(KEY_APP_RESTRICTION_ENABLED, true);
reducedBatteryEnabled = mParser.getBoolean(KEY_REDUCED_BATTERY_ENABLED, false);
reducedBatteryPercent = mParser.getInt(KEY_REDUCED_BATTERY_PERCENT, 50);
diff --git a/src/com/android/settings/fuelgauge/batterytip/HighUsageDataParser.java b/src/com/android/settings/fuelgauge/batterytip/HighUsageDataParser.java
new file mode 100644
index 0000000..cc5aed6
--- /dev/null
+++ b/src/com/android/settings/fuelgauge/batterytip/HighUsageDataParser.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2018 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.fuelgauge.batterytip;
+
+import android.os.BatteryStats;
+
+import com.android.settings.fuelgauge.BatteryInfo;
+
+/**
+ * DataParser used to go through battery data and detect whether battery is
+ * heavily used.
+ */
+public class HighUsageDataParser implements BatteryInfo.BatteryDataParser {
+ /**
+ * time period to check the battery usage
+ */
+ private final long mTimePeriodMs;
+ /**
+ * treat device as heavily used if battery usage is more than {@code threshold}. 1 means 1%
+ * battery usage.
+ */
+ private int mThreshold;
+ private long mEndTimeMs;
+ private byte mEndBatteryLevel;
+ private byte mLastPeriodBatteryLevel;
+ private int mBatteryDrain;
+
+ public HighUsageDataParser(long timePeriodMs, int threshold) {
+ mTimePeriodMs = timePeriodMs;
+ mThreshold = threshold;
+ }
+
+ @Override
+ public void onParsingStarted(long startTime, long endTime) {
+ mEndTimeMs = endTime;
+ }
+
+ @Override
+ public void onDataPoint(long time, BatteryStats.HistoryItem record) {
+ if (record.currentTime <= mEndTimeMs - mTimePeriodMs) {
+ // Since onDataPoint is invoked sorted by time, so we could use this way to get the
+ // closet battery level 'mTimePeriodMs' time ago.
+ mLastPeriodBatteryLevel = record.batteryLevel;
+ }
+ mEndBatteryLevel = record.batteryLevel;
+ }
+
+ @Override
+ public void onDataGap() {
+ // do nothing
+ }
+
+ @Override
+ public void onParsingDone() {
+ mBatteryDrain = mLastPeriodBatteryLevel - mEndBatteryLevel;
+ }
+
+ /**
+ * Return {@code true} if the battery drain in {@link #mTimePeriodMs} is too much
+ */
+ public boolean isDeviceHeavilyUsed() {
+ return mBatteryDrain > mThreshold;
+ }
+}
+
diff --git a/src/com/android/settings/fuelgauge/batterytip/actions/BatteryTipAction.java b/src/com/android/settings/fuelgauge/batterytip/actions/BatteryTipAction.java
index 1bf08b7..9fa69fd 100644
--- a/src/com/android/settings/fuelgauge/batterytip/actions/BatteryTipAction.java
+++ b/src/com/android/settings/fuelgauge/batterytip/actions/BatteryTipAction.java
@@ -18,7 +18,7 @@
import android.content.Context;
-import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
+import com.android.settings.core.instrumentation.MetricsFeatureProvider;
/**
* Abstract class for battery tip action, which is triggered if we need to handle the battery tip
diff --git a/src/com/android/settings/fuelgauge/batterytip/actions/SmartBatteryAction.java b/src/com/android/settings/fuelgauge/batterytip/actions/SmartBatteryAction.java
index cbd1581..a19471e 100644
--- a/src/com/android/settings/fuelgauge/batterytip/actions/SmartBatteryAction.java
+++ b/src/com/android/settings/fuelgauge/batterytip/actions/SmartBatteryAction.java
@@ -22,8 +22,8 @@
import com.android.settings.R;
import com.android.settings.SettingsActivity;
+import com.android.settings.core.instrumentation.MetricsFeatureProvider;
import com.android.settings.fuelgauge.SmartBatterySettings;
-import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
public class SmartBatteryAction extends BatteryTipAction {
private SettingsActivity mSettingsActivity;
diff --git a/src/com/android/settings/fuelgauge/batterytip/detectors/HighUsageDetector.java b/src/com/android/settings/fuelgauge/batterytip/detectors/HighUsageDetector.java
index 3c69667..ed3fa04 100644
--- a/src/com/android/settings/fuelgauge/batterytip/detectors/HighUsageDetector.java
+++ b/src/com/android/settings/fuelgauge/batterytip/detectors/HighUsageDetector.java
@@ -19,13 +19,14 @@
import android.content.Context;
import android.os.BatteryStats;
import android.support.annotation.VisibleForTesting;
-import android.text.format.DateUtils;
import com.android.internal.os.BatterySipper;
import com.android.internal.os.BatteryStatsHelper;
import com.android.settings.fuelgauge.BatteryUtils;
import com.android.settings.fuelgauge.batterytip.BatteryTipPolicy;
import com.android.settings.fuelgauge.batterytip.AppInfo;
+import com.android.settings.fuelgauge.BatteryInfo;
+import com.android.settings.fuelgauge.batterytip.HighUsageDataParser;
import com.android.settings.fuelgauge.batterytip.tips.BatteryTip;
import com.android.settings.fuelgauge.batterytip.tips.HighUsageTip;
@@ -43,6 +44,8 @@
private List<AppInfo> mHighUsageAppList;
private Context mContext;
@VisibleForTesting
+ HighUsageDataParser mDataParser;
+ @VisibleForTesting
BatteryUtils mBatteryUtils;
public HighUsageDetector(Context context, BatteryTipPolicy policy,
@@ -52,32 +55,42 @@
mBatteryStatsHelper = batteryStatsHelper;
mHighUsageAppList = new ArrayList<>();
mBatteryUtils = BatteryUtils.getInstance(context);
+ mDataParser = new HighUsageDataParser(mPolicy.highUsagePeriodMs,
+ mPolicy.highUsageBatteryDraining);
}
@Override
public BatteryTip detect() {
final long screenUsageTimeMs = mBatteryUtils.calculateScreenUsageTime(mBatteryStatsHelper);
- //TODO(b/70570352): Change it to detect whether battery drops 25% in last 2 hours
- if (mPolicy.highUsageEnabled && screenUsageTimeMs > DateUtils.HOUR_IN_MILLIS) {
- final List<BatterySipper> batterySippers = mBatteryStatsHelper.getUsageList();
- for (int i = 0, size = batterySippers.size(); i < size; i++) {
- final BatterySipper batterySipper = batterySippers.get(i);
- if (!mBatteryUtils.shouldHideSipper(batterySipper)) {
- final long foregroundTimeMs = mBatteryUtils.getProcessTimeMs(
- BatteryUtils.StatusType.FOREGROUND, batterySipper.uidObj,
- BatteryStats.STATS_SINCE_CHARGED);
- mHighUsageAppList.add(new AppInfo.Builder()
- .setPackageName(mBatteryUtils.getPackageName(batterySipper.getUid()))
- .setScreenOnTimeMs(foregroundTimeMs)
- .build());
+ if (mPolicy.highUsageEnabled) {
+ parseBatteryData();
+ if (mDataParser.isDeviceHeavilyUsed()) {
+ final List<BatterySipper> batterySippers = mBatteryStatsHelper.getUsageList();
+ for (int i = 0, size = batterySippers.size(); i < size; i++) {
+ final BatterySipper batterySipper = batterySippers.get(i);
+ if (!mBatteryUtils.shouldHideSipper(batterySipper)) {
+ final long foregroundTimeMs = mBatteryUtils.getProcessTimeMs(
+ BatteryUtils.StatusType.FOREGROUND, batterySipper.uidObj,
+ BatteryStats.STATS_SINCE_CHARGED);
+ mHighUsageAppList.add(new AppInfo.Builder()
+ .setPackageName(
+ mBatteryUtils.getPackageName(batterySipper.getUid()))
+ .setScreenOnTimeMs(foregroundTimeMs)
+ .build());
+ }
}
- }
- mHighUsageAppList = mHighUsageAppList.subList(0,
- Math.min(mPolicy.highUsageAppCount, mHighUsageAppList.size()));
- Collections.sort(mHighUsageAppList, Collections.reverseOrder());
+ mHighUsageAppList = mHighUsageAppList.subList(0,
+ Math.min(mPolicy.highUsageAppCount, mHighUsageAppList.size()));
+ Collections.sort(mHighUsageAppList, Collections.reverseOrder());
+ }
}
return new HighUsageTip(screenUsageTimeMs, mHighUsageAppList);
}
+
+ @VisibleForTesting
+ void parseBatteryData() {
+ BatteryInfo.parse(mBatteryStatsHelper.getStats(), mDataParser);
+ }
}
diff --git a/src/com/android/settings/inputmethod/UserDictionarySettings.java b/src/com/android/settings/inputmethod/UserDictionarySettings.java
index 3bbc581..9680af1 100644
--- a/src/com/android/settings/inputmethod/UserDictionarySettings.java
+++ b/src/com/android/settings/inputmethod/UserDictionarySettings.java
@@ -42,11 +42,10 @@
import android.widget.TextView;
import com.android.internal.logging.nano.MetricsProto;
-import com.android.settings.overlay.FeatureFactory;
import com.android.settings.R;
import com.android.settings.SettingsActivity;
-import com.android.settingslib.core.instrumentation.Instrumentable;
-import com.android.settingslib.core.instrumentation.VisibilityLoggerMixin;
+import com.android.settings.core.instrumentation.Instrumentable;
+import com.android.settings.core.instrumentation.VisibilityLoggerMixin;
public class UserDictionarySettings extends ListFragment implements Instrumentable,
LoaderManager.LoaderCallbacks<Cursor> {
@@ -60,7 +59,8 @@
private static final int OPTIONS_MENU_ADD = Menu.FIRST;
private static final int LOADER_ID = 1;
- private VisibilityLoggerMixin mVisibilityLoggerMixin;
+ private final VisibilityLoggerMixin mVisibilityLoggerMixin =
+ new VisibilityLoggerMixin(getMetricsCategory());
private Cursor mCursor;
private String mLocale;
@@ -71,12 +71,15 @@
}
@Override
+ public void onAttach(Context context) {
+ super.onAttach(context);
+ mVisibilityLoggerMixin.onAttach(context);
+ }
+
+ @Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- mVisibilityLoggerMixin = new VisibilityLoggerMixin(getMetricsCategory(),
- FeatureFactory.getFactory(getContext()).getMetricsFeatureProvider());
-
final Intent intent = getActivity().getIntent();
final String localeFromIntent =
null == intent ? null : intent.getStringExtra("locale");
diff --git a/src/com/android/settings/location/LocationEnabler.java b/src/com/android/settings/location/LocationEnabler.java
index 4dcdac0..28ee213 100644
--- a/src/com/android/settings/location/LocationEnabler.java
+++ b/src/com/android/settings/location/LocationEnabler.java
@@ -34,8 +34,10 @@
import com.android.settingslib.core.lifecycle.events.OnResume;
import static com.android.settingslib.Utils.updateLocationMode;
+import static com.android.settingslib.Utils.updateLocationEnabled;
import static com.android.settingslib.RestrictedLockUtils.checkIfRestrictionEnforced;
+
/**
* A class that listens to location settings change and modifies location settings
* settings.
@@ -106,6 +108,25 @@
}
}
+ void setLocationEnabled(boolean enabled) {
+ final int currentMode = Settings.Secure.getInt(mContext.getContentResolver(),
+ Settings.Secure.LOCATION_MODE, Settings.Secure.LOCATION_MODE_OFF);
+
+ if (isRestricted()) {
+ // Location toggling disabled by user restriction. Read the current location mode to
+ // update the location master switch.
+ if (Log.isLoggable(TAG, Log.INFO)) {
+ Log.i(TAG, "Restricted user, not setting location mode");
+ }
+ if (mListener != null) {
+ mListener.onLocationModeChanged(currentMode, true);
+ }
+ return;
+ }
+ updateLocationEnabled(mContext, enabled, UserHandle.myUserId());
+ refreshLocationMode();
+ }
+
void setLocationMode(int mode) {
final int currentMode = Settings.Secure.getInt(mContext.getContentResolver(),
Settings.Secure.LOCATION_MODE, Settings.Secure.LOCATION_MODE_OFF);
diff --git a/src/com/android/settings/location/LocationSettings.java b/src/com/android/settings/location/LocationSettings.java
index d0fca16..85c049d 100644
--- a/src/com/android/settings/location/LocationSettings.java
+++ b/src/com/android/settings/location/LocationSettings.java
@@ -47,15 +47,8 @@
* <ul>
* <li>Platform location controls</li>
* <ul>
- * <li>In switch bar: location master switch. Used to toggle
- * {@link android.provider.Settings.Secure#LOCATION_MODE} between
- * {@link android.provider.Settings.Secure#LOCATION_MODE_OFF} and another location mode.
+ * <li>In switch bar: location master switch. Used to toggle location on and off.
* </li>
- * <li>Mode preference: only available if the master switch is on, selects between
- * {@link android.provider.Settings.Secure#LOCATION_MODE} of
- * {@link android.provider.Settings.Secure#LOCATION_MODE_HIGH_ACCURACY},
- * {@link android.provider.Settings.Secure#LOCATION_MODE_BATTERY_SAVING}, or
- * {@link android.provider.Settings.Secure#LOCATION_MODE_SENSORS_ONLY}.</li>
* </ul>
* <li>Recent location requests: automatically populated by {@link RecentLocationApps}</li>
* <li>Location services: multi-app settings provided from outside the Android framework. Each
diff --git a/src/com/android/settings/location/LocationSwitchBarController.java b/src/com/android/settings/location/LocationSwitchBarController.java
index 6522dc7..ca1932f 100644
--- a/src/com/android/settings/location/LocationSwitchBarController.java
+++ b/src/com/android/settings/location/LocationSwitchBarController.java
@@ -96,9 +96,6 @@
*/
@Override
public void onSwitchChanged(Switch switchView, boolean isChecked) {
- mLocationEnabler.setLocationMode(isChecked
- ? android.provider.Settings.Secure.LOCATION_MODE_PREVIOUS
- : android.provider.Settings.Secure.LOCATION_MODE_OFF);
+ mLocationEnabler.setLocationEnabled(isChecked);
}
-
}
diff --git a/src/com/android/settings/network/AirplaneModePreferenceController.java b/src/com/android/settings/network/AirplaneModePreferenceController.java
index 0b77179..17cf211 100644
--- a/src/com/android/settings/network/AirplaneModePreferenceController.java
+++ b/src/com/android/settings/network/AirplaneModePreferenceController.java
@@ -28,10 +28,10 @@
import com.android.internal.telephony.TelephonyProperties;
import com.android.settings.AirplaneModeEnabler;
import com.android.settings.core.PreferenceControllerMixin;
+import com.android.settings.core.instrumentation.MetricsFeatureProvider;
import com.android.settings.overlay.FeatureFactory;
import com.android.settings.R;
import com.android.settingslib.core.AbstractPreferenceController;
-import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
import com.android.settingslib.core.lifecycle.LifecycleObserver;
import com.android.settingslib.core.lifecycle.events.OnPause;
import com.android.settingslib.core.lifecycle.events.OnResume;
diff --git a/src/com/android/settings/network/NetworkDashboardFragment.java b/src/com/android/settings/network/NetworkDashboardFragment.java
index 74c1910..4b1da31 100644
--- a/src/com/android/settings/network/NetworkDashboardFragment.java
+++ b/src/com/android/settings/network/NetworkDashboardFragment.java
@@ -31,13 +31,13 @@
import com.android.internal.logging.nano.MetricsProto;
import com.android.settings.R;
+import com.android.settings.core.instrumentation.MetricsFeatureProvider;
import com.android.settings.dashboard.DashboardFragment;
import com.android.settings.dashboard.SummaryLoader;
import com.android.settings.network.MobilePlanPreferenceController.MobilePlanPreferenceHost;
import com.android.settings.search.BaseSearchIndexProvider;
import com.android.settings.wifi.WifiMasterSwitchPreferenceController;
import com.android.settingslib.core.AbstractPreferenceController;
-import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
import com.android.settingslib.core.lifecycle.Lifecycle;
import java.util.ArrayList;
diff --git a/src/com/android/settings/notification/AbstractZenModePreferenceController.java b/src/com/android/settings/notification/AbstractZenModePreferenceController.java
index 9180791..81ceca1 100644
--- a/src/com/android/settings/notification/AbstractZenModePreferenceController.java
+++ b/src/com/android/settings/notification/AbstractZenModePreferenceController.java
@@ -34,9 +34,9 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.settings.core.PreferenceControllerMixin;
+import com.android.settings.core.instrumentation.MetricsFeatureProvider;
import com.android.settings.overlay.FeatureFactory;
import com.android.settingslib.core.AbstractPreferenceController;
-import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
import com.android.settingslib.core.lifecycle.Lifecycle;
import com.android.settingslib.core.lifecycle.LifecycleObserver;
import com.android.settingslib.core.lifecycle.events.OnPause;
diff --git a/src/com/android/settings/notification/AppNotificationSettings.java b/src/com/android/settings/notification/AppNotificationSettings.java
index ef0f40b..333e060 100644
--- a/src/com/android/settings/notification/AppNotificationSettings.java
+++ b/src/com/android/settings/notification/AppNotificationSettings.java
@@ -176,15 +176,6 @@
} else {
groupCategory.setTitle(group.getName());
groupCategory.setKey(group.getId());
- Bundle groupArgs = new Bundle();
- groupArgs.putInt(AppInfoBase.ARG_PACKAGE_UID, mUid);
- groupArgs.putString(AppInfoBase.ARG_PACKAGE_NAME, mPkg);
- groupArgs.putString(Settings.EXTRA_CHANNEL_GROUP_ID, group.getId());
- Intent channelIntent = Utils.onBuildStartFragmentIntent(getActivity(),
- ChannelGroupNotificationSettings.class.getName(),
- groupArgs, null, R.string.notification_group_title,
- null, false, getMetricsCategory());
- groupCategory.setIntent(channelIntent);
populateGroupToggle(groupCategory, group);
}
diff --git a/src/com/android/settings/notification/ConfigureNotificationSettings.java b/src/com/android/settings/notification/ConfigureNotificationSettings.java
index 2533466..7cfa124 100644
--- a/src/com/android/settings/notification/ConfigureNotificationSettings.java
+++ b/src/com/android/settings/notification/ConfigureNotificationSettings.java
@@ -17,6 +17,8 @@
package com.android.settings.notification;
import android.app.Activity;
+import android.app.Application;
+import android.app.Fragment;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
@@ -77,11 +79,18 @@
@Override
protected List<AbstractPreferenceController> getPreferenceControllers(Context context) {
- return buildPreferenceControllers(context, getLifecycle());
+ final Activity activity = getActivity();
+ final Application app;
+ if (activity != null) {
+ app = activity.getApplication();
+ } else {
+ app = null;
+ }
+ return buildPreferenceControllers(context, getLifecycle(), app, this);
}
private static List<AbstractPreferenceController> buildPreferenceControllers(Context context,
- Lifecycle lifecycle) {
+ Lifecycle lifecycle, Application app, Fragment host) {
final List<AbstractPreferenceController> controllers = new ArrayList<>();
final BadgingNotificationPreferenceController badgeController =
new BadgingNotificationPreferenceController(context);
@@ -96,6 +105,8 @@
lifecycle.addObserver(pulseController);
lifecycle.addObserver(lockScreenNotificationController);
}
+ controllers.add(new RecentNotifyingAppsPreferenceController(
+ context, new NotificationBackend(), app, host));
controllers.add(new SwipeToNotificationPreferenceController(context, lifecycle,
KEY_SWIPE_DOWN));
controllers.add(badgeController);
@@ -167,7 +178,7 @@
@Override
public List<AbstractPreferenceController> getPreferenceControllers(
Context context) {
- return buildPreferenceControllers(context, null);
+ return buildPreferenceControllers(context, null, null, null);
}
@Override
diff --git a/src/com/android/settings/notification/EnableZenModeDialog.java b/src/com/android/settings/notification/EnableZenModeDialog.java
new file mode 100644
index 0000000..f683a21
--- /dev/null
+++ b/src/com/android/settings/notification/EnableZenModeDialog.java
@@ -0,0 +1,467 @@
+package com.android.settings.notification;
+
+/*
+ * Copyright (C) 2018 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.
+ */
+
+import static android.util.Log.wtf;
+
+import android.app.Activity;
+import android.app.ActivityManager;
+import android.app.AlarmManager;
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.app.NotificationManager;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.net.Uri;
+import android.os.Bundle;
+import android.provider.Settings;
+import android.service.notification.Condition;
+import android.service.notification.ZenModeConfig;
+import android.text.TextUtils;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.CompoundButton;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.RadioButton;
+import android.widget.RadioGroup;
+import android.widget.ScrollView;
+import android.widget.TextView;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.nano.MetricsProto;
+import com.android.settings.R;
+import com.android.settings.core.instrumentation.InstrumentedDialogFragment;
+
+import java.util.Arrays;
+import java.util.Calendar;
+import java.util.GregorianCalendar;
+import java.util.Objects;
+
+public class EnableZenModeDialog extends InstrumentedDialogFragment {
+
+ private static final String TAG = "EnableZenModeDialog";
+ private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+
+ private static final int[] MINUTE_BUCKETS = ZenModeConfig.MINUTE_BUCKETS;
+ private static final int MIN_BUCKET_MINUTES = MINUTE_BUCKETS[0];
+ private static final int MAX_BUCKET_MINUTES = MINUTE_BUCKETS[MINUTE_BUCKETS.length - 1];
+ private static final int DEFAULT_BUCKET_INDEX = Arrays.binarySearch(MINUTE_BUCKETS, 60);
+
+ @VisibleForTesting
+ public static final int FOREVER_CONDITION_INDEX = 0;
+ @VisibleForTesting
+ public static final int COUNTDOWN_CONDITION_INDEX = 1;
+ @VisibleForTesting
+ public static final int COUNTDOWN_ALARM_CONDITION_INDEX = 2;
+ @VisibleForTesting
+ protected Activity mActivity;
+
+ private static final int SECONDS_MS = 1000;
+ private static final int MINUTES_MS = 60 * SECONDS_MS;
+
+ @VisibleForTesting
+ protected Uri mForeverId;
+ private int mBucketIndex = -1;
+
+ private AlarmManager mAlarmManager;
+ private int mUserId;
+ private boolean mAttached;
+
+ @VisibleForTesting
+ protected Context mContext;
+
+ private RadioGroup mZenRadioGroup;
+ @VisibleForTesting
+ protected LinearLayout mZenRadioGroupContent;
+ private int MAX_MANUAL_DND_OPTIONS = 3;
+
+ @Override
+ public Dialog onCreateDialog(Bundle savedInstanceState) {
+ NotificationManager noMan = (NotificationManager) getContext().
+ getSystemService(Context.NOTIFICATION_SERVICE);
+ mContext = getContext();
+ mForeverId = Condition.newId(mContext).appendPath("forever").build();
+ mAlarmManager = (AlarmManager) getContext().getSystemService(Context.ALARM_SERVICE);
+ mUserId = mContext.getUserId();
+ mAttached = false;
+
+ final AlertDialog.Builder builder = new AlertDialog.Builder(getContext())
+ .setTitle(R.string.zen_mode_settings_turn_on_dialog_title)
+ .setNegativeButton(R.string.cancel, null)
+ .setPositiveButton(R.string.zen_mode_enable_dialog_turn_on,
+ new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ int checkedId = mZenRadioGroup.getCheckedRadioButtonId();
+ ConditionTag tag = getConditionTagAt(checkedId);
+
+ if (isForever(tag.condition)) {
+ MetricsLogger.action(getContext(),
+ MetricsProto.MetricsEvent.
+ NOTIFICATION_ZEN_MODE_TOGGLE_ON_FOREVER);
+ } else if (isAlarm(tag.condition)) {
+ MetricsLogger.action(getContext(),
+ MetricsProto.MetricsEvent.
+ NOTIFICATION_ZEN_MODE_TOGGLE_ON_ALARM);
+ } else if (isCountdown(tag.condition)) {
+ MetricsLogger.action(getContext(),
+ MetricsProto.MetricsEvent.
+ NOTIFICATION_ZEN_MODE_TOGGLE_ON_COUNTDOWN);
+ } else {
+ wtf(TAG, "Invalid manual condition: " + tag.condition);
+ }
+ // always triggers priority-only dnd with chosen condition
+ noMan.setZenMode(Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS,
+ getRealConditionId(tag.condition), TAG);
+ }
+ });
+
+ View contentView = getContentView();
+ bindConditions(forever());
+ builder.setView(contentView);
+ return builder.create();
+ }
+
+ private void hideAllConditions() {
+ final int N = mZenRadioGroupContent.getChildCount();
+ for (int i = 0; i < N; i++) {
+ mZenRadioGroupContent.getChildAt(i).setVisibility(View.GONE);
+ }
+ }
+
+ protected View getContentView() {
+ if (mActivity == null) {
+ mActivity = getActivity();
+ }
+ final LayoutInflater inflater = mActivity.getLayoutInflater();
+ View contentView = inflater.inflate(R.layout.zen_mode_turn_on_dialog_container, null);
+ ScrollView container = (ScrollView) contentView.findViewById(R.id.container);
+
+ mZenRadioGroup = container.findViewById(R.id.zen_radio_buttons);
+ mZenRadioGroupContent = container.findViewById(R.id.zen_radio_buttons_content);
+
+ for (int i = 0; i < MAX_MANUAL_DND_OPTIONS; i++) {
+ final View radioButton = inflater.inflate(R.layout.zen_mode_radio_button,
+ mZenRadioGroup, false);
+ mZenRadioGroup.addView(radioButton);
+ radioButton.setId(i);
+
+ final View radioButtonContent = inflater.inflate(R.layout.zen_mode_condition,
+ mZenRadioGroupContent, false);
+ radioButtonContent.setId(i + MAX_MANUAL_DND_OPTIONS);
+ mZenRadioGroupContent.addView(radioButtonContent);
+ }
+ hideAllConditions();
+ return contentView;
+ }
+
+ @Override
+ public int getMetricsCategory() {
+ return MetricsProto.MetricsEvent.NOTIFICATION_ZEN_MODE_ENABLE_DIALOG;
+ }
+
+ @VisibleForTesting
+ protected void bind(final Condition condition, final View row, final int rowId) {
+ if (condition == null) throw new IllegalArgumentException("condition must not be null");
+ final boolean enabled = condition.state == Condition.STATE_TRUE;
+ final ConditionTag tag = row.getTag() != null ? (ConditionTag) row.getTag() :
+ new ConditionTag();
+ row.setTag(tag);
+ final boolean first = tag.rb == null;
+ if (tag.rb == null) {
+ tag.rb = (RadioButton) mZenRadioGroup.getChildAt(rowId);
+ }
+ tag.condition = condition;
+ final Uri conditionId = getConditionId(tag.condition);
+ if (DEBUG) Log.d(TAG, "bind i=" + mZenRadioGroupContent.indexOfChild(row) + " first="
+ + first + " condition=" + conditionId);
+ tag.rb.setEnabled(enabled);
+ tag.rb.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
+ @Override
+ public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
+ if (isChecked) {
+ tag.rb.setChecked(true);
+ if (DEBUG) Log.d(TAG, "onCheckedChanged " + conditionId);
+ MetricsLogger.action(mContext,
+ MetricsProto.MetricsEvent.QS_DND_CONDITION_SELECT);
+ announceConditionSelection(tag);
+ }
+ }
+ });
+
+ updateUi(tag, row, condition, enabled, rowId, conditionId);
+ row.setVisibility(View.VISIBLE);
+ }
+
+ @VisibleForTesting
+ protected ConditionTag getConditionTagAt(int index) {
+ return (ConditionTag) mZenRadioGroupContent.getChildAt(index).getTag();
+ }
+
+ @VisibleForTesting
+ protected void bindConditions(Condition c) {
+ // forever
+ bind(forever(), mZenRadioGroupContent.getChildAt(FOREVER_CONDITION_INDEX),
+ FOREVER_CONDITION_INDEX);
+ if (c == null) {
+ bindGenericCountdown();
+ bindNextAlarm(getTimeUntilNextAlarmCondition());
+ } else if (isForever(c)) {
+ getConditionTagAt(FOREVER_CONDITION_INDEX).rb.setChecked(true);
+ bindGenericCountdown();
+ bindNextAlarm(getTimeUntilNextAlarmCondition());
+ } else {
+ if (isAlarm(c)) {
+ bindGenericCountdown();
+ bindNextAlarm(c);
+ getConditionTagAt(COUNTDOWN_ALARM_CONDITION_INDEX).rb.setChecked(true);
+ } else if (isCountdown(c)) {
+ bindNextAlarm(getTimeUntilNextAlarmCondition());
+ bind(c, mZenRadioGroupContent.getChildAt(COUNTDOWN_CONDITION_INDEX),
+ COUNTDOWN_CONDITION_INDEX);
+ getConditionTagAt(COUNTDOWN_CONDITION_INDEX).rb.setChecked(true);
+ } else {
+ wtf(TAG, "Invalid manual condition: " + c);
+ }
+ }
+ }
+
+ public static Uri getConditionId(Condition condition) {
+ return condition != null ? condition.id : null;
+ }
+
+ public Condition forever() {
+ Uri foreverId = Condition.newId(mContext).appendPath("forever").build();
+ return new Condition(foreverId, foreverSummary(mContext), "", "", 0 /*icon*/,
+ Condition.STATE_TRUE, 0 /*flags*/);
+ }
+
+ public long getNextAlarm() {
+ final AlarmManager.AlarmClockInfo info = mAlarmManager.getNextAlarmClock(mUserId);
+ return info != null ? info.getTriggerTime() : 0;
+ }
+
+ @VisibleForTesting
+ protected boolean isAlarm(Condition c) {
+ return c != null && ZenModeConfig.isValidCountdownToAlarmConditionId(c.id);
+ }
+
+ @VisibleForTesting
+ protected boolean isCountdown(Condition c) {
+ return c != null && ZenModeConfig.isValidCountdownConditionId(c.id);
+ }
+
+ private boolean isForever(Condition c) {
+ return c != null && mForeverId.equals(c.id);
+ }
+
+ private Uri getRealConditionId(Condition condition) {
+ return isForever(condition) ? null : getConditionId(condition);
+ }
+
+ private String foreverSummary(Context context) {
+ return context.getString(com.android.internal.R.string.zen_mode_forever);
+ }
+
+ private static void setToMidnight(Calendar calendar) {
+ calendar.set(Calendar.HOUR_OF_DAY, 0);
+ calendar.set(Calendar.MINUTE, 0);
+ calendar.set(Calendar.SECOND, 0);
+ calendar.set(Calendar.MILLISECOND, 0);
+ }
+
+ // Returns a time condition if the next alarm is within the next week.
+ @VisibleForTesting
+ protected Condition getTimeUntilNextAlarmCondition() {
+ GregorianCalendar weekRange = new GregorianCalendar();
+ setToMidnight(weekRange);
+ weekRange.add(Calendar.DATE, 6);
+ final long nextAlarmMs = getNextAlarm();
+ if (nextAlarmMs > 0) {
+ GregorianCalendar nextAlarm = new GregorianCalendar();
+ nextAlarm.setTimeInMillis(nextAlarmMs);
+ setToMidnight(nextAlarm);
+
+ if (weekRange.compareTo(nextAlarm) >= 0) {
+ return ZenModeConfig.toNextAlarmCondition(mContext, nextAlarmMs,
+ ActivityManager.getCurrentUser());
+ }
+ }
+ return null;
+ }
+
+ @VisibleForTesting
+ protected void bindGenericCountdown() {
+ mBucketIndex = DEFAULT_BUCKET_INDEX;
+ Condition countdown = ZenModeConfig.toTimeCondition(mContext,
+ MINUTE_BUCKETS[mBucketIndex], ActivityManager.getCurrentUser());
+ if (!mAttached || getConditionTagAt(COUNTDOWN_CONDITION_INDEX).condition == null) {
+ bind(countdown, mZenRadioGroupContent.getChildAt(COUNTDOWN_CONDITION_INDEX),
+ COUNTDOWN_CONDITION_INDEX);
+ }
+ }
+
+ private void updateUi(ConditionTag tag, View row, Condition condition,
+ boolean enabled, int rowId, Uri conditionId) {
+ if (tag.lines == null) {
+ tag.lines = row.findViewById(android.R.id.content);
+ }
+ if (tag.line1 == null) {
+ tag.line1 = (TextView) row.findViewById(android.R.id.text1);
+ }
+
+ if (tag.line2 == null) {
+ tag.line2 = (TextView) row.findViewById(android.R.id.text2);
+ }
+
+ final String line1 = !TextUtils.isEmpty(condition.line1) ? condition.line1
+ : condition.summary;
+ final String line2 = condition.line2;
+ tag.line1.setText(line1);
+ if (TextUtils.isEmpty(line2)) {
+ tag.line2.setVisibility(View.GONE);
+ } else {
+ tag.line2.setVisibility(View.VISIBLE);
+ tag.line2.setText(line2);
+ }
+ tag.lines.setEnabled(enabled);
+ tag.lines.setAlpha(enabled ? 1 : .4f);
+
+ tag.lines.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ tag.rb.setChecked(true);
+ }
+ });
+
+ // minus button
+ final ImageView button1 = (ImageView) row.findViewById(android.R.id.button1);
+ button1.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ onClickTimeButton(row, tag, false /*down*/, rowId);
+ }
+ });
+
+ // plus button
+ final ImageView button2 = (ImageView) row.findViewById(android.R.id.button2);
+ button2.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ onClickTimeButton(row, tag, true /*up*/, rowId);
+ }
+ });
+
+ final long time = ZenModeConfig.tryParseCountdownConditionId(conditionId);
+ if (rowId == COUNTDOWN_CONDITION_INDEX && time > 0) {
+ button1.setVisibility(View.VISIBLE);
+ button2.setVisibility(View.VISIBLE);
+ if (mBucketIndex > -1) {
+ button1.setEnabled(mBucketIndex > 0);
+ button2.setEnabled(mBucketIndex < MINUTE_BUCKETS.length - 1);
+ } else {
+ final long span = time - System.currentTimeMillis();
+ button1.setEnabled(span > MIN_BUCKET_MINUTES * MINUTES_MS);
+ final Condition maxCondition = ZenModeConfig.toTimeCondition(mContext,
+ MAX_BUCKET_MINUTES, ActivityManager.getCurrentUser());
+ button2.setEnabled(!Objects.equals(condition.summary, maxCondition.summary));
+ }
+
+ button1.setAlpha(button1.isEnabled() ? 1f : .5f);
+ button2.setAlpha(button2.isEnabled() ? 1f : .5f);
+ } else {
+ button1.setVisibility(View.GONE);
+ button2.setVisibility(View.GONE);
+ }
+ }
+
+ @VisibleForTesting
+ protected void bindNextAlarm(Condition c) {
+ View alarmContent = mZenRadioGroupContent.getChildAt(COUNTDOWN_ALARM_CONDITION_INDEX);
+ ConditionTag tag = (ConditionTag) alarmContent.getTag();
+
+ if (c != null && (!mAttached || tag == null || tag.condition == null)) {
+ bind(c, alarmContent, COUNTDOWN_ALARM_CONDITION_INDEX);
+ }
+
+ // hide the alarm radio button if there isn't a "next alarm condition"
+ tag = (ConditionTag) alarmContent.getTag();
+ boolean showAlarm = tag != null && tag.condition != null;
+ mZenRadioGroup.getChildAt(COUNTDOWN_ALARM_CONDITION_INDEX).setVisibility(
+ showAlarm ? View.VISIBLE : View.GONE);
+ alarmContent.setVisibility(showAlarm ? View.VISIBLE : View.GONE);
+ }
+
+ private void onClickTimeButton(View row, ConditionTag tag, boolean up, int rowId) {
+ MetricsLogger.action(mContext, MetricsProto.MetricsEvent.QS_DND_TIME, up);
+ Condition newCondition = null;
+ final int N = MINUTE_BUCKETS.length;
+ if (mBucketIndex == -1) {
+ // not on a known index, search for the next or prev bucket by time
+ final Uri conditionId = getConditionId(tag.condition);
+ final long time = ZenModeConfig.tryParseCountdownConditionId(conditionId);
+ final long now = System.currentTimeMillis();
+ for (int i = 0; i < N; i++) {
+ int j = up ? i : N - 1 - i;
+ final int bucketMinutes = MINUTE_BUCKETS[j];
+ final long bucketTime = now + bucketMinutes * MINUTES_MS;
+ if (up && bucketTime > time || !up && bucketTime < time) {
+ mBucketIndex = j;
+ newCondition = ZenModeConfig.toTimeCondition(mContext,
+ bucketTime, bucketMinutes, ActivityManager.getCurrentUser(),
+ false /*shortVersion*/);
+ break;
+ }
+ }
+ if (newCondition == null) {
+ mBucketIndex = DEFAULT_BUCKET_INDEX;
+ newCondition = ZenModeConfig.toTimeCondition(mContext,
+ MINUTE_BUCKETS[mBucketIndex], ActivityManager.getCurrentUser());
+ }
+ } else {
+ // on a known index, simply increment or decrement
+ mBucketIndex = Math.max(0, Math.min(N - 1, mBucketIndex + (up ? 1 : -1)));
+ newCondition = ZenModeConfig.toTimeCondition(mContext,
+ MINUTE_BUCKETS[mBucketIndex], ActivityManager.getCurrentUser());
+ }
+ bind(newCondition, row, rowId);
+ tag.rb.setChecked(true);
+ announceConditionSelection(tag);
+ }
+
+ private void announceConditionSelection(ConditionTag tag) {
+ // condition will always be priority-only
+ String modeText = mContext.getString(R.string.zen_interruption_level_priority);
+ if (tag.line1 != null) {
+ mZenRadioGroupContent.announceForAccessibility(mContext.getString(
+ R.string.zen_mode_and_condition, modeText, tag.line1.getText()));
+ }
+ }
+
+ // used as the view tag on condition rows
+ @VisibleForTesting
+ protected static class ConditionTag {
+ public RadioButton rb;
+ public View lines;
+ public TextView line1;
+ public TextView line2;
+ public Condition condition;
+ }
+}
diff --git a/src/com/android/settings/notification/NotificationBackend.java b/src/com/android/settings/notification/NotificationBackend.java
index 4de528e..e047efa 100644
--- a/src/com/android/settings/notification/NotificationBackend.java
+++ b/src/com/android/settings/notification/NotificationBackend.java
@@ -27,12 +27,16 @@
import android.graphics.drawable.Drawable;
import android.os.ServiceManager;
import android.os.UserHandle;
+import android.service.notification.NotifyingApp;
import android.util.IconDrawableFactory;
import android.util.Log;
import com.android.internal.annotations.VisibleForTesting;
import com.android.settingslib.Utils;
+import java.util.ArrayList;
+import java.util.List;
+
public class NotificationBackend {
private static final String TAG = "NotificationBackend";
@@ -185,7 +189,6 @@
}
}
-
public int getDeletedChannelCount(String pkg, int uid) {
try {
return sINM.getDeletedChannelCount(pkg, uid);
@@ -204,6 +207,15 @@
}
}
+ public List<NotifyingApp> getRecentApps() {
+ try {
+ return sINM.getRecentNotifyingAppsForUser(UserHandle.myUserId()).getList();
+ } catch (Exception e) {
+ Log.w(TAG, "Error calling NoMan", e);
+ return new ArrayList<>();
+ }
+ }
+
static class Row {
public String section;
}
diff --git a/src/com/android/settings/notification/NotificationSettingsBase.java b/src/com/android/settings/notification/NotificationSettingsBase.java
index 2a7e7d5..8b0ed46 100644
--- a/src/com/android/settings/notification/NotificationSettingsBase.java
+++ b/src/com/android/settings/notification/NotificationSettingsBase.java
@@ -168,14 +168,7 @@
mChannel = (args != null && args.containsKey(Settings.EXTRA_CHANNEL_ID)) ?
mBackend.getChannel(mPkg, mUid, args.getString(Settings.EXTRA_CHANNEL_ID)) : null;
- NotificationChannelGroup group =
- (args != null && args.containsKey(Settings.EXTRA_CHANNEL_GROUP_ID))
- ? mBackend.getGroupWithChannels(mPkg, mUid,
- args.getString(Settings.EXTRA_CHANNEL_GROUP_ID))
- : null;
- if (group != null) {
- mChannelGroup = new NotificationChannelGroupWrapper(group);
- }
+ NotificationChannelGroup group = null;
mSuspendedAppsAdmin = RestrictedLockUtils.checkIfApplicationIsSuspended(
mContext, mPkg, mUserId);
diff --git a/src/com/android/settings/notification/RecentNotifyingAppsPreferenceController.java b/src/com/android/settings/notification/RecentNotifyingAppsPreferenceController.java
new file mode 100644
index 0000000..ef34a9b
--- /dev/null
+++ b/src/com/android/settings/notification/RecentNotifyingAppsPreferenceController.java
@@ -0,0 +1,293 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.notification;
+
+import android.app.Application;
+import android.app.Fragment;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.os.UserHandle;
+import android.service.notification.NotifyingApp;
+import android.support.annotation.VisibleForTesting;
+import android.support.v7.preference.Preference;
+import android.support.v7.preference.PreferenceCategory;
+import android.support.v7.preference.PreferenceScreen;
+import android.text.TextUtils;
+import android.util.ArrayMap;
+import android.util.ArraySet;
+import android.util.IconDrawableFactory;
+import android.util.Log;
+
+import com.android.internal.logging.nano.MetricsProto;
+import com.android.settings.R;
+import com.android.settings.Utils;
+import com.android.settings.applications.AppInfoBase;
+import com.android.settings.applications.InstalledAppCounter;
+import com.android.settings.core.PreferenceControllerMixin;
+import com.android.settings.widget.AppPreference;
+import com.android.settingslib.applications.AppUtils;
+import com.android.settingslib.applications.ApplicationsState;
+import com.android.settingslib.core.AbstractPreferenceController;
+import com.android.settingslib.wrapper.PackageManagerWrapper;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * This controller displays a list of recently used apps and a "See all" button. If there is
+ * no recently used app, "See all" will be displayed as "Notifications".
+ */
+public class RecentNotifyingAppsPreferenceController extends AbstractPreferenceController
+ implements PreferenceControllerMixin {
+
+ private static final String TAG = "RecentNotisCtrl";
+ private static final String KEY_PREF_CATEGORY = "recent_notifications_category";
+ @VisibleForTesting
+ static final String KEY_DIVIDER = "all_notifications_divider";
+ @VisibleForTesting
+ static final String KEY_SEE_ALL = "all_notifications";
+ private static final int SHOW_RECENT_APP_COUNT = 5;
+ private static final Set<String> SKIP_SYSTEM_PACKAGES = new ArraySet<>();
+
+ private final Fragment mHost;
+ private final PackageManager mPm;
+ private final NotificationBackend mNotificationBackend;
+ private final int mUserId;
+ private final IconDrawableFactory mIconDrawableFactory;
+
+ private List<NotifyingApp> mApps;
+ private final ApplicationsState mApplicationsState;
+
+ private PreferenceCategory mCategory;
+ private Preference mSeeAllPref;
+ private Preference mDivider;
+ private boolean mHasRecentApps;
+
+ static {
+ SKIP_SYSTEM_PACKAGES.addAll(Arrays.asList(
+ "android",
+ "com.android.phone",
+ "com.android.settings",
+ "com.android.systemui",
+ "com.android.providers.calendar",
+ "com.android.providers.media"
+ ));
+ }
+
+ public RecentNotifyingAppsPreferenceController(Context context, NotificationBackend backend,
+ Application app, Fragment host) {
+ this(context, backend, app == null ? null : ApplicationsState.getInstance(app), host);
+ }
+
+ @VisibleForTesting(otherwise = VisibleForTesting.NONE)
+ RecentNotifyingAppsPreferenceController(Context context, NotificationBackend backend,
+ ApplicationsState appState, Fragment host) {
+ super(context);
+ mIconDrawableFactory = IconDrawableFactory.newInstance(context);
+ mUserId = UserHandle.myUserId();
+ mPm = context.getPackageManager();
+ mHost = host;
+ mApplicationsState = appState;
+ mNotificationBackend = backend;
+ }
+
+ @Override
+ public boolean isAvailable() {
+ return true;
+ }
+
+ @Override
+ public String getPreferenceKey() {
+ return KEY_PREF_CATEGORY;
+ }
+
+ @Override
+ public void updateNonIndexableKeys(List<String> keys) {
+ PreferenceControllerMixin.super.updateNonIndexableKeys(keys);
+ // Don't index category name into search. It's not actionable.
+ keys.add(KEY_PREF_CATEGORY);
+ keys.add(KEY_DIVIDER);
+ }
+
+ @Override
+ public void displayPreference(PreferenceScreen screen) {
+ mCategory = (PreferenceCategory) screen.findPreference(getPreferenceKey());
+ mSeeAllPref = screen.findPreference(KEY_SEE_ALL);
+ mDivider = screen.findPreference(KEY_DIVIDER);
+ super.displayPreference(screen);
+ refreshUi(mCategory.getContext());
+ }
+
+ @Override
+ public void updateState(Preference preference) {
+ super.updateState(preference);
+ refreshUi(mCategory.getContext());
+ // Show total number of installed apps as See all's summary.
+ new InstalledAppCounter(mContext, InstalledAppCounter.IGNORE_INSTALL_REASON,
+ new PackageManagerWrapper(mContext.getPackageManager())) {
+ @Override
+ protected void onCountComplete(int num) {
+ if (mHasRecentApps) {
+ mSeeAllPref.setTitle(mContext.getString(R.string.see_all_apps_title, num));
+ } else {
+ mSeeAllPref.setSummary(mContext.getString(R.string.apps_summary, num));
+ }
+ }
+ }.execute();
+
+ }
+
+ @VisibleForTesting
+ void refreshUi(Context prefContext) {
+ reloadData();
+ final List<NotifyingApp> recentApps = getDisplayableRecentAppList();
+ if (recentApps != null && !recentApps.isEmpty()) {
+ mHasRecentApps = true;
+ displayRecentApps(prefContext, recentApps);
+ } else {
+ mHasRecentApps = false;
+ displayOnlyAllAppsLink();
+ }
+ }
+
+ @VisibleForTesting
+ void reloadData() {
+ mApps = mNotificationBackend.getRecentApps();
+ }
+
+ private void displayOnlyAllAppsLink() {
+ mCategory.setTitle(null);
+ mDivider.setVisible(false);
+ mSeeAllPref.setTitle(R.string.notifications_title);
+ mSeeAllPref.setIcon(null);
+ int prefCount = mCategory.getPreferenceCount();
+ for (int i = prefCount - 1; i >= 0; i--) {
+ final Preference pref = mCategory.getPreference(i);
+ if (!TextUtils.equals(pref.getKey(), KEY_SEE_ALL)) {
+ mCategory.removePreference(pref);
+ }
+ }
+ }
+
+ private void displayRecentApps(Context prefContext, List<NotifyingApp> recentApps) {
+ mCategory.setTitle(R.string.recent_notifications);
+ mDivider.setVisible(true);
+ mSeeAllPref.setSummary(null);
+ mSeeAllPref.setIcon(R.drawable.ic_chevron_right_24dp);
+
+ // Rebind prefs/avoid adding new prefs if possible. Adding/removing prefs causes jank.
+ // Build a cached preference pool
+ final Map<String, Preference> appPreferences = new ArrayMap<>();
+ int prefCount = mCategory.getPreferenceCount();
+ for (int i = 0; i < prefCount; i++) {
+ final Preference pref = mCategory.getPreference(i);
+ final String key = pref.getKey();
+ if (!TextUtils.equals(key, KEY_SEE_ALL)) {
+ appPreferences.put(key, pref);
+ }
+ }
+ final int recentAppsCount = recentApps.size();
+ for (int i = 0; i < recentAppsCount; i++) {
+ final NotifyingApp app = recentApps.get(i);
+ // Bind recent apps to existing prefs if possible, or create a new pref.
+ final String pkgName = app.getPackage();
+ final ApplicationsState.AppEntry appEntry =
+ mApplicationsState.getEntry(app.getPackage(), mUserId);
+ if (appEntry == null) {
+ continue;
+ }
+
+ boolean rebindPref = true;
+ Preference pref = appPreferences.remove(pkgName);
+ if (pref == null) {
+ pref = new AppPreference(prefContext);
+ rebindPref = false;
+ }
+ pref.setKey(pkgName);
+ pref.setTitle(appEntry.label);
+ pref.setIcon(mIconDrawableFactory.getBadgedIcon(appEntry.info));
+ pref.setSummary(Utils.formatRelativeTime(mContext,
+ System.currentTimeMillis() - app.getLastNotified(), false));
+ pref.setOrder(i);
+ pref.setOnPreferenceClickListener(preference -> {
+ AppInfoBase.startAppInfoFragment(AppNotificationSettings.class,
+ R.string.notifications_title, pkgName, appEntry.info.uid, mHost,
+ 1001 /*RequestCode */,
+ MetricsProto.MetricsEvent.MANAGE_APPLICATIONS_NOTIFICATIONS);
+ return true;
+ });
+ if (!rebindPref) {
+ mCategory.addPreference(pref);
+ }
+ }
+ // Remove unused prefs from pref cache pool
+ for (Preference unusedPrefs : appPreferences.values()) {
+ mCategory.removePreference(unusedPrefs);
+ }
+ }
+
+ private List<NotifyingApp> getDisplayableRecentAppList() {
+ Collections.sort(mApps);
+ List<NotifyingApp> displayableApps = new ArrayList<>(SHOW_RECENT_APP_COUNT);
+ int count = 0;
+ for (NotifyingApp app : mApps) {
+ final ApplicationsState.AppEntry appEntry = mApplicationsState.getEntry(
+ app.getPackage(), mUserId);
+ if (appEntry == null) {
+ continue;
+ }
+ if (!shouldIncludePkgInRecents(app.getPackage())) {
+ continue;
+ }
+ displayableApps.add(app);
+ count++;
+ if (count >= SHOW_RECENT_APP_COUNT) {
+ break;
+ }
+ }
+ return displayableApps;
+ }
+
+
+ /**
+ * Whether or not the app should be included in recent list.
+ */
+ private boolean shouldIncludePkgInRecents(String pkgName) {
+ if (SKIP_SYSTEM_PACKAGES.contains(pkgName)) {
+ Log.d(TAG, "System package, skipping " + pkgName);
+ return false;
+ }
+ final Intent launchIntent = new Intent().addCategory(Intent.CATEGORY_LAUNCHER)
+ .setPackage(pkgName);
+
+ if (mPm.resolveActivity(launchIntent, 0) == null) {
+ // Not visible on launcher -> likely not a user visible app, skip if non-instant.
+ final ApplicationsState.AppEntry appEntry =
+ mApplicationsState.getEntry(pkgName, mUserId);
+ if (!AppUtils.isInstant(appEntry.info)) {
+ Log.d(TAG, "Not a user visible or instant app, skipping " + pkgName);
+ return false;
+ }
+ }
+ return true;
+ }
+}
diff --git a/src/com/android/settings/notification/ZenModeButtonPreferenceController.java b/src/com/android/settings/notification/ZenModeButtonPreferenceController.java
index f5169f0..da540f4 100644
--- a/src/com/android/settings/notification/ZenModeButtonPreferenceController.java
+++ b/src/com/android/settings/notification/ZenModeButtonPreferenceController.java
@@ -16,6 +16,7 @@
package com.android.settings.notification;
+import android.app.FragmentManager;
import android.content.Context;
import android.provider.Settings;
import android.support.v7.preference.Preference;
@@ -31,12 +32,16 @@
public class ZenModeButtonPreferenceController extends AbstractZenModePreferenceController
implements PreferenceControllerMixin {
+ private static final String TAG = "EnableZenModeButton";
protected static final String KEY = "zen_mode_settings_button_container";
private Button mZenButtonOn;
private Button mZenButtonOff;
+ private FragmentManager mFragment;
- public ZenModeButtonPreferenceController(Context context, Lifecycle lifecycle) {
+ public ZenModeButtonPreferenceController(Context context, Lifecycle lifecycle, FragmentManager
+ fragment) {
super(context, KEY, lifecycle);
+ mFragment = fragment;
}
@Override
@@ -56,11 +61,8 @@
if (null == mZenButtonOn) {
mZenButtonOn = (Button) ((LayoutPreference) preference)
.findViewById(R.id.zen_mode_settings_turn_on_button);
- mZenButtonOn.setOnClickListener(v -> {
- mMetricsFeatureProvider.action(mContext,
- MetricsProto.MetricsEvent.ACTION_ZEN_TOGGLE_DND_BUTTON, true);
- mBackend.setZenMode(Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS);
- });
+ mZenButtonOn.setOnClickListener(v ->
+ new EnableZenModeDialog().show(mFragment, TAG));
}
if (null == mZenButtonOff) {
diff --git a/src/com/android/settings/notification/ZenModeSettings.java b/src/com/android/settings/notification/ZenModeSettings.java
index 1ee20d3..a6145c4 100644
--- a/src/com/android/settings/notification/ZenModeSettings.java
+++ b/src/com/android/settings/notification/ZenModeSettings.java
@@ -17,6 +17,7 @@
package com.android.settings.notification;
import android.app.AutomaticZenRule;
+import android.app.FragmentManager;
import android.app.NotificationManager;
import android.app.NotificationManager.Policy;
import android.content.Context;
@@ -50,7 +51,7 @@
@Override
protected List<AbstractPreferenceController> getPreferenceControllers(Context context) {
- return buildPreferenceControllers(context, getLifecycle());
+ return buildPreferenceControllers(context, getLifecycle(), getFragmentManager());
}
@Override
@@ -59,11 +60,11 @@
}
private static List<AbstractPreferenceController> buildPreferenceControllers(Context context,
- Lifecycle lifecycle) {
+ Lifecycle lifecycle, FragmentManager fragmentManager) {
List<AbstractPreferenceController> controllers = new ArrayList<>();
controllers.add(new ZenModeBehaviorPreferenceController(context, lifecycle));
controllers.add(new ZenModeAutomationPreferenceController(context));
- controllers.add(new ZenModeButtonPreferenceController(context, lifecycle));
+ controllers.add(new ZenModeButtonPreferenceController(context, lifecycle, fragmentManager));
controllers.add(new ZenModeSettingsFooterPreferenceController(context, lifecycle));
return controllers;
}
@@ -211,7 +212,7 @@
@Override
public List<AbstractPreferenceController> getPreferenceControllers(Context
context) {
- return buildPreferenceControllers(context, null);
+ return buildPreferenceControllers(context, null, null);
}
};
}
diff --git a/src/com/android/settings/notification/ZenRulePreference.java b/src/com/android/settings/notification/ZenRulePreference.java
index fee390f..7193873 100644
--- a/src/com/android/settings/notification/ZenRulePreference.java
+++ b/src/com/android/settings/notification/ZenRulePreference.java
@@ -30,10 +30,10 @@
import com.android.internal.logging.nano.MetricsProto;
import com.android.settings.R;
+import com.android.settings.core.instrumentation.MetricsFeatureProvider;
import com.android.settings.utils.ManagedServiceSettings;
import com.android.settings.utils.ZenServiceListing;
import com.android.settingslib.TwoTargetPreference;
-import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
import java.util.Map;
@@ -145,4 +145,4 @@
? mContext.getResources().getString(R.string.switch_off_text)
: mContext.getResources().getString(R.string.switch_on_text);
}
-}
+}
\ No newline at end of file
diff --git a/src/com/android/settings/overlay/FeatureFactory.java b/src/com/android/settings/overlay/FeatureFactory.java
index 0805766..71fbaa4 100644
--- a/src/com/android/settings/overlay/FeatureFactory.java
+++ b/src/com/android/settings/overlay/FeatureFactory.java
@@ -21,9 +21,11 @@
import android.util.Log;
import com.android.settings.R;
+import com.android.settings.accounts.AccountFeatureProvider;
import com.android.settings.applications.ApplicationFeatureProvider;
import com.android.settings.bluetooth.BluetoothFeatureProvider;
import com.android.settings.connecteddevice.SmsMirroringFeatureProvider;
+import com.android.settings.core.instrumentation.MetricsFeatureProvider;
import com.android.settings.dashboard.DashboardFeatureProvider;
import com.android.settings.dashboard.suggestions.SuggestionFeatureProvider;
import com.android.settings.datausage.DataPlanFeatureProvider;
@@ -35,7 +37,6 @@
import com.android.settings.search.SearchFeatureProvider;
import com.android.settings.slices.SlicesFeatureProvider;
import com.android.settings.users.UserFeatureProvider;
-import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
/**
* Abstract class for creating feature controllers. Allows OEM implementations to define their own
@@ -109,6 +110,8 @@
public abstract SlicesFeatureProvider getSlicesFeatureProvider();
+ public abstract AccountFeatureProvider getAccountFeatureProvider();
+
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 f817d4b..45dc238 100644
--- a/src/com/android/settings/overlay/FeatureFactoryImpl.java
+++ b/src/com/android/settings/overlay/FeatureFactoryImpl.java
@@ -23,12 +23,15 @@
import android.os.UserManager;
import android.support.annotation.Keep;
+import com.android.settings.accounts.AccountFeatureProvider;
+import com.android.settings.accounts.AccountFeatureProviderImpl;
import com.android.settings.applications.ApplicationFeatureProvider;
import com.android.settings.applications.ApplicationFeatureProviderImpl;
import com.android.settings.bluetooth.BluetoothFeatureProvider;
import com.android.settings.bluetooth.BluetoothFeatureProviderImpl;
import com.android.settings.connecteddevice.SmsMirroringFeatureProvider;
import com.android.settings.connecteddevice.SmsMirroringFeatureProviderImpl;
+import com.android.settings.core.instrumentation.MetricsFeatureProvider;
import com.android.settings.dashboard.DashboardFeatureProvider;
import com.android.settings.dashboard.DashboardFeatureProviderImpl;
import com.android.settings.dashboard.suggestions.SuggestionFeatureProvider;
@@ -54,7 +57,6 @@
import com.android.settings.wrapper.ConnectivityManagerWrapper;
import com.android.settings.wrapper.DevicePolicyManagerWrapper;
import com.android.settings.wrapper.IPackageManagerWrapper;
-import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
import com.android.settingslib.wrapper.PackageManagerWrapper;
/**
@@ -78,6 +80,7 @@
private DataPlanFeatureProvider mDataPlanFeatureProvider;
private SmsMirroringFeatureProvider mSmsMirroringFeatureProvider;
private SlicesFeatureProvider mSlicesFeatureProvider;
+ private AccountFeatureProvider mAccountFeatureProvider;
@Override
public SupportFeatureProvider getSupportFeatureProvider(Context context) {
@@ -219,4 +222,12 @@
}
return mSlicesFeatureProvider;
}
+
+ @Override
+ public AccountFeatureProvider getAccountFeatureProvider() {
+ if (mAccountFeatureProvider == null) {
+ mAccountFeatureProvider = new AccountFeatureProviderImpl();
+ }
+ return mAccountFeatureProvider;
+ }
}
diff --git a/src/com/android/settings/search/SearchIndexableResourcesImpl.java b/src/com/android/settings/search/SearchIndexableResourcesImpl.java
index 2c20703..034cbd0 100644
--- a/src/com/android/settings/search/SearchIndexableResourcesImpl.java
+++ b/src/com/android/settings/search/SearchIndexableResourcesImpl.java
@@ -21,6 +21,7 @@
import com.android.settings.DateTimeSettings;
import com.android.settings.DisplaySettings;
import com.android.settings.LegalSettings;
+import com.android.settings.deviceinfo.aboutphone.MyDeviceInfoFragment;
import com.android.settings.accessibility.AccessibilitySettings;
import com.android.settings.accessibility.AccessibilityShortcutPreferenceFragment;
import com.android.settings.accessibility.MagnificationPreferenceFragment;
@@ -173,6 +174,7 @@
addIndex(ZenModeAutomationSettings.class);
addIndex(NightDisplaySettings.class);
addIndex(SmartBatterySettings.class);
+ addIndex(MyDeviceInfoFragment.class);
}
@Override
diff --git a/src/com/android/settings/security/LockdownButtonPreferenceController.java b/src/com/android/settings/security/LockdownButtonPreferenceController.java
new file mode 100644
index 0000000..8960502
--- /dev/null
+++ b/src/com/android/settings/security/LockdownButtonPreferenceController.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2018 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.os.UserHandle;
+import android.provider.Settings;
+import android.support.v7.preference.Preference;
+import android.support.v7.preference.TwoStatePreference;
+
+import com.android.internal.widget.LockPatternUtils;
+import com.android.settings.core.BasePreferenceController;
+import com.android.settings.core.TogglePreferenceController;
+
+public class LockdownButtonPreferenceController extends TogglePreferenceController {
+
+ private static final String KEY_LOCKDOWN_ENALBED = "security_setting_lockdown_enabled";
+
+ private final LockPatternUtils mLockPatternUtils;
+
+ public LockdownButtonPreferenceController(Context context) {
+ super(context, KEY_LOCKDOWN_ENALBED);
+ mLockPatternUtils = new LockPatternUtils(context);
+ }
+
+ @Override
+ public int getAvailabilityStatus() {
+ if (mLockPatternUtils.isSecure(UserHandle.myUserId())) {
+ return BasePreferenceController.AVAILABLE;
+ } else {
+ return BasePreferenceController.DISABLED_FOR_USER;
+ }
+ }
+
+ @Override
+ public boolean isChecked() {
+ return Settings.Secure.getInt(mContext.getContentResolver(),
+ Settings.Secure.LOCKDOWN_IN_POWER_MENU, 0) != 0;
+ }
+
+ @Override
+ public boolean setChecked(boolean isChecked) {
+ Settings.Secure.putInt(mContext.getContentResolver(),
+ Settings.Secure.LOCKDOWN_IN_POWER_MENU, isChecked ? 1 : 0);
+ return true;
+ }
+}
diff --git a/src/com/android/settings/security/LockscreenDashboardFragment.java b/src/com/android/settings/security/LockscreenDashboardFragment.java
index df4ca30..7054181 100644
--- a/src/com/android/settings/security/LockscreenDashboardFragment.java
+++ b/src/com/android/settings/security/LockscreenDashboardFragment.java
@@ -93,6 +93,8 @@
mOwnerInfoPreferenceController =
new OwnerInfoPreferenceController(context, this, lifecycle);
controllers.add(mOwnerInfoPreferenceController);
+ controllers.add(new LockdownButtonPreferenceController(context));
+
return controllers;
}
@@ -122,6 +124,7 @@
KEY_ADD_USER_FROM_LOCK_SCREEN));
controllers.add(new OwnerInfoPreferenceController(
context, null /* fragment */, null /* lifecycle */));
+ controllers.add(new LockdownButtonPreferenceController(context));
return controllers;
}
diff --git a/src/com/android/settings/widget/AppCheckBoxPreference.java b/src/com/android/settings/widget/AppCheckBoxPreference.java
new file mode 100644
index 0000000..9cb1d78
--- /dev/null
+++ b/src/com/android/settings/widget/AppCheckBoxPreference.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.widget;
+
+import android.content.Context;
+import android.support.v7.preference.CheckBoxPreference;
+import android.util.AttributeSet;
+
+import com.android.settings.R;
+
+/**
+ * {@link CheckBoxPreference} that used only to display app
+ */
+public class AppCheckBoxPreference extends CheckBoxPreference {
+ public AppCheckBoxPreference(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ setLayoutResource(R.layout.preference_app);
+ }
+
+ public AppCheckBoxPreference(Context context) {
+ super(context);
+ setLayoutResource(R.layout.preference_app);
+ }
+}
diff --git a/src/com/android/settings/widget/SettingsAppWidgetProvider.java b/src/com/android/settings/widget/SettingsAppWidgetProvider.java
index 7dacaf5..5ccfc1b 100644
--- a/src/com/android/settings/widget/SettingsAppWidgetProvider.java
+++ b/src/com/android/settings/widget/SettingsAppWidgetProvider.java
@@ -16,6 +16,7 @@
package com.android.settings.widget;
+import android.app.ActivityManager;
import android.app.PendingIntent;
import android.appwidget.AppWidgetManager;
import android.appwidget.AppWidgetProvider;
@@ -33,10 +34,12 @@
import android.os.Handler;
import android.os.IPowerManager;
import android.os.PowerManager;
+import android.os.Process;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.UserManager;
import android.provider.Settings;
+import android.provider.Settings.Secure;
import android.util.Log;
import android.widget.RemoteViews;
@@ -561,27 +564,14 @@
final UserManager um =
(UserManager) context.getSystemService(Context.USER_SERVICE);
if (!um.hasUserRestriction(UserManager.DISALLOW_SHARE_LOCATION)) {
- int currentMode = Settings.Secure.getInt(resolver,
- Settings.Secure.LOCATION_MODE, Settings.Secure.LOCATION_MODE_OFF);
- int mode = Settings.Secure.LOCATION_MODE_HIGH_ACCURACY;
- switch (currentMode) {
- case Settings.Secure.LOCATION_MODE_HIGH_ACCURACY:
- mode = Settings.Secure.LOCATION_MODE_BATTERY_SAVING;
- break;
- case Settings.Secure.LOCATION_MODE_BATTERY_SAVING:
- mode = Settings.Secure.LOCATION_MODE_HIGH_ACCURACY;
- break;
- case Settings.Secure.LOCATION_MODE_SENSORS_ONLY:
- mode = Settings.Secure.LOCATION_MODE_OFF;
- break;
- case Settings.Secure.LOCATION_MODE_OFF:
- mode = Settings.Secure.LOCATION_MODE_PREVIOUS;
- break;
- }
- Settings.Secure.putInt(resolver, Settings.Secure.LOCATION_MODE, mode);
- return mode != Settings.Secure.LOCATION_MODE_OFF;
+ LocationManager lm =
+ (LocationManager) context.getSystemService(
+ Context.LOCATION_SERVICE);
+ boolean currentLocationEnabled = lm.isLocationEnabled();
+ lm.setLocationEnabledForUser(
+ !currentLocationEnabled, Process.myUserHandle());
+ return lm.isLocationEnabled();
}
-
return getActualState(context) == STATE_ENABLED;
}
diff --git a/src/com/android/settings/widget/SwitchBar.java b/src/com/android/settings/widget/SwitchBar.java
index 3be5eca..749ec0a 100644
--- a/src/com/android/settings/widget/SwitchBar.java
+++ b/src/com/android/settings/widget/SwitchBar.java
@@ -39,9 +39,9 @@
import android.widget.TextView;
import com.android.settings.R;
+import com.android.settings.core.instrumentation.MetricsFeatureProvider;
import com.android.settings.overlay.FeatureFactory;
import com.android.settingslib.RestrictedLockUtils;
-import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
import java.util.ArrayList;
import java.util.List;
diff --git a/src/com/android/settings/wifi/WifiEnabler.java b/src/com/android/settings/wifi/WifiEnabler.java
index c5e79b2..9c43142 100644
--- a/src/com/android/settings/wifi/WifiEnabler.java
+++ b/src/com/android/settings/wifi/WifiEnabler.java
@@ -33,9 +33,9 @@
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.settings.R;
+import com.android.settings.core.instrumentation.MetricsFeatureProvider;
import com.android.settings.widget.SwitchWidgetController;
import com.android.settings.wrapper.ConnectivityManagerWrapper;
-import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
import com.android.settingslib.RestrictedLockUtils;
import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
import com.android.settingslib.WirelessUtils;
diff --git a/src/com/android/settings/wifi/WifiMasterSwitchPreferenceController.java b/src/com/android/settings/wifi/WifiMasterSwitchPreferenceController.java
index 8843d93..de1b030 100644
--- a/src/com/android/settings/wifi/WifiMasterSwitchPreferenceController.java
+++ b/src/com/android/settings/wifi/WifiMasterSwitchPreferenceController.java
@@ -19,12 +19,12 @@
import android.support.v7.preference.PreferenceScreen;
import com.android.settings.core.PreferenceControllerMixin;
+import com.android.settings.core.instrumentation.MetricsFeatureProvider;
import com.android.settings.R;
import com.android.settings.widget.SummaryUpdater;
import com.android.settings.widget.MasterSwitchPreference;
import com.android.settings.widget.MasterSwitchController;
import com.android.settingslib.core.AbstractPreferenceController;
-import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
import com.android.settingslib.core.lifecycle.LifecycleObserver;
import com.android.settingslib.core.lifecycle.events.OnPause;
import com.android.settingslib.core.lifecycle.events.OnResume;
diff --git a/src/com/android/settings/wifi/details/WifiDetailPreferenceController.java b/src/com/android/settings/wifi/details/WifiDetailPreferenceController.java
index 13ffd5b..82ffc38 100644
--- a/src/com/android/settings/wifi/details/WifiDetailPreferenceController.java
+++ b/src/com/android/settings/wifi/details/WifiDetailPreferenceController.java
@@ -54,6 +54,7 @@
import com.android.settings.Utils;
import com.android.settings.applications.LayoutPreference;
import com.android.settings.core.PreferenceControllerMixin;
+import com.android.settings.core.instrumentation.MetricsFeatureProvider;
import com.android.settings.widget.ActionButtonPreference;
import com.android.settings.widget.EntityHeaderController;
import com.android.settings.wifi.WifiDetailPreference;
@@ -62,7 +63,6 @@
import com.android.settings.wifi.WifiUtils;
import com.android.settings.wrapper.ConnectivityManagerWrapper;
import com.android.settingslib.core.AbstractPreferenceController;
-import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
import com.android.settingslib.core.lifecycle.Lifecycle;
import com.android.settingslib.core.lifecycle.LifecycleObserver;
import com.android.settingslib.core.lifecycle.events.OnPause;
@@ -280,7 +280,7 @@
.setButton1Text(R.string.forget)
.setButton1Positive(false)
.setButton1OnClickListener(view -> forgetNetwork())
- .setButton2Text(R.string.support_sign_in_button_text)
+ .setButton2Text(R.string.wifi_sign_in_button_text)
.setButton2Positive(true)
.setButton2OnClickListener(view -> signIntoNetwork());
diff --git a/src/com/android/settings/wifi/tether/WifiTetherApBandPreferenceController.java b/src/com/android/settings/wifi/tether/WifiTetherApBandPreferenceController.java
index 1e299ab..4c47a0d 100644
--- a/src/com/android/settings/wifi/tether/WifiTetherApBandPreferenceController.java
+++ b/src/com/android/settings/wifi/tether/WifiTetherApBandPreferenceController.java
@@ -18,6 +18,7 @@
import static android.net.wifi.WifiConfiguration.AP_BAND_2GHZ;
import static android.net.wifi.WifiConfiguration.AP_BAND_5GHZ;
+import static android.net.wifi.WifiConfiguration.AP_BAND_ANY;
import android.content.Context;
import android.net.wifi.WifiConfiguration;
@@ -32,7 +33,8 @@
private static final String TAG = "WifiTetherApBandPref";
private static final String PREF_KEY = "wifi_tether_network_ap_band";
private static final String[] BAND_VALUES =
- {String.valueOf(AP_BAND_2GHZ), String.valueOf(AP_BAND_5GHZ)};
+ {String.valueOf(AP_BAND_ANY), String.valueOf(AP_BAND_2GHZ),
+ String.valueOf(AP_BAND_5GHZ)};
private final String[] mBandEntries;
private int mBandIndex;
@@ -65,7 +67,7 @@
} else {
preference.setEntries(mBandEntries);
preference.setEntryValues(BAND_VALUES);
- preference.setSummary(mBandEntries[mBandIndex]);
+ preference.setSummary(mBandEntries[mBandIndex + 1]);
preference.setValue(String.valueOf(mBandIndex));
}
}
@@ -78,7 +80,8 @@
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
mBandIndex = Integer.parseInt((String) newValue);
- preference.setSummary(mBandEntries[mBandIndex]);
+ Log.d(TAG, "Band preference changed, updating band index to " + mBandIndex);
+ preference.setSummary(mBandEntries[mBandIndex + 1]);
mListener.onTetherConfigUpdated();
return true;
}
diff --git a/src/com/android/settings/wifi/tether/WifiTetherPreferenceController.java b/src/com/android/settings/wifi/tether/WifiTetherPreferenceController.java
index fa10607..11f1f59 100644
--- a/src/com/android/settings/wifi/tether/WifiTetherPreferenceController.java
+++ b/src/com/android/settings/wifi/tether/WifiTetherPreferenceController.java
@@ -24,6 +24,7 @@
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiManager;
import android.provider.Settings;
+import android.support.annotation.VisibleForTesting;
import android.support.v7.preference.PreferenceScreen;
import android.text.BidiFormatter;
@@ -51,7 +52,11 @@
private final WifiManager mWifiManager;
private final Lifecycle mLifecycle;
private WifiTetherSwitchBarController mSwitchController;
- private MasterSwitchPreference mPreference;
+ private int mSoftApState;
+ @VisibleForTesting
+ MasterSwitchPreference mPreference;
+ @VisibleForTesting
+ WifiTetherSoftApManager mWifiTetherSoftApManager;
static {
WIFI_TETHER_INTENT_FILTER = new IntentFilter(WifiManager.WIFI_AP_STATE_CHANGED_ACTION);
@@ -60,6 +65,12 @@
}
public WifiTetherPreferenceController(Context context, Lifecycle lifecycle) {
+ this(context, lifecycle, true /* initSoftApManager */);
+ }
+
+ @VisibleForTesting
+ WifiTetherPreferenceController(Context context, Lifecycle lifecycle,
+ boolean initSoftApManager) {
super(context);
mConnectivityManager =
(ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
@@ -69,6 +80,9 @@
if (lifecycle != null) {
lifecycle.addObserver(this);
}
+ if (initSoftApManager) {
+ initWifiTetherSoftApManager();
+ }
}
@Override
@@ -101,6 +115,9 @@
if (mPreference != null) {
mContext.registerReceiver(mReceiver, WIFI_TETHER_INTENT_FILTER);
clearSummaryForAirplaneMode();
+ if (mWifiTetherSoftApManager != null) {
+ mWifiTetherSoftApManager.registerSoftApCallback();
+ }
}
}
@@ -108,9 +125,36 @@
public void onStop() {
if (mPreference != null) {
mContext.unregisterReceiver(mReceiver);
+ if (mWifiTetherSoftApManager != null) {
+ mWifiTetherSoftApManager.unRegisterSoftApCallback();
+ }
}
}
+ @VisibleForTesting
+ void initWifiTetherSoftApManager() {
+ // This manager only handles the number of connected devices, other parts are handled by
+ // normal BroadcastReceiver in this controller
+ mWifiTetherSoftApManager = new WifiTetherSoftApManager(mWifiManager,
+ new WifiTetherSoftApManager.WifiTetherSoftApCallback() {
+ @Override
+ public void onStateChanged(int state, int failureReason) {
+ mSoftApState = state;
+ }
+
+ @Override
+ public void onNumClientsChanged(int numClients) {
+ if (mPreference != null
+ && mSoftApState == WifiManager.WIFI_AP_STATE_ENABLED) {
+ // Only show the number of clients when state is on
+ mPreference.setSummary(mContext.getResources().getQuantityString(
+ R.plurals.wifi_tether_connected_summary, numClients,
+ numClients));
+ }
+ }
+ });
+ }
+
//
// Everything below is copied from WifiApEnabler
//
diff --git a/src/com/android/settings/wifi/tether/WifiTetherSoftApManager.java b/src/com/android/settings/wifi/tether/WifiTetherSoftApManager.java
new file mode 100644
index 0000000..77a44b0
--- /dev/null
+++ b/src/com/android/settings/wifi/tether/WifiTetherSoftApManager.java
@@ -0,0 +1,47 @@
+package com.android.settings.wifi.tether;
+
+import android.net.wifi.WifiManager;
+import android.os.Handler;
+
+/**
+ * Wrapper for {@link android.net.wifi.WifiManager.SoftApCallback} to pass the robo test
+ */
+public class WifiTetherSoftApManager {
+
+ private WifiManager mWifiManager;
+ private WifiTetherSoftApCallback mWifiTetherSoftApCallback;
+
+ private WifiManager.SoftApCallback mSoftApCallback = new WifiManager.SoftApCallback() {
+ @Override
+ public void onStateChanged(int state, int failureReason) {
+ mWifiTetherSoftApCallback.onStateChanged(state, failureReason);
+ }
+
+ @Override
+ public void onNumClientsChanged(int numClients) {
+ mWifiTetherSoftApCallback.onNumClientsChanged(numClients);
+ }
+ };
+ private Handler mHandler;
+
+ WifiTetherSoftApManager(WifiManager wifiManager,
+ WifiTetherSoftApCallback wifiTetherSoftApCallback) {
+ mWifiManager = wifiManager;
+ mWifiTetherSoftApCallback = wifiTetherSoftApCallback;
+ mHandler = new Handler();
+ }
+
+ public void registerSoftApCallback() {
+ mWifiManager.registerSoftApCallback(mSoftApCallback, mHandler);
+ }
+
+ public void unRegisterSoftApCallback() {
+ mWifiManager.unregisterSoftApCallback(mSoftApCallback);
+ }
+
+ public interface WifiTetherSoftApCallback {
+ void onStateChanged(int state, int failureReason);
+
+ void onNumClientsChanged(int numClients);
+ }
+}
diff --git a/src/com/android/settings/wrapper/RecoverySystemWrapper.java b/src/com/android/settings/wrapper/RecoverySystemWrapper.java
new file mode 100644
index 0000000..c7ce244
--- /dev/null
+++ b/src/com/android/settings/wrapper/RecoverySystemWrapper.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2018 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.wrapper;
+
+import android.content.Context;
+import android.os.RecoverySystem;
+
+/**
+ * This class replicates a subset of the {@link RecoverySystem}.
+ * The interface exists so that we can use a thin wrapper around the RecoverySystem in
+ * production code and a mock in tests.
+ */
+public class RecoverySystemWrapper {
+
+ /**
+ * Returns whether wipe Euicc data successfully or not.
+ *
+ * @param packageName the package name of the caller app.
+ */
+ public boolean wipeEuiccData(
+ Context context, final String packageName) {
+ return RecoverySystem.wipeEuiccData(context, packageName);
+ }
+}
diff --git a/tests/robotests/res/values-mcc999/config.xml b/tests/robotests/res/values-mcc999/config.xml
index a3205f3..e755f27 100644
--- a/tests/robotests/res/values-mcc999/config.xml
+++ b/tests/robotests/res/values-mcc999/config.xml
@@ -20,6 +20,7 @@
<bool name="config_show_camera_laser_sensor">false</bool>
<bool name="config_show_connectivity_monitor">false</bool>
<bool name="config_display_recent_apps">false</bool>
+ <bool name="config_additional_system_update_setting_enable">true</bool>
<bool name="config_show_wifi_settings">false</bool>
<bool name="config_show_toggle_airplane">false</bool>
<bool name="config_show_high_power_apps">false</bool>
@@ -54,4 +55,6 @@
<bool name="config_show_vibrate_input_devices">false</bool>
<bool name="config_show_color_correction_preference">false</bool>
<bool name="config_show_color_inversion_preference">false</bool>
+ <bool name="config_show_system_update_settings">false</bool>
+ <bool name="config_wifi_support_connected_mac_randomization">false</bool>
</resources>
diff --git a/tests/robotests/res/values/config.xml b/tests/robotests/res/values/config.xml
index 4004106..359df6c 100644
--- a/tests/robotests/res/values/config.xml
+++ b/tests/robotests/res/values/config.xml
@@ -21,4 +21,5 @@
<bool name="config_show_camera_laser_sensor">true</bool>
<bool name="config_show_connectivity_monitor">true</bool>
<bool name="config_display_recent_apps">true</bool>
+ <bool name="config_wifi_support_connected_mac_randomization">true</bool>
</resources>
\ No newline at end of file
diff --git a/tests/robotests/src/android/content/om/IOverlayManager.java b/tests/robotests/src/android/content/om/IOverlayManager.java
index cc1d0ef..8a895e7 100644
--- a/tests/robotests/src/android/content/om/IOverlayManager.java
+++ b/tests/robotests/src/android/content/om/IOverlayManager.java
@@ -16,10 +16,15 @@
import android.os.IBinder;
+import java.util.ArrayList;
+import java.util.LinkedList;
+
public interface IOverlayManager {
public OverlayInfo getOverlayInfo(String packageName, int userId);
+ public java.util.List getOverlayInfosForTarget(java.lang.String targetPackageName, int userId);
+
public boolean setEnabled(java.lang.String packageName, boolean enable, int userId);
public static class Stub {
diff --git a/tests/robotests/src/android/content/om/OverlayInfo.java b/tests/robotests/src/android/content/om/OverlayInfo.java
index 98ce091..fb7fef1 100644
--- a/tests/robotests/src/android/content/om/OverlayInfo.java
+++ b/tests/robotests/src/android/content/om/OverlayInfo.java
@@ -14,8 +14,17 @@
package android.content.om;
+import android.annotation.NonNull;
+
public class OverlayInfo {
+ public final String packageName;
+
+ public OverlayInfo(@NonNull String packageName, @NonNull String targetPackageName,
+ @NonNull String baseCodePath, int state, int userId) {
+ this.packageName = packageName;
+ }
+
public boolean isEnabled() {
return false;
}
diff --git a/tests/robotests/src/android/service/notification/NotifyingApp.java b/tests/robotests/src/android/service/notification/NotifyingApp.java
new file mode 100644
index 0000000..f36069b
--- /dev/null
+++ b/tests/robotests/src/android/service/notification/NotifyingApp.java
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2018 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 android.service.notification;
+
+import android.annotation.NonNull;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.Objects;
+
+/**
+ * Stub implementation of framework's NotifyingApp for Robolectric tests. Otherwise Robolectric
+ * throws ClassNotFoundError.
+ *
+ * TODO: Remove this class when Robolectric supports P
+ */
+public final class NotifyingApp implements Comparable<NotifyingApp> {
+
+ private int mUid;
+ private String mPkg;
+ private long mLastNotified;
+
+ public NotifyingApp() {}
+
+ public int getUid() {
+ return mUid;
+ }
+
+ /**
+ * Sets the uid of the package that sent the notification. Returns self.
+ */
+ public NotifyingApp setUid(int mUid) {
+ this.mUid = mUid;
+ return this;
+ }
+
+ public String getPackage() {
+ return mPkg;
+ }
+
+ /**
+ * Sets the package that sent the notification. Returns self.
+ */
+ public NotifyingApp setPackage(@NonNull String mPkg) {
+ this.mPkg = mPkg;
+ return this;
+ }
+
+ public long getLastNotified() {
+ return mLastNotified;
+ }
+
+ /**
+ * Sets the time the notification was originally sent. Returns self.
+ */
+ public NotifyingApp setLastNotified(long mLastNotified) {
+ this.mLastNotified = mLastNotified;
+ return this;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ NotifyingApp that = (NotifyingApp) o;
+ return getUid() == that.getUid()
+ && getLastNotified() == that.getLastNotified()
+ && Objects.equals(mPkg, that.mPkg);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(getUid(), mPkg, getLastNotified());
+ }
+
+ /**
+ * Sorts notifying apps from newest last notified date to oldest.
+ */
+ @Override
+ public int compareTo(NotifyingApp o) {
+ if (getLastNotified() == o.getLastNotified()) {
+ if (getUid() == o.getUid()) {
+ return getPackage().compareTo(o.getPackage());
+ }
+ return Integer.compare(getUid(), o.getUid());
+ }
+
+ return -Long.compare(getLastNotified(), o.getLastNotified());
+ }
+
+ @Override
+ public String toString() {
+ return "NotifyingApp{"
+ + "mUid=" + mUid
+ + ", mPkg='" + mPkg + '\''
+ + ", mLastNotified=" + mLastNotified
+ + '}';
+ }
+}
diff --git a/tests/robotests/src/com/android/settings/MasterClearTest.java b/tests/robotests/src/com/android/settings/MasterClearTest.java
index 361bc8f..9bf3310 100644
--- a/tests/robotests/src/com/android/settings/MasterClearTest.java
+++ b/tests/robotests/src/com/android/settings/MasterClearTest.java
@@ -19,20 +19,29 @@
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.eq;
+import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;
import static org.robolectric.Shadows.shadowOf;
+import android.accounts.Account;
+import android.accounts.AccountManager;
import android.app.Activity;
import android.app.Fragment;
import android.content.ComponentName;
import android.content.ContentResolver;
+import android.content.Context;
import android.content.Intent;
+import android.content.pm.ActivityInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
import android.os.Bundle;
import android.provider.Settings;
import android.view.LayoutInflater;
import android.view.View;
+import android.widget.CheckBox;
import android.widget.LinearLayout;
import android.widget.ScrollView;
@@ -46,6 +55,7 @@
import org.mockito.MockitoAnnotations;
import org.robolectric.Robolectric;
import org.robolectric.annotation.Config;
+import org.robolectric.shadows.ShadowAccountManager;
import org.robolectric.shadows.ShadowActivity;
@RunWith(SettingsRobolectricTestRunner.class)
@@ -55,6 +65,9 @@
shadows = {ShadowUtils.class}
)
public class MasterClearTest {
+ private static final String TEST_ACCOUNT_TYPE = "android.test.account.type";
+ private static final String TEST_CONFIRMATION_PACKAGE = "android.test.confirmation.pkg";
+ private static final String TEST_ACCOUNT_NAME = "test@example.com";
@Mock
private MasterClear mMasterClear;
@@ -62,7 +75,18 @@
private ScrollView mScrollView;
@Mock
private LinearLayout mLinearLayout;
+
+ @Mock
+ private PackageManager mPackageManager;
+
+ @Mock
+ private AccountManager mAccountManager;
+
+ @Mock
+ private Activity mMockActivity;
+
private ShadowActivity mShadowActivity;
+ private ShadowAccountManager mShadowAccountManager;
private Activity mActivity;
private View mContentView;
@@ -86,6 +110,7 @@
mMasterClear = spy(new MasterClear());
mActivity = Robolectric.setupActivity(Activity.class);
mShadowActivity = shadowOf(mActivity);
+ // mShadowAccountManager = shadowOf(AccountManager.get(mActivity));
mContentView = LayoutInflater.from(mActivity).inflate(R.layout.master_clear, null);
// Make scrollView only have one child
@@ -94,6 +119,32 @@
}
@Test
+ public void testShowFinalConfirmation_eraseEsimChecked() {
+ ActivityForTest testActivity = new ActivityForTest();
+ when(mMasterClear.getActivity()).thenReturn(testActivity);
+
+ mMasterClear.mEsimStorage = mContentView.findViewById(R.id.erase_esim);
+ mMasterClear.mExternalStorage = mContentView.findViewById(R.id.erase_external);
+ mMasterClear.mEsimStorage.setChecked(true);
+ mMasterClear.showFinalConfirmation();
+ assertThat(testActivity.getArgs().getBoolean(MasterClear.ERASE_ESIMS_EXTRA, false))
+ .isTrue();
+ }
+
+ @Test
+ public void testShowFinalConfirmation_eraseEsimUnchecked() {
+ ActivityForTest testActivity = new ActivityForTest();
+ when(mMasterClear.getActivity()).thenReturn(testActivity);
+
+ mMasterClear.mEsimStorage = mContentView.findViewById(R.id.erase_esim);
+ mMasterClear.mExternalStorage = mContentView.findViewById(R.id.erase_external);
+ mMasterClear.mEsimStorage.setChecked(false);
+ mMasterClear.showFinalConfirmation();
+ assertThat(testActivity.getArgs().getBoolean(MasterClear.ERASE_ESIMS_EXTRA, true))
+ .isFalse();
+ }
+
+ @Test
public void testShowWipeEuicc_euiccDisabled() {
prepareEuiccState(
false /* isEuiccEnabled */, true /* isEuiccProvisioned */);
@@ -162,9 +213,68 @@
@Test
public void testTryShowAccountConfirmation_unsupported() {
- doReturn(mActivity).when(mMasterClear).getActivity();
- /* Using the default resources, account confirmation shouldn't trigger */
- assertThat(mMasterClear.tryShowAccountConfirmation()).isFalse();
+ when(mMasterClear.getActivity()).thenReturn(mActivity);
+ /* Using the default resources, account confirmation shouldn't trigger */
+ assertThat(mMasterClear.tryShowAccountConfirmation()).isFalse();
+ }
+
+ @Test
+ public void testTryShowAccountConfirmation_no_relevant_accounts() {
+ when(mMasterClear.getActivity()).thenReturn(mMockActivity);
+ when(mMockActivity.getString(R.string.account_type)).thenReturn(TEST_ACCOUNT_TYPE);
+ when(mMockActivity.getString(R.string.account_confirmation_package)).thenReturn(TEST_CONFIRMATION_PACKAGE);
+
+ Account[] accounts = new Account[0];
+ when(mMockActivity.getSystemService(Context.ACCOUNT_SERVICE)).thenReturn(mAccountManager);
+ when(mAccountManager.getAccountsByType(TEST_ACCOUNT_TYPE)).thenReturn(accounts);
+ assertThat(mMasterClear.tryShowAccountConfirmation()).isFalse();
+ }
+
+ @Test
+ public void testTryShowAccountConfirmation_unresolved() {
+ when(mMasterClear.getActivity()).thenReturn(mMockActivity);
+ when(mMockActivity.getString(R.string.account_type)).thenReturn(TEST_ACCOUNT_TYPE);
+ when(mMockActivity.getString(R.string.account_confirmation_package)).thenReturn(TEST_CONFIRMATION_PACKAGE);
+ Account[] accounts = new Account[] { new Account(TEST_ACCOUNT_NAME, TEST_ACCOUNT_TYPE) };
+ when(mMockActivity.getSystemService(Context.ACCOUNT_SERVICE)).thenReturn(mAccountManager);
+ when(mAccountManager.getAccountsByType(TEST_ACCOUNT_TYPE)).thenReturn(accounts);
+ // The package manager should not resolve the confirmation intent targeting the non-existent
+ // confirmation package.
+ when(mMockActivity.getPackageManager()).thenReturn(mPackageManager);
+ assertThat(mMasterClear.tryShowAccountConfirmation()).isFalse();
+ }
+
+ @Test
+ public void testTryShowAccountConfirmation_ok() {
+ when(mMasterClear.getActivity()).thenReturn(mMockActivity);
+ // Only try to show account confirmation if the appropriate resource overlays are available.
+ when(mMockActivity.getString(R.string.account_type)).thenReturn(TEST_ACCOUNT_TYPE);
+ when(mMockActivity.getString(R.string.account_confirmation_package)).thenReturn(TEST_CONFIRMATION_PACKAGE);
+ // Add accounts to trigger the search for a resolving intent.
+ Account[] accounts = new Account[] { new Account(TEST_ACCOUNT_NAME, TEST_ACCOUNT_TYPE) };
+ when(mMockActivity.getSystemService(Context.ACCOUNT_SERVICE)).thenReturn(mAccountManager);
+ when(mAccountManager.getAccountsByType(TEST_ACCOUNT_TYPE)).thenReturn(accounts);
+ // The package manager should not resolve the confirmation intent targeting the non-existent
+ // confirmation package.
+ when(mMockActivity.getPackageManager()).thenReturn(mPackageManager);
+
+ ActivityInfo activityInfo = new ActivityInfo();
+ activityInfo.packageName = TEST_CONFIRMATION_PACKAGE;
+ ResolveInfo resolveInfo = new ResolveInfo();
+ resolveInfo.activityInfo = activityInfo;
+ when(mPackageManager.resolveActivity(any(), eq(0))).thenReturn(resolveInfo);
+
+ // Finally mock out the startActivityForResultCall
+ doNothing().when(mMockActivity).startActivityForResult(any(), eq(MasterClear.CREDENTIAL_CONFIRM_REQUEST));
+
+ assertThat(mMasterClear.tryShowAccountConfirmation()).isTrue();
+ }
+
+ @Test
+ public void testIsValidRequestCode() {
+ assertThat(mMasterClear.isValidRequestCode(MasterClear.KEYGUARD_REQUEST)).isTrue();
+ assertThat(mMasterClear.isValidRequestCode(MasterClear.CREDENTIAL_CONFIRM_REQUEST)).isTrue();
+ assertThat(mMasterClear.isValidRequestCode(0)).isFalse();
}
private void initScrollView(int height, int scrollY, int childBottom) {
diff --git a/tests/robotests/src/com/android/settings/ResetNetworkConfirmTest.java b/tests/robotests/src/com/android/settings/ResetNetworkConfirmTest.java
new file mode 100644
index 0000000..f4b5f4c
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/ResetNetworkConfirmTest.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings;
+
+
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyBoolean;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+
+import android.app.Activity;
+import android.content.Context;
+
+import com.android.settings.testutils.SettingsRobolectricTestRunner;
+import com.android.settings.wrapper.RecoverySystemWrapper;
+
+import org.junit.Assert;
+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;
+
+@RunWith(SettingsRobolectricTestRunner.class)
+@Config(
+ manifest = TestConfig.MANIFEST_PATH,
+ sdk = TestConfig.SDK_VERSION
+)
+public class ResetNetworkConfirmTest {
+
+ private Activity mActivity;
+ @Mock
+ private ResetNetworkConfirm mResetNetworkConfirm;
+ @Mock
+ private RecoverySystemWrapper mRecoverySystem;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ mResetNetworkConfirm = spy(new ResetNetworkConfirm());
+ mRecoverySystem = spy(new RecoverySystemWrapper());
+ ResetNetworkConfirm.mRecoverySystem = mRecoverySystem;
+ mActivity = Robolectric.setupActivity(Activity.class);
+ }
+
+ @Test
+ public void testResetNetworkData_resetEsim() {
+ mResetNetworkConfirm.mEraseEsim = true;
+ doReturn(true)
+ .when(mRecoverySystem).wipeEuiccData(any(Context.class), anyString());
+
+ mResetNetworkConfirm.esimFactoryReset(mActivity, "" /* packageName */);
+ try {
+ // Waiting the Async task finished
+ Thread.sleep(10000); // 10 sec
+ } catch (InterruptedException ignore) {
+
+ }
+
+ Assert.assertNotNull(mResetNetworkConfirm.mEraseEsimTask);
+ verify(mRecoverySystem).wipeEuiccData(any(Context.class), anyString());
+ }
+
+ @Test
+ public void testResetNetworkData_notResetEsim() {
+ mResetNetworkConfirm.mEraseEsim = false;
+
+ mResetNetworkConfirm.esimFactoryReset(mActivity, "" /* packageName */);
+
+ Assert.assertNull(mResetNetworkConfirm.mEraseEsimTask);
+ verify(mRecoverySystem, never())
+ .wipeEuiccData(any(Context.class), anyString());
+ }
+}
diff --git a/tests/robotests/src/com/android/settings/SettingsDialogFragmentTest.java b/tests/robotests/src/com/android/settings/SettingsDialogFragmentTest.java
index 3a7d094..942634a 100644
--- a/tests/robotests/src/com/android/settings/SettingsDialogFragmentTest.java
+++ b/tests/robotests/src/com/android/settings/SettingsDialogFragmentTest.java
@@ -17,7 +17,6 @@
import android.app.Dialog;
import android.app.Fragment;
-import android.content.Context;
import org.junit.Before;
import org.junit.Test;
@@ -40,8 +39,6 @@
private static final int DIALOG_ID = 15;
@Mock
- private Context mContext;
- @Mock
private DialogCreatableFragment mDialogCreatable;
private SettingsPreferenceFragment.SettingsDialogFragment mDialogFragment;
@@ -56,10 +53,9 @@
mDialogFragment =
new SettingsPreferenceFragment.SettingsDialogFragment(mDialogCreatable, DIALOG_ID);
- mDialogFragment.onAttach(mContext);
mDialogFragment.getMetricsCategory();
- // getDialogMetricsCategory called in onAttach, and explicitly in test.
+ // getDialogMetricsCategory called in constructor, and explicitly in test.
verify(mDialogCreatable, times(2)).getDialogMetricsCategory(DIALOG_ID);
}
@@ -70,7 +66,6 @@
try {
mDialogFragment = new SettingsPreferenceFragment.SettingsDialogFragment(
mDialogCreatable, DIALOG_ID);
- mDialogFragment.onAttach(mContext);
} catch (IllegalStateException e) {
// getDialogMetricsCategory called in constructor
verify(mDialogCreatable).getDialogMetricsCategory(DIALOG_ID);
diff --git a/tests/robotests/src/com/android/settings/applications/instantapps/InstantAppButtonsControllerTest.java b/tests/robotests/src/com/android/settings/applications/instantapps/InstantAppButtonsControllerTest.java
index f85d43a..5c0badc 100644
--- a/tests/robotests/src/com/android/settings/applications/instantapps/InstantAppButtonsControllerTest.java
+++ b/tests/robotests/src/com/android/settings/applications/instantapps/InstantAppButtonsControllerTest.java
@@ -42,9 +42,9 @@
import com.android.settings.R;
import com.android.settings.TestConfig;
+import com.android.settings.core.instrumentation.MetricsFeatureProvider;
import com.android.settings.testutils.FakeFeatureFactory;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
-import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
import com.android.settingslib.wrapper.PackageManagerWrapper;
import org.junit.Before;
diff --git a/tests/robotests/src/com/android/settings/bluetooth/BluetoothDevicePreferenceTest.java b/tests/robotests/src/com/android/settings/bluetooth/BluetoothDevicePreferenceTest.java
index 71020be..e9d37f6 100644
--- a/tests/robotests/src/com/android/settings/bluetooth/BluetoothDevicePreferenceTest.java
+++ b/tests/robotests/src/com/android/settings/bluetooth/BluetoothDevicePreferenceTest.java
@@ -32,11 +32,11 @@
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.settings.R;
import com.android.settings.TestConfig;
+import com.android.settings.core.instrumentation.MetricsFeatureProvider;
import com.android.settings.testutils.FakeFeatureFactory;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
import com.android.settings.testutils.shadow.SettingsShadowResources;
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
-import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
import org.junit.Before;
import org.junit.Test;
diff --git a/tests/robotests/src/com/android/settings/bluetooth/BluetoothEnablerTest.java b/tests/robotests/src/com/android/settings/bluetooth/BluetoothEnablerTest.java
index 828b5a1..b973edb 100644
--- a/tests/robotests/src/com/android/settings/bluetooth/BluetoothEnablerTest.java
+++ b/tests/robotests/src/com/android/settings/bluetooth/BluetoothEnablerTest.java
@@ -29,13 +29,13 @@
import com.android.settings.R;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
import com.android.settings.TestConfig;
+import com.android.settings.core.instrumentation.MetricsFeatureProvider;
import com.android.settings.testutils.shadow.SettingsShadowResources;
import com.android.settings.widget.MasterSwitchController;
import com.android.settings.widget.MasterSwitchPreference;
import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
import com.android.settingslib.bluetooth.LocalBluetoothAdapter;
import com.android.settingslib.bluetooth.LocalBluetoothManager;
-import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
import org.junit.Before;
import org.junit.BeforeClass;
diff --git a/tests/robotests/src/com/android/settings/bluetooth/UtilsTest.java b/tests/robotests/src/com/android/settings/bluetooth/UtilsTest.java
index c3b22b3..8666ce3 100644
--- a/tests/robotests/src/com/android/settings/bluetooth/UtilsTest.java
+++ b/tests/robotests/src/com/android/settings/bluetooth/UtilsTest.java
@@ -26,11 +26,11 @@
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.settings.TestConfig;
+import com.android.settings.core.instrumentation.MetricsFeatureProvider;
import com.android.settings.testutils.FakeFeatureFactory;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
import com.android.settings.testutils.shadow.SettingsShadowResources;
import com.android.settingslib.bluetooth.LocalBluetoothManager;
-import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
import org.junit.Before;
import org.junit.Test;
diff --git a/tests/robotests/src/com/android/settings/core/instrumentation/InstrumentableFragmentCodeInspector.java b/tests/robotests/src/com/android/settings/core/instrumentation/InstrumentableFragmentCodeInspector.java
index 867b5df..4455549 100644
--- a/tests/robotests/src/com/android/settings/core/instrumentation/InstrumentableFragmentCodeInspector.java
+++ b/tests/robotests/src/com/android/settings/core/instrumentation/InstrumentableFragmentCodeInspector.java
@@ -20,7 +20,6 @@
import android.util.ArraySet;
import com.android.settings.core.codeinspection.CodeInspector;
-import com.android.settingslib.core.instrumentation.Instrumentable;
import java.util.ArrayList;
import java.util.List;
diff --git a/tests/robotests/src/com/android/settings/core/instrumentation/InstrumentedDialogFragmentTest.java b/tests/robotests/src/com/android/settings/core/instrumentation/InstrumentedDialogFragmentTest.java
index 8ad2d69..9e37896 100644
--- a/tests/robotests/src/com/android/settings/core/instrumentation/InstrumentedDialogFragmentTest.java
+++ b/tests/robotests/src/com/android/settings/core/instrumentation/InstrumentedDialogFragmentTest.java
@@ -21,7 +21,6 @@
import com.android.settings.TestConfig;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
-import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
import org.junit.Test;
import org.junit.runner.RunWith;
diff --git a/tests/robotests/src/com/android/settings/core/instrumentation/MetricsFeatureProviderTest.java b/tests/robotests/src/com/android/settings/core/instrumentation/MetricsFeatureProviderTest.java
index 2950c07..da48f15 100644
--- a/tests/robotests/src/com/android/settings/core/instrumentation/MetricsFeatureProviderTest.java
+++ b/tests/robotests/src/com/android/settings/core/instrumentation/MetricsFeatureProviderTest.java
@@ -31,9 +31,6 @@
import com.android.settings.TestConfig;
import com.android.settings.overlay.FeatureFactory;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
-import com.android.settingslib.core.instrumentation.LogWriter;
-import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
-import com.android.settingslib.core.instrumentation.VisibilityLoggerMixin;
import org.junit.Before;
import org.junit.Test;
@@ -61,6 +58,7 @@
@Mock private VisibilityLoggerMixin mockVisibilityLogger;
private Context mContext;
+ private MetricsFeatureProvider mProvider;
@Captor
private ArgumentCaptor<Pair> mPairCaptor;
@@ -69,6 +67,12 @@
public void setUp() {
MockitoAnnotations.initMocks(this);
mContext = RuntimeEnvironment.application;
+ mProvider = new MetricsFeatureProvider();
+ List<LogWriter> writers = new ArrayList<>();
+ writers.add(mockLogWriter);
+ ReflectionHelpers.setField(mProvider, "mLoggerWriters", writers);
+
+ when(mockVisibilityLogger.elapsedTimeSinceVisible()).thenReturn(ELAPSED_TIME);
}
@Test
@@ -80,4 +84,60 @@
assertThat(feature1 == feature2).isTrue();
}
+
+ @Test
+ public void logDashboardStartIntent_intentEmpty_shouldNotLog() {
+ mProvider.logDashboardStartIntent(mContext, null /* intent */,
+ MetricsEvent.SETTINGS_GESTURES);
+
+ verifyNoMoreInteractions(mockLogWriter);
+ }
+
+ @Test
+ public void logDashboardStartIntent_intentHasNoComponent_shouldLog() {
+ final Intent intent = new Intent(Intent.ACTION_ASSIST);
+
+ mProvider.logDashboardStartIntent(mContext, intent, MetricsEvent.SETTINGS_GESTURES);
+
+ verify(mockLogWriter).action(
+ eq(mContext),
+ eq(MetricsEvent.ACTION_SETTINGS_TILE_CLICK),
+ anyString(),
+ eq(Pair.create(MetricsEvent.FIELD_CONTEXT, MetricsEvent.SETTINGS_GESTURES)));
+ }
+
+ @Test
+ public void logDashboardStartIntent_intentIsExternal_shouldLog() {
+ final Intent intent = new Intent().setComponent(new ComponentName("pkg", "cls"));
+
+ mProvider.logDashboardStartIntent(mContext, intent, MetricsEvent.SETTINGS_GESTURES);
+
+ verify(mockLogWriter).action(
+ eq(mContext),
+ eq(MetricsEvent.ACTION_SETTINGS_TILE_CLICK),
+ anyString(),
+ eq(Pair.create(MetricsEvent.FIELD_CONTEXT, MetricsEvent.SETTINGS_GESTURES)));
+ }
+
+ @Test
+ public void action_BooleanLogsElapsedTime() {
+ mProvider.action(mockVisibilityLogger, CATEGORY, SUBTYPE_BOOLEAN);
+ verify(mockLogWriter).action(eq(CATEGORY), eq(SUBTYPE_BOOLEAN), mPairCaptor.capture());
+
+ Pair value = mPairCaptor.getValue();
+ assertThat(value.first instanceof Integer).isTrue();
+ assertThat((int) value.first).isEqualTo(MetricsEvent.NOTIFICATION_SINCE_VISIBLE_MILLIS);
+ assertThat(value.second).isEqualTo(ELAPSED_TIME);
+ }
+
+ @Test
+ public void action_IntegerLogsElapsedTime() {
+ mProvider.action(mockVisibilityLogger, CATEGORY, SUBTYPE_INTEGER);
+ verify(mockLogWriter).action(eq(CATEGORY), eq(SUBTYPE_INTEGER), mPairCaptor.capture());
+
+ Pair value = mPairCaptor.getValue();
+ assertThat(value.first instanceof Integer).isTrue();
+ assertThat((int) value.first).isEqualTo(MetricsEvent.NOTIFICATION_SINCE_VISIBLE_MILLIS);
+ assertThat(value.second).isEqualTo(ELAPSED_TIME);
+ }
}
diff --git a/tests/robotests/src/com/android/settings/core/instrumentation/SharedPreferenceLoggerTest.java b/tests/robotests/src/com/android/settings/core/instrumentation/SharedPreferenceLoggerTest.java
new file mode 100644
index 0000000..c80e3a8
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/core/instrumentation/SharedPreferenceLoggerTest.java
@@ -0,0 +1,185 @@
+/*
+ * 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.core.instrumentation;
+
+import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.ACTION_SETTINGS_PREFERENCE_CHANGE;
+import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_SETTINGS_PREFERENCE_CHANGE_FLOAT_VALUE;
+import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_SETTINGS_PREFERENCE_CHANGE_INT_VALUE;
+import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_SETTINGS_PREFERENCE_CHANGE_NAME;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Matchers.argThat;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.util.Pair;
+
+import com.android.settings.TestConfig;
+import com.android.settings.testutils.FakeFeatureFactory;
+import com.android.settings.testutils.SettingsRobolectricTestRunner;
+
+import com.google.common.truth.Platform;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Answers;
+import org.mockito.ArgumentMatcher;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.annotation.Config;
+
+@RunWith(SettingsRobolectricTestRunner.class)
+@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
+public class SharedPreferenceLoggerTest {
+
+ private static final String TEST_TAG = "tag";
+ private static final String TEST_KEY = "key";
+
+ @Mock(answer = Answers.RETURNS_DEEP_STUBS)
+ private Context mContext;
+
+ private ArgumentMatcher<Pair<Integer, Object>> mNamePairMatcher;
+ private FakeFeatureFactory mFactory;
+ private MetricsFeatureProvider mMetricsFeature;
+ private SharedPreferencesLogger mSharedPrefLogger;
+
+ @Before
+ public void init() {
+ MockitoAnnotations.initMocks(this);
+ mFactory = FakeFeatureFactory.setupForTest();
+ mMetricsFeature = mFactory.metricsFeatureProvider;
+
+ mSharedPrefLogger = new SharedPreferencesLogger(mContext, TEST_TAG);
+ mNamePairMatcher = pairMatches(FIELD_SETTINGS_PREFERENCE_CHANGE_NAME, String.class);
+ }
+
+ @Test
+ public void putInt_shouldNotLogInitialPut() {
+ final SharedPreferences.Editor editor = mSharedPrefLogger.edit();
+ editor.putInt(TEST_KEY, 1);
+ editor.putInt(TEST_KEY, 1);
+ editor.putInt(TEST_KEY, 1);
+ editor.putInt(TEST_KEY, 2);
+ editor.putInt(TEST_KEY, 2);
+ editor.putInt(TEST_KEY, 2);
+ editor.putInt(TEST_KEY, 2);
+
+ verify(mMetricsFeature, times(6)).action(any(Context.class), anyInt(),
+ argThat(mNamePairMatcher),
+ argThat(pairMatches(FIELD_SETTINGS_PREFERENCE_CHANGE_INT_VALUE, Integer.class)));
+ }
+
+ @Test
+ public void putBoolean_shouldNotLogInitialPut() {
+ final SharedPreferences.Editor editor = mSharedPrefLogger.edit();
+ editor.putBoolean(TEST_KEY, true);
+ editor.putBoolean(TEST_KEY, true);
+ editor.putBoolean(TEST_KEY, false);
+ editor.putBoolean(TEST_KEY, false);
+ editor.putBoolean(TEST_KEY, false);
+
+
+ verify(mMetricsFeature).action(any(Context.class), anyInt(),
+ argThat(mNamePairMatcher),
+ argThat(pairMatches(FIELD_SETTINGS_PREFERENCE_CHANGE_INT_VALUE, true)));
+ verify(mMetricsFeature, times(3)).action(any(Context.class), anyInt(),
+ argThat(mNamePairMatcher),
+ argThat(pairMatches(FIELD_SETTINGS_PREFERENCE_CHANGE_INT_VALUE, false)));
+ }
+
+ @Test
+ public void putLong_shouldNotLogInitialPut() {
+ final SharedPreferences.Editor editor = mSharedPrefLogger.edit();
+ editor.putLong(TEST_KEY, 1);
+ editor.putLong(TEST_KEY, 1);
+ editor.putLong(TEST_KEY, 1);
+ editor.putLong(TEST_KEY, 1);
+ editor.putLong(TEST_KEY, 2);
+
+ verify(mMetricsFeature, times(4)).action(any(Context.class), anyInt(),
+ argThat(mNamePairMatcher),
+ argThat(pairMatches(FIELD_SETTINGS_PREFERENCE_CHANGE_INT_VALUE, Integer.class)));
+ }
+
+ @Test
+ public void putLong_biggerThanIntMax_shouldLogIntMax() {
+ final SharedPreferences.Editor editor = mSharedPrefLogger.edit();
+ final long veryBigNumber = 500L + Integer.MAX_VALUE;
+ editor.putLong(TEST_KEY, 1);
+ editor.putLong(TEST_KEY, veryBigNumber);
+
+ verify(mMetricsFeature).action(any(Context.class), anyInt(),
+ argThat(mNamePairMatcher),
+ argThat(pairMatches(
+ FIELD_SETTINGS_PREFERENCE_CHANGE_INT_VALUE, Integer.MAX_VALUE)));
+ }
+
+ @Test
+ public void putLong_smallerThanIntMin_shouldLogIntMin() {
+ final SharedPreferences.Editor editor = mSharedPrefLogger.edit();
+ final long veryNegativeNumber = -500L + Integer.MIN_VALUE;
+ editor.putLong(TEST_KEY, 1);
+ editor.putLong(TEST_KEY, veryNegativeNumber);
+
+ verify(mMetricsFeature).action(any(Context.class), anyInt(),
+ argThat(mNamePairMatcher),
+ argThat(pairMatches(
+ FIELD_SETTINGS_PREFERENCE_CHANGE_INT_VALUE, Integer.MIN_VALUE)));
+ }
+
+ @Test
+ public void putFloat_shouldNotLogInitialPut() {
+ final SharedPreferences.Editor editor = mSharedPrefLogger.edit();
+ editor.putFloat(TEST_KEY, 1);
+ editor.putFloat(TEST_KEY, 1);
+ editor.putFloat(TEST_KEY, 1);
+ editor.putFloat(TEST_KEY, 1);
+ editor.putFloat(TEST_KEY, 2);
+
+ verify(mMetricsFeature, times(4)).action(any(Context.class), anyInt(),
+ argThat(mNamePairMatcher),
+ argThat(pairMatches(FIELD_SETTINGS_PREFERENCE_CHANGE_FLOAT_VALUE, Float.class)));
+ }
+
+ @Test
+ public void logPackage_shouldUseLogPackageApi() {
+ mSharedPrefLogger.logPackageName("key", "com.android.settings");
+ verify(mMetricsFeature).action(any(Context.class),
+ eq(ACTION_SETTINGS_PREFERENCE_CHANGE),
+ eq("com.android.settings"),
+ any(Pair.class));
+ }
+
+ private ArgumentMatcher<Pair<Integer, Object>> pairMatches(int tag, Class clazz) {
+ return pair -> pair.first == tag && Platform.isInstanceOfType(pair.second, clazz);
+ }
+
+ private ArgumentMatcher<Pair<Integer, Object>> pairMatches(int tag, boolean bool) {
+ return pair -> pair.first == tag
+ && Platform.isInstanceOfType(pair.second, Integer.class)
+ && pair.second.equals((bool ? 1 : 0));
+ }
+
+ private ArgumentMatcher<Pair<Integer, Object>> pairMatches(int tag, int val) {
+ return pair -> pair.first == tag
+ && Platform.isInstanceOfType(pair.second, Integer.class)
+ && pair.second.equals(val);
+ }
+}
diff --git a/tests/robotests/src/com/android/settings/core/instrumentation/VisibilityLoggerMixinTest.java b/tests/robotests/src/com/android/settings/core/instrumentation/VisibilityLoggerMixinTest.java
new file mode 100644
index 0000000..1a47a66
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/core/instrumentation/VisibilityLoggerMixinTest.java
@@ -0,0 +1,123 @@
+/*
+ * 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.core.instrumentation;
+
+import static com.android.settings.core.instrumentation.Instrumentable.METRICS_CATEGORY_UNKNOWN;
+
+import static org.mockito.ArgumentMatchers.nullable;
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.Intent;
+
+import com.android.internal.logging.nano.MetricsProto;
+import com.android.settings.SettingsActivity;
+import com.android.settings.testutils.SettingsRobolectricTestRunner;
+import com.android.settings.TestConfig;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.annotation.Config;
+
+
+@RunWith(SettingsRobolectricTestRunner.class)
+@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
+public class VisibilityLoggerMixinTest {
+
+ @Mock
+ private MetricsFeatureProvider mMetricsFeature;
+
+ private VisibilityLoggerMixin mMixin;
+
+ @Before
+ public void init() {
+ MockitoAnnotations.initMocks(this);
+ mMixin = new VisibilityLoggerMixin(TestInstrumentable.TEST_METRIC, mMetricsFeature);
+ }
+
+ @Test
+ public void shouldLogVisibleOnResume() {
+ mMixin.onResume();
+
+ verify(mMetricsFeature, times(1))
+ .visible(nullable(Context.class), eq(MetricsProto.MetricsEvent.VIEW_UNKNOWN),
+ eq(TestInstrumentable.TEST_METRIC));
+ }
+
+ @Test
+ public void shouldLogVisibleWithSource() {
+ final Intent sourceIntent = new Intent()
+ .putExtra(SettingsActivity.EXTRA_SOURCE_METRICS_CATEGORY,
+ MetricsProto.MetricsEvent.SETTINGS_GESTURES);
+ final Activity activity = mock(Activity.class);
+ when(activity.getIntent()).thenReturn(sourceIntent);
+ mMixin.setSourceMetricsCategory(activity);
+ mMixin.onResume();
+
+ verify(mMetricsFeature, times(1))
+ .visible(nullable(Context.class), eq(MetricsProto.MetricsEvent.SETTINGS_GESTURES),
+ eq(TestInstrumentable.TEST_METRIC));
+ }
+
+ @Test
+ public void shouldLogHideOnPause() {
+ mMixin.onPause();
+
+ verify(mMetricsFeature, times(1))
+ .hidden(nullable(Context.class), eq(TestInstrumentable.TEST_METRIC));
+ }
+
+ @Test
+ public void shouldNotLogIfMetricsFeatureIsNull() {
+ mMixin = new VisibilityLoggerMixin(TestInstrumentable.TEST_METRIC);
+ mMixin.onResume();
+ mMixin.onPause();
+
+ verify(mMetricsFeature, never())
+ .hidden(nullable(Context.class), anyInt());
+ }
+
+ @Test
+ public void shouldNotLogIfMetricsCategoryIsUnknown() {
+ mMixin = new VisibilityLoggerMixin(METRICS_CATEGORY_UNKNOWN, mMetricsFeature);
+
+ mMixin.onResume();
+ mMixin.onPause();
+
+ verify(mMetricsFeature, never())
+ .hidden(nullable(Context.class), anyInt());
+ }
+
+ private final class TestInstrumentable implements Instrumentable {
+
+ public static final int TEST_METRIC = 12345;
+
+ @Override
+ public int getMetricsCategory() {
+ return TEST_METRIC;
+ }
+ }
+}
diff --git a/tests/robotests/src/com/android/settings/dashboard/DashboardFeatureProviderImplTest.java b/tests/robotests/src/com/android/settings/dashboard/DashboardFeatureProviderImplTest.java
index afa914c..741f2bc 100644
--- a/tests/robotests/src/com/android/settings/dashboard/DashboardFeatureProviderImplTest.java
+++ b/tests/robotests/src/com/android/settings/dashboard/DashboardFeatureProviderImplTest.java
@@ -51,7 +51,6 @@
import com.android.settings.testutils.shadow.ShadowThreadUtils;
import com.android.settings.testutils.shadow.ShadowTileUtils;
import com.android.settings.testutils.shadow.ShadowUserManager;
-import com.android.settingslib.core.instrumentation.VisibilityLoggerMixin;
import com.android.settingslib.drawer.CategoryKey;
import com.android.settingslib.drawer.CategoryManager;
import com.android.settingslib.drawer.DashboardCategory;
@@ -373,7 +372,7 @@
final Intent launchIntent = shadowActivity.getNextStartedActivityForResult().intent;
assertThat(launchIntent.getAction())
.isEqualTo("TestAction");
- assertThat(launchIntent.getIntExtra(VisibilityLoggerMixin.EXTRA_SOURCE_METRICS_CATEGORY, 0))
+ assertThat(launchIntent.getIntExtra(SettingsActivity.EXTRA_SOURCE_METRICS_CATEGORY, 0))
.isEqualTo(MetricsProto.MetricsEvent.SETTINGS_GESTURES);
}
diff --git a/tests/robotests/src/com/android/settings/dashboard/DashboardFragmentTest.java b/tests/robotests/src/com/android/settings/dashboard/DashboardFragmentTest.java
index 40e590a..6c663ab 100644
--- a/tests/robotests/src/com/android/settings/dashboard/DashboardFragmentTest.java
+++ b/tests/robotests/src/com/android/settings/dashboard/DashboardFragmentTest.java
@@ -33,10 +33,10 @@
import com.android.settings.TestConfig;
import com.android.settings.core.PreferenceControllerMixin;
+import com.android.settings.core.instrumentation.VisibilityLoggerMixin;
import com.android.settings.testutils.FakeFeatureFactory;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
import com.android.settingslib.core.AbstractPreferenceController;
-import com.android.settingslib.core.instrumentation.VisibilityLoggerMixin;
import com.android.settingslib.drawer.DashboardCategory;
import com.android.settingslib.drawer.Tile;
import com.android.settingslib.drawer.TileUtils;
diff --git a/tests/robotests/src/com/android/settings/dashboard/conditional/ConditionTest.java b/tests/robotests/src/com/android/settings/dashboard/conditional/ConditionTest.java
index 1a3fa5e..d077e6f 100644
--- a/tests/robotests/src/com/android/settings/dashboard/conditional/ConditionTest.java
+++ b/tests/robotests/src/com/android/settings/dashboard/conditional/ConditionTest.java
@@ -22,7 +22,7 @@
import com.android.internal.logging.nano.MetricsProto;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
import com.android.settings.TestConfig;
-import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
+import com.android.settings.core.instrumentation.MetricsFeatureProvider;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
diff --git a/tests/robotests/src/com/android/settings/datausage/DataUsageListTest.java b/tests/robotests/src/com/android/settings/datausage/DataUsageListTest.java
index 8b3c770..9ab88d3 100644
--- a/tests/robotests/src/com/android/settings/datausage/DataUsageListTest.java
+++ b/tests/robotests/src/com/android/settings/datausage/DataUsageListTest.java
@@ -60,7 +60,6 @@
@Test
public void resumePause_shouldListenUnlistenDataStateChange() {
- mDataUsageList.onAttach(mContext);
mDataUsageList.onResume();
verify(mListener).setListener(true, 0, mContext);
diff --git a/tests/robotests/src/com/android/settings/datetime/ZonePickerTest.java b/tests/robotests/src/com/android/settings/datetime/ZonePickerTest.java
index 9f6d0ef..92807e9 100644
--- a/tests/robotests/src/com/android/settings/datetime/ZonePickerTest.java
+++ b/tests/robotests/src/com/android/settings/datetime/ZonePickerTest.java
@@ -28,8 +28,8 @@
import com.android.settings.testutils.SettingsRobolectricTestRunner;
import com.android.settings.TestConfig;
+import com.android.settings.core.instrumentation.VisibilityLoggerMixin;
import com.android.settings.testutils.shadow.ShadowZoneGetter;
-import com.android.settingslib.core.instrumentation.VisibilityLoggerMixin;
import org.junit.Before;
import org.junit.Test;
diff --git a/tests/robotests/src/com/android/settings/deletionhelper/AutomaticStorageManagerSwitchBarControllerTest.java b/tests/robotests/src/com/android/settings/deletionhelper/AutomaticStorageManagerSwitchBarControllerTest.java
index ab32fa2..66ccc6e 100644
--- a/tests/robotests/src/com/android/settings/deletionhelper/AutomaticStorageManagerSwitchBarControllerTest.java
+++ b/tests/robotests/src/com/android/settings/deletionhelper/AutomaticStorageManagerSwitchBarControllerTest.java
@@ -31,11 +31,11 @@
import com.android.internal.logging.nano.MetricsProto;
import com.android.settings.TestConfig;
+import com.android.settings.core.instrumentation.MetricsFeatureProvider;
import com.android.settings.testutils.FakeFeatureFactory;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
import com.android.settings.testutils.shadow.SettingsShadowSystemProperties;
import com.android.settings.widget.SwitchBar;
-import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
import org.junit.Before;
import org.junit.Test;
diff --git a/tests/robotests/src/com/android/settings/development/EmulateDisplayCutoutPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/development/EmulateDisplayCutoutPreferenceControllerTest.java
index c9841f6..a6af6d6 100644
--- a/tests/robotests/src/com/android/settings/development/EmulateDisplayCutoutPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/development/EmulateDisplayCutoutPreferenceControllerTest.java
@@ -16,6 +16,9 @@
package com.android.settings.development;
+import static com.android.settings.development.EmulateDisplayCutoutPreferenceController
+ .EMULATION_OVERLAY_PREFIX;
+
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
@@ -29,7 +32,8 @@
import android.content.Context;
import android.content.om.IOverlayManager;
import android.content.om.OverlayInfo;
-import android.support.v7.preference.TwoStatePreference;
+import android.content.pm.PackageManager;
+import android.support.v7.preference.ListPreference;
import com.android.settings.TestConfig;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
@@ -41,78 +45,95 @@
import org.mockito.MockitoAnnotations;
import org.robolectric.annotation.Config;
+import java.util.Arrays;
+
@RunWith(SettingsRobolectricTestRunner.class)
@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
public class EmulateDisplayCutoutPreferenceControllerTest {
+ static final OverlayInfo ONE_DISABLED =
+ new FakeOverlay(EMULATION_OVERLAY_PREFIX + ".one", false);
+ static final OverlayInfo ONE_ENABLED =
+ new FakeOverlay(EMULATION_OVERLAY_PREFIX + ".one", true);
+ static final OverlayInfo TWO_DISABLED =
+ new FakeOverlay(EMULATION_OVERLAY_PREFIX + ".two", false);
+ static final OverlayInfo TWO_ENABLED =
+ new FakeOverlay(EMULATION_OVERLAY_PREFIX + ".two", true);
+
@Mock Context mContext;
@Mock IOverlayManager mOverlayManager;
- @Mock TwoStatePreference mPreference;
+ @Mock PackageManager mPackageManager;
+ @Mock ListPreference mPreference;
EmulateDisplayCutoutPreferenceController mController;
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
- when(mOverlayManager.getOverlayInfo(any(), anyInt())).thenReturn(DISABLED);
- mController = new EmulateDisplayCutoutPreferenceController(mContext, mOverlayManager);
+ mockCurrentOverlays();
+ when(mPackageManager.getApplicationInfo(any(), anyInt())).thenThrow(
+ PackageManager.NameNotFoundException.class);
+ mController = createController();
mController.setPreference(mPreference);
}
+ Object mockCurrentOverlays(OverlayInfo... overlays) {
+ return when(mOverlayManager.getOverlayInfosForTarget(eq("android"), anyInt()))
+ .thenReturn(Arrays.<OverlayInfo>asList(overlays));
+ }
+
@Test
public void isAvailable_true() throws Exception {
- when(mOverlayManager.getOverlayInfo(any(), anyInt())).thenReturn(DISABLED);
+ mockCurrentOverlays(ONE_DISABLED, TWO_DISABLED);
- assertThat(new EmulateDisplayCutoutPreferenceController(mContext, mOverlayManager)
- .isAvailable()).isTrue();
+ assertThat(createController().isAvailable()).isTrue();
}
@Test
public void isAvailable_false() throws Exception {
- when(mOverlayManager.getOverlayInfo(any(), anyInt())).thenReturn(null);
+ mockCurrentOverlays();
- assertThat(new EmulateDisplayCutoutPreferenceController(mContext, mOverlayManager)
- .isAvailable()).isFalse();
+ assertThat(createController().isAvailable()).isFalse();
}
@Test
public void onPreferenceChange_enable() throws Exception {
- when(mOverlayManager.getOverlayInfo(any(), anyInt())).thenReturn(DISABLED);
+ mockCurrentOverlays(ONE_DISABLED, TWO_DISABLED);
- mController.onPreferenceChange(null, true);
+ mController.onPreferenceChange(null, TWO_DISABLED.packageName);
- verify(mOverlayManager).setEnabled(any(), eq(true), anyInt());
+ verify(mOverlayManager).setEnabled(eq(TWO_DISABLED.packageName), eq(true), anyInt());
}
@Test
public void onPreferenceChange_disable() throws Exception {
- when(mOverlayManager.getOverlayInfo(any(), anyInt())).thenReturn(ENABLED);
+ mockCurrentOverlays(ONE_DISABLED, TWO_ENABLED);
- mController.onPreferenceChange(null, false);
+ mController.onPreferenceChange(null, "");
- verify(mOverlayManager).setEnabled(any(), eq(false), anyInt());
+ verify(mOverlayManager).setEnabled(eq(TWO_ENABLED.packageName), eq(false), anyInt());
}
@Test
public void updateState_enabled() throws Exception {
- when(mOverlayManager.getOverlayInfo(any(), anyInt())).thenReturn(ENABLED);
+ mockCurrentOverlays(ONE_DISABLED, TWO_ENABLED);
mController.updateState(null);
- verify(mPreference).setChecked(true);
+ verify(mPreference).setValueIndex(2);
}
@Test
public void updateState_disabled() throws Exception {
- when(mOverlayManager.getOverlayInfo(any(), anyInt())).thenReturn(DISABLED);
+ mockCurrentOverlays(ONE_DISABLED, TWO_DISABLED);
mController.updateState(null);
- verify(mPreference).setChecked(false);
+ verify(mPreference).setValueIndex(0);
}
@Test
public void onDeveloperOptionsSwitchEnabled() throws Exception {
- when(mOverlayManager.getOverlayInfo(any(), anyInt())).thenReturn(DISABLED);
+ mockCurrentOverlays();
mController.onDeveloperOptionsSwitchEnabled();
@@ -122,27 +143,30 @@
@Test
public void onDeveloperOptionsSwitchDisabled() throws Exception {
- when(mOverlayManager.getOverlayInfo(any(), anyInt())).thenReturn(ENABLED);
+ mockCurrentOverlays(ONE_ENABLED, TWO_DISABLED);
mController.onDeveloperOptionsSwitchDisabled();
verify(mPreference).setEnabled(false);
- verify(mPreference).setChecked(false);
- verify(mOverlayManager).setEnabled(any(), eq(false), anyInt());
+ verify(mOverlayManager).setEnabled(eq(ONE_ENABLED.packageName), eq(false), anyInt());
}
- static final OverlayInfo ENABLED = new OverlayInfo() {
+ private EmulateDisplayCutoutPreferenceController createController() {
+ return new EmulateDisplayCutoutPreferenceController(mContext, mPackageManager,
+ mOverlayManager);
+ }
+
+ private static class FakeOverlay extends OverlayInfo {
+ private final boolean mEnabled;
+
+ public FakeOverlay(String pkg, boolean enabled) {
+ super(pkg, "android", "/", 0, 0);
+ mEnabled = enabled;
+ }
+
@Override
public boolean isEnabled() {
- return true;
+ return mEnabled;
}
- };
-
- static final OverlayInfo DISABLED = new OverlayInfo() {
- @Override
- public boolean isEnabled() {
- return false;
- }
- };
-
+ }
}
\ No newline at end of file
diff --git a/tests/robotests/src/com/android/settings/development/WifiConnectedMacRandomizationPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/development/WifiConnectedMacRandomizationPreferenceControllerTest.java
new file mode 100644
index 0000000..9a80c5c
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/development/WifiConnectedMacRandomizationPreferenceControllerTest.java
@@ -0,0 +1,133 @@
+/*
+ * 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.development;
+
+import static com.android.settings.development.WifiConnectedMacRandomizationPreferenceController
+ .SETTING_VALUE_OFF;
+import static com.android.settings.development.WifiConnectedMacRandomizationPreferenceController
+ .SETTING_VALUE_ON;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.provider.Settings;
+import android.support.v14.preference.SwitchPreference;
+import android.support.v7.preference.PreferenceScreen;
+
+import com.android.settings.TestConfig;
+import com.android.settings.testutils.SettingsRobolectricTestRunner;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.annotation.Config;
+import org.robolectric.RuntimeEnvironment;
+
+@RunWith(SettingsRobolectricTestRunner.class)
+@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
+public class WifiConnectedMacRandomizationPreferenceControllerTest {
+
+ @Mock
+ private PreferenceScreen mPreferenceScreen;
+
+ private Context mContext;
+ private SwitchPreference mPreference;
+ private WifiConnectedMacRandomizationPreferenceController mController;
+
+ @Before
+ public void setup() {
+ MockitoAnnotations.initMocks(this);
+ mContext = RuntimeEnvironment.application;
+ mController = new WifiConnectedMacRandomizationPreferenceController(mContext);
+ mPreference = new SwitchPreference(mContext);
+ when(mPreferenceScreen.findPreference(mController.getPreferenceKey())).thenReturn(
+ mPreference);
+ mController.displayPreference(mPreferenceScreen);
+ }
+
+ @Test
+ public void isAvailable_trueSupportFlag_shouldReturnTrue() {
+ assertThat(mController.isAvailable()).isTrue();
+ }
+
+ @Test
+ @Config(qualifiers = "mcc999")
+ public void isAvailable_falseSupportFlag_shouldReturnFalse() {
+ assertThat(mController.isAvailable()).isFalse();
+ }
+
+ @Test
+ public void onPreferenceChange_settingEnabled_shouldEnableConnectedMacRandomization() {
+ mController.onPreferenceChange(mPreference, true /* new value */);
+
+ final int mode = Settings.Global.getInt(mContext.getContentResolver(),
+ Settings.Global.WIFI_CONNECTED_MAC_RANDOMIZATION_ENABLED, -1 /* default */);
+
+ assertThat(mode).isEqualTo(SETTING_VALUE_ON);
+ }
+
+ @Test
+ public void onPreferenceChange_settingDisabled_shouldDisableConnectedMacRandomization() {
+ mController.onPreferenceChange(mPreference, false /* new value */);
+
+ final int mode = Settings.Global.getInt(mContext.getContentResolver(),
+ Settings.Global.WIFI_CONNECTED_MAC_RANDOMIZATION_ENABLED, -1 /* default */);
+
+ assertThat(mode).isEqualTo(SETTING_VALUE_OFF);
+ }
+
+ @Test
+ public void updateState_settingEnabled_shouldEnablePreference() {
+ Settings.Global.putInt(mContext.getContentResolver(),
+ Settings.Global.WIFI_CONNECTED_MAC_RANDOMIZATION_ENABLED, SETTING_VALUE_ON);
+ mController.updateState(mPreference);
+
+ assertThat(mPreference.isChecked()).isTrue();
+ }
+
+ @Test
+ public void updateState_settingDisabled_shouldDisablePreference() {
+ Settings.Global.putInt(mContext.getContentResolver(),
+ Settings.Global.WIFI_CONNECTED_MAC_RANDOMIZATION_ENABLED, SETTING_VALUE_OFF);
+ mController.updateState(mPreference);
+
+ assertThat(mPreference.isChecked()).isFalse();
+ }
+
+ @Test
+ public void onDeveloperOptionsSwitchEnabled_shouldEnablePreference() {
+ mController.onDeveloperOptionsSwitchEnabled();
+
+ assertThat(mPreference.isEnabled()).isTrue();
+ }
+
+ @Test
+ public void onDeveloperOptionsSwitchDisabled_shouldDisablePreference() {
+ mController.onDeveloperOptionsSwitchDisabled();
+
+ final int mode = Settings.Global.getInt(mContext.getContentResolver(),
+ Settings.Global.WIFI_CONNECTED_MAC_RANDOMIZATION_ENABLED, -1 /* default */);
+
+ assertThat(mode).isEqualTo(SETTING_VALUE_OFF);
+ assertThat(mPreference.isChecked()).isFalse();
+ assertThat(mPreference.isEnabled()).isFalse();
+ }
+}
diff --git a/tests/robotests/src/com/android/settings/deviceinfo/AdditionalSystemUpdatePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/deviceinfo/AdditionalSystemUpdatePreferenceControllerTest.java
new file mode 100644
index 0000000..e5708ba
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/deviceinfo/AdditionalSystemUpdatePreferenceControllerTest.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.settings.deviceinfo;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.content.Context;
+
+import com.android.settings.R;
+import com.android.settings.TestConfig;
+import com.android.settings.testutils.SettingsRobolectricTestRunner;
+
+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;
+
+@RunWith(SettingsRobolectricTestRunner.class)
+@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
+public class AdditionalSystemUpdatePreferenceControllerTest {
+
+ private Context mContext;
+ private AdditionalSystemUpdatePreferenceController mController;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+
+ mContext = RuntimeEnvironment.application;
+ mController = new AdditionalSystemUpdatePreferenceController(mContext);
+ }
+
+ @Test
+ public void displayPrefs_ifNotAvailable_shouldNotDisplay() {
+ assertThat(mController.isAvailable()).isFalse();
+ }
+
+ @Test
+ @Config(qualifiers = "mcc999")
+ public void displayPrefs_ifAvailable_shouldDisplay() {
+ assertThat(mController.isAvailable()).isTrue();
+ }
+}
diff --git a/tests/robotests/src/com/android/settings/deviceinfo/BrandedAccountPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/deviceinfo/BrandedAccountPreferenceControllerTest.java
new file mode 100644
index 0000000..521800b
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/deviceinfo/BrandedAccountPreferenceControllerTest.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.deviceinfo;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.when;
+
+import android.accounts.Account;
+import android.content.Context;
+
+import com.android.settings.TestConfig;
+import com.android.settings.testutils.FakeFeatureFactory;
+import com.android.settings.testutils.SettingsRobolectricTestRunner;
+
+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;
+
+@RunWith(SettingsRobolectricTestRunner.class)
+@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
+public class BrandedAccountPreferenceControllerTest {
+ @Mock(answer = Answers.RETURNS_DEEP_STUBS)
+ private Context mContext;
+ private BrandedAccountPreferenceController mController;
+ private FakeFeatureFactory fakeFeatureFactory;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ fakeFeatureFactory = FakeFeatureFactory.setupForTest();
+ mController = new BrandedAccountPreferenceController(mContext);
+ }
+
+ @Test
+ public void isAvailable_defaultOff() {
+ assertThat(mController.isAvailable()).isFalse();
+ }
+
+ @Test
+ public void isAvailable_onWhenAccountIsAvailable() {
+ when(fakeFeatureFactory.mAccountFeatureProvider.getAccounts(any(Context.class))).thenReturn(
+ new Account[]
+ {new Account("fake@account.foo", "fake.reallyfake")});
+ mController = new BrandedAccountPreferenceController(mContext);
+ assertThat(mController.isAvailable()).isTrue();
+ }
+}
diff --git a/tests/robotests/src/com/android/settings/deviceinfo/MyDeviceInfoFragmentTest.java b/tests/robotests/src/com/android/settings/deviceinfo/MyDeviceInfoFragmentTest.java
new file mode 100644
index 0000000..36f0662
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/deviceinfo/MyDeviceInfoFragmentTest.java
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.deviceinfo;
+
+import static com.android.settings.SettingsActivity.EXTRA_FRAGMENT_ARG_KEY;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.app.Activity;
+import android.content.Context;
+import android.os.Bundle;
+import android.support.v7.preference.PreferenceScreen;
+import android.telephony.TelephonyManager;
+
+import com.android.settings.deviceinfo.aboutphone.MyDeviceInfoFragment;
+import com.android.settings.TestConfig;
+import com.android.settings.testutils.FakeFeatureFactory;
+import com.android.settings.testutils.SettingsRobolectricTestRunner;
+import com.android.settings.testutils.shadow.SettingsShadowResources;
+import com.android.settings.testutils.shadow.SettingsShadowSystemProperties;
+import com.android.settings.testutils.shadow.ShadowConnectivityManager;
+import com.android.settings.testutils.shadow.ShadowUserManager;
+
+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.shadows.ShadowApplication;
+
+@RunWith(SettingsRobolectricTestRunner.class)
+@Config(
+ manifest = TestConfig.MANIFEST_PATH,
+ sdk = TestConfig.SDK_VERSION,
+ shadows = {ShadowConnectivityManager.class, ShadowUserManager.class}
+)
+public class MyDeviceInfoFragmentTest {
+ @Mock
+ private Activity mActivity;
+ @Mock
+ private PreferenceScreen mScreen;
+ @Mock
+ private TelephonyManager mTelephonyManager;
+
+ private Context mContext;
+ private MyDeviceInfoFragment mSettings;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ FakeFeatureFactory.setupForTest();
+ mContext = RuntimeEnvironment.application;
+ mSettings = spy(new MyDeviceInfoFragment());
+
+ when(mSettings.getActivity()).thenReturn(mActivity);
+ when(mSettings.getContext()).thenReturn(mContext);
+ when(mActivity.getTheme()).thenReturn(mContext.getTheme());
+ when(mActivity.getResources()).thenReturn(mContext.getResources());
+ doNothing().when(mSettings).onCreatePreferences(any(), any());
+
+ doReturn(mScreen).when(mSettings).getPreferenceScreen();
+ when(mSettings.getPreferenceScreen()).thenReturn(mScreen);
+ ShadowApplication.getInstance().setSystemService(Context.TELEPHONY_SERVICE,
+ mTelephonyManager);
+ }
+
+ @Test
+ @Config(shadows = {SettingsShadowResources.SettingsShadowTheme.class,
+ SettingsShadowSystemProperties.class})
+ public void onCreate_fromSearch_shouldNotOverrideInitialExpandedCount() {
+ final Bundle args = new Bundle();
+ args.putString(EXTRA_FRAGMENT_ARG_KEY, "search_key");
+ mSettings.setArguments(args);
+
+ mSettings.onCreate(null /* icicle */);
+
+ verify(mScreen).setInitialExpandedChildrenCount(Integer.MAX_VALUE);
+ }
+}
diff --git a/tests/robotests/src/com/android/settings/deviceinfo/SystemUpdatePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/deviceinfo/SystemUpdatePreferenceControllerTest.java
index 1fd5430..b5b84da 100644
--- a/tests/robotests/src/com/android/settings/deviceinfo/SystemUpdatePreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/deviceinfo/SystemUpdatePreferenceControllerTest.java
@@ -16,7 +16,9 @@
package com.android.settings.deviceinfo;
import static com.google.common.truth.Truth.assertThat;
+
import static org.mockito.Answers.RETURNS_DEEP_STUBS;
+import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;
import android.content.Context;
@@ -28,6 +30,7 @@
import com.android.settings.R;
import com.android.settings.TestConfig;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
+import com.android.settings.testutils.shadow.ShadowUserManager;
import org.junit.Before;
import org.junit.Test;
@@ -36,29 +39,32 @@
import org.mockito.MockitoAnnotations;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Config;
+import org.robolectric.shadows.ShadowApplication;
import java.util.ArrayList;
import java.util.List;
@RunWith(SettingsRobolectricTestRunner.class)
-@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
+@Config(
+ manifest = TestConfig.MANIFEST_PATH,
+ sdk = TestConfig.SDK_VERSION,
+ shadows = {
+ ShadowUserManager.class
+ })
public class SystemUpdatePreferenceControllerTest {
- @Mock(answer = RETURNS_DEEP_STUBS)
- private Context mContext;
- @Mock
- private UserManager mUserManager;
@Mock
private PreferenceScreen mScreen;
+ private Context mContext;
private SystemUpdatePreferenceController mController;
private Preference mPreference;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
+ mContext = RuntimeEnvironment.application;
- when(mContext.getSystemService(Context.USER_SERVICE)).thenReturn(mUserManager);
mController = new SystemUpdatePreferenceController(mContext);
mPreference = new Preference(RuntimeEnvironment.application);
mPreference.setKey(mController.getPreferenceKey());
@@ -66,12 +72,9 @@
}
@Test
- public void updateNonIndexable_bothAvailable_shouldNotUpdate() {
+ public void updateNonIndexable_ifAvailable_shouldNotUpdate() {
final List<String> keys = new ArrayList<>();
- when(mUserManager.isAdminUser()).thenReturn(true);
- when(mContext.getResources().getBoolean(
- R.bool.config_additional_system_update_setting_enable))
- .thenReturn(true);
+ ShadowUserManager.getShadow().setIsAdminUser(true);
mController.updateNonIndexableKeys(keys);
@@ -79,7 +82,8 @@
}
@Test
- public void updateNonIndexable_nothingAvailable_shouldUpdateWith2Prefs() {
+ public void updateNonIndexable_ifNotAvailable_shouldUpdate() {
+ ShadowUserManager.getShadow().setIsAdminUser(false);
final List<String> keys = new ArrayList<>();
mController.updateNonIndexableKeys(keys);
@@ -88,31 +92,37 @@
}
@Test
- public void displayPrefs_nothingAvailable_shouldNotDisplay() {
+ public void displayPrefs_ifVisible_butNotAdminUser_shouldNotDisplay() {
+ ShadowUserManager.getShadow().setIsAdminUser(false);
mController.displayPreference(mScreen);
assertThat(mPreference.isVisible()).isFalse();
}
@Test
- public void updateState_shouldSetToAndroidVersion() {
- mController = new SystemUpdatePreferenceController(RuntimeEnvironment.application);
+ @Config(qualifiers = "mcc999")
+ public void displayPrefs_ifAdminUser_butNotVisible_shouldNotDisplay() {
+ ShadowUserManager.getShadow().setIsAdminUser(true);
+ mController.displayPreference(mScreen);
+ assertThat(mPreference.isVisible()).isFalse();
+ }
+
+ @Test
+ public void displayPrefs_ifAvailable_shouldDisplay() {
+ ShadowUserManager.getShadow().setIsAdminUser(true);
+
+ mController.displayPreference(mScreen);
+
+ assertThat(mPreference.isVisible()).isTrue();
+ }
+
+ @Test
+ public void updateState_shouldSetToAndroidVersion() {
mController.updateState(mPreference);
assertThat(mPreference.getSummary())
.isEqualTo(RuntimeEnvironment.application.getString(R.string.about_summary,
Build.VERSION.RELEASE));
}
-
- @Test
- public void displayPrefs_oneAvailable_shouldDisplayOne() {
- when(mContext.getResources().getBoolean(
- R.bool.config_additional_system_update_setting_enable))
- .thenReturn(true);
-
- mController.displayPreference(mScreen);
-
- assertThat(mPreference.isVisible()).isFalse();
- }
-}
+}
\ No newline at end of file
diff --git a/tests/robotests/src/com/android/settings/deviceinfo/storage/AutomaticStorageManagementSwitchPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/deviceinfo/storage/AutomaticStorageManagementSwitchPreferenceControllerTest.java
index 9c56611..90ce395 100644
--- a/tests/robotests/src/com/android/settings/deviceinfo/storage/AutomaticStorageManagementSwitchPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/deviceinfo/storage/AutomaticStorageManagementSwitchPreferenceControllerTest.java
@@ -37,13 +37,13 @@
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.internal.os.RoSystemProperties;
import com.android.settings.TestConfig;
+import com.android.settings.core.instrumentation.MetricsFeatureProvider;
import com.android.settings.deletionhelper.ActivationWarningFragment;
import com.android.settings.overlay.FeatureFactory;
import com.android.settings.testutils.FakeFeatureFactory;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
import com.android.settings.testutils.shadow.SettingsShadowSystemProperties;
import com.android.settings.widget.MasterSwitchPreference;
-import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
import org.junit.After;
import org.junit.Before;
diff --git a/tests/robotests/src/com/android/settings/deviceinfo/storage/StorageItemPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/deviceinfo/storage/StorageItemPreferenceControllerTest.java
index 2da756f..1a3139d 100644
--- a/tests/robotests/src/com/android/settings/deviceinfo/storage/StorageItemPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/deviceinfo/storage/StorageItemPreferenceControllerTest.java
@@ -50,13 +50,13 @@
import com.android.settings.SubSettings;
import com.android.settings.TestConfig;
import com.android.settings.applications.manageapplications.ManageApplications;
+import com.android.settings.core.instrumentation.MetricsFeatureProvider;
import com.android.settings.deviceinfo.PrivateVolumeSettings;
import com.android.settings.deviceinfo.StorageItemPreference;
import com.android.settings.testutils.FakeFeatureFactory;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
import com.android.settings.testutils.shadow.SettingsShadowResources;
import com.android.settingslib.applications.StorageStatsSource;
-import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
import com.android.settingslib.deviceinfo.StorageVolumeProvider;
import org.junit.After;
diff --git a/tests/robotests/src/com/android/settings/deviceinfo/storage/StorageSummaryDonutPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/deviceinfo/storage/StorageSummaryDonutPreferenceControllerTest.java
index e251be0..6ad37ce 100644
--- a/tests/robotests/src/com/android/settings/deviceinfo/storage/StorageSummaryDonutPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/deviceinfo/storage/StorageSummaryDonutPreferenceControllerTest.java
@@ -38,10 +38,10 @@
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.settings.R;
import com.android.settings.TestConfig;
+import com.android.settings.core.instrumentation.MetricsFeatureProvider;
import com.android.settings.testutils.FakeFeatureFactory;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
import com.android.settings.testutils.shadow.SettingsShadowResources;
-import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
import com.android.settingslib.deviceinfo.StorageVolumeProvider;
import org.junit.After;
diff --git a/tests/robotests/src/com/android/settings/display/AmbientDisplayNotificationsPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/display/AmbientDisplayNotificationsPreferenceControllerTest.java
index c003f17..e1ce694 100644
--- a/tests/robotests/src/com/android/settings/display/AmbientDisplayNotificationsPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/display/AmbientDisplayNotificationsPreferenceControllerTest.java
@@ -32,11 +32,11 @@
import com.android.internal.hardware.AmbientDisplayConfiguration;
import com.android.settings.TestConfig;
+import com.android.settings.core.instrumentation.MetricsFeatureProvider;
import com.android.settings.search.InlinePayload;
import com.android.settings.search.InlineSwitchPayload;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
import com.android.settings.testutils.shadow.ShadowSecureSettings;
-import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
import org.junit.Before;
import org.junit.Test;
diff --git a/tests/robotests/src/com/android/settings/fingerprint/FingerprintEnrollEnrollingTest.java b/tests/robotests/src/com/android/settings/fingerprint/FingerprintEnrollEnrollingTest.java
index 5418ead..c590fd3 100644
--- a/tests/robotests/src/com/android/settings/fingerprint/FingerprintEnrollEnrollingTest.java
+++ b/tests/robotests/src/com/android/settings/fingerprint/FingerprintEnrollEnrollingTest.java
@@ -36,7 +36,6 @@
import com.android.settings.R;
import com.android.settings.TestConfig;
import com.android.settings.password.ChooseLockSettingsHelper;
-import com.android.settings.testutils.FakeFeatureFactory;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
import com.android.settings.testutils.shadow.ShadowUtils;
import com.android.settings.testutils.shadow.ShadowVibrator;
@@ -70,15 +69,12 @@
private FingerprintEnrollEnrolling mActivity;
- private FakeFeatureFactory mFactory;
-
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
ShadowUtils.setFingerprintManager(mFingerprintManager);
ShadowVibrator.addToServiceMap();
- mFactory = FakeFeatureFactory.setupForTest();
mActivity = Robolectric.buildActivity(
FingerprintEnrollEnrolling.class,
new Intent()
diff --git a/tests/robotests/src/com/android/settings/fingerprint/FingerprintEnrollFindSensorTest.java b/tests/robotests/src/com/android/settings/fingerprint/FingerprintEnrollFindSensorTest.java
index be53aa5..d495b74 100644
--- a/tests/robotests/src/com/android/settings/fingerprint/FingerprintEnrollFindSensorTest.java
+++ b/tests/robotests/src/com/android/settings/fingerprint/FingerprintEnrollFindSensorTest.java
@@ -33,7 +33,6 @@
import com.android.settings.R;
import com.android.settings.TestConfig;
import com.android.settings.password.ChooseLockSettingsHelper;
-import com.android.settings.testutils.FakeFeatureFactory;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
import com.android.settings.testutils.shadow.SettingsShadowResources;
import com.android.settings.testutils.shadow.ShadowEventLogWriter;
@@ -70,13 +69,10 @@
private FingerprintEnrollFindSensor mActivity;
- private FakeFeatureFactory mFactory;
-
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
ShadowUtils.setFingerprintManager(mFingerprintManager);
- mFactory = FakeFeatureFactory.setupForTest();
mActivity = Robolectric.buildActivity(
FingerprintEnrollFindSensor.class,
diff --git a/tests/robotests/src/com/android/settings/fingerprint/FingerprintSuggestionActivityTest.java b/tests/robotests/src/com/android/settings/fingerprint/FingerprintSuggestionActivityTest.java
index f52f437..0254bcb 100644
--- a/tests/robotests/src/com/android/settings/fingerprint/FingerprintSuggestionActivityTest.java
+++ b/tests/robotests/src/com/android/settings/fingerprint/FingerprintSuggestionActivityTest.java
@@ -30,7 +30,6 @@
import com.android.settings.R;
import com.android.settings.TestConfig;
-import com.android.settings.testutils.FakeFeatureFactory;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
import com.android.settings.testutils.shadow.ShadowEventLogWriter;
import com.android.settings.testutils.shadow.ShadowLockPatternUtils;
@@ -64,12 +63,9 @@
private ActivityController<FingerprintSuggestionActivity> mController;
- private FakeFeatureFactory mFactory;
-
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
- mFactory = FakeFeatureFactory.setupForTest();
final Intent intent = new Intent();
mController = Robolectric.buildActivity(FingerprintSuggestionActivity.class, intent);
diff --git a/tests/robotests/src/com/android/settings/fingerprint/SetupFingerprintEnrollFindSensorTest.java b/tests/robotests/src/com/android/settings/fingerprint/SetupFingerprintEnrollFindSensorTest.java
index c786608..c3899e9 100644
--- a/tests/robotests/src/com/android/settings/fingerprint/SetupFingerprintEnrollFindSensorTest.java
+++ b/tests/robotests/src/com/android/settings/fingerprint/SetupFingerprintEnrollFindSensorTest.java
@@ -27,7 +27,6 @@
import com.android.settings.R;
import com.android.settings.TestConfig;
import com.android.settings.password.ChooseLockSettingsHelper;
-import com.android.settings.testutils.FakeFeatureFactory;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
import com.android.settings.testutils.shadow.SettingsShadowResources;
import com.android.settings.testutils.shadow.ShadowEventLogWriter;
@@ -62,13 +61,10 @@
private SetupFingerprintEnrollFindSensor mActivity;
- private FakeFeatureFactory mFactory;
-
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
ShadowUtils.setFingerprintManager(mFingerprintManager);
- mFactory = FakeFeatureFactory.setupForTest();
}
private void createActivity(Intent intent) {
diff --git a/tests/robotests/src/com/android/settings/fingerprint/SetupFingerprintEnrollIntroductionTest.java b/tests/robotests/src/com/android/settings/fingerprint/SetupFingerprintEnrollIntroductionTest.java
index f5b0c8a..2d98bf4 100644
--- a/tests/robotests/src/com/android/settings/fingerprint/SetupFingerprintEnrollIntroductionTest.java
+++ b/tests/robotests/src/com/android/settings/fingerprint/SetupFingerprintEnrollIntroductionTest.java
@@ -35,7 +35,6 @@
import com.android.settings.password.SetupChooseLockGeneric.SetupChooseLockGenericFragment;
import com.android.settings.password.SetupSkipDialog;
import com.android.settings.password.StorageManagerWrapper;
-import com.android.settings.testutils.FakeFeatureFactory;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
import com.android.settings.testutils.shadow.ShadowEventLogWriter;
import com.android.settings.testutils.shadow.ShadowFingerprintManager;
@@ -73,7 +72,6 @@
@Mock
private UserInfo mUserInfo;
- private FakeFeatureFactory mFactory;
private ActivityController<SetupFingerprintEnrollIntroduction> mController;
@@ -85,8 +83,6 @@
.setSystemFeature(PackageManager.FEATURE_FINGERPRINT, true);
ShadowFingerprintManager.addToServiceMap();
- mFactory = FakeFeatureFactory.setupForTest();
-
final Intent intent = new Intent();
mController = Robolectric.buildActivity(SetupFingerprintEnrollIntroduction.class, intent);
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/BackgroundActivityPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/fuelgauge/BackgroundActivityPreferenceControllerTest.java
index 0c9e394..30fdccb 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/BackgroundActivityPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/BackgroundActivityPreferenceControllerTest.java
@@ -22,6 +22,7 @@
import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.anyString;
import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
@@ -38,6 +39,7 @@
import android.os.Build;
import android.os.UserManager;
import android.support.v14.preference.SwitchPreference;
+import android.support.v7.preference.Preference;
import android.widget.Button;
import com.android.settings.R;
@@ -92,12 +94,12 @@
private DevicePolicyManager mDevicePolicyManager;
@Mock
private DevicePolicyManagerWrapper mDevicePolicyManagerWrapper;
- @Mock
+ @Mock(answer = Answers.RETURNS_DEEP_STUBS)
private AdvancedPowerUsageDetail mFragment;
@Mock
private PowerWhitelistBackend mPowerWhitelistBackend;
private BackgroundActivityPreferenceController mController;
- private SwitchPreference mPreference;
+ private Preference mPreference;
private Context mShadowContext;
private BatteryUtils mBatteryUtils;
@@ -125,7 +127,8 @@
mBatteryUtils = spy(new BatteryUtils(mShadowContext));
doNothing().when(mBatteryUtils).setForceAppStandby(anyInt(), anyString(), anyInt());
- mPreference = new SwitchPreference(mShadowContext);
+ mPreference = new Preference(mShadowContext);
+ mPreference.setKey(BackgroundActivityPreferenceController.KEY_BACKGROUND_ACTIVITY);
mController = spy(new BackgroundActivityPreferenceController(
mContext, mFragment, UID_LOW_SDK, LOW_SDK_PACKAGE, mPowerWhitelistBackend));
mController.mDpm = mDevicePolicyManagerWrapper;
@@ -133,49 +136,33 @@
}
@Test
- public void testOnPreferenceChange_TurnOnCheck_MethodInvoked() {
- mController.onPreferenceChange(mPreference, true);
+ public void testHandlePreferenceTreeClick_restrictApp_showDialog() {
+ doReturn(AppOpsManager.MODE_ALLOWED).when(mAppOpsManager).checkOpNoThrow(anyInt(),
+ anyInt(), anyString());
+
+ mController.handlePreferenceTreeClick(mPreference);
+
+ verify(mController).showDialog();
+ }
+
+ @Test
+ public void testHandlePreferenceTreeClick_unRestrictApp_setModeAllowed() {
+ doReturn(AppOpsManager.MODE_IGNORED).when(mAppOpsManager).checkOpNoThrow(anyInt(),
+ anyInt(), anyString());
+
+ mController.handlePreferenceTreeClick(mPreference);
verify(mBatteryUtils).setForceAppStandby(UID_LOW_SDK, LOW_SDK_PACKAGE,
AppOpsManager.MODE_ALLOWED);
- assertThat(mPreference.getSummary())
- .isEqualTo(mShadowContext.getText(R.string.background_activity_summary_on));
}
@Test
- public void testOnPreferenceChange_TurnOnCheckHighSDK_MethodInvoked() {
- mController = new BackgroundActivityPreferenceController(mContext, mFragment, UID_HIGH_SDK,
- HIGH_SDK_PACKAGE, mPowerWhitelistBackend);
- mController.mBatteryUtils = mBatteryUtils;
-
- mController.onPreferenceChange(mPreference, true);
-
- verify(mBatteryUtils).setForceAppStandby(UID_HIGH_SDK, HIGH_SDK_PACKAGE,
- AppOpsManager.MODE_ALLOWED);
- assertThat(mPreference.getSummary())
- .isEqualTo(mShadowContext.getText(R.string.background_activity_summary_on));
- }
-
- @Test
- public void testUpdateState_CheckOn_SetCheckedTrue() {
+ public void testUpdateState_noError_setEnabled() {
when(mAppOpsManager.checkOpNoThrow(AppOpsManager.OP_RUN_ANY_IN_BACKGROUND, UID_LOW_SDK,
LOW_SDK_PACKAGE)).thenReturn(AppOpsManager.MODE_ALLOWED);
mController.updateState(mPreference);
- assertThat(mPreference.isChecked()).isTrue();
- assertThat(mPreference.isEnabled()).isTrue();
- verify(mController).updateSummary(mPreference);
- }
-
- @Test
- public void testUpdateState_CheckOff_SetCheckedFalse() {
- when(mAppOpsManager.checkOpNoThrow(AppOpsManager.OP_RUN_ANY_IN_BACKGROUND, UID_LOW_SDK,
- LOW_SDK_PACKAGE)).thenReturn(AppOpsManager.MODE_IGNORED);
-
- mController.updateState(mPreference);
-
- assertThat(mPreference.isChecked()).isFalse();
assertThat(mPreference.isEnabled()).isTrue();
verify(mController).updateSummary(mPreference);
}
@@ -184,7 +171,6 @@
public void testUpdateState_whitelisted() {
when(mPowerWhitelistBackend.isWhitelisted(LOW_SDK_PACKAGE)).thenReturn(true);
mController.updateState(mPreference);
- assertThat(mPreference.isChecked()).isTrue();
assertThat(mPreference.isEnabled()).isFalse();
assertThat(mPreference.getSummary()).isEqualTo(
mShadowContext.getText(R.string.background_activity_summary_whitelisted));
@@ -202,27 +188,23 @@
}
@Test
- public void testUpdateSummary_modeDefault_showSummaryOn() {
+ public void testUpdateSummary_modeDefault_showNotRestricted() {
when(mAppOpsManager.checkOpNoThrow(AppOpsManager.OP_RUN_ANY_IN_BACKGROUND, UID_LOW_SDK,
LOW_SDK_PACKAGE)).thenReturn(AppOpsManager.MODE_DEFAULT);
- final CharSequence expectedSummary = mShadowContext.getText(
- R.string.background_activity_summary_on);
mController.updateSummary(mPreference);
- assertThat(mPreference.getSummary()).isEqualTo(expectedSummary);
+ assertThat(mPreference.getSummary()).isEqualTo("No");
}
@Test
- public void testUpdateSummary_modeIgnored_showSummaryOff() {
+ public void testUpdateSummary_modeIgnored_showRestricted() {
when(mAppOpsManager.checkOpNoThrow(AppOpsManager.OP_RUN_ANY_IN_BACKGROUND, UID_LOW_SDK,
LOW_SDK_PACKAGE)).thenReturn(AppOpsManager.MODE_IGNORED);
- final CharSequence expectedSummary = mShadowContext.getText(
- R.string.background_activity_summary_off);
mController.updateSummary(mPreference);
- assertThat(mPreference.getSummary()).isEqualTo(expectedSummary);
+ assertThat(mPreference.getSummary()).isEqualTo("Yes");
}
@Test
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/RestrictedAppDetailsTest.java b/tests/robotests/src/com/android/settings/fuelgauge/RestrictedAppDetailsTest.java
index a9de061..521ead4 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/RestrictedAppDetailsTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/RestrictedAppDetailsTest.java
@@ -28,6 +28,7 @@
import android.support.v7.preference.Preference;
import android.support.v7.preference.PreferenceCategory;
import android.support.v7.preference.PreferenceManager;
+import android.util.IconDrawableFactory;
import com.android.settings.TestConfig;
@@ -53,6 +54,8 @@
private PackageManager mPackageManager;
@Mock
private ApplicationInfo mApplicationInfo;
+ @Mock
+ private IconDrawableFactory mIconDrawableFactory;
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
private PreferenceManager mPreferenceManager;
private RestrictedAppDetails mFragment;
@@ -68,6 +71,7 @@
doReturn(mPreferenceManager).when(mFragment).getPreferenceManager();
doReturn(mContext).when(mPreferenceManager).getContext();
mFragment.mPackageManager = mPackageManager;
+ mFragment.mIconDrawableFactory = mIconDrawableFactory;
mFragment.mPackageOpsList = new ArrayList<>();
mFragment.mPackageOpsList.add(
new AppOpsManager.PackageOps(PACKAGE_NAME, UID, null /* entries */));
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/anomaly/AnomalyUtilsTest.java b/tests/robotests/src/com/android/settings/fuelgauge/anomaly/AnomalyUtilsTest.java
index 3e33823..38391c9 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/anomaly/AnomalyUtilsTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/anomaly/AnomalyUtilsTest.java
@@ -24,6 +24,7 @@
import android.util.Pair;
import com.android.internal.logging.nano.MetricsProto;
+import com.android.settings.core.instrumentation.MetricsFeatureProvider;
import com.android.settings.fuelgauge.anomaly.action.StopAndBackgroundCheckAction;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
import com.android.settings.TestConfig;
@@ -31,7 +32,6 @@
import com.android.settings.fuelgauge.anomaly.checker.WakeLockAnomalyDetector;
import com.android.settings.testutils.shadow.ShadowKeyValueListParserWrapperImpl;
import com.android.settings.fuelgauge.anomaly.checker.WakeupAlarmAnomalyDetector;
-import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
import org.junit.Before;
import org.junit.Test;
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batterytip/BatteryTipLoaderTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/BatteryTipLoaderTest.java
index 53c9766..83b3225 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batterytip/BatteryTipLoaderTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/BatteryTipLoaderTest.java
@@ -37,6 +37,7 @@
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.RuntimeEnvironment;
@@ -54,7 +55,7 @@
BatteryTip.TipType.BATTERY_SAVER,
BatteryTip.TipType.LOW_BATTERY,
BatteryTip.TipType.SUMMARY};
- @Mock
+ @Mock(answer = Answers.RETURNS_DEEP_STUBS)
private BatteryStatsHelper mBatteryStatsHelper;
@Mock
private PowerManager mPowerManager;
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batterytip/BatteryTipPolicyTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/BatteryTipPolicyTest.java
index bb9a37b..78c86f8 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batterytip/BatteryTipPolicyTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/BatteryTipPolicyTest.java
@@ -24,6 +24,7 @@
import android.content.Context;
import android.provider.Settings;
+import android.text.format.DateUtils;
import com.android.settings.TestConfig;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
@@ -42,6 +43,8 @@
+ ",battery_saver_tip_enabled=false"
+ ",high_usage_enabled=true"
+ ",high_usage_app_count=5"
+ + ",high_usage_period_ms=2000"
+ + ",high_usage_battery_draining=30"
+ ",app_restriction_enabled=true"
+ ",reduced_battery_enabled=true"
+ ",reduced_battery_percent=30"
@@ -66,6 +69,8 @@
assertThat(batteryTipPolicy.batterySaverTipEnabled).isFalse();
assertThat(batteryTipPolicy.highUsageEnabled).isTrue();
assertThat(batteryTipPolicy.highUsageAppCount).isEqualTo(5);
+ assertThat(batteryTipPolicy.highUsagePeriodMs).isEqualTo(2000);
+ assertThat(batteryTipPolicy.highUsageBatteryDraining).isEqualTo(30);
assertThat(batteryTipPolicy.appRestrictionEnabled).isTrue();
assertThat(batteryTipPolicy.reducedBatteryEnabled).isTrue();
assertThat(batteryTipPolicy.reducedBatteryPercent).isEqualTo(30);
@@ -85,6 +90,8 @@
assertThat(batteryTipPolicy.batterySaverTipEnabled).isTrue();
assertThat(batteryTipPolicy.highUsageEnabled).isTrue();
assertThat(batteryTipPolicy.highUsageAppCount).isEqualTo(3);
+ assertThat(batteryTipPolicy.highUsagePeriodMs).isEqualTo(2 * DateUtils.HOUR_IN_MILLIS);
+ assertThat(batteryTipPolicy.highUsageBatteryDraining).isEqualTo(25);
assertThat(batteryTipPolicy.appRestrictionEnabled).isTrue();
assertThat(batteryTipPolicy.reducedBatteryEnabled).isFalse();
assertThat(batteryTipPolicy.reducedBatteryPercent).isEqualTo(50);
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batterytip/HighUsageDataParserTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/HighUsageDataParserTest.java
new file mode 100644
index 0000000..5bdae0c
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/HighUsageDataParserTest.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2018 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.fuelgauge.batterytip;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.os.BatteryStats;
+import android.text.format.DateUtils;
+
+import com.android.settings.TestConfig;
+import com.android.settings.testutils.SettingsRobolectricTestRunner;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.annotation.Config;
+
+import java.time.Duration;
+
+@RunWith(SettingsRobolectricTestRunner.class)
+@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
+public class HighUsageDataParserTest {
+ private static final long PERIOD_ONE_MINUTE_MS = Duration.ofMinutes(1).toMillis();
+ private static final long END_TIME_MS = 2 * PERIOD_ONE_MINUTE_MS;
+ private static final int THRESHOLD_LOW = 10;
+ private static final int THRESHOLD_HIGH = 20;
+ private HighUsageDataParser mDataParser;
+ private BatteryStats.HistoryItem mFirstItem;
+ private BatteryStats.HistoryItem mSecondItem;
+ private BatteryStats.HistoryItem mThirdItem;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+
+ mFirstItem = new BatteryStats.HistoryItem();
+ mFirstItem.batteryLevel = 100;
+ mFirstItem.currentTime = 0;
+ mSecondItem = new BatteryStats.HistoryItem();
+ mSecondItem.batteryLevel = 95;
+ mSecondItem.currentTime = PERIOD_ONE_MINUTE_MS;
+ mThirdItem = new BatteryStats.HistoryItem();
+ mThirdItem.batteryLevel = 80;
+ mThirdItem.currentTime = END_TIME_MS;
+ }
+
+ @Test
+ public void testDataParser_thresholdLow_isHeavilyUsed() {
+ mDataParser = new HighUsageDataParser(PERIOD_ONE_MINUTE_MS, THRESHOLD_LOW);
+ parseData();
+
+ assertThat(mDataParser.isDeviceHeavilyUsed()).isTrue();
+ }
+
+ @Test
+ public void testDataParser_thresholdHigh_notHeavilyUsed() {
+ mDataParser = new HighUsageDataParser(PERIOD_ONE_MINUTE_MS, THRESHOLD_HIGH);
+ parseData();
+
+ assertThat(mDataParser.isDeviceHeavilyUsed()).isFalse();
+ }
+
+ private void parseData() {
+ mDataParser.onParsingStarted(0, END_TIME_MS);
+ mDataParser.onDataPoint(0, mFirstItem);
+ mDataParser.onDataPoint(PERIOD_ONE_MINUTE_MS, mSecondItem);
+ mDataParser.onDataPoint(END_TIME_MS, mThirdItem);
+
+ mDataParser.onParsingDone();
+ }
+}
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batterytip/detectors/HighUsageDetectorTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/detectors/HighUsageDetectorTest.java
index 2a71991..8df7c56 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batterytip/detectors/HighUsageDetectorTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/detectors/HighUsageDetectorTest.java
@@ -18,6 +18,8 @@
import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.spy;
@@ -31,6 +33,7 @@
import com.android.settings.fuelgauge.BatteryInfo;
import com.android.settings.fuelgauge.BatteryUtils;
import com.android.settings.fuelgauge.batterytip.BatteryTipPolicy;
+import com.android.settings.fuelgauge.batterytip.HighUsageDataParser;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
import org.junit.Before;
@@ -55,6 +58,8 @@
private BatteryUtils mBatteryUtils;
@Mock
private BatterySipper mBatterySipper;
+ @Mock
+ private HighUsageDataParser mDataParser;
private BatteryTipPolicy mPolicy;
private HighUsageDetector mHighUsageDetector;
@@ -66,8 +71,10 @@
mContext = RuntimeEnvironment.application;
mPolicy = spy(new BatteryTipPolicy(mContext));
- mHighUsageDetector = new HighUsageDetector(mContext, mPolicy, mBatteryStatsHelper);
+ mHighUsageDetector = spy(new HighUsageDetector(mContext, mPolicy, mBatteryStatsHelper));
mHighUsageDetector.mBatteryUtils = mBatteryUtils;
+ mHighUsageDetector.mDataParser = mDataParser;
+ doNothing().when(mHighUsageDetector).parseBatteryData();
mUsageList = new ArrayList<>();
mUsageList.add(mBatterySipper);
@@ -82,8 +89,7 @@
@Test
public void testDetect_containsHighUsageApp_tipVisible() {
- doReturn(2 * DateUtils.HOUR_IN_MILLIS).when(mBatteryUtils).calculateScreenUsageTime(
- mBatteryStatsHelper);
+ doReturn(true).when(mDataParser).isDeviceHeavilyUsed();
doReturn(mUsageList).when(mBatteryStatsHelper).getUsageList();
doReturn(DateUtils.HOUR_IN_MILLIS).when(mBatteryUtils).getProcessTimeMs(
BatteryUtils.StatusType.FOREGROUND, mBatterySipper.uidObj,
diff --git a/tests/robotests/src/com/android/settings/localepicker/LocaleListEditorTest.java b/tests/robotests/src/com/android/settings/localepicker/LocaleListEditorTest.java
index 737c16d..1ee52ca 100644
--- a/tests/robotests/src/com/android/settings/localepicker/LocaleListEditorTest.java
+++ b/tests/robotests/src/com/android/settings/localepicker/LocaleListEditorTest.java
@@ -20,7 +20,6 @@
import android.view.View;
import android.widget.TextView;
import com.android.settings.TestConfig;
-import com.android.settings.testutils.FakeFeatureFactory;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
import com.android.settings.testutils.shadow.ShadowSettingsPreferenceFragment;
@@ -28,7 +27,6 @@
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
-import org.mockito.Mock;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Config;
import org.robolectric.util.ReflectionHelpers;
@@ -41,11 +39,6 @@
private LocaleListEditor mLocaleListEditor;
- @Mock
- private Context mContext;
-
- private FakeFeatureFactory mFactory;
-
@Before
public void setUp() {
mLocaleListEditor = new LocaleListEditor();
@@ -55,13 +48,11 @@
RuntimeEnvironment.application.getSystemService(Context.RESTRICTIONS_SERVICE));
ReflectionHelpers.setField(mLocaleListEditor, "mUserManager",
RuntimeEnvironment.application.getSystemService(Context.USER_SERVICE));
- mFactory = FakeFeatureFactory.setupForTest();
}
@Test
public void testDisallowConfigLocale_unrestrict() {
ReflectionHelpers.setField(mLocaleListEditor, "mIsUiRestricted", true);
- mLocaleListEditor.onAttach(mContext);
mLocaleListEditor.onResume();
Assert.assertEquals(View.GONE, mLocaleListEditor.getEmptyTextView().getVisibility());
}
@@ -69,7 +60,6 @@
@Test
public void testDisallowConfigLocale_restrict() {
ReflectionHelpers.setField(mLocaleListEditor, "mIsUiRestricted", false);
- mLocaleListEditor.onAttach(mContext);
mLocaleListEditor.onResume();
Assert.assertEquals(View.VISIBLE, mLocaleListEditor.getEmptyTextView().getVisibility());
}
diff --git a/tests/robotests/src/com/android/settings/location/LocationEnablerTest.java b/tests/robotests/src/com/android/settings/location/LocationEnablerTest.java
index f456f41..8cc92cd 100644
--- a/tests/robotests/src/com/android/settings/location/LocationEnablerTest.java
+++ b/tests/robotests/src/com/android/settings/location/LocationEnablerTest.java
@@ -43,6 +43,7 @@
import com.android.settings.testutils.SettingsRobolectricTestRunner;
import com.android.settings.testutils.shadow.ShadowSecureSettings;
import com.android.settingslib.core.lifecycle.Lifecycle;
+import com.android.settingslib.wrapper.LocationManagerWrapper;
import java.util.ArrayList;
import java.util.List;
import org.junit.Before;
@@ -53,11 +54,15 @@
import org.mockito.MockitoAnnotations;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Config;
+import org.robolectric.annotation.Implementation;
+import org.robolectric.annotation.Implements;
@RunWith(SettingsRobolectricTestRunner.class)
@Config(manifest = TestConfig.MANIFEST_PATH,
sdk = TestConfig.SDK_VERSION,
- shadows = {ShadowSecureSettings.class})
+ shadows = {
+ ShadowSecureSettings.class,
+ LocationEnablerTest.ShadowLocationManagerWrapper.class})
public class LocationEnablerTest {
@Mock
@@ -124,7 +129,7 @@
}
@Test
- public void isEnabled_locationONotRestricted_shouldReturnTrue() {
+ public void isEnabled_locationNotRestricted_shouldReturnTrue() {
when(mUserManager.hasUserRestriction(anyString())).thenReturn(false);
assertThat(mEnabler.isEnabled(Settings.Secure.LOCATION_MODE_BATTERY_SAVING)).isTrue();
@@ -178,14 +183,35 @@
when(mUserManager.hasUserRestriction(anyString())).thenReturn(false);
Settings.Secure.putInt(mContext.getContentResolver(),
Settings.Secure.LOCATION_MODE, Settings.Secure.LOCATION_MODE_BATTERY_SAVING);
-
mEnabler.setLocationMode(Settings.Secure.LOCATION_MODE_HIGH_ACCURACY);
verify(mContext).sendBroadcastAsUser(
argThat(actionMatches(LocationManager.MODE_CHANGING_ACTION)),
eq(UserHandle.of(ActivityManager.getCurrentUser())),
eq(WRITE_SECURE_SETTINGS));
+ }
+ @Test
+ public void setLocationEnabled_notRestricted_shouldRefreshLocation() {
+ when(mUserManager.hasUserRestriction(anyString())).thenReturn(false);
+ Settings.Secure.putInt(mContext.getContentResolver(),
+ Settings.Secure.LOCATION_MODE, Settings.Secure.LOCATION_MODE_OFF);
+ mEnabler.setLocationEnabled(true);
+
+ verify(mEnabler).refreshLocationMode();
+ }
+
+ @Test
+ public void setLocationEnabled_notRestricted_shouldBroadcastUpdate() {
+ when(mUserManager.hasUserRestriction(anyString())).thenReturn(false);
+ Settings.Secure.putInt(mContext.getContentResolver(),
+ Settings.Secure.LOCATION_MODE, Settings.Secure.LOCATION_MODE_OFF);
+ mEnabler.setLocationEnabled(true);
+
+ verify(mContext).sendBroadcastAsUser(
+ argThat(actionMatches(LocationManager.MODE_CHANGING_ACTION)),
+ eq(UserHandle.of(ActivityManager.getCurrentUser())),
+ eq(WRITE_SECURE_SETTINGS));
}
@Test
@@ -241,5 +267,12 @@
return intent -> TextUtils.equals(expected, intent.getAction());
}
+ @Implements(value = LocationManagerWrapper.class)
+ public static class ShadowLocationManagerWrapper {
+ @Implementation
+ public void setLocationEnabledForUser(boolean enabled, UserHandle userHandle) {
+ // Do nothing
+ }
+ }
}
diff --git a/tests/robotests/src/com/android/settings/location/LocationSwitchBarControllerTest.java b/tests/robotests/src/com/android/settings/location/LocationSwitchBarControllerTest.java
index 6d824ac..4410d6f 100644
--- a/tests/robotests/src/com/android/settings/location/LocationSwitchBarControllerTest.java
+++ b/tests/robotests/src/com/android/settings/location/LocationSwitchBarControllerTest.java
@@ -88,18 +88,17 @@
}
@Test
- public void onSwitchChanged_switchChecked_shouldSetPreviousLocationMode() {
+ public void onSwitchChanged_switchChecked_shouldSetLocationEnabled() {
mController.onSwitchChanged(mSwitch, true);
- verify(mEnabler).setLocationMode(
- android.provider.Settings.Secure.LOCATION_MODE_PREVIOUS);
+ verify(mEnabler).setLocationEnabled(true);
}
@Test
- public void onSwitchChanged_switchUnchecked_shouldSetLocationModeOff() {
+ public void onSwitchChanged_switchUnchecked_shouldSetLocationDisabled() {
mController.onSwitchChanged(mSwitch, false);
- verify(mEnabler).setLocationMode(android.provider.Settings.Secure.LOCATION_MODE_OFF);
+ verify(mEnabler).setLocationEnabled(false);
}
@Test
diff --git a/tests/robotests/src/com/android/settings/notification/EnableZenModeDialogTest.java b/tests/robotests/src/com/android/settings/notification/EnableZenModeDialogTest.java
new file mode 100644
index 0000000..8b5ef79
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/notification/EnableZenModeDialogTest.java
@@ -0,0 +1,152 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.notification;
+
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertTrue;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.when;
+
+import android.app.Activity;
+import android.app.Fragment;
+import android.content.Context;
+import android.net.Uri;
+import android.service.notification.Condition;
+import android.view.LayoutInflater;
+
+import com.android.settings.TestConfig;
+import com.android.settings.testutils.SettingsRobolectricTestRunner;
+
+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;
+
+@RunWith(SettingsRobolectricTestRunner.class)
+@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
+public class EnableZenModeDialogTest {
+ private EnableZenModeDialog mController;
+
+ @Mock
+ private Context mContext;
+ @Mock
+ private Activity mActivity;
+ @Mock
+ private Fragment mFragment;
+
+ private Context mShadowContext;
+ private LayoutInflater mLayoutInflater;
+ private Condition mCountdownCondition;
+ private Condition mAlarmCondition;
+
+ @Before
+ public void setup() {
+ MockitoAnnotations.initMocks(this);
+ mShadowContext = RuntimeEnvironment.application;
+ when(mActivity.getApplicationContext()).thenReturn(mShadowContext);
+ when(mContext.getApplicationContext()).thenReturn(mContext);
+ when(mFragment.getContext()).thenReturn(mShadowContext);
+ mLayoutInflater = LayoutInflater.from(mShadowContext);
+ when(mActivity.getLayoutInflater()).thenReturn(mLayoutInflater);
+
+ mController = spy(new EnableZenModeDialog());
+ mController.mContext = mContext;
+ mController.mActivity = mActivity;
+ mController.mForeverId = Condition.newId(mContext).appendPath("forever").build();
+ when(mContext.getString(com.android.internal.R.string.zen_mode_forever))
+ .thenReturn("testSummary");
+ mController.getContentView();
+
+ // these methods use static calls to ZenModeConfig which would normally fail in robotests,
+ // so instead do nothing:
+ doNothing().when(mController).bindGenericCountdown();
+ doReturn(null).when(mController).getTimeUntilNextAlarmCondition();
+ doNothing().when(mController).bindNextAlarm(any());
+
+ // as a result of doing nothing above, must bind manually:
+ Uri alarm = Condition.newId(mContext).appendPath("alarm").build();
+ mAlarmCondition = new Condition(alarm, "alarm", "", "", 0, 0, 0);
+ Uri countdown = Condition.newId(mContext).appendPath("countdown").build();
+ mCountdownCondition = new Condition(countdown, "countdown", "", "", 0, 0, 0);
+ mController.bind(mCountdownCondition,
+ mController.mZenRadioGroupContent.getChildAt(
+ EnableZenModeDialog.COUNTDOWN_CONDITION_INDEX),
+ EnableZenModeDialog.COUNTDOWN_CONDITION_INDEX);
+ mController.bind(mAlarmCondition,
+ mController.mZenRadioGroupContent.getChildAt(
+ EnableZenModeDialog.COUNTDOWN_ALARM_CONDITION_INDEX),
+ EnableZenModeDialog.COUNTDOWN_ALARM_CONDITION_INDEX);
+ }
+
+ @Test
+ public void testForeverChecked() {
+ mController.bindConditions(mController.forever());
+
+ assertTrue(mController.getConditionTagAt(EnableZenModeDialog.FOREVER_CONDITION_INDEX).rb
+ .isChecked());
+ assertFalse(mController.getConditionTagAt(EnableZenModeDialog.COUNTDOWN_CONDITION_INDEX).rb
+ .isChecked());
+ assertFalse(mController.getConditionTagAt(
+ EnableZenModeDialog.COUNTDOWN_ALARM_CONDITION_INDEX).rb.isChecked());
+ }
+
+ @Test
+ public void testNoneChecked() {
+ mController.bindConditions(null);
+ assertFalse(mController.getConditionTagAt(EnableZenModeDialog.FOREVER_CONDITION_INDEX).rb
+ .isChecked());
+ assertFalse(mController.getConditionTagAt(EnableZenModeDialog.COUNTDOWN_CONDITION_INDEX).rb
+ .isChecked());
+ assertFalse(mController.getConditionTagAt(
+ EnableZenModeDialog.COUNTDOWN_ALARM_CONDITION_INDEX).rb.isChecked());
+ }
+
+ @Test
+ public void testAlarmChecked() {
+ doReturn(false).when(mController).isCountdown(mAlarmCondition);
+ doReturn(true).when(mController).isAlarm(mAlarmCondition);
+
+ mController.bindConditions(mAlarmCondition);
+ assertFalse(mController.getConditionTagAt(EnableZenModeDialog.FOREVER_CONDITION_INDEX).rb
+ .isChecked());
+ assertFalse(mController.getConditionTagAt(EnableZenModeDialog.COUNTDOWN_CONDITION_INDEX).rb
+ .isChecked());
+ assertTrue(mController.getConditionTagAt(
+ EnableZenModeDialog.COUNTDOWN_ALARM_CONDITION_INDEX).rb.isChecked());
+ }
+
+ @Test
+ public void testCountdownChecked() {
+ doReturn(false).when(mController).isAlarm(mCountdownCondition);
+ doReturn(true).when(mController).isCountdown(mCountdownCondition);
+
+ mController.bindConditions(mCountdownCondition);
+ assertFalse(mController.getConditionTagAt(EnableZenModeDialog.FOREVER_CONDITION_INDEX).rb
+ .isChecked());
+ assertTrue(mController.getConditionTagAt(EnableZenModeDialog.COUNTDOWN_CONDITION_INDEX).rb
+ .isChecked());
+ assertFalse(mController.getConditionTagAt(
+ EnableZenModeDialog.COUNTDOWN_ALARM_CONDITION_INDEX).rb.isChecked());
+ }
+}
\ No newline at end of file
diff --git a/tests/robotests/src/com/android/settings/notification/RecentNotifyingAppsPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/RecentNotifyingAppsPreferenceControllerTest.java
new file mode 100644
index 0000000..a25bb00
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/notification/RecentNotifyingAppsPreferenceControllerTest.java
@@ -0,0 +1,301 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.notification;
+
+import static 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.Matchers.argThat;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.app.Application;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.service.notification.NotifyingApp;
+import android.support.v7.preference.Preference;
+import android.support.v7.preference.PreferenceCategory;
+import android.support.v7.preference.PreferenceScreen;
+import android.text.TextUtils;
+
+import com.android.settings.R;
+import com.android.settings.TestConfig;
+import com.android.settings.testutils.SettingsRobolectricTestRunner;
+import com.android.settingslib.applications.AppUtils;
+import com.android.settingslib.applications.ApplicationsState;
+import com.android.settingslib.applications.instantapps.InstantAppDataProvider;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.ArgumentMatcher;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.Config;
+import org.robolectric.util.ReflectionHelpers;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@RunWith(SettingsRobolectricTestRunner.class)
+@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
+public class RecentNotifyingAppsPreferenceControllerTest {
+
+ @Mock
+ private PreferenceScreen mScreen;
+ @Mock
+ private PreferenceCategory mCategory;
+ @Mock
+ private Preference mSeeAllPref;
+ @Mock
+ private PreferenceCategory mDivider;
+ @Mock
+ private UserManager mUserManager;
+ @Mock
+ private ApplicationsState mAppState;
+ @Mock
+ private PackageManager mPackageManager;
+ @Mock
+ private ApplicationsState.AppEntry mAppEntry;
+ @Mock
+ private ApplicationInfo mApplicationInfo;
+ @Mock
+ private NotificationBackend mBackend;
+
+ private Context mContext;
+ private RecentNotifyingAppsPreferenceController mController;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ mContext = spy(RuntimeEnvironment.application);
+ doReturn(mUserManager).when(mContext).getSystemService(Context.USER_SERVICE);
+ doReturn(mPackageManager).when(mContext).getPackageManager();
+
+ mController = new RecentNotifyingAppsPreferenceController(
+ mContext, mBackend, mAppState, null);
+ when(mScreen.findPreference(anyString())).thenReturn(mCategory);
+
+ when(mScreen.findPreference(RecentNotifyingAppsPreferenceController.KEY_SEE_ALL))
+ .thenReturn(mSeeAllPref);
+ when(mScreen.findPreference(RecentNotifyingAppsPreferenceController.KEY_DIVIDER))
+ .thenReturn(mDivider);
+ when(mCategory.getContext()).thenReturn(mContext);
+ }
+
+ @Test
+ public void isAlwaysAvailable() {
+ assertThat(mController.isAvailable()).isTrue();
+ }
+
+ @Test
+ public void doNotIndexCategory() {
+ final List<String> nonIndexable = new ArrayList<>();
+
+ mController.updateNonIndexableKeys(nonIndexable);
+
+ assertThat(nonIndexable).containsAllOf(mController.getPreferenceKey(),
+ RecentNotifyingAppsPreferenceController.KEY_DIVIDER);
+ }
+
+ @Test
+ public void onDisplayAndUpdateState_shouldRefreshUi() {
+ mController = spy(new RecentNotifyingAppsPreferenceController(
+ mContext, null, (ApplicationsState) null, null));
+
+ doNothing().when(mController).refreshUi(mContext);
+
+ mController.displayPreference(mScreen);
+ mController.updateState(mCategory);
+
+ verify(mController, times(2)).refreshUi(mContext);
+ }
+
+ @Test
+ @Config(qualifiers = "mcc999")
+ public void display_shouldNotShowRecents_showAppInfoPreference() {
+ mController.displayPreference(mScreen);
+
+ verify(mCategory, never()).addPreference(any(Preference.class));
+ verify(mCategory).setTitle(null);
+ verify(mSeeAllPref).setTitle(R.string.notifications_title);
+ verify(mSeeAllPref).setIcon(null);
+ verify(mDivider).setVisible(false);
+ }
+
+ @Test
+ public void display_showRecents() {
+ final List<NotifyingApp> apps = new ArrayList<>();
+ final NotifyingApp app1 = new NotifyingApp()
+ .setPackage("pkg.class")
+ .setLastNotified(System.currentTimeMillis());
+ final NotifyingApp app2 = new NotifyingApp()
+ .setLastNotified(System.currentTimeMillis())
+ .setPackage("com.android.settings");
+ final NotifyingApp app3 = new NotifyingApp()
+ .setLastNotified(System.currentTimeMillis() - 1000)
+ .setPackage("pkg.class2");
+
+ apps.add(app1);
+ apps.add(app2);
+ apps.add(app3);
+
+ // app1, app2 are valid apps. app3 is invalid.
+ when(mAppState.getEntry(app1.getPackage(), UserHandle.myUserId()))
+ .thenReturn(mAppEntry);
+ when(mAppState.getEntry(app2.getPackage(), UserHandle.myUserId()))
+ .thenReturn(mAppEntry);
+ when(mAppState.getEntry(app3.getPackage(), UserHandle.myUserId()))
+ .thenReturn(null);
+ when(mPackageManager.resolveActivity(any(Intent.class), anyInt())).thenReturn(
+ new ResolveInfo());
+ when(mBackend.getRecentApps()).thenReturn(apps);
+ mAppEntry.info = mApplicationInfo;
+
+ mController.displayPreference(mScreen);
+
+ verify(mCategory).setTitle(R.string.recent_notifications);
+ // Only add app1. app2 is skipped because of the package name, app3 skipped because
+ // it's invalid app.
+ verify(mCategory, times(1)).addPreference(any(Preference.class));
+
+ verify(mSeeAllPref).setSummary(null);
+ verify(mSeeAllPref).setIcon(R.drawable.ic_chevron_right_24dp);
+ verify(mDivider).setVisible(true);
+ }
+
+ @Test
+ public void display_showRecentsWithInstantApp() {
+ // Regular app.
+ final List<NotifyingApp> apps = new ArrayList<>();
+ final NotifyingApp app1 = new NotifyingApp().
+ setLastNotified(System.currentTimeMillis())
+ .setPackage("com.foo.bar");
+ apps.add(app1);
+
+ // Instant app.
+ final NotifyingApp app2 = new NotifyingApp()
+ .setLastNotified(System.currentTimeMillis() + 200)
+ .setPackage("com.foo.barinstant");
+ apps.add(app2);
+
+ ApplicationsState.AppEntry app1Entry = mock(ApplicationsState.AppEntry.class);
+ ApplicationsState.AppEntry app2Entry = mock(ApplicationsState.AppEntry.class);
+ app1Entry.info = mApplicationInfo;
+ app2Entry.info = mApplicationInfo;
+
+ when(mAppState.getEntry(app1.getPackage(), UserHandle.myUserId())).thenReturn(app1Entry);
+ when(mAppState.getEntry(app2.getPackage(), UserHandle.myUserId())).thenReturn(app2Entry);
+
+ // Only the regular app app1 should have its intent resolve.
+ when(mPackageManager.resolveActivity(argThat(intentMatcher(app1.getPackage())),
+ anyInt())).thenReturn(new ResolveInfo());
+
+ when(mBackend.getRecentApps()).thenReturn(apps);
+
+ // Make sure app2 is considered an instant app.
+ ReflectionHelpers.setStaticField(AppUtils.class, "sInstantAppDataProvider",
+ (InstantAppDataProvider) (ApplicationInfo info) -> {
+ if (info == app2Entry.info) {
+ return true;
+ } else {
+ return false;
+ }
+ });
+
+ mController.displayPreference(mScreen);
+
+ ArgumentCaptor<Preference> prefCaptor = ArgumentCaptor.forClass(Preference.class);
+ verify(mCategory, times(2)).addPreference(prefCaptor.capture());
+ List<Preference> prefs = prefCaptor.getAllValues();
+ assertThat(prefs.get(1).getKey()).isEqualTo(app1.getPackage());
+ assertThat(prefs.get(0).getKey()).isEqualTo(app2.getPackage());
+ }
+
+ @Test
+ public void display_hasRecentButNoneDisplayable_showAppInfo() {
+ final List<NotifyingApp> apps = new ArrayList<>();
+ final NotifyingApp app1 = new NotifyingApp()
+ .setPackage("com.android.phone")
+ .setLastNotified(System.currentTimeMillis());
+ final NotifyingApp app2 = new NotifyingApp()
+ .setPackage("com.android.settings")
+ .setLastNotified(System.currentTimeMillis());
+ apps.add(app1);
+ apps.add(app2);
+
+ // app1, app2 are not displayable
+ when(mAppState.getEntry(app1.getPackage(), UserHandle.myUserId()))
+ .thenReturn(mock(ApplicationsState.AppEntry.class));
+ when(mAppState.getEntry(app2.getPackage(), UserHandle.myUserId()))
+ .thenReturn(mock(ApplicationsState.AppEntry.class));
+ when(mPackageManager.resolveActivity(any(Intent.class), anyInt())).thenReturn(
+ new ResolveInfo());
+ when(mBackend.getRecentApps()).thenReturn(apps);
+
+ mController.displayPreference(mScreen);
+
+ verify(mCategory, never()).addPreference(any(Preference.class));
+ verify(mCategory).setTitle(null);
+ verify(mSeeAllPref).setTitle(R.string.notifications_title);
+ verify(mSeeAllPref).setIcon(null);
+ }
+
+ @Test
+ public void display_showRecents_formatSummary() {
+ final List<NotifyingApp> apps = new ArrayList<>();
+ final NotifyingApp app1 = new NotifyingApp()
+ .setLastNotified(System.currentTimeMillis())
+ .setPackage("pkg.class");
+ apps.add(app1);
+
+ when(mAppState.getEntry(app1.getPackage(), UserHandle.myUserId()))
+ .thenReturn(mAppEntry);
+ when(mPackageManager.resolveActivity(any(Intent.class), anyInt())).thenReturn(
+ new ResolveInfo());
+ when(mBackend.getRecentApps()).thenReturn(apps);
+ mAppEntry.info = mApplicationInfo;
+
+ mController.displayPreference(mScreen);
+
+ verify(mCategory).addPreference(argThat(summaryMatches("0 min. ago")));
+ }
+
+ private static ArgumentMatcher<Preference> summaryMatches(String expected) {
+ return preference -> TextUtils.equals(expected, preference.getSummary());
+ }
+
+ // Used for matching an intent with a specific package name.
+ private static ArgumentMatcher<Intent> intentMatcher(String packageName) {
+ return intent -> packageName.equals(intent.getPackage());
+ }
+}
diff --git a/tests/robotests/src/com/android/settings/notification/ZenModeButtonPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/ZenModeButtonPreferenceControllerTest.java
index 862b8d0..ed42890 100644
--- a/tests/robotests/src/com/android/settings/notification/ZenModeButtonPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/notification/ZenModeButtonPreferenceControllerTest.java
@@ -26,6 +26,7 @@
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import android.app.FragmentManager;
import android.app.NotificationManager;
import android.content.ContentResolver;
import android.content.Context;
@@ -79,7 +80,8 @@
mContext = shadowApplication.getApplicationContext();
mContentResolver = RuntimeEnvironment.application.getContentResolver();
- mController = new ZenModeButtonPreferenceController(mContext, mock(Lifecycle.class));
+ mController = new ZenModeButtonPreferenceController(mContext, mock(Lifecycle.class),
+ mock(FragmentManager.class));
when(mNotificationManager.getNotificationPolicy()).thenReturn(mPolicy);
ReflectionHelpers.setField(mController, "mBackend", mBackend);
ReflectionHelpers.setField(mController, "mZenButtonOn", mZenButtonOn);
diff --git a/tests/robotests/src/com/android/settings/security/LockdownButtonPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/security/LockdownButtonPreferenceControllerTest.java
new file mode 100644
index 0000000..7738f86
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/security/LockdownButtonPreferenceControllerTest.java
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2018 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 static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.provider.Settings;
+import android.support.v14.preference.SwitchPreference;
+
+import com.android.internal.widget.LockPatternUtils;
+import com.android.settings.TestConfig;
+import com.android.settings.testutils.SettingsRobolectricTestRunner;
+
+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.util.ReflectionHelpers;
+
+@RunWith(SettingsRobolectricTestRunner.class)
+@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
+public class LockdownButtonPreferenceControllerTest {
+ @Mock
+ private LockPatternUtils mLockPatternUtils;
+ private SwitchPreference mPreference;
+
+ private Context mContext;
+ private LockdownButtonPreferenceController mController;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ mContext = RuntimeEnvironment.application;
+ mPreference = new SwitchPreference(mContext);
+
+ mController = spy(new LockdownButtonPreferenceController(mContext));
+ ReflectionHelpers.setField(mController, "mLockPatternUtils", mLockPatternUtils);
+ }
+
+ @Test
+ public void isAvailable_lockSet_shouldReturnTrue() throws Exception {
+ when(mLockPatternUtils.isSecure(anyInt())).thenReturn(true);
+ assertThat(mController.isAvailable()).isTrue();
+ }
+
+ @Test
+ public void isAvailable_lockUnset_shouldReturnFalse() throws Exception {
+ when(mLockPatternUtils.isSecure(anyInt())).thenReturn(false);
+ assertThat(mController.isAvailable()).isFalse();
+ }
+
+ @Test
+ public void onPreferenceChange_settingIsUpdated() throws Exception {
+ boolean state = Settings.Secure.getInt(mContext.getContentResolver(),
+ Settings.Secure.LOCKDOWN_IN_POWER_MENU, 0) != 0;
+ assertThat(mController.onPreferenceChange(mPreference, !state)).isTrue();
+ boolean newState = Settings.Secure.getInt(mContext.getContentResolver(),
+ Settings.Secure.LOCKDOWN_IN_POWER_MENU, 0) != 0;
+ assertThat(newState).isEqualTo(!state);
+ }
+
+ @Test
+ public void onSettingChange_preferenceIsUpdated() throws Exception {
+ boolean state = Settings.Secure.getInt(mContext.getContentResolver(),
+ Settings.Secure.LOCKDOWN_IN_POWER_MENU, 0) != 0;
+ mController.updateState(mPreference);
+ assertThat(mPreference.isChecked()).isEqualTo(state);
+ Settings.Secure.putInt(mContext.getContentResolver(),
+ Settings.Secure.LOCKDOWN_IN_POWER_MENU, state ? 0 : 1);
+
+ mController.updateState(mPreference);
+ assertThat(mPreference.isChecked()).isEqualTo(!state);
+ }
+}
diff --git a/tests/robotests/src/com/android/settings/testutils/FakeFeatureFactory.java b/tests/robotests/src/com/android/settings/testutils/FakeFeatureFactory.java
index 3325332..ad51f79 100644
--- a/tests/robotests/src/com/android/settings/testutils/FakeFeatureFactory.java
+++ b/tests/robotests/src/com/android/settings/testutils/FakeFeatureFactory.java
@@ -21,9 +21,11 @@
import android.content.Context;
+import com.android.settings.accounts.AccountFeatureProvider;
import com.android.settings.applications.ApplicationFeatureProvider;
import com.android.settings.bluetooth.BluetoothFeatureProvider;
import com.android.settings.connecteddevice.SmsMirroringFeatureProvider;
+import com.android.settings.core.instrumentation.MetricsFeatureProvider;
import com.android.settings.dashboard.DashboardFeatureProvider;
import com.android.settings.dashboard.suggestions.SuggestionFeatureProvider;
import com.android.settings.datausage.DataPlanFeatureProvider;
@@ -38,7 +40,6 @@
import com.android.settings.security.SecurityFeatureProvider;
import com.android.settings.slices.SlicesFeatureProvider;
import com.android.settings.users.UserFeatureProvider;
-import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
import org.mockito.Answers;
@@ -65,6 +66,7 @@
public final SmsMirroringFeatureProvider smsMirroringFeatureProvider;
public final SlicesFeatureProvider slicesFeatureProvider;
public SearchFeatureProvider searchFeatureProvider;
+ public final AccountFeatureProvider mAccountFeatureProvider;
/**
* Call this in {@code @Before} method of the test class to use fake factory.
@@ -104,6 +106,7 @@
dataPlanFeatureProvider = mock(DataPlanFeatureProvider.class);
smsMirroringFeatureProvider = mock(SmsMirroringFeatureProvider.class);
slicesFeatureProvider = mock(SlicesFeatureProvider.class);
+ mAccountFeatureProvider = mock(AccountFeatureProvider.class);
}
@Override
@@ -190,4 +193,9 @@
public SlicesFeatureProvider getSlicesFeatureProvider() {
return slicesFeatureProvider;
}
+
+ @Override
+ public AccountFeatureProvider getAccountFeatureProvider() {
+ return mAccountFeatureProvider;
+ }
}
diff --git a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowEventLogWriter.java b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowEventLogWriter.java
index 9caf09f..dcced4e 100644
--- a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowEventLogWriter.java
+++ b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowEventLogWriter.java
@@ -19,7 +19,7 @@
import android.content.Context;
-import com.android.settingslib.core.instrumentation.EventLogWriter;
+import com.android.settings.core.instrumentation.EventLogWriter;
import org.robolectric.annotation.Implementation;
import org.robolectric.annotation.Implements;
diff --git a/tests/robotests/src/com/android/settings/webview/WebViewAppPickerTest.java b/tests/robotests/src/com/android/settings/webview/WebViewAppPickerTest.java
index 59a08ae..e44be0e 100644
--- a/tests/robotests/src/com/android/settings/webview/WebViewAppPickerTest.java
+++ b/tests/robotests/src/com/android/settings/webview/WebViewAppPickerTest.java
@@ -44,10 +44,10 @@
import com.android.settings.TestConfig;
import com.android.settings.applications.defaultapps.DefaultAppInfo;
+import com.android.settings.core.instrumentation.MetricsFeatureProvider;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
import com.android.settings.widget.RadioButtonPreference;
import com.android.settings.wrapper.UserPackageWrapper;
-import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
import com.android.settingslib.wrapper.PackageManagerWrapper;
import org.junit.Before;
diff --git a/tests/robotests/src/com/android/settings/widget/AppCheckBoxPreferenceTest.java b/tests/robotests/src/com/android/settings/widget/AppCheckBoxPreferenceTest.java
new file mode 100644
index 0000000..d540a62
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/widget/AppCheckBoxPreferenceTest.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.widget;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.content.Context;
+
+import com.android.settings.R;
+import com.android.settings.TestConfig;
+import com.android.settings.testutils.SettingsRobolectricTestRunner;
+
+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 AppCheckBoxPreferenceTest {
+
+ private Context mContext;
+ private AppCheckBoxPreference mPreference;
+ private AppCheckBoxPreference mAttrPreference;
+
+ @Before
+ public void setUp() {
+ mContext = RuntimeEnvironment.application;
+ mPreference = new AppCheckBoxPreference(mContext);
+ mAttrPreference = new AppCheckBoxPreference(mContext, null /* attrs */);
+ }
+
+ @Test
+ public void testGetLayoutResource() {
+ assertThat(mPreference.getLayoutResource()).isEqualTo(R.layout.preference_app);
+ assertThat(mAttrPreference.getLayoutResource()).isEqualTo(R.layout.preference_app);
+ }
+}
diff --git a/tests/robotests/src/com/android/settings/wifi/WifiEnablerTest.java b/tests/robotests/src/com/android/settings/wifi/WifiEnablerTest.java
index 84549a6..63f89e6 100644
--- a/tests/robotests/src/com/android/settings/wifi/WifiEnablerTest.java
+++ b/tests/robotests/src/com/android/settings/wifi/WifiEnablerTest.java
@@ -22,9 +22,9 @@
import com.android.settings.testutils.SettingsRobolectricTestRunner;
import com.android.settings.TestConfig;
+import com.android.settings.core.instrumentation.MetricsFeatureProvider;
import com.android.settings.widget.SwitchWidgetController;
import com.android.settings.wrapper.ConnectivityManagerWrapper;
-import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
import org.junit.Before;
import org.junit.Test;
diff --git a/tests/robotests/src/com/android/settings/wifi/WifiMasterSwitchPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/wifi/WifiMasterSwitchPreferenceControllerTest.java
index 82569c7..1708e36 100644
--- a/tests/robotests/src/com/android/settings/wifi/WifiMasterSwitchPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/wifi/WifiMasterSwitchPreferenceControllerTest.java
@@ -30,10 +30,10 @@
import android.support.v7.preference.PreferenceScreen;
import com.android.settings.TestConfig;
+import com.android.settings.core.instrumentation.MetricsFeatureProvider;
import com.android.settings.testutils.FakeFeatureFactory;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
import com.android.settings.widget.MasterSwitchPreference;
-import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
import org.junit.Before;
import org.junit.Test;
diff --git a/tests/robotests/src/com/android/settings/wifi/details/WifiDetailPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/wifi/details/WifiDetailPreferenceControllerTest.java
index ca2cac0..4f77435 100644
--- a/tests/robotests/src/com/android/settings/wifi/details/WifiDetailPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/wifi/details/WifiDetailPreferenceControllerTest.java
@@ -65,6 +65,7 @@
import com.android.settings.R;
import com.android.settings.TestConfig;
import com.android.settings.applications.LayoutPreference;
+import com.android.settings.core.instrumentation.MetricsFeatureProvider;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
import com.android.settings.testutils.shadow.ShadowBidiFormatter;
import com.android.settings.testutils.shadow.ShadowDevicePolicyManagerWrapper;
@@ -75,7 +76,6 @@
import com.android.settings.widget.EntityHeaderController;
import com.android.settings.wifi.WifiDetailPreference;
import com.android.settings.wrapper.ConnectivityManagerWrapper;
-import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
import com.android.settingslib.core.lifecycle.Lifecycle;
import com.android.settingslib.wifi.AccessPoint;
diff --git a/tests/robotests/src/com/android/settings/wifi/tether/WifiTetherApBandPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/wifi/tether/WifiTetherApBandPreferenceControllerTest.java
index 6832ca8..2a633d9 100644
--- a/tests/robotests/src/com/android/settings/wifi/tether/WifiTetherApBandPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/wifi/tether/WifiTetherApBandPreferenceControllerTest.java
@@ -80,7 +80,7 @@
mController.displayPreference(mScreen);
- assertThat(mListPreference.getEntries().length).isEqualTo(2);
+ assertThat(mListPreference.getEntries().length).isEqualTo(3);
}
@Test
@@ -113,13 +113,18 @@
when(mWifiManager.is5GHzBandSupported()).thenReturn(true);
mController.displayPreference(mScreen);
+
+ // -1 is WifiConfiguration.AP_BAND_ANY, for 'Auto' option.
+ mController.onPreferenceChange(mListPreference, "-1");
+ assertThat(mController.getBandIndex()).isEqualTo(-1);
+
mController.onPreferenceChange(mListPreference, "1");
assertThat(mController.getBandIndex()).isEqualTo(1);
mController.onPreferenceChange(mListPreference, "0");
assertThat(mController.getBandIndex()).isEqualTo(0);
- verify(mListener, times(2)).onTetherConfigUpdated();
+ verify(mListener, times(3)).onTetherConfigUpdated();
}
@Test
diff --git a/tests/robotests/src/com/android/settings/wifi/tether/WifiTetherPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/wifi/tether/WifiTetherPreferenceControllerTest.java
index 00d9585..dca6974 100644
--- a/tests/robotests/src/com/android/settings/wifi/tether/WifiTetherPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/wifi/tether/WifiTetherPreferenceControllerTest.java
@@ -18,11 +18,15 @@
import static android.arch.lifecycle.Lifecycle.Event.ON_START;
import static android.arch.lifecycle.Lifecycle.Event.ON_STOP;
+
import static com.google.common.truth.Truth.assertThat;
+
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -65,6 +69,7 @@
shadows = {
WifiTetherPreferenceControllerTest.ShadowWifiTetherSettings.class,
WifiTetherPreferenceControllerTest.ShadowWifiTetherSwitchBarController.class,
+ WifiTetherPreferenceControllerTest.ShadowWifiTetherSoftApManager.class
})
public class WifiTetherPreferenceControllerTest {
@@ -94,8 +99,9 @@
when(mContext.getSystemService(Context.WIFI_SERVICE)).thenReturn(mWifiManager);
when(mScreen.findPreference(anyString())).thenReturn(mPreference);
- when(mConnectivityManager.getTetherableWifiRegexs()).thenReturn(new String[] {"1", "2"});
- mController = new WifiTetherPreferenceController(mContext, mLifecycle);
+ when(mConnectivityManager.getTetherableWifiRegexs()).thenReturn(new String[]{"1", "2"});
+ mController = new WifiTetherPreferenceController(mContext, mLifecycle,
+ false /* initSoftApManager */);
}
@After
@@ -105,8 +111,9 @@
@Test
public void isAvailable_noTetherRegex_shouldReturnFalse() {
- when(mConnectivityManager.getTetherableWifiRegexs()).thenReturn(new String[] {});
- mController = new WifiTetherPreferenceController(mContext, mLifecycle);
+ when(mConnectivityManager.getTetherableWifiRegexs()).thenReturn(new String[]{});
+ mController = new WifiTetherPreferenceController(mContext, mLifecycle,
+ false /* initSoftApManager */);
assertThat(mController.isAvailable()).isFalse();
}
@@ -244,6 +251,19 @@
}
}
+ @Implements(WifiTetherSoftApManager.class)
+ public static final class ShadowWifiTetherSoftApManager {
+ @Implementation
+ public void registerSoftApCallback() {
+ // do nothing
+ }
+
+ @Implementation
+ public void unRegisterSoftApCallback() {
+ // do nothing
+ }
+ }
+
@Implements(WifiTetherSwitchBarController.class)
public static final class ShadowWifiTetherSwitchBarController {
diff --git a/tests/unit/src/com/android/settings/notification/ChannelGroupNotificationSettingsTest.java b/tests/unit/src/com/android/settings/notification/ChannelGroupNotificationSettingsTest.java
deleted file mode 100644
index ce2c408..0000000
--- a/tests/unit/src/com/android/settings/notification/ChannelGroupNotificationSettingsTest.java
+++ /dev/null
@@ -1,133 +0,0 @@
-/*
- * 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.notification;
-
-import static android.app.NotificationManager.IMPORTANCE_HIGH;
-import static android.app.NotificationManager.IMPORTANCE_MIN;
-import static android.support.test.espresso.Espresso.onView;
-import static android.support.test.espresso.assertion.ViewAssertions.matches;
-import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed;
-import static android.support.test.espresso.matcher.ViewMatchers.withId;
-import static android.support.test.espresso.matcher.ViewMatchers.withText;
-
-import static org.hamcrest.Matchers.allOf;
-import static org.junit.Assert.fail;
-
-import android.app.INotificationManager;
-import android.app.Instrumentation;
-import android.app.NotificationChannel;
-import android.app.NotificationChannelGroup;
-import android.app.NotificationManager;
-import android.content.Context;
-import android.content.Intent;
-import android.os.Process;
-import android.os.ServiceManager;
-import android.provider.Settings;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public class ChannelGroupNotificationSettingsTest {
-
- private Context mTargetContext;
- private Instrumentation mInstrumentation;
- private NotificationManager mNm;
-
- @Before
- public void setUp() {
- mInstrumentation = InstrumentationRegistry.getInstrumentation();
- mTargetContext = mInstrumentation.getTargetContext();
- mNm = (NotificationManager) mTargetContext.getSystemService(Context.NOTIFICATION_SERVICE);
- }
-
- @Test
- public void launchNotificationSetting_displaysChannels() {
- NotificationChannelGroup group =
- new NotificationChannelGroup(this.getClass().getName(), this.getClass().getName());
- group.setDescription("description");
- NotificationChannel channel = new NotificationChannel(this.getClass().getName(),
- "channel" + this.getClass().getName(), IMPORTANCE_MIN);
- channel.setGroup(this.getClass().getName());
- NotificationChannel channel2 = new NotificationChannel("2"+this.getClass().getName(),
- "2channel" + this.getClass().getName(), IMPORTANCE_MIN);
- channel2.setGroup(this.getClass().getName());
-
- mNm.createNotificationChannelGroup(group);
- mNm.createNotificationChannel(channel);
- mNm.createNotificationChannel(channel2);
-
- final Intent intent = new Intent(Settings.ACTION_CHANNEL_GROUP_NOTIFICATION_SETTINGS)
- .putExtra(Settings.EXTRA_APP_PACKAGE, mTargetContext.getPackageName())
- .putExtra(Settings.EXTRA_CHANNEL_GROUP_ID, group.getId());
-
- mInstrumentation.startActivitySync(intent);
-
- onView(allOf(withText(group.getName().toString()))).check(matches(isDisplayed()));
- onView(allOf(withText(channel.getName().toString()))).check(
- matches(isDisplayed()));
- onView(allOf(withText(group.getDescription().toString()))).check(
- matches(isDisplayed()));
- onView(allOf(withText(channel2.getName().toString()))).check(
- matches(isDisplayed()));
- try {
- onView(allOf(withText("Android is blocking this group of notifications from"
- + " appearing on this device"))).check(matches(isDisplayed()));
- fail("Blocking footer erroneously appearing");
- } catch (Exception e) {
- // expected
- }
- }
-
- @Test
- public void launchNotificationSettings_blockedGroup() throws Exception {
- NotificationChannelGroup blocked =
- new NotificationChannelGroup("blocked", "blocked");
- NotificationChannel channel =
- new NotificationChannel("channel", "channel", IMPORTANCE_HIGH);
- channel.setGroup(blocked.getId());
- mNm.createNotificationChannelGroup(blocked);
- mNm.createNotificationChannel(channel);
-
- INotificationManager sINM = INotificationManager.Stub.asInterface(
- ServiceManager.getService(Context.NOTIFICATION_SERVICE));
- blocked.setBlocked(true);
- sINM.updateNotificationChannelGroupForPackage(
- mTargetContext.getPackageName(), Process.myUid(), blocked);
-
- final Intent intent = new Intent(Settings.ACTION_CHANNEL_GROUP_NOTIFICATION_SETTINGS)
- .putExtra(Settings.EXTRA_APP_PACKAGE, mTargetContext.getPackageName())
- .putExtra(Settings.EXTRA_CHANNEL_GROUP_ID, blocked.getId());
- mInstrumentation.startActivitySync(intent);
-
- onView(allOf(withText("Off"), isDisplayed())).check(matches(isDisplayed()));
- onView(allOf(withText("Android is blocking this group of notifications from"
- + " appearing on this device"))).check(matches(isDisplayed()));
-
- try {
- onView(allOf(withText(channel.getName().toString()))).check(matches(isDisplayed()));
- fail("settings appearing for blocked group");
- } catch (Exception e) {
- // expected
- }
- }
-}