diff --git a/color-check-baseline.xml b/color-check-baseline.xml
index 365cbe71abd..cbfae2e6ac2 100644
--- a/color-check-baseline.xml
+++ b/color-check-baseline.xml
@@ -109,6 +109,22 @@
column="5"/>
+
+
+
+
+
+
+
+
+ errorLine1=" <color name="homepage_location_background">#2EC7DC</color>"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ errorLine1=" <color name="homepage_privacy_background">#5E97F6</color>"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ file="res/values/colors.xml"
+ line="130"
+ column="5"/>
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -1369,7 +1417,7 @@
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
@@ -1385,7 +1433,7 @@
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
@@ -1401,7 +1449,7 @@
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
@@ -1417,7 +1465,7 @@
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
@@ -1433,7 +1481,7 @@
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
@@ -1449,7 +1497,7 @@
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
@@ -1734,7 +1782,7 @@
summary="Using hardcoded color"
explanation="Hardcoded color values are bad because theme changes cannot be uniformly applied.Instead use the theme specific colors such as `?android:attr/textColorPrimary` in attributes.
This ensures that a theme change from a light to a dark theme can be uniformlyapplied across the app."
errorLine1=" android:color="@color/homepage_about_background" />"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
@@ -2521,7 +2569,7 @@
errorLine2=" ~~~~~~~~~~~~~~~~~~~">
@@ -2537,7 +2585,7 @@
errorLine2=" ~~~~~~~~~~~~~~~~~~~">
@@ -2553,7 +2601,7 @@
errorLine2=" ~~~~~~~~~~~~~~~~~~~">
@@ -2569,7 +2617,7 @@
errorLine2=" ~~~~~~~~~~~~~~~~~~~">
@@ -2585,7 +2633,7 @@
errorLine2=" ~~~~~~~~~~~~~~~~~~~">
@@ -2601,7 +2649,7 @@
errorLine2=" ^">
@@ -2617,7 +2665,7 @@
errorLine2=" ^">
@@ -2633,7 +2681,7 @@
errorLine2=" ^">
@@ -2649,7 +2697,7 @@
errorLine2=" ^">
@@ -2713,7 +2761,7 @@
errorLine2=" ^">
@@ -2725,12 +2773,12 @@
priority="4"
summary="Using hardcoded color"
explanation="Hardcoded color values are bad because theme changes cannot be uniformly applied.Instead use the theme specific colors such as `?android:attr/textColorPrimary` in attributes.
This ensures that a theme change from a light to a dark theme can be uniformlyapplied across the app."
- errorLine1=" <item name="android:statusBarColor">#00000000</item>"
- errorLine2=" ^">
+ errorLine1=" <item name="switchBarBackgroundColor">@color/switch_bar_background</item>"
+ errorLine2=" ^">
+ line="91"
+ column="47"/>
+ errorLine1=" <item name="android:trackTint">@color/switchbar_switch_track_tint</item>"
+ errorLine2=" ^">
+ line="97"
+ column="40"/>
+
+
+
+
+ errorLine1=" <item name="android:statusBarColor">#00000000</item>"
+ errorLine2=" ^">
+ line="169"
+ column="45"/>
+
+
+
+
@@ -2921,7 +3001,7 @@
errorLine2=" ^">
@@ -2937,7 +3017,7 @@
errorLine2=" ^">
diff --git a/res/drawable/ic_friction_lock_closed.xml b/res/drawable/ic_friction_lock_closed.xml
index 194c9afb404..dab8c913684 100644
--- a/res/drawable/ic_friction_lock_closed.xml
+++ b/res/drawable/ic_friction_lock_closed.xml
@@ -21,6 +21,5 @@
android:height="18dp">
+ android:fillColor="?attr/frictionIconColor" />
diff --git a/res/drawable/ic_friction_money.xml b/res/drawable/ic_friction_money.xml
index 1018533d035..b17092144ea 100644
--- a/res/drawable/ic_friction_money.xml
+++ b/res/drawable/ic_friction_money.xml
@@ -20,8 +20,7 @@
android:width="18dp"
android:height="18dp">
-
-
-
-
\ No newline at end of file
+
+
+
diff --git a/res/drawable/ic_settings_delete.xml b/res/drawable/ic_settings_delete.xml
new file mode 100644
index 00000000000..10125acd498
--- /dev/null
+++ b/res/drawable/ic_settings_delete.xml
@@ -0,0 +1,31 @@
+
+
+
+
+
+
+
diff --git a/res/drawable/ic_settings_force_stop.xml b/res/drawable/ic_settings_force_stop.xml
new file mode 100644
index 00000000000..eda6079c48f
--- /dev/null
+++ b/res/drawable/ic_settings_force_stop.xml
@@ -0,0 +1,31 @@
+
+
+
+
+
+
+
diff --git a/res/drawable/ic_settings_install.xml b/res/drawable/ic_settings_install.xml
new file mode 100644
index 00000000000..5bd5e300eae
--- /dev/null
+++ b/res/drawable/ic_settings_install.xml
@@ -0,0 +1,28 @@
+
+
+
+
+
+
diff --git a/res/color/switchbar_switch_track_tint.xml b/res/drawable/ic_settings_open.xml
similarity index 60%
rename from res/color/switchbar_switch_track_tint.xml
rename to res/drawable/ic_settings_open.xml
index 141f9775bba..ea7771028b1 100644
--- a/res/color/switchbar_switch_track_tint.xml
+++ b/res/drawable/ic_settings_open.xml
@@ -1,4 +1,3 @@
-
-
-
-
\ No newline at end of file
+
+
+
diff --git a/res/layout-land/storage_summary_donut.xml b/res/layout-land/storage_summary_donut.xml
new file mode 100644
index 00000000000..5fe4cc89aa4
--- /dev/null
+++ b/res/layout-land/storage_summary_donut.xml
@@ -0,0 +1,78 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/res/layout-sw360dp/storage_summary_donut.xml b/res/layout-sw360dp/storage_summary_donut.xml
new file mode 100644
index 00000000000..5fe4cc89aa4
--- /dev/null
+++ b/res/layout-sw360dp/storage_summary_donut.xml
@@ -0,0 +1,78 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/res/layout/search_bar.xml b/res/layout/search_bar.xml
index 3d4d0d64722..9135ebf8f1a 100644
--- a/res/layout/search_bar.xml
+++ b/res/layout/search_bar.xml
@@ -21,15 +21,15 @@
android:id="@+id/search_bar_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- app:layout_scrollFlags="scroll|enterAlways"
- android:background="?android:attr/colorPrimary">
+ android:background="?android:attr/colorBackground"
+ android:theme="@style/ThemeOverlay.Settings.SearchBar"
+ app:layout_scrollFlags="scroll|enterAlways">
+ android:navigationIcon="@drawable/ic_search_24dp">
+ android:gravity="center"
+ android:orientation="vertical"
+ android:paddingTop="32dp"
+ android:paddingBottom="32dp" >
-
+ android:ellipsize="marquee"
+ android:fadingEdge="horizontal"
+ android:fontFamily="@*android:string/config_headlineFontFamily"
+ android:singleLine="true"
+ android:textAlignment="center"
+ android:textAppearance="@android:style/TextAppearance.Material.Display1"
+ android:textSize="36sp" />
-
-
-
-
-
-
+
+ android:layout_width="168dp"
+ android:layout_height="168dp"
+ android:layout_marginTop="4dp"
+ android:layout_marginBottom="4dp"
+ android:minWidth="58dp" />
+
+
diff --git a/res/layout/switch_bar.xml b/res/layout/switch_bar.xml
index 8cb6f5102bf..3bdfbd49cbc 100644
--- a/res/layout/switch_bar.xml
+++ b/res/layout/switch_bar.xml
@@ -28,7 +28,7 @@
android:maxLines="2"
android:ellipsize="end"
android:textAppearance="@style/TextAppearance.Switch"
- android:textColor="?android:attr/textColorPrimary"
+ android:textColor="?android:attr/textColorPrimaryInverse"
android:textAlignment="viewStart"/>
-
-
-
-
+ android:paddingTop="20dp"
+ android:paddingBottom="20dp"/>
-
-
-
-
+ android:paddingTop="20dp"
+ android:paddingBottom="20dp"/>
\ No newline at end of file
diff --git a/res/values-land/dimens.xml b/res/values-land/dimens.xml
index 37e71e2174e..d426411a7f1 100755
--- a/res/values-land/dimens.xml
+++ b/res/values-land/dimens.xml
@@ -30,4 +30,9 @@
160dp
+
+ 30sp
+
+ 14sp
+
diff --git a/res/values-night/colors.xml b/res/values-night/colors.xml
new file mode 100644
index 00000000000..595f429cd5f
--- /dev/null
+++ b/res/values-night/colors.xml
@@ -0,0 +1,23 @@
+
+
+
+
+ @android:color/black
+ #dadce0
+ #82000000
+ @android:color/black
+
+
diff --git a/res/values-night/styles.xml b/res/values-night/styles.xml
new file mode 100644
index 00000000000..87159b8b76f
--- /dev/null
+++ b/res/values-night/styles.xml
@@ -0,0 +1,24 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/res/values-night/themes.xml b/res/values-night/themes.xml
index 725fe17685d..8deae1cb359 100644
--- a/res/values-night/themes.xml
+++ b/res/values-night/themes.xml
@@ -20,6 +20,21 @@
+
+
+
+
+
+
diff --git a/res/values-sw400dp/dimens.xml b/res/values-sw360dp/dimens.xml
similarity index 81%
rename from res/values-sw400dp/dimens.xml
rename to res/values-sw360dp/dimens.xml
index 23a11761ebb..b81a98a695c 100755
--- a/res/values-sw400dp/dimens.xml
+++ b/res/values-sw360dp/dimens.xml
@@ -25,4 +25,8 @@
22dp
+
+ 30sp
+
+ 14sp
diff --git a/res/values/arrays.xml b/res/values/arrays.xml
index 4bd86dce0d6..80224bd2fec 100644
--- a/res/values/arrays.xml
+++ b/res/values/arrays.xml
@@ -697,6 +697,33 @@
- Accessibility volume
+
+
+ - accessibility_content_timeout_default
+ - accessibility_content_timeout_10secs
+ - accessibility_content_timeout_30secs
+ - accessibility_content_timeout_1min
+ - accessibility_content_timeout_2mins
+
+
+
+
+ - accessibility_control_timeout_default
+ - accessibility_control_timeout_10secs
+ - accessibility_control_timeout_30secs
+ - accessibility_control_timeout_1min
+ - accessibility_control_timeout_2mins
+
+
+
+
+ - 0
+ - 10000
+ - 30000
+ - 60000
+ - 120000
+
+
diff --git a/res/values/attrs.xml b/res/values/attrs.xml
index afff3cebe22..752fd3dada5 100644
--- a/res/values/attrs.xml
+++ b/res/values/attrs.xml
@@ -154,4 +154,5 @@
+
diff --git a/res/values/colors.xml b/res/values/colors.xml
index f55eb1a7813..34885b4770a 100644
--- a/res/values/colors.xml
+++ b/res/values/colors.xml
@@ -130,6 +130,10 @@
#5E97F6
+ @android:color/white
+ #BFFFFFFF
+ @android:color/white
+
@*android:color/material_red_A700
#43a047
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index caaea90d19c..aa464a0e859 100755
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -274,11 +274,11 @@
16dp
- 30sp
+ 45sp
20sp
- 14sp
+ 21sp
10sp
diff --git a/res/values/strings.xml b/res/values/strings.xml
index f15eeb2292e..d9ac590240e 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -4002,8 +4002,6 @@
Uninstall for all users
Install
-
- Disable
Enable
@@ -4575,6 +4573,24 @@
Mono audio
Combine channels when playing audio
+
+
+ Default
+
+ 10 seconds
+
+ 30 seconds
+
+ 1 minute
+
+ 2 minutes
+
+ Content Timeout
+
+ Control Timeout
+
+ Choose how long it takes before automatically disappearing messages go away.\nSome apps may not support this setting yet.
+
Touch & hold delay
@@ -8025,6 +8041,19 @@
Allow events
+
+ Allow apps to override
+
+
+ Overrides Do Not Disturb
+
+
+
+ - No apps can override Do Not Disturb
+ - 1 app can override Do Not Disturb
+ - %1$d apps can override Do Not Disturb
+
+
events
@@ -10302,4 +10331,7 @@
Keep
Remove this suggestion?
+
+
+ Storage is low. %1$s used - %2$s free
\ No newline at end of file
diff --git a/res/values/styles.xml b/res/values/styles.xml
index 8fa357bc75f..28bc1a08201 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -16,12 +16,15 @@
-
-
@@ -426,6 +429,11 @@
+
+
-
+
+
-
+
+
@@ -183,4 +190,9 @@
- true
+
+
diff --git a/res/xml/accessibility_content_timeout_settings.xml b/res/xml/accessibility_content_timeout_settings.xml
new file mode 100644
index 00000000000..51573c958e5
--- /dev/null
+++ b/res/xml/accessibility_content_timeout_settings.xml
@@ -0,0 +1,63 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/res/xml/accessibility_control_timeout_settings.xml b/res/xml/accessibility_control_timeout_settings.xml
new file mode 100644
index 00000000000..45596503f32
--- /dev/null
+++ b/res/xml/accessibility_control_timeout_settings.xml
@@ -0,0 +1,63 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/res/xml/accessibility_settings.xml b/res/xml/accessibility_settings.xml
index a76bef7f185..1cd4a4816b1 100644
--- a/res/xml/accessibility_settings.xml
+++ b/res/xml/accessibility_settings.xml
@@ -71,6 +71,14 @@
+
+
+
+
+
+ android:order="-10000"
+ settings:allowDividerBelow="true"/>
+ settings:controller="com.android.settings.applications.appinfo.AppNotificationPreferenceController"
+ settings:allowDividerAbove="true"/>
+ android:selectable="false"
+ settings:allowDividerBelow="true"/>
diff --git a/res/xml/wifi_network_details_fragment.xml b/res/xml/wifi_network_details_fragment.xml
index 7c8d9a00aa2..4198b76fb2c 100644
--- a/res/xml/wifi_network_details_fragment.xml
+++ b/res/xml/wifi_network_details_fragment.xml
@@ -23,7 +23,8 @@
android:key="connection_header"
android:layout="@layout/settings_entity_header"
android:selectable="false"
- android:order="-10000"/>
+ android:order="-10000"
+ settings:allowDividerBelow="true"/>
+
+
+
diff --git a/res/xml/zen_mode_sound_vibration_settings.xml b/res/xml/zen_mode_sound_vibration_settings.xml
index 3d1da2fec8c..30e2abb7513 100644
--- a/res/xml/zen_mode_sound_vibration_settings.xml
+++ b/res/xml/zen_mode_sound_vibration_settings.xml
@@ -20,50 +20,55 @@
android:key="zen_mode_sound_vibration_settings_page"
android:title="@string/zen_category_exceptions" >
-
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
+
+
+
diff --git a/src/com/android/settings/SettingsInitialize.java b/src/com/android/settings/SettingsInitialize.java
index 9c37df6b3dc..784617aa39d 100644
--- a/src/com/android/settings/SettingsInitialize.java
+++ b/src/com/android/settings/SettingsInitialize.java
@@ -128,6 +128,9 @@ public class SettingsInitialize extends BroadcastReceiver {
final List pinnedShortcuts = shortcutManager.getPinnedShortcuts();
final List updates = new ArrayList<>();
for (ShortcutInfo info : pinnedShortcuts) {
+ if (info.isImmutable()) {
+ continue;
+ }
final Intent shortcutIntent = info.getIntent();
shortcutIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
final ShortcutInfo updatedInfo = new ShortcutInfo.Builder(context, info.getId())
diff --git a/src/com/android/settings/accessibility/AccessibilityContentTimeoutPreferenceFragment.java b/src/com/android/settings/accessibility/AccessibilityContentTimeoutPreferenceFragment.java
new file mode 100644
index 00000000000..4fc61591d54
--- /dev/null
+++ b/src/com/android/settings/accessibility/AccessibilityContentTimeoutPreferenceFragment.java
@@ -0,0 +1,130 @@
+/*
+ * 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.accessibility;
+
+import android.provider.SearchIndexableResource;
+import android.content.Context;
+import android.content.res.Resources;
+
+import androidx.preference.Preference;
+
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+import com.android.settings.R;
+import com.android.settings.dashboard.DashboardFragment;
+import com.android.settings.search.BaseSearchIndexProvider;
+import com.android.settings.search.Indexable;
+import com.android.settingslib.core.AbstractPreferenceController;
+import com.android.settingslib.core.lifecycle.Lifecycle;
+import com.android.settingslib.search.SearchIndexable;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+@SearchIndexable
+public final class AccessibilityContentTimeoutPreferenceFragment extends DashboardFragment
+ implements AccessibilityTimeoutController.OnChangeListener {
+
+ static final String TAG = "AccessibilityContentTimeoutPreferenceFragment";
+ private static final List sControllers = new ArrayList<>();
+
+ @Override
+ public void onCheckedChanged(Preference preference) {
+ for (AbstractPreferenceController controller : sControllers) {
+ controller.updateState(preference);
+ }
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+
+ for (AbstractPreferenceController controller :
+ buildPreferenceControllers(getPrefContext(), getSettingsLifecycle())) {
+ ((AccessibilityTimeoutController)controller).setOnChangeListener(this);
+ }
+ }
+
+ @Override
+ public void onPause() {
+ super.onPause();
+
+ for (AbstractPreferenceController controller :
+ buildPreferenceControllers(getPrefContext(), getSettingsLifecycle())) {
+ ((AccessibilityTimeoutController)controller).setOnChangeListener(null);
+ }
+ }
+
+ @Override
+ public int getMetricsCategory() {
+ return MetricsEvent.ACCESSIBILITY;
+ }
+
+ @Override
+ protected String getLogTag() {
+ return TAG;
+ }
+
+ @Override
+ protected int getPreferenceScreenResId() {
+ return R.xml.accessibility_content_timeout_settings;
+ }
+
+ @Override
+ protected List createPreferenceControllers(Context context) {
+ return buildPreferenceControllers(context, getSettingsLifecycle());
+ }
+
+ private static List buildPreferenceControllers(Context context,
+ Lifecycle lifecycle) {
+ if (sControllers.size() == 0) {
+ Resources resources = context.getResources();
+
+ String[] timeoutKeys = resources.getStringArray(
+ R.array.accessibility_timeout_content_selector_keys);
+
+ for (int i=0; i < timeoutKeys.length; i++) {
+ sControllers.add(new AccessibilityTimeoutController(
+ context, lifecycle, timeoutKeys[i], TAG));
+ }
+ }
+ return sControllers;
+ }
+
+ public static final SearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
+ new BaseSearchIndexProvider() {
+ @Override
+ public List getXmlResourcesToIndex(Context context,
+ boolean enabled) {
+ final SearchIndexableResource sir = new SearchIndexableResource(context);
+ sir.xmlResId = R.xml.accessibility_content_timeout_settings;
+ return Arrays.asList(sir);
+ }
+
+ @Override
+ public List getNonIndexableKeys(Context context) {
+ final List keys = super.getNonIndexableKeys(context);
+ return keys;
+ }
+
+ @Override
+ public List createPreferenceControllers(
+ Context context) {
+ return buildPreferenceControllers(context, null);
+ }
+ };
+}
\ No newline at end of file
diff --git a/src/com/android/settings/accessibility/AccessibilityControlTimeoutPreferenceFragment.java b/src/com/android/settings/accessibility/AccessibilityControlTimeoutPreferenceFragment.java
new file mode 100644
index 00000000000..56424af36c0
--- /dev/null
+++ b/src/com/android/settings/accessibility/AccessibilityControlTimeoutPreferenceFragment.java
@@ -0,0 +1,130 @@
+/*
+ * 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.accessibility;
+
+import android.provider.SearchIndexableResource;
+import android.content.Context;
+import android.content.res.Resources;
+
+import androidx.preference.Preference;
+
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+import com.android.settings.R;
+import com.android.settings.dashboard.DashboardFragment;
+import com.android.settings.search.BaseSearchIndexProvider;
+import com.android.settings.search.Indexable;
+import com.android.settingslib.core.AbstractPreferenceController;
+import com.android.settingslib.core.lifecycle.Lifecycle;
+import com.android.settingslib.search.SearchIndexable;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+@SearchIndexable
+public final class AccessibilityControlTimeoutPreferenceFragment extends DashboardFragment
+ implements AccessibilityTimeoutController.OnChangeListener {
+
+ static final String TAG = "AccessibilityControlTimeoutPreferenceFragment";
+ private static final List sControllers = new ArrayList<>();
+
+ @Override
+ public void onCheckedChanged(Preference preference) {
+ for (AbstractPreferenceController controller : sControllers) {
+ controller.updateState(preference);
+ }
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+
+ for (AbstractPreferenceController controller :
+ buildPreferenceControllers(getPrefContext(), getSettingsLifecycle())) {
+ ((AccessibilityTimeoutController)controller).setOnChangeListener(this);
+ }
+ }
+
+ @Override
+ public void onPause() {
+ super.onPause();
+
+ for (AbstractPreferenceController controller :
+ buildPreferenceControllers(getPrefContext(), getSettingsLifecycle())) {
+ ((AccessibilityTimeoutController)controller).setOnChangeListener(null);
+ }
+ }
+
+ @Override
+ public int getMetricsCategory() {
+ return MetricsEvent.ACCESSIBILITY;
+ }
+
+ @Override
+ protected String getLogTag() {
+ return TAG;
+ }
+
+ @Override
+ protected int getPreferenceScreenResId() {
+ return R.xml.accessibility_control_timeout_settings;
+ }
+
+ @Override
+ protected List createPreferenceControllers(Context context) {
+ return buildPreferenceControllers(context, getSettingsLifecycle());
+ }
+
+ private static List buildPreferenceControllers(Context context,
+ Lifecycle lifecycle) {
+ if (sControllers.size() == 0) {
+ Resources resources = context.getResources();
+
+ String[] timeoutKeys = resources.getStringArray(
+ R.array.accessibility_timeout_control_selector_keys);
+
+ for (int i=0; i < timeoutKeys.length; i++) {
+ sControllers.add(new AccessibilityTimeoutController(
+ context, lifecycle, timeoutKeys[i], TAG));
+ }
+ }
+ return sControllers;
+ }
+
+ public static final SearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
+ new BaseSearchIndexProvider() {
+ @Override
+ public List getXmlResourcesToIndex(Context context,
+ boolean enabled) {
+ final SearchIndexableResource sir = new SearchIndexableResource(context);
+ sir.xmlResId = R.xml.accessibility_control_timeout_settings;
+ return Arrays.asList(sir);
+ }
+
+ @Override
+ public List getNonIndexableKeys(Context context) {
+ final List keys = super.getNonIndexableKeys(context);
+ return keys;
+ }
+
+ @Override
+ public List createPreferenceControllers(
+ Context context) {
+ return buildPreferenceControllers(context, null);
+ }
+ };
+}
\ No newline at end of file
diff --git a/src/com/android/settings/accessibility/AccessibilityTimeoutController.java b/src/com/android/settings/accessibility/AccessibilityTimeoutController.java
new file mode 100644
index 00000000000..2995df542ee
--- /dev/null
+++ b/src/com/android/settings/accessibility/AccessibilityTimeoutController.java
@@ -0,0 +1,167 @@
+/*
+ * 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.accessibility;
+
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.res.Resources;
+import android.provider.Settings;
+
+import androidx.lifecycle.LifecycleObserver;
+import androidx.preference.Preference;
+import androidx.preference.PreferenceScreen;
+
+import com.android.settings.R;
+import com.android.settings.core.PreferenceControllerMixin;
+import com.android.settings.widget.RadioButtonPreference;
+import com.android.settingslib.core.AbstractPreferenceController;
+import com.android.settingslib.core.lifecycle.Lifecycle;
+
+import java.lang.Integer;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class AccessibilityTimeoutController extends AbstractPreferenceController implements
+ LifecycleObserver, RadioButtonPreference.OnClickListener, PreferenceControllerMixin {
+
+ // pair the preference key and timeout value
+ private final Map mAccessibilityTimeoutKeyToValueMap = new HashMap<>();
+
+ private final String mPreferenceKey;
+ private final String mfragmentTag;
+ private final ContentResolver mContentResolver;
+ private final Resources mResources;
+ private OnChangeListener mOnChangeListener;
+ private RadioButtonPreference mPreference;
+ private int mAccessibilityUiTimeoutValue;
+
+ public AccessibilityTimeoutController(Context context, Lifecycle lifecycle,
+ String preferenceKey, String fragmentTag) {
+ super(context);
+
+ mContentResolver = context.getContentResolver();
+ mResources = context.getResources();
+
+ if (lifecycle != null) {
+ lifecycle.addObserver(this);
+ }
+ mPreferenceKey = preferenceKey;
+ mfragmentTag = fragmentTag;
+ }
+
+ public void setOnChangeListener(OnChangeListener listener) {
+ mOnChangeListener = listener;
+ }
+
+ private Map getTimeoutValueToKeyMap() {
+ if (mAccessibilityTimeoutKeyToValueMap.size() == 0) {
+
+ String[] timeoutKeys = null;
+ if (mfragmentTag.equals(AccessibilityContentTimeoutPreferenceFragment.TAG)) {
+ timeoutKeys = mResources.getStringArray(
+ R.array.accessibility_timeout_content_selector_keys);
+ } else if (mfragmentTag.equals(AccessibilityControlTimeoutPreferenceFragment.TAG)) {
+ timeoutKeys = mResources.getStringArray(
+ R.array.accessibility_timeout_control_selector_keys);
+ }
+
+ int[] timeoutValues = mResources.getIntArray(
+ R.array.accessibility_timeout_selector_values);
+
+ final int timeoutValueCount = timeoutValues.length;
+ for (int i = 0; i < timeoutValueCount; i++) {
+ mAccessibilityTimeoutKeyToValueMap.put(timeoutKeys[i], timeoutValues[i]);
+ }
+ }
+ return mAccessibilityTimeoutKeyToValueMap;
+ }
+
+ private void putSecureString(String name, String value) {
+ Settings.Secure.putString(mContentResolver, name, value);
+ }
+
+ private void handlePreferenceChange(String value) {
+ if (mfragmentTag.equals(AccessibilityContentTimeoutPreferenceFragment.TAG)) {
+ putSecureString(Settings.Secure.ACCESSIBILITY_NON_INTERACTIVE_UI_TIMEOUT_MS, value);
+ } else if (mfragmentTag.equals(AccessibilityControlTimeoutPreferenceFragment.TAG)) {
+ putSecureString(Settings.Secure.ACCESSIBILITY_INTERACTIVE_UI_TIMEOUT_MS, value);
+ }
+ }
+
+ @Override
+ public boolean isAvailable() {
+ return true;
+ }
+
+ @Override
+ public String getPreferenceKey() {
+ return mPreferenceKey;
+ }
+
+ @Override
+ public void displayPreference(PreferenceScreen screen) {
+ super.displayPreference(screen);
+
+ mPreference = (RadioButtonPreference)
+ screen.findPreference(getPreferenceKey());
+ mPreference.setOnClickListener(this);
+ }
+
+ @Override
+ public void onRadioButtonClicked(RadioButtonPreference preference) {
+ int value = getTimeoutValueToKeyMap().get(mPreferenceKey);
+ handlePreferenceChange(String.valueOf(value));
+ if (mOnChangeListener != null) {
+ mOnChangeListener.onCheckedChanged(mPreference);
+ }
+ }
+
+ protected void getAccessibilityUiValue() {
+ String timeoutValue = null;
+ if (mfragmentTag.equals(AccessibilityContentTimeoutPreferenceFragment.TAG)) {
+ timeoutValue = Settings.Secure.getString(mContentResolver,
+ Settings.Secure.ACCESSIBILITY_NON_INTERACTIVE_UI_TIMEOUT_MS);
+ } else if (mfragmentTag.equals(AccessibilityControlTimeoutPreferenceFragment.TAG)) {
+ timeoutValue = Settings.Secure.getString(mContentResolver,
+ Settings.Secure.ACCESSIBILITY_INTERACTIVE_UI_TIMEOUT_MS);
+ }
+ mAccessibilityUiTimeoutValue = timeoutValue == null? 0: Integer.parseInt(timeoutValue);
+ }
+
+ protected void updatePreferenceCheckedState(int value) {
+ if (mAccessibilityUiTimeoutValue == value) {
+ mPreference.setChecked(true);
+ }
+ }
+
+ @Override
+ public void updateState(Preference preference) {
+ super.updateState(preference);
+
+ getAccessibilityUiValue();
+
+ // reset RadioButton
+ mPreference.setChecked(false);
+ int preferenceValue = getTimeoutValueToKeyMap().get(mPreference.getKey());
+ updatePreferenceCheckedState(preferenceValue);
+ }
+
+ public static interface OnChangeListener {
+ void onCheckedChanged(Preference preference);
+ }
+}
\ No newline at end of file
diff --git a/src/com/android/settings/applications/AppPermissionsPreferenceController.java b/src/com/android/settings/applications/AppPermissionsPreferenceController.java
index 38a56aff004..0137276c942 100644
--- a/src/com/android/settings/applications/AppPermissionsPreferenceController.java
+++ b/src/com/android/settings/applications/AppPermissionsPreferenceController.java
@@ -33,7 +33,6 @@ import java.util.Set;
public class AppPermissionsPreferenceController extends BasePreferenceController {
private static final String TAG = "AppPermissionPrefCtrl";
- private static final String KEY_APP_PERMISSION_GROUPS = "manage_perms";
private static final String[] PERMISSION_GROUPS = new String[]{
"android.permission-group.LOCATION",
"android.permission-group.MICROPHONE",
@@ -46,8 +45,8 @@ public class AppPermissionsPreferenceController extends BasePreferenceController
private final PackageManager mPackageManager;
- public AppPermissionsPreferenceController(Context context) {
- super(context, KEY_APP_PERMISSION_GROUPS);
+ public AppPermissionsPreferenceController(Context context, String preferenceKey) {
+ super(context, preferenceKey);
mPackageManager = context.getPackageManager();
}
diff --git a/src/com/android/settings/applications/AppStorageSettings.java b/src/com/android/settings/applications/AppStorageSettings.java
index c926da38a7b..841fb5150f8 100644
--- a/src/com/android/settings/applications/AppStorageSettings.java
+++ b/src/com/android/settings/applications/AppStorageSettings.java
@@ -167,10 +167,7 @@ public class AppStorageSettings extends AppInfoWithHeader
.setComputingString(R.string.computing_size)
.setErrorString(R.string.invalid_size_value)
.build();
- mButtonsPref = ((ActionButtonPreference) findPreference(KEY_HEADER_BUTTONS))
- .setButton1Positive(false)
- .setButton2Positive(false);
-
+ mButtonsPref = ((ActionButtonPreference) findPreference(KEY_HEADER_BUTTONS));
mStorageUsed = findPreference(KEY_STORAGE_USED);
mChangeStorageButton = (Button) ((LayoutPreference) findPreference(KEY_CHANGE_STORAGE))
.findViewById(R.id.button);
@@ -178,7 +175,9 @@ public class AppStorageSettings extends AppInfoWithHeader
mChangeStorageButton.setOnClickListener(this);
// Cache section
- mButtonsPref.setButton2Text(R.string.clear_cache_btn_text);
+ mButtonsPref
+ .setButton2Text(R.string.clear_cache_btn_text)
+ .setButton2Icon(R.drawable.ic_settings_delete);
// URI permissions section
mUri = (PreferenceCategory) findPreference(KEY_URI_CATEGORY);
@@ -304,16 +303,20 @@ public class AppStorageSettings extends AppInfoWithHeader
|| !isManageSpaceActivityAvailable) {
mButtonsPref
.setButton1Text(R.string.clear_user_data_text)
+ .setButton1Icon(R.drawable.ic_settings_delete)
.setButton1Enabled(false);
mCanClearData = false;
} else {
if (appHasSpaceManagementUI) {
mButtonsPref.setButton1Text(R.string.manage_space_text);
} else {
- mButtonsPref.setButton1Text(R.string.clear_user_data_text);
+ mButtonsPref
+ .setButton1Text(R.string.clear_user_data_text)
+ .setButton1Icon(R.drawable.ic_settings_delete);
}
mButtonsPref
.setButton1Text(R.string.clear_user_data_text)
+ .setButton1Icon(R.drawable.ic_settings_delete)
.setButton1OnClickListener(v -> handleClearDataClick());
}
@@ -384,7 +387,9 @@ public class AppStorageSettings extends AppInfoWithHeader
private void processClearMsg(Message msg) {
int result = msg.arg1;
String packageName = mAppEntry.info.packageName;
- mButtonsPref.setButton1Text(R.string.clear_user_data_text);
+ mButtonsPref
+ .setButton1Text(R.string.clear_user_data_text)
+ .setButton1Icon(R.drawable.ic_settings_delete);
if (result == OP_SUCCESSFUL) {
Log.i(TAG, "Cleared user data for package : " + packageName);
updateSize();
diff --git a/src/com/android/settings/applications/ApplicationFeatureProviderImpl.java b/src/com/android/settings/applications/ApplicationFeatureProviderImpl.java
index d29fc950b1d..c246c58eadc 100644
--- a/src/com/android/settings/applications/ApplicationFeatureProviderImpl.java
+++ b/src/com/android/settings/applications/ApplicationFeatureProviderImpl.java
@@ -32,6 +32,7 @@ import android.text.TextUtils;
import android.util.ArraySet;
import com.android.internal.telephony.SmsApplication;
+import com.android.settings.R;
import java.util.ArrayList;
import java.util.List;
@@ -138,6 +139,9 @@ public class ApplicationFeatureProviderImpl implements ApplicationFeatureProvide
if (defaultSms != null) {
keepEnabledPackages.add(defaultSms.getPackageName());
}
+ // Keep Settings intelligence enabled, otherwise search feature will be disabled.
+ keepEnabledPackages.add(
+ mContext.getString(R.string.config_settingsintelligence_package_name));
return keepEnabledPackages;
}
diff --git a/src/com/android/settings/applications/appinfo/AppButtonsPreferenceController.java b/src/com/android/settings/applications/appinfo/AppButtonsPreferenceController.java
index 6d726b9eed9..9740ecb5aa0 100644
--- a/src/com/android/settings/applications/appinfo/AppButtonsPreferenceController.java
+++ b/src/com/android/settings/applications/appinfo/AppButtonsPreferenceController.java
@@ -167,11 +167,11 @@ public class AppButtonsPreferenceController extends BasePreferenceController imp
if (isAvailable()) {
mButtonsPref = ((ActionButtonPreference) screen.findPreference(KEY_ACTION_BUTTONS))
.setButton1Text(R.string.uninstall_text)
+ .setButton1Icon(R.drawable.ic_settings_delete)
.setButton2Text(R.string.force_stop)
+ .setButton2Icon(R.drawable.ic_settings_force_stop)
.setButton1OnClickListener(new UninstallAndDisableButtonListener())
.setButton2OnClickListener(new ForceStopButtonListener())
- .setButton1Positive(false)
- .setButton2Positive(false)
.setButton2Enabled(false);
}
}
@@ -547,16 +547,16 @@ public class AppButtonsPreferenceController extends BasePreferenceController imp
if (mHomePackages.contains(mAppEntry.info.packageName)
|| isSystemPackage(mActivity.getResources(), mPm, mPackageInfo)) {
// Disable button for core system applications.
- mButtonsPref.setButton1Text(R.string.disable_text)
- .setButton1Positive(false);
+ mButtonsPref.setButton1Text(R.string.uninstall_text)
+ .setButton1Icon(R.drawable.ic_settings_delete);
} else if (mAppEntry.info.enabled && !isDisabledUntilUsed()) {
- mButtonsPref.setButton1Text(R.string.disable_text)
- .setButton1Positive(false);
+ mButtonsPref.setButton1Text(R.string.uninstall_text)
+ .setButton1Icon(R.drawable.ic_settings_delete);
disableable = !mApplicationFeatureProvider.getKeepEnabledPackages()
.contains(mAppEntry.info.packageName);
} else {
- mButtonsPref.setButton1Text(R.string.enable_text)
- .setButton1Positive(true);
+ mButtonsPref.setButton1Text(R.string.install_text)
+ .setButton1Icon(R.drawable.ic_settings_install);
disableable = true;
}
diff --git a/src/com/android/settings/applications/appinfo/AppInfoDashboardFragment.java b/src/com/android/settings/applications/appinfo/AppInfoDashboardFragment.java
index 64fd36d2450..32880d39441 100755
--- a/src/com/android/settings/applications/appinfo/AppInfoDashboardFragment.java
+++ b/src/com/android/settings/applications/appinfo/AppInfoDashboardFragment.java
@@ -88,7 +88,7 @@ public class AppInfoDashboardFragment extends DashboardFragment
// Result code identifiers
@VisibleForTesting
static final int REQUEST_UNINSTALL = 0;
- private static final int REQUEST_REMOVE_DEVICE_ADMIN = 1;
+ private static final int REQUEST_REMOVE_DEVICE_ADMIN = 5;
static final int SUB_INFO_FRAGMENT = 1;
diff --git a/src/com/android/settings/biometrics/face/FaceEnrollEnrolling.java b/src/com/android/settings/biometrics/face/FaceEnrollEnrolling.java
index b09d0aaa468..37b949c7709 100644
--- a/src/com/android/settings/biometrics/face/FaceEnrollEnrolling.java
+++ b/src/com/android/settings/biometrics/face/FaceEnrollEnrolling.java
@@ -94,7 +94,7 @@ public class FaceEnrollEnrolling extends BiometricsEnrollEnrolling {
if (shouldLaunchConfirmLock()) {
launchConfirmLock(R.string.security_settings_face_preference_title,
- Utils.getFingerprintManagerOrNull(this).preEnroll());
+ Utils.getFaceManagerOrNull(this).generateChallenge());
mShouldFinishOnStop = false;
} else {
startEnrollment();
diff --git a/src/com/android/settings/bluetooth/BluetoothDetailsButtonsController.java b/src/com/android/settings/bluetooth/BluetoothDetailsButtonsController.java
index 09632df1554..563a06a01f3 100644
--- a/src/com/android/settings/bluetooth/BluetoothDetailsButtonsController.java
+++ b/src/com/android/settings/bluetooth/BluetoothDetailsButtonsController.java
@@ -53,8 +53,8 @@ public class BluetoothDetailsButtonsController extends BluetoothDetailsControlle
protected void init(PreferenceScreen screen) {
mActionButtons = ((ActionButtonPreference) screen.findPreference(getPreferenceKey()))
.setButton1Text(R.string.forget)
+ .setButton1Icon(R.drawable.ic_settings_delete)
.setButton1OnClickListener((view) -> onForgetButtonPressed())
- .setButton1Positive(false)
.setButton1Enabled(true);
}
@@ -68,17 +68,17 @@ public class BluetoothDetailsButtonsController extends BluetoothDetailsControlle
if (!mConnectButtonInitialized || !previouslyConnected) {
mActionButtons
.setButton2Text(R.string.bluetooth_device_context_disconnect)
- .setButton2OnClickListener(view -> mCachedDevice.disconnect())
- .setButton2Positive(false);
+ .setButton2Icon(R.drawable.ic_settings_close)
+ .setButton2OnClickListener(view -> mCachedDevice.disconnect());
mConnectButtonInitialized = true;
}
} else {
if (!mConnectButtonInitialized || previouslyConnected) {
mActionButtons
.setButton2Text(R.string.bluetooth_device_context_connect)
+ // TODO (b/119646923) Icon is not ready.
.setButton2OnClickListener(
- view -> mCachedDevice.connect(true /* connectAllProfiles */))
- .setButton2Positive(true);
+ view -> mCachedDevice.connect(true /* connectAllProfiles */));
mConnectButtonInitialized = true;
}
}
diff --git a/src/com/android/settings/deviceinfo/aboutphone/TopLevelAboutDevicePreferenceController.java b/src/com/android/settings/deviceinfo/aboutphone/TopLevelAboutDevicePreferenceController.java
index ba28f3a1b48..d2ffd0dbae0 100644
--- a/src/com/android/settings/deviceinfo/aboutphone/TopLevelAboutDevicePreferenceController.java
+++ b/src/com/android/settings/deviceinfo/aboutphone/TopLevelAboutDevicePreferenceController.java
@@ -19,7 +19,7 @@ package com.android.settings.deviceinfo.aboutphone;
import android.content.Context;
import com.android.settings.core.BasePreferenceController;
-import com.android.settings.deviceinfo.DeviceModelPreferenceController;
+import com.android.settings.deviceinfo.DeviceNamePreferenceController;
public class TopLevelAboutDevicePreferenceController extends BasePreferenceController {
@@ -34,6 +34,8 @@ public class TopLevelAboutDevicePreferenceController extends BasePreferenceContr
@Override
public CharSequence getSummary() {
- return DeviceModelPreferenceController.getDeviceModel();
+ final DeviceNamePreferenceController deviceNamePreferenceController =
+ new DeviceNamePreferenceController(mContext);
+ return deviceNamePreferenceController.getSummary();
}
}
diff --git a/src/com/android/settings/homepage/contextualcards/ContextualCard.java b/src/com/android/settings/homepage/contextualcards/ContextualCard.java
index 8d439147af8..4e4e34f282f 100644
--- a/src/com/android/settings/homepage/contextualcards/ContextualCard.java
+++ b/src/com/android/settings/homepage/contextualcards/ContextualCard.java
@@ -63,7 +63,7 @@ public class ContextualCard {
private final boolean mIsHalfWidth;
private final Drawable mIconDrawable;
- String getName() {
+ public String getName() {
return mName;
}
diff --git a/src/com/android/settings/homepage/contextualcards/ContextualCardManager.java b/src/com/android/settings/homepage/contextualcards/ContextualCardManager.java
index 8bb8b4dd86a..30eae298752 100644
--- a/src/com/android/settings/homepage/contextualcards/ContextualCardManager.java
+++ b/src/com/android/settings/homepage/contextualcards/ContextualCardManager.java
@@ -62,10 +62,12 @@ public class ContextualCardManager implements ContextualCardLoader.CardContentLo
private static final int[] SETTINGS_CARDS =
{ContextualCard.CardType.CONDITIONAL, ContextualCard.CardType.LEGACY_SUGGESTION};
+ @VisibleForTesting
+ final List mContextualCards;
+
private final Context mContext;
private final ControllerRendererPool mControllerRendererPool;
private final Lifecycle mLifecycle;
- private final List mContextualCards;
private final List mLifecycleObservers;
private ContextualCardUpdateListener mListener;
@@ -122,10 +124,23 @@ public class ContextualCardManager implements ContextualCardLoader.CardContentLo
public void onContextualCardUpdated(Map> updateList) {
final Set cardTypes = updateList.keySet();
//Remove the existing data that matches the certain cardType before inserting new data.
- final List cardsToKeep = mContextualCards
- .stream()
- .filter(card -> !cardTypes.contains(card.getCardType()))
- .collect(Collectors.toList());
+ List cardsToKeep;
+
+ // We are not sure how many card types will be in the database, so when the list coming
+ // from the database is empty (e.g. no eligible cards/cards are dismissed), we cannot
+ // assign a specific card type for its map which is sending here. Thus, we assume that
+ // except Conditional cards, all other cards are from the database. So when the map sent
+ // here is empty, we only keep Conditional cards.
+ if (cardTypes.isEmpty()) {
+ cardsToKeep = mContextualCards.stream()
+ .filter(card -> card.getCardType() == ContextualCard.CardType.CONDITIONAL)
+ .collect(Collectors.toList());
+ } else {
+ cardsToKeep = mContextualCards.stream()
+ .filter(card -> !cardTypes.contains(card.getCardType()))
+ .collect(Collectors.toList());
+ }
+
final List allCards = new ArrayList<>();
allCards.addAll(cardsToKeep);
allCards.addAll(
diff --git a/src/com/android/settings/homepage/contextualcards/SettingsContextualCardProvider.java b/src/com/android/settings/homepage/contextualcards/SettingsContextualCardProvider.java
index c736c4d1487..f58ec7434b5 100644
--- a/src/com/android/settings/homepage/contextualcards/SettingsContextualCardProvider.java
+++ b/src/com/android/settings/homepage/contextualcards/SettingsContextualCardProvider.java
@@ -22,6 +22,7 @@ import android.annotation.Nullable;
import com.android.settings.homepage.contextualcards.deviceinfo.BatterySlice;
import com.android.settings.homepage.contextualcards.slices.ConnectedDeviceSlice;
+import com.android.settings.homepage.contextualcards.slices.LowStorageSlice;
import com.android.settings.intelligence.ContextualCardProto.ContextualCard;
import com.android.settings.intelligence.ContextualCardProto.ContextualCardList;
import com.android.settings.wifi.WifiSlice;
@@ -54,10 +55,17 @@ public class SettingsContextualCardProvider extends ContextualCardProvider {
.setCardName(ConnectedDeviceSlice.PATH_CONNECTED_DEVICE)
.setCardCategory(ContextualCard.Category.IMPORTANT)
.build();
+ final ContextualCard lowStorageCard =
+ ContextualCard.newBuilder()
+ .setSliceUri(LowStorageSlice.LOW_STORAGE_URI.toString())
+ .setCardName(LowStorageSlice.PATH_LOW_STORAGE)
+ .setCardCategory(ContextualCard.Category.IMPORTANT)
+ .build();
final ContextualCardList cards = ContextualCardList.newBuilder()
.addCard(wifiCard)
.addCard(batteryInfoCard)
.addCard(connectedDeviceCard)
+ .addCard(lowStorageCard)
.build();
return cards;
diff --git a/src/com/android/settings/homepage/contextualcards/slices/LowStorageSlice.java b/src/com/android/settings/homepage/contextualcards/slices/LowStorageSlice.java
new file mode 100644
index 00000000000..7f6efccd49e
--- /dev/null
+++ b/src/com/android/settings/homepage/contextualcards/slices/LowStorageSlice.java
@@ -0,0 +1,144 @@
+/*
+ * 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.homepage.contextualcards.slices;
+
+import android.app.PendingIntent;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.Intent;
+import android.net.Uri;
+import android.os.storage.StorageManager;
+import android.text.format.Formatter;
+import android.util.Log;
+
+import androidx.core.graphics.drawable.IconCompat;
+import androidx.slice.Slice;
+import androidx.slice.builders.ListBuilder;
+import androidx.slice.builders.ListBuilder.RowBuilder;
+import androidx.slice.builders.SliceAction;
+
+import com.android.internal.logging.nano.MetricsProto;
+import com.android.settings.R;
+import com.android.settings.SubSettings;
+import com.android.settings.Utils;
+import com.android.settings.deviceinfo.StorageSettings;
+import com.android.settings.slices.CustomSliceable;
+import com.android.settings.slices.SettingsSliceProvider;
+import com.android.settings.slices.SliceBuilderUtils;
+import com.android.settingslib.deviceinfo.PrivateStorageInfo;
+import com.android.settingslib.deviceinfo.StorageManagerVolumeProvider;
+
+import java.text.NumberFormat;
+
+public class LowStorageSlice implements CustomSliceable {
+
+ /**
+ * The path denotes the unique name of Low storage Slice.
+ */
+ public static final String PATH_LOW_STORAGE = "low_storage";
+
+ /**
+ * Backing Uri for Low storage Slice.
+ */
+ public static final Uri LOW_STORAGE_URI = new Uri.Builder()
+ .scheme(ContentResolver.SCHEME_CONTENT)
+ .authority(SettingsSliceProvider.SLICE_AUTHORITY)
+ .appendPath(PATH_LOW_STORAGE)
+ .build();
+
+ private static final String TAG = "LowStorageSlice";
+
+ /**
+ * If user used >= 85% storage.
+ */
+ private static final double LOW_STORAGE_THRESHOLD = 0.85;
+
+ private final Context mContext;
+
+ public LowStorageSlice(Context context) {
+ mContext = context;
+ }
+
+ /**
+ * Return a Low storage Slice bound to {@link #LOW_STORAGE_URI}
+ */
+ @Override
+ public Slice getSlice() {
+ // Get current storage percentage from StorageManager.
+ final PrivateStorageInfo info = PrivateStorageInfo.getPrivateStorageInfo(
+ new StorageManagerVolumeProvider(mContext.getSystemService(StorageManager.class)));
+ final double currentStoragePercentage =
+ (double) (info.totalBytes - info.freeBytes) / info.totalBytes;
+
+ // Used storage < 85%. NOT show Low storage Slice.
+ if (currentStoragePercentage < LOW_STORAGE_THRESHOLD) {
+ /**
+ * TODO(b/114808204): Contextual Home Page - "Low Storage"
+ * The behavior is under decision making, will update new behavior or remove TODO later.
+ */
+ Log.i(TAG, "Not show low storage slice, not match condition.");
+ return null;
+ }
+
+ // Show Low storage Slice.
+ final IconCompat icon = IconCompat.createWithResource(mContext, R.drawable.ic_storage);
+ final CharSequence title = mContext.getText(R.string.storage_menu_free);
+ final SliceAction primarySliceAction = new SliceAction(
+ PendingIntent.getActivity(mContext, 0, getIntent(), 0), icon, title);
+ final String lowStorageSummary = mContext.getString(R.string.low_storage_summary,
+ NumberFormat.getPercentInstance().format(currentStoragePercentage),
+ Formatter.formatFileSize(mContext, info.freeBytes));
+
+ /**
+ * TODO(b/114808204): Contextual Home Page - "Low Storage"
+ * Slices doesn't support "Icon on the left" in header. Now we intend to start with Icon
+ * right aligned. Will update the icon to left until Slices support it.
+ */
+ return new ListBuilder(mContext, LOW_STORAGE_URI, ListBuilder.INFINITY)
+ .setAccentColor(Utils.getColorAccentDefaultColor(mContext))
+ .addRow(new RowBuilder()
+ .setTitle(title)
+ .setSubtitle(lowStorageSummary)
+ .addEndItem(icon, ListBuilder.ICON_IMAGE)
+ .setPrimaryAction(primarySliceAction))
+ .build();
+ }
+
+ @Override
+ public Uri getUri() {
+ return LOW_STORAGE_URI;
+ }
+
+ @Override
+ public void onNotifyChange(Intent intent) {
+
+ }
+
+ @Override
+ public Intent getIntent() {
+ final String screenTitle = mContext.getText(R.string.storage_label)
+ .toString();
+ final Uri contentUri = new Uri.Builder().appendPath(PATH_LOW_STORAGE).build();
+
+ return SliceBuilderUtils.buildSearchResultPageIntent(mContext,
+ StorageSettings.class.getName(), PATH_LOW_STORAGE,
+ screenTitle,
+ MetricsProto.MetricsEvent.SLICE)
+ .setClassName(mContext.getPackageName(), SubSettings.class.getName())
+ .setData(contentUri);
+ }
+}
\ No newline at end of file
diff --git a/src/com/android/settings/notification/NotificationBackend.java b/src/com/android/settings/notification/NotificationBackend.java
index 03b4ec30264..d5fea09598b 100644
--- a/src/com/android/settings/notification/NotificationBackend.java
+++ b/src/com/android/settings/notification/NotificationBackend.java
@@ -21,6 +21,7 @@ import static android.app.NotificationManager.IMPORTANCE_UNSPECIFIED;
import android.app.INotificationManager;
import android.app.NotificationChannel;
import android.app.NotificationChannelGroup;
+import android.app.NotificationManager;
import android.app.usage.IUsageStatsManager;
import android.app.usage.UsageEvents;
import android.content.Context;
@@ -38,8 +39,6 @@ import android.text.format.DateUtils;
import android.util.IconDrawableFactory;
import android.util.Log;
-import androidx.annotation.VisibleForTesting;
-
import com.android.settingslib.R;
import com.android.settingslib.Utils;
import com.android.settingslib.utils.StringUtil;
@@ -49,6 +48,8 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import androidx.annotation.VisibleForTesting;
+
public class NotificationBackend {
private static final String TAG = "NotificationBackend";
@@ -208,6 +209,19 @@ public class NotificationBackend {
}
}
+ /**
+ * Returns all notification channels associated with the package and uid that will bypass DND
+ */
+ public ParceledListSlice getNotificationChannelsBypassingDnd(String pkg,
+ int uid) {
+ try {
+ return sINM.getNotificationChannelsBypassingDnd(pkg, uid);
+ } catch (Exception e) {
+ Log.w(TAG, "Error calling NoMan", e);
+ return ParceledListSlice.emptyList();
+ }
+ }
+
public void updateChannel(String pkg, int uid, NotificationChannel channel) {
try {
sINM.updateNotificationChannelForPackage(pkg, uid, channel);
@@ -260,6 +274,15 @@ public class NotificationBackend {
}
}
+ public int getNumAppsBypassingDnd(int uid) {
+ try {
+ return sINM.getAppsBypassingDndCount(uid);
+ } catch (Exception e) {
+ Log.w(TAG, "Error calling NoMan", e);
+ return 0;
+ }
+ }
+
public List getRecentApps() {
try {
return sINM.getRecentNotifyingAppsForUser(UserHandle.myUserId()).getList();
diff --git a/src/com/android/settings/notification/ZenModeAllBypassingAppsPreferenceController.java b/src/com/android/settings/notification/ZenModeAllBypassingAppsPreferenceController.java
new file mode 100644
index 00000000000..5539ba4e6a2
--- /dev/null
+++ b/src/com/android/settings/notification/ZenModeAllBypassingAppsPreferenceController.java
@@ -0,0 +1,200 @@
+/*
+ * 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.NotificationChannel;
+import android.content.Context;
+import android.os.Bundle;
+import android.provider.Settings;
+
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+import com.android.settings.R;
+import com.android.settings.applications.AppInfoBase;
+import com.android.settings.core.PreferenceControllerMixin;
+import com.android.settings.core.SubSettingLauncher;
+import com.android.settingslib.applications.ApplicationsState;
+import com.android.settingslib.core.AbstractPreferenceController;
+import com.android.settingslib.widget.apppreference.AppPreference;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import androidx.annotation.VisibleForTesting;
+import androidx.core.text.BidiFormatter;
+import androidx.fragment.app.Fragment;
+import androidx.lifecycle.Lifecycle;
+import androidx.preference.Preference;
+import androidx.preference.PreferenceScreen;
+
+/**
+ * Adds a preference to the PreferenceScreen for each notification channel that can bypass DND.
+ */
+public class ZenModeAllBypassingAppsPreferenceController extends AbstractPreferenceController
+ implements PreferenceControllerMixin {
+
+ private final String KEY = "zen_mode_bypassing_apps_category";
+
+ @VisibleForTesting ApplicationsState mApplicationsState;
+ @VisibleForTesting PreferenceScreen mPreferenceScreen;
+ @VisibleForTesting Context mPrefContext;
+
+ private ApplicationsState.Session mAppSession;
+ private NotificationBackend mNotificationBackend = new NotificationBackend();
+ private Fragment mHostFragment;
+
+ public ZenModeAllBypassingAppsPreferenceController(Context context, Application app,
+ Fragment host) {
+
+ this(context, app == null ? null : ApplicationsState.getInstance(app), host);
+ }
+
+ private ZenModeAllBypassingAppsPreferenceController(Context context, ApplicationsState appState,
+ Fragment host) {
+ super(context);
+ mApplicationsState = appState;
+ mHostFragment = host;
+
+ if (mApplicationsState != null && host != null) {
+ mAppSession = mApplicationsState.newSession(mAppSessionCallbacks, host.getLifecycle());
+ }
+ }
+
+ @Override
+ public void displayPreference(PreferenceScreen screen) {
+ mPreferenceScreen = screen;
+ mPrefContext = mPreferenceScreen.getContext();
+ updateNotificationChannelList();
+ super.displayPreference(screen);
+ }
+
+ @Override
+ public boolean isAvailable() {
+ return true;
+ }
+
+ @Override
+ public String getPreferenceKey() {
+ return KEY;
+ }
+
+ /**
+ * Call this method to trigger the notification channels list to refresh.
+ */
+ public void updateNotificationChannelList() {
+ if (mAppSession == null) {
+ return;
+ }
+
+ ApplicationsState.AppFilter filter = ApplicationsState.FILTER_ALL_ENABLED;
+ List apps = mAppSession.rebuild(filter,
+ ApplicationsState.ALPHA_COMPARATOR);
+ if (apps != null) {
+ updateNotificationChannelList(apps);
+ }
+ }
+
+ @VisibleForTesting
+ void updateNotificationChannelList(List apps) {
+ if (mPreferenceScreen == null || apps == null) {
+ return;
+ }
+
+ List channelsBypassingDnd = new ArrayList<>();
+ for (ApplicationsState.AppEntry entry : apps) {
+ String pkg = entry.info.packageName;
+ mApplicationsState.ensureIcon(entry);
+ for (NotificationChannel channel : mNotificationBackend
+ .getNotificationChannelsBypassingDnd(pkg, entry.info.uid).getList()) {
+ Preference pref = new AppPreference(mPrefContext);
+ pref.setKey(pkg + "|" + channel.getId());
+ pref.setTitle(BidiFormatter.getInstance().unicodeWrap(entry.label));
+ pref.setIcon(entry.icon);
+ pref.setSummary(BidiFormatter.getInstance().unicodeWrap(channel.getName()));
+
+ pref.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
+ @Override
+ public boolean onPreferenceClick(Preference preference) {
+ Bundle args = new Bundle();
+ args.putString(AppInfoBase.ARG_PACKAGE_NAME, entry.info.packageName);
+ args.putInt(AppInfoBase.ARG_PACKAGE_UID, entry.info.uid);
+ args.putString(Settings.EXTRA_CHANNEL_ID, channel.getId());
+ new SubSettingLauncher(mContext)
+ .setDestination(ChannelNotificationSettings.class.getName())
+ .setArguments(args)
+ .setTitleRes(R.string.notification_channel_title)
+ .setResultListener(mHostFragment, 0)
+ .setSourceMetricsCategory(
+ MetricsEvent.NOTIFICATION_ZEN_MODE_OVERRIDING_APP)
+ .launch();
+ return true;
+ }
+ });
+ channelsBypassingDnd.add(pref);
+ }
+
+ mPreferenceScreen.removeAll();
+ if (channelsBypassingDnd.size() > 0) {
+ for (Preference prefToAdd : channelsBypassingDnd) {
+ mPreferenceScreen.addPreference(prefToAdd);
+ }
+ }
+ }
+ }
+
+ private final ApplicationsState.Callbacks mAppSessionCallbacks =
+ new ApplicationsState.Callbacks() {
+
+ @Override
+ public void onRunningStateChanged(boolean running) {
+ updateNotificationChannelList();
+ }
+
+ @Override
+ public void onPackageListChanged() {
+ updateNotificationChannelList();
+ }
+
+ @Override
+ public void onRebuildComplete(ArrayList apps) {
+ updateNotificationChannelList(apps);
+ }
+
+ @Override
+ public void onPackageIconChanged() {
+ updateNotificationChannelList();
+ }
+
+ @Override
+ public void onPackageSizeChanged(String packageName) {
+ updateNotificationChannelList();
+ }
+
+ @Override
+ public void onAllSizesComputed() { }
+
+ @Override
+ public void onLauncherInfoChanged() {
+ updateNotificationChannelList();
+ }
+
+ @Override
+ public void onLoadEntriesCompleted() {
+ updateNotificationChannelList();
+ }
+ };
+}
diff --git a/src/com/android/settings/notification/ZenModeBypassingAppsPreferenceController.java b/src/com/android/settings/notification/ZenModeBypassingAppsPreferenceController.java
new file mode 100644
index 00000000000..33e03d954d0
--- /dev/null
+++ b/src/com/android/settings/notification/ZenModeBypassingAppsPreferenceController.java
@@ -0,0 +1,30 @@
+package com.android.settings.notification;
+
+import android.content.Context;
+import android.os.UserHandle;
+
+import com.android.settings.R;
+import com.android.settingslib.core.lifecycle.Lifecycle;
+
+public class ZenModeBypassingAppsPreferenceController extends AbstractZenModePreferenceController {
+
+ protected static final String KEY = "zen_mode_bypassing_apps";
+ private NotificationBackend mNotificationBackend = new NotificationBackend();
+
+ public ZenModeBypassingAppsPreferenceController(Context context, Lifecycle lifecycle) {
+ super(context, KEY, lifecycle);
+ }
+
+ @Override
+ public boolean isAvailable() {
+ return mNotificationBackend.getNumAppsBypassingDnd(UserHandle.getCallingUserId()) != 0;
+ }
+
+ @Override
+ public String getSummary() {
+ final int channelsBypassing =
+ mNotificationBackend.getNumAppsBypassingDnd(UserHandle.getCallingUserId());
+ return mContext.getResources().getQuantityString(R.plurals.zen_mode_bypassing_apps_subtext,
+ channelsBypassing, channelsBypassing);
+ }
+}
diff --git a/src/com/android/settings/notification/ZenModeBypassingAppsSettings.java b/src/com/android/settings/notification/ZenModeBypassingAppsSettings.java
new file mode 100644
index 00000000000..53dc8d1bb6f
--- /dev/null
+++ b/src/com/android/settings/notification/ZenModeBypassingAppsSettings.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.notification;
+
+import android.app.Activity;
+import android.app.Application;
+import android.content.Context;
+import android.provider.SearchIndexableResource;
+
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+import com.android.settings.R;
+import com.android.settings.search.BaseSearchIndexProvider;
+import com.android.settings.search.Indexable;
+import com.android.settingslib.core.AbstractPreferenceController;
+import com.android.settingslib.search.SearchIndexable;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import androidx.fragment.app.Fragment;
+
+@SearchIndexable
+public class ZenModeBypassingAppsSettings extends ZenModeSettingsBase implements
+ Indexable {
+ private final String TAG = "ZenBypassingApps";
+
+ @Override
+ protected List createPreferenceControllers(Context context) {
+ final Activity activity = getActivity();
+ final Application app;
+ if (activity != null) {
+ app = activity.getApplication();
+ } else {
+ app = null;
+ }
+ return buildPreferenceControllers(context, app, this);
+ }
+
+ private static List buildPreferenceControllers(Context context,
+ Application app, Fragment host) {
+ final List controllers = new ArrayList<>();
+ controllers.add(new ZenModeAllBypassingAppsPreferenceController(context, app, host));
+ return controllers;
+ }
+
+ @Override
+ protected int getPreferenceScreenResId() {
+ return R.xml.zen_mode_bypassing_apps;
+ }
+
+ @Override
+ protected String getLogTag() {
+ return TAG;
+ }
+
+ @Override
+ public int getMetricsCategory() {
+ return MetricsEvent.NOTIFICATION_ZEN_MODE_OVERRIDING_APPS;
+ }
+
+ /**
+ * For Search.
+ */
+ public static final SearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
+ new BaseSearchIndexProvider() {
+
+ @Override
+ public List getXmlResourcesToIndex(Context context,
+ boolean enabled) {
+ final ArrayList result = new ArrayList<>();
+
+ final SearchIndexableResource sir = new SearchIndexableResource(context);
+ sir.xmlResId = R.xml.zen_mode_bypassing_apps;
+ result.add(sir);
+ return result;
+ }
+
+ @Override
+ public List createPreferenceControllers(
+ Context context) {
+ return buildPreferenceControllers(context, null, null);
+ }
+ };
+}
diff --git a/src/com/android/settings/notification/ZenModeSoundVibrationSettings.java b/src/com/android/settings/notification/ZenModeSoundVibrationSettings.java
index df924468924..5bc58485102 100644
--- a/src/com/android/settings/notification/ZenModeSoundVibrationSettings.java
+++ b/src/com/android/settings/notification/ZenModeSoundVibrationSettings.java
@@ -16,8 +16,6 @@
package com.android.settings.notification;
-import static android.app.NotificationManager.Policy.PRIORITY_CATEGORY_MESSAGES;
-
import android.content.Context;
import android.provider.SearchIndexableResource;
@@ -55,6 +53,7 @@ public class ZenModeSoundVibrationSettings extends ZenModeSettingsBase implement
controllers.add(new ZenModeEventsPreferenceController(context, lifecycle));
controllers.add(new ZenModeBehaviorFooterPreferenceController(context, lifecycle,
R.string.zen_sound_footer));
+ controllers.add(new ZenModeBypassingAppsPreferenceController(context, lifecycle));
return controllers;
}
diff --git a/src/com/android/settings/notification/ZenModeStarredContactsPreferenceController.java b/src/com/android/settings/notification/ZenModeStarredContactsPreferenceController.java
index adb65b6093d..66c2ddd2db4 100644
--- a/src/com/android/settings/notification/ZenModeStarredContactsPreferenceController.java
+++ b/src/com/android/settings/notification/ZenModeStarredContactsPreferenceController.java
@@ -28,16 +28,16 @@ import android.icu.text.ListFormatter;
import android.provider.Contacts;
import android.provider.ContactsContract;
-import androidx.annotation.VisibleForTesting;
-import androidx.preference.Preference;
-import androidx.preference.PreferenceScreen;
-
import com.android.settings.R;
import com.android.settingslib.core.lifecycle.Lifecycle;
import java.util.ArrayList;
import java.util.List;
+import androidx.annotation.VisibleForTesting;
+import androidx.preference.Preference;
+import androidx.preference.PreferenceScreen;
+
public class ZenModeStarredContactsPreferenceController extends
AbstractZenModePreferenceController implements Preference.OnPreferenceClickListener {
@@ -134,7 +134,6 @@ public class ZenModeStarredContactsPreferenceController extends
@VisibleForTesting
List getStarredContacts(Cursor cursor) {
List starredContacts = new ArrayList<>();
-
if (cursor.moveToFirst()) {
do {
String contact = cursor.getString(0);
@@ -147,7 +146,15 @@ public class ZenModeStarredContactsPreferenceController extends
}
private List getStarredContacts() {
- return getStarredContacts(queryData());
+ Cursor cursor = null;
+ try {
+ cursor = queryData();
+ return getStarredContacts(cursor);
+ } finally {
+ if (cursor != null) {
+ cursor.close();
+ }
+ }
}
private Cursor queryData() {
diff --git a/src/com/android/settings/privacy/PrivacyDashboardFragment.java b/src/com/android/settings/privacy/PrivacyDashboardFragment.java
index e3cd45768f6..dd4c8fa03f5 100644
--- a/src/com/android/settings/privacy/PrivacyDashboardFragment.java
+++ b/src/com/android/settings/privacy/PrivacyDashboardFragment.java
@@ -23,8 +23,6 @@ import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.settings.R;
import com.android.settings.dashboard.DashboardFragment;
import com.android.settings.search.BaseSearchIndexProvider;
-import com.android.settings.security.ShowPasswordPreferenceController;
-import com.android.settingslib.core.AbstractPreferenceController;
import com.android.settingslib.search.SearchIndexable;
import java.util.ArrayList;
diff --git a/src/com/android/settings/search/SearchFeatureProvider.java b/src/com/android/settings/search/SearchFeatureProvider.java
index 464b8f5ef2f..3c1c62b43c7 100644
--- a/src/com/android/settings/search/SearchFeatureProvider.java
+++ b/src/com/android/settings/search/SearchFeatureProvider.java
@@ -23,6 +23,7 @@ import android.app.Activity;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
+import android.content.pm.PackageManager;
import android.provider.Settings;
import android.view.View;
import android.view.ViewGroup;
@@ -88,6 +89,11 @@ public interface SearchFeatureProvider {
intent.setPackage(getSettingsIntelligencePkgName(activity));
final Context context = activity.getApplicationContext();
+ if (activity.getPackageManager().queryIntentActivities(intent,
+ PackageManager.MATCH_DEFAULT_ONLY).isEmpty()) {
+ return;
+ }
+
FeatureFactory.getFactory(context).getSlicesFeatureProvider()
.indexSliceDataAsync(activity.getApplicationContext());
FeatureFactory.getFactory(context).getMetricsFeatureProvider()
diff --git a/src/com/android/settings/search/actionbar/SearchMenuController.java b/src/com/android/settings/search/actionbar/SearchMenuController.java
index 22adbeba775..643f0c3493a 100644
--- a/src/com/android/settings/search/actionbar/SearchMenuController.java
+++ b/src/com/android/settings/search/actionbar/SearchMenuController.java
@@ -19,6 +19,7 @@ package com.android.settings.search.actionbar;
import android.annotation.NonNull;
import android.content.Context;
import android.content.Intent;
+import android.content.pm.PackageManager;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuInflater;
@@ -80,6 +81,12 @@ public class SearchMenuController implements LifecycleObserver, OnCreateOptionsM
searchItem.setOnMenuItemClickListener(target -> {
final Intent intent = SearchFeatureProvider.SEARCH_UI_INTENT;
intent.setPackage(SettingsIntelligencePkgName);
+
+ if (context.getPackageManager().queryIntentActivities(intent,
+ PackageManager.MATCH_DEFAULT_ONLY).isEmpty()) {
+ return true;
+ }
+
FeatureFactory.getFactory(context).getMetricsFeatureProvider()
.action(context, MetricsProto.MetricsEvent.ACTION_SEARCH_RESULTS);
mHost.startActivityForResult(intent, 0 /* requestCode */);
diff --git a/src/com/android/settings/slices/CustomSliceManager.java b/src/com/android/settings/slices/CustomSliceManager.java
index 556c69817b3..5b2549800c8 100644
--- a/src/com/android/settings/slices/CustomSliceManager.java
+++ b/src/com/android/settings/slices/CustomSliceManager.java
@@ -25,6 +25,7 @@ import com.android.settings.homepage.contextualcards.deviceinfo.DataUsageSlice;
import com.android.settings.homepage.contextualcards.deviceinfo.DeviceInfoSlice;
import com.android.settings.homepage.contextualcards.deviceinfo.StorageSlice;
import com.android.settings.homepage.contextualcards.slices.ConnectedDeviceSlice;
+import com.android.settings.homepage.contextualcards.slices.LowStorageSlice;
import com.android.settings.wifi.WifiSlice;
import java.util.Map;
@@ -105,5 +106,6 @@ public class CustomSliceManager {
mUriMap.put(StorageSlice.STORAGE_CARD_URI, StorageSlice.class);
mUriMap.put(BatterySlice.BATTERY_CARD_URI, BatterySlice.class);
mUriMap.put(ConnectedDeviceSlice.CONNECTED_DEVICE_URI, ConnectedDeviceSlice.class);
+ mUriMap.put(LowStorageSlice.LOW_STORAGE_URI, LowStorageSlice.class);
}
}
diff --git a/src/com/android/settings/tts/TextToSpeechSettings.java b/src/com/android/settings/tts/TextToSpeechSettings.java
index cce871b4f33..b1a1f8fcf6a 100644
--- a/src/com/android/settings/tts/TextToSpeechSettings.java
+++ b/src/com/android/settings/tts/TextToSpeechSettings.java
@@ -171,11 +171,9 @@ public class TextToSpeechSettings extends SettingsPreferenceFragment
mActionButtons = ((ActionButtonPreference) findPreference(KEY_ACTION_BUTTONS))
.setButton1Text(R.string.tts_play)
- .setButton1Positive(true)
.setButton1OnClickListener(v -> speakSampleText())
.setButton1Enabled(false)
.setButton2Text(R.string.tts_reset)
- .setButton2Positive(false)
.setButton2OnClickListener(v -> resetTts())
.setButton1Enabled(true);
diff --git a/src/com/android/settings/widget/ActionButtonPreference.java b/src/com/android/settings/widget/ActionButtonPreference.java
index 347a784b2ba..7ce84bd0529 100644
--- a/src/com/android/settings/widget/ActionButtonPreference.java
+++ b/src/com/android/settings/widget/ActionButtonPreference.java
@@ -17,11 +17,15 @@
package com.android.settings.widget;
import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.drawable.Drawable;
import android.text.TextUtils;
import android.util.AttributeSet;
+import android.util.Log;
import android.view.View;
import android.widget.Button;
+import androidx.annotation.DrawableRes;
import androidx.annotation.StringRes;
import androidx.preference.Preference;
import androidx.preference.PreferenceViewHolder;
@@ -30,6 +34,7 @@ import com.android.settings.R;
public class ActionButtonPreference extends Preference {
+ private final String TAG = "ActionButtonPreference";
private final ButtonInfo mButton1Info = new ButtonInfo();
private final ButtonInfo mButton2Info = new ButtonInfo();
@@ -62,12 +67,11 @@ public class ActionButtonPreference extends Preference {
@Override
public void onBindViewHolder(PreferenceViewHolder holder) {
super.onBindViewHolder(holder);
- holder.setDividerAllowedAbove(false);
- holder.setDividerAllowedBelow(false);
- mButton1Info.mPositiveButton = (Button) holder.findViewById(R.id.button1_positive);
- mButton1Info.mNegativeButton = (Button) holder.findViewById(R.id.button1_negative);
- mButton2Info.mPositiveButton = (Button) holder.findViewById(R.id.button2_positive);
- mButton2Info.mNegativeButton = (Button) holder.findViewById(R.id.button2_negative);
+ holder.setDividerAllowedAbove(true);
+ holder.setDividerAllowedBelow(true);
+
+ mButton1Info.mButton = (Button) holder.findViewById(R.id.button1);
+ mButton2Info.mButton = (Button) holder.findViewById(R.id.button2);
mButton1Info.setUpButton();
mButton2Info.setUpButton();
@@ -82,6 +86,22 @@ public class ActionButtonPreference extends Preference {
return this;
}
+ public ActionButtonPreference setButton1Icon(@DrawableRes int iconResId) {
+ if (iconResId == 0) {
+ return this;
+ }
+
+ final Drawable icon;
+ try {
+ icon = getContext().getDrawable(iconResId);
+ mButton1Info.mIcon = icon;
+ notifyChanged();
+ } catch (Resources.NotFoundException exception) {
+ Log.e(TAG, "Resource does not exist: " + iconResId);
+ }
+ return this;
+ }
+
public ActionButtonPreference setButton1Enabled(boolean isEnabled) {
if (isEnabled != mButton1Info.mIsEnabled) {
mButton1Info.mIsEnabled = isEnabled;
@@ -99,6 +119,22 @@ public class ActionButtonPreference extends Preference {
return this;
}
+ public ActionButtonPreference setButton2Icon(@DrawableRes int iconResId) {
+ if (iconResId == 0) {
+ return this;
+ }
+
+ final Drawable icon;
+ try {
+ icon = getContext().getDrawable(iconResId);
+ mButton2Info.mIcon = icon;
+ notifyChanged();
+ } catch (Resources.NotFoundException exception) {
+ Log.e(TAG, "Resource does not exist: " + iconResId);
+ }
+ return this;
+ }
+
public ActionButtonPreference setButton2Enabled(boolean isEnabled) {
if (isEnabled != mButton2Info.mIsEnabled) {
mButton2Info.mIsEnabled = isEnabled;
@@ -123,65 +159,41 @@ public class ActionButtonPreference extends Preference {
return this;
}
- public ActionButtonPreference setButton1Positive(boolean isPositive) {
- if (isPositive != mButton1Info.mIsPositive) {
- mButton1Info.mIsPositive = isPositive;
+ public ActionButtonPreference setButton1Visible(boolean isVisible) {
+ if (isVisible != mButton1Info.mIsVisible) {
+ mButton1Info.mIsVisible = isVisible;
notifyChanged();
}
return this;
}
- public ActionButtonPreference setButton2Positive(boolean isPositive) {
- if (isPositive != mButton2Info.mIsPositive) {
- mButton2Info.mIsPositive = isPositive;
- notifyChanged();
- }
- return this;
- }
- public ActionButtonPreference setButton1Visible(boolean isPositive) {
- if (isPositive != mButton1Info.mIsVisible) {
- mButton1Info.mIsVisible = isPositive;
- notifyChanged();
- }
- return this;
- }
-
- public ActionButtonPreference setButton2Visible(boolean isPositive) {
- if (isPositive != mButton2Info.mIsVisible) {
- mButton2Info.mIsVisible = isPositive;
+ public ActionButtonPreference setButton2Visible(boolean isVisible) {
+ if (isVisible != mButton2Info.mIsVisible) {
+ mButton2Info.mIsVisible = isVisible;
notifyChanged();
}
return this;
}
static class ButtonInfo {
- private Button mPositiveButton;
- private Button mNegativeButton;
+ private Button mButton;
private CharSequence mText;
+ private Drawable mIcon;
private View.OnClickListener mListener;
- private boolean mIsPositive = true;
private boolean mIsEnabled = true;
private boolean mIsVisible = true;
void setUpButton() {
- setUpButton(mPositiveButton);
- setUpButton(mNegativeButton);
- if (!mIsVisible) {
- mPositiveButton.setVisibility(View.INVISIBLE);
- mNegativeButton.setVisibility(View.INVISIBLE);
- } else if (mIsPositive) {
- mPositiveButton.setVisibility(View.VISIBLE);
- mNegativeButton.setVisibility(View.INVISIBLE);
+ mButton.setText(mText);
+ mButton.setOnClickListener(mListener);
+ mButton.setEnabled(mIsEnabled);
+ mButton.setCompoundDrawablesWithIntrinsicBounds(
+ null /* left */, mIcon /* top */, null /* right */, null /* bottom */);
+ if (mIsVisible) {
+ mButton.setVisibility(View.VISIBLE);
} else {
- mPositiveButton.setVisibility(View.INVISIBLE);
- mNegativeButton.setVisibility(View.VISIBLE);
+ mButton.setVisibility(View.GONE);
}
}
-
- private void setUpButton(Button button) {
- button.setText(mText);
- button.setOnClickListener(mListener);
- button.setEnabled(mIsEnabled);
- }
}
}
\ No newline at end of file
diff --git a/src/com/android/settings/wifi/details/WifiDetailPreferenceController.java b/src/com/android/settings/wifi/details/WifiDetailPreferenceController.java
index 46f485c9ba5..3bf38a773ae 100644
--- a/src/com/android/settings/wifi/details/WifiDetailPreferenceController.java
+++ b/src/com/android/settings/wifi/details/WifiDetailPreferenceController.java
@@ -278,10 +278,9 @@ public class WifiDetailPreferenceController extends AbstractPreferenceController
mButtonsPref = ((ActionButtonPreference) screen.findPreference(KEY_BUTTONS_PREF))
.setButton1Text(R.string.forget)
- .setButton1Positive(false)
+ .setButton1Icon(R.drawable.ic_settings_delete)
.setButton1OnClickListener(view -> forgetNetwork())
.setButton2Text(R.string.wifi_sign_in_button_text)
- .setButton2Positive(true)
.setButton2OnClickListener(view -> signIntoNetwork());
mSignalStrengthPref =
diff --git a/src/com/android/settings/wifi/qrcode/QrDecorateView.java b/src/com/android/settings/wifi/qrcode/QrDecorateView.java
new file mode 100644
index 00000000000..253bdb8973b
--- /dev/null
+++ b/src/com/android/settings/wifi/qrcode/QrDecorateView.java
@@ -0,0 +1,136 @@
+/*
+ * 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.wifi.qrcode;
+
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.Point;
+import android.graphics.Rect;
+import android.graphics.RectF;
+import android.util.AttributeSet;
+import android.util.TypedValue;
+import android.view.View;
+
+import com.android.settings.R;
+
+/**
+ * Draws the lines at the corner of the inner frame.
+ */
+public class QrDecorateView extends View {
+ private static final float CORNER_STROKE_WIDTH = 3f; // 3dp
+ private static final float CORNER_LINE_LENGTH = 20f; // 20dp
+
+ final private Paint mPaint;
+ private RectF mFrame;
+ private boolean mFocused;
+
+ public QrDecorateView(Context context) {
+ this(context, null);
+ }
+
+ public QrDecorateView(Context context, AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public QrDecorateView(Context context, AttributeSet attrs, int defStyleAttr) {
+ this(context, attrs, defStyleAttr, 0);
+ }
+
+ public QrDecorateView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
+ super(context, attrs, defStyleAttr, defStyleRes);
+ final float strokeWidth = TypedValue.applyDimension(
+ TypedValue.COMPLEX_UNIT_DIP,
+ CORNER_STROKE_WIDTH,
+ getResources().getDisplayMetrics()
+ );
+ mPaint = new Paint();
+ mPaint.setStrokeWidth(strokeWidth);
+ mFocused = false;
+ }
+
+ @Override
+ protected void onDraw(Canvas canvas) {
+ calculateFramePos();
+ final float cornerLineLength = TypedValue.applyDimension(
+ TypedValue.COMPLEX_UNIT_DIP,
+ CORNER_LINE_LENGTH,
+ getResources().getDisplayMetrics()
+ );
+ mPaint.setColor(mFocused ? Color.GREEN : Color.WHITE);
+ drawCorner(mFrame, cornerLineLength, canvas);
+ super.onDraw(canvas);
+ }
+
+ private void drawCorner(RectF frame, float lineLength, Canvas canvas) {
+ final float strokeWidth = TypedValue.applyDimension(
+ TypedValue.COMPLEX_UNIT_DIP,
+ CORNER_STROKE_WIDTH,
+ getResources().getDisplayMetrics()
+ );
+ // Draw top-left corner.
+ canvas.drawLine(
+ frame.left - strokeWidth / 2,
+ frame.top,
+ frame.left + lineLength,
+ frame.top,
+ mPaint);
+ canvas.drawLine(frame.left, frame.top, frame.left, frame.top + lineLength, mPaint);
+ // Draw top-right corner.
+ canvas.drawLine(
+ frame.right + strokeWidth / 2,
+ frame.top,
+ frame.right - lineLength,
+ frame.top,
+ mPaint);
+ canvas.drawLine(frame.right, frame.top, frame.right, frame.top + lineLength, mPaint);
+ // Draw bottom-left corner.
+ canvas.drawLine(
+ frame.left - strokeWidth / 2,
+ frame.bottom,
+ frame.left + lineLength,
+ frame.bottom,
+ mPaint);
+ canvas.drawLine(frame.left, frame.bottom, frame.left, frame.bottom - lineLength, mPaint);
+ // Draw bottom-right corner.
+ canvas.drawLine(
+ frame.right + strokeWidth / 2,
+ frame.bottom,
+ frame.right - lineLength,
+ frame.bottom,
+ mPaint);
+ canvas.drawLine(frame.right, frame.bottom, frame.right, frame.bottom - lineLength, mPaint);
+ }
+
+ private void calculateFramePos() {
+ final int centralX = getWidth() / 2;
+ final int centralY = getHeight() / 2;
+ final float halfFrameWidth = getWidth() / 3;
+ mFrame = new RectF(
+ centralX - halfFrameWidth,
+ centralY - halfFrameWidth,
+ centralX + halfFrameWidth,
+ centralY + halfFrameWidth);
+ }
+
+ // Draws green lines if focued. Otherwise, draws white lines.
+ public void setFocused(boolean focused) {
+ mFocused = focused;
+ invalidate();
+ }
+}
diff --git a/tests/robotests/src/com/android/settings/SettingsInitializeTest.java b/tests/robotests/src/com/android/settings/SettingsInitializeTest.java
index 1c1c14ce0cc..fe067909ff3 100644
--- a/tests/robotests/src/com/android/settings/SettingsInitializeTest.java
+++ b/tests/robotests/src/com/android/settings/SettingsInitializeTest.java
@@ -78,4 +78,23 @@ public class SettingsInitializeTest {
assertThat(flags & Intent.FLAG_ACTIVITY_CLEAR_TOP).isEqualTo(
Intent.FLAG_ACTIVITY_CLEAR_TOP);
}
+
+ @Test
+ public void refreshExistingShortcuts_shouldNotUpdateImmutableShortcut() {
+ final String id = "test_shortcut_id";
+ final ShortcutInfo info = new ShortcutInfo.Builder(mContext, id)
+ .setShortLabel("test123")
+ .setIntent(new Intent(Intent.ACTION_DEFAULT))
+ .build();
+ info.addFlags(ShortcutInfo.FLAG_IMMUTABLE);
+ final List shortcuts = new ArrayList<>();
+ shortcuts.add(info);
+ ShadowShortcutManager.get().setPinnedShortcuts(shortcuts);
+
+ mSettingsInitialize.refreshExistingShortcuts(mContext);
+
+ final List updatedShortcuts =
+ ShadowShortcutManager.get().getLastUpdatedShortcuts();
+ assertThat(updatedShortcuts).isEmpty();
+ }
}
diff --git a/tests/robotests/src/com/android/settings/SettingsPreferenceFragmentTest.java b/tests/robotests/src/com/android/settings/SettingsPreferenceFragmentTest.java
index 68487931262..2fc3dcb1297 100644
--- a/tests/robotests/src/com/android/settings/SettingsPreferenceFragmentTest.java
+++ b/tests/robotests/src/com/android/settings/SettingsPreferenceFragmentTest.java
@@ -69,6 +69,7 @@ public class SettingsPreferenceFragmentTest {
mContext = RuntimeEnvironment.application;
mFragment = spy(new TestFragment());
doReturn(mActivity).when(mFragment).getActivity();
+ when(mFragment.getContext()).thenReturn(mContext);
mEmptyView = new View(mContext);
ReflectionHelpers.setField(mFragment, "mEmptyView", mEmptyView);
diff --git a/tests/robotests/src/com/android/settings/accessibility/AccessibilityTimeoutControllerTest.java b/tests/robotests/src/com/android/settings/accessibility/AccessibilityTimeoutControllerTest.java
new file mode 100644
index 00000000000..632eea77aa7
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/accessibility/AccessibilityTimeoutControllerTest.java
@@ -0,0 +1,120 @@
+/*
+ * 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.accessibility;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.ContentResolver;
+import android.content.Context;
+import android.provider.Settings;
+
+import androidx.preference.Preference;
+import androidx.preference.PreferenceScreen;
+
+import com.android.settings.R;
+import com.android.settings.testutils.SettingsRobolectricTestRunner;
+import com.android.settings.widget.RadioButtonPreference;
+import com.android.settingslib.core.lifecycle.Lifecycle;
+
+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;
+
+@RunWith(SettingsRobolectricTestRunner.class)
+public class AccessibilityTimeoutControllerTest
+ implements AccessibilityTimeoutController.OnChangeListener {
+ private static final String PREF_KEY = "accessibility_content_timeout_30secs";
+ private static String PREF_TITLE;
+
+ private AccessibilityTimeoutController mController;
+
+ @Mock
+ private RadioButtonPreference mMockPref;
+ private Context mContext;
+ private ContentResolver mContentResolver;
+
+ @Mock
+ private PreferenceScreen mScreen;
+
+ @Before
+ public void setup() {
+ MockitoAnnotations.initMocks(this);
+ mContext = RuntimeEnvironment.application;
+ mController = new AccessibilityTimeoutController(mContext, mock(Lifecycle.class),
+ PREF_KEY, AccessibilityContentTimeoutPreferenceFragment.TAG);
+ mController.setOnChangeListener(this);
+ mContentResolver = mContext.getContentResolver();
+ PREF_TITLE = mContext.getResources().getString(R.string.accessibility_timeout_30secs);
+
+ when(mScreen.findPreference(mController.getPreferenceKey())).thenReturn(mMockPref);
+ when(mMockPref.getKey()).thenReturn(PREF_KEY);
+ when(mMockPref.getTitle()).thenReturn(PREF_TITLE);
+ mController.displayPreference(mScreen);
+ }
+
+ @Override
+ public void onCheckedChanged(Preference preference) {
+ mController.updateState(preference);
+ }
+
+ @Test
+ public void isAvailable() {
+ assertTrue(mController.isAvailable());
+ }
+
+ @Test
+ public void updateState_notChecked() {
+ Settings.Secure.putString(mContentResolver,
+ Settings.Secure.ACCESSIBILITY_NON_INTERACTIVE_UI_TIMEOUT_MS, "0");
+
+ mController.updateState(mMockPref);
+
+ // the first checked state is seted to false by control
+ verify(mMockPref).setChecked(false);
+ verify(mMockPref).setChecked(false);
+ }
+
+ @Test
+ public void updateState_checked() {
+ Settings.Secure.putString(mContentResolver,
+ Settings.Secure.ACCESSIBILITY_NON_INTERACTIVE_UI_TIMEOUT_MS, "30000");
+
+ mController.updateState(mMockPref);
+
+ // the first checked state is seted to false by control
+ verify(mMockPref).setChecked(false);
+ verify(mMockPref).setChecked(true);
+ }
+
+ @Test
+ public void onRadioButtonClick() {
+ mController.onRadioButtonClicked(mMockPref);
+
+ String accessibilityUiTimeoutValue = Settings.Secure.getString(mContentResolver,
+ Settings.Secure.ACCESSIBILITY_NON_INTERACTIVE_UI_TIMEOUT_MS);
+
+ assertThat(accessibilityUiTimeoutValue).isEqualTo("30000");
+ }
+}
\ No newline at end of file
diff --git a/tests/robotests/src/com/android/settings/applications/AppPermissionsPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/applications/AppPermissionsPreferenceControllerTest.java
index cb3d3ad7e18..e828a628bb9 100644
--- a/tests/robotests/src/com/android/settings/applications/AppPermissionsPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/applications/AppPermissionsPreferenceControllerTest.java
@@ -143,7 +143,7 @@ public class AppPermissionsPreferenceControllerTest {
when(mPackageManager.queryPermissionsByGroup(anyString(), anyInt()))
.thenReturn(permissions);
- mController = spy(new AppPermissionsPreferenceController(mContext));
+ mController = spy(new AppPermissionsPreferenceController(mContext, "pref_key"));
}
@Test
diff --git a/tests/robotests/src/com/android/settings/applications/ApplicationFeatureProviderImplTest.java b/tests/robotests/src/com/android/settings/applications/ApplicationFeatureProviderImplTest.java
index ba07dc5caed..128f34547a4 100644
--- a/tests/robotests/src/com/android/settings/applications/ApplicationFeatureProviderImplTest.java
+++ b/tests/robotests/src/com/android/settings/applications/ApplicationFeatureProviderImplTest.java
@@ -34,6 +34,7 @@ import android.os.Build;
import android.os.UserHandle;
import android.os.UserManager;
+import com.android.settings.R;
import com.android.settings.testutils.ApplicationTestUtils;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
import com.android.settingslib.testutils.shadow.ShadowDefaultDialerManager;
@@ -258,13 +259,16 @@ public final class ApplicationFeatureProviderImplTest {
public void getKeepEnabledPackages_shouldContainDefaultPhoneAndSms() {
final String testDialer = "com.android.test.defaultdialer";
final String testSms = "com.android.test.defaultsms";
+ final String settingsIntelligence = RuntimeEnvironment.application.getString(
+ R.string.config_settingsintelligence_package_name);
ShadowSmsApplication.setDefaultSmsApplication(new ComponentName(testSms, "receiver"));
ShadowDefaultDialerManager.setDefaultDialerApplication(testDialer);
ReflectionHelpers.setField(mProvider, "mContext", RuntimeEnvironment.application);
final Set keepEnabledPackages = mProvider.getKeepEnabledPackages();
- final List expectedPackages = Arrays.asList(testDialer, testSms);
+ final List expectedPackages = Arrays.asList(testDialer, testSms,
+ settingsIntelligence);
assertThat(keepEnabledPackages).containsExactlyElementsIn(expectedPackages);
}
diff --git a/tests/robotests/src/com/android/settings/applications/LayoutPreferenceTest.java b/tests/robotests/src/com/android/settings/applications/LayoutPreferenceTest.java
index da65165c1e9..1d2bb3a0b88 100644
--- a/tests/robotests/src/com/android/settings/applications/LayoutPreferenceTest.java
+++ b/tests/robotests/src/com/android/settings/applications/LayoutPreferenceTest.java
@@ -75,12 +75,12 @@ public class LayoutPreferenceTest {
@Test
public void disableSomeView_shouldMaintainStateAfterBind() {
- mPreference.findViewById(R.id.button1_positive).setEnabled(false);
- mPreference.findViewById(R.id.button2_positive).setEnabled(true);
+ mPreference.findViewById(R.id.button1).setEnabled(false);
+ mPreference.findViewById(R.id.button2).setEnabled(true);
mPreference.onBindViewHolder(mHolder);
- assertThat(mPreference.findViewById(R.id.button1_positive).isEnabled()).isFalse();
- assertThat(mPreference.findViewById(R.id.button2_positive).isEnabled()).isTrue();
+ assertThat(mPreference.findViewById(R.id.button1).isEnabled()).isFalse();
+ assertThat(mPreference.findViewById(R.id.button2).isEnabled()).isTrue();
}
}
diff --git a/tests/robotests/src/com/android/settings/applications/appinfo/AppButtonsPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/applications/appinfo/AppButtonsPreferenceControllerTest.java
index f7b27003aa8..815c76b49d0 100644
--- a/tests/robotests/src/com/android/settings/applications/appinfo/AppButtonsPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/applications/appinfo/AppButtonsPreferenceControllerTest.java
@@ -308,7 +308,7 @@ public class AppButtonsPreferenceControllerTest {
final boolean controllable = mController.handleDisableable();
- verify(mButtonPrefs).setButton1Text(R.string.disable_text);
+ verify(mButtonPrefs).setButton1Text(R.string.uninstall_text);
assertThat(controllable).isFalse();
}
@@ -320,7 +320,7 @@ public class AppButtonsPreferenceControllerTest {
final boolean controllable = mController.handleDisableable();
- verify(mButtonPrefs).setButton1Text(R.string.disable_text);
+ verify(mButtonPrefs).setButton1Text(R.string.uninstall_text);
assertThat(controllable).isTrue();
}
@@ -332,7 +332,7 @@ public class AppButtonsPreferenceControllerTest {
final boolean controllable = mController.handleDisableable();
- verify(mButtonPrefs).setButton1Text(R.string.enable_text);
+ verify(mButtonPrefs).setButton1Text(R.string.install_text);
assertThat(controllable).isTrue();
}
diff --git a/tests/robotests/src/com/android/settings/bluetooth/BluetoothDetailsButtonsControllerTest.java b/tests/robotests/src/com/android/settings/bluetooth/BluetoothDetailsButtonsControllerTest.java
index d17fd9640a0..6c555dd2ff2 100644
--- a/tests/robotests/src/com/android/settings/bluetooth/BluetoothDetailsButtonsControllerTest.java
+++ b/tests/robotests/src/com/android/settings/bluetooth/BluetoothDetailsButtonsControllerTest.java
@@ -56,8 +56,8 @@ public class BluetoothDetailsButtonsControllerTest extends BluetoothDetailsContr
super.setUp();
final View buttons = View.inflate(
RuntimeEnvironment.application, R.layout.two_action_buttons, null /* parent */);
- mConnectButton = buttons.findViewById(R.id.button2_positive);
- mForgetButton = buttons.findViewById(R.id.button1_positive);
+ mConnectButton = buttons.findViewById(R.id.button2);
+ mForgetButton = buttons.findViewById(R.id.button1);
mController =
new BluetoothDetailsButtonsController(mContext, mFragment, mCachedDevice, mLifecycle);
mButtonsPref = ActionButtonPreferenceTest.createMock();
diff --git a/tests/robotests/src/com/android/settings/bluetooth/RemoteDeviceNameDialogFragmentTest.java b/tests/robotests/src/com/android/settings/bluetooth/RemoteDeviceNameDialogFragmentTest.java
index 31dec3facd5..945d9b01553 100644
--- a/tests/robotests/src/com/android/settings/bluetooth/RemoteDeviceNameDialogFragmentTest.java
+++ b/tests/robotests/src/com/android/settings/bluetooth/RemoteDeviceNameDialogFragmentTest.java
@@ -41,6 +41,7 @@ import com.android.settings.testutils.shadow.ShadowDynamicLayout;
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
import org.junit.Before;
+import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Answers;
@@ -83,6 +84,7 @@ public class RemoteDeviceNameDialogFragmentTest {
return (AlertDialog) ShadowDialog.getLatestDialog();
}
+ @Ignore("b/119592320")
@Test
public void deviceNameDisplayIsCorrect() {
String deviceName = "ABC Corp Headphones";
@@ -98,6 +100,7 @@ public class RemoteDeviceNameDialogFragmentTest {
assertThat(negativeButton.isEnabled()).isTrue();
}
+ @Ignore("b/119592320")
@Test
public void deviceNameEditSucceeds() {
String deviceNameInitial = "ABC Corp Headphones";
@@ -120,6 +123,7 @@ public class RemoteDeviceNameDialogFragmentTest {
verify(mCachedDevice).setName(deviceNameModified);
}
+ @Ignore("b/119592320")
@Test
public void deviceNameEditThenCancelDoesntRename() {
String deviceNameInitial = "ABC Corp Headphones";
diff --git a/tests/robotests/src/com/android/settings/deviceinfo/aboutphone/TopLevelAboutDevicePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/deviceinfo/aboutphone/TopLevelAboutDevicePreferenceControllerTest.java
index ae3007c9d84..25fbeee178a 100644
--- a/tests/robotests/src/com/android/settings/deviceinfo/aboutphone/TopLevelAboutDevicePreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/deviceinfo/aboutphone/TopLevelAboutDevicePreferenceControllerTest.java
@@ -23,6 +23,7 @@ import static com.google.common.truth.Truth.assertThat;
import android.content.Context;
import android.os.Build;
+import android.provider.Settings.Global;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
@@ -49,7 +50,15 @@ public class TopLevelAboutDevicePreferenceControllerTest {
}
@Test
- public void getSummary_shouldReturnDeviceModel() {
+ public void getSummary_deviceNameNotSet_shouldReturnDeviceModel() {
assertThat(mController.getSummary().toString()).isEqualTo(Build.MODEL);
}
+
+ @Test
+ public void getSummary_deviceNameSet_shouldReturnDeviceName() {
+ Global.putString(mContext.getContentResolver(), Global.DEVICE_NAME, "Test");
+ assertThat(mController.getSummary().toString()).isEqualTo("Test");
+ }
+
+
}
diff --git a/tests/robotests/src/com/android/settings/homepage/contextualcards/ContextualCardManagerTest.java b/tests/robotests/src/com/android/settings/homepage/contextualcards/ContextualCardManagerTest.java
index 091a51b1d4c..82876722efa 100644
--- a/tests/robotests/src/com/android/settings/homepage/contextualcards/ContextualCardManagerTest.java
+++ b/tests/robotests/src/com/android/settings/homepage/contextualcards/ContextualCardManagerTest.java
@@ -18,8 +18,12 @@ package com.android.settings.homepage.contextualcards;
import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.ArgumentMatchers.anyMap;
+import static org.mockito.Mockito.doNothing;
+
import android.content.Context;
import android.net.Uri;
+import android.util.ArrayMap;
import com.android.settings.homepage.contextualcards.conditional.ConditionalContextualCard;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
@@ -27,6 +31,8 @@ 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 java.util.ArrayList;
@@ -35,11 +41,17 @@ import java.util.List;
@RunWith(SettingsRobolectricTestRunner.class)
public class ContextualCardManagerTest {
+ private static final String TEST_SLICE_URI = "context://test/test";
+
+ @Mock
+ ContextualCardUpdateListener mListener;
+
private Context mContext;
private ContextualCardManager mManager;
@Before
public void setUp() {
+ MockitoAnnotations.initMocks(this);
mContext = RuntimeEnvironment.application;
final ContextualCardsFragment fragment = new ContextualCardsFragment();
mManager = new ContextualCardManager(mContext, fragment.getSettingsLifecycle());
@@ -47,10 +59,9 @@ public class ContextualCardManagerTest {
@Test
public void sortCards_hasConditionalAndSliceCards_conditionalShouldAlwaysBeTheLast() {
- final String sliceUri = "content://com.android.settings.slices/action/flashlight";
final List cards = new ArrayList<>();
cards.add(new ConditionalContextualCard.Builder().build());
- cards.add(buildContextualCard(sliceUri));
+ cards.add(buildContextualCard(TEST_SLICE_URI));
final List sortedCards = mManager.sortCards(cards);
@@ -58,6 +69,21 @@ public class ContextualCardManagerTest {
.isEqualTo(ContextualCard.CardType.CONDITIONAL);
}
+ @Test
+ public void onContextualCardUpdated_emtpyMapWithExistingCards_shouldOnlyKeepConditionalCard() {
+ mManager.mContextualCards.add(new ConditionalContextualCard.Builder().build());
+ mManager.mContextualCards.add(
+ buildContextualCard(TEST_SLICE_URI));
+ mManager.setListener(mListener);
+
+ //Simulate database returns no contents.
+ mManager.onContextualCardUpdated(new ArrayMap<>());
+
+ assertThat(mManager.mContextualCards).hasSize(1);
+ assertThat(mManager.mContextualCards.get(0).getCardType())
+ .isEqualTo(ContextualCard.CardType.CONDITIONAL);
+ }
+
private ContextualCard buildContextualCard(String sliceUri) {
return new ContextualCard.Builder()
.setName("test_name")
diff --git a/tests/robotests/src/com/android/settings/homepage/contextualcards/slices/LowStorageSliceTest.java b/tests/robotests/src/com/android/settings/homepage/contextualcards/slices/LowStorageSliceTest.java
new file mode 100644
index 00000000000..0be55d928f6
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/homepage/contextualcards/slices/LowStorageSliceTest.java
@@ -0,0 +1,109 @@
+/*
+ * 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.homepage.contextualcards.slices;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.content.Context;
+
+import androidx.slice.Slice;
+import androidx.slice.SliceItem;
+import androidx.slice.SliceProvider;
+import androidx.slice.widget.SliceLiveData;
+
+import com.android.settings.R;
+import com.android.settings.testutils.SettingsRobolectricTestRunner;
+import com.android.settings.testutils.SliceTester;
+import com.android.settingslib.deviceinfo.PrivateStorageInfo;
+import com.android.settingslib.deviceinfo.StorageVolumeProvider;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.Config;
+import org.robolectric.annotation.Implementation;
+import org.robolectric.annotation.Implements;
+import org.robolectric.annotation.Resetter;
+
+import java.util.List;
+
+@RunWith(SettingsRobolectricTestRunner.class)
+public class LowStorageSliceTest {
+
+ private Context mContext;
+ private LowStorageSlice mLowStorageSlice;
+
+ @Before
+ public void setUp() {
+ mContext = RuntimeEnvironment.application;
+
+ // Set-up specs for SliceMetadata.
+ SliceProvider.setSpecs(SliceLiveData.SUPPORTED_SPECS);
+
+ mLowStorageSlice = new LowStorageSlice(mContext);
+ }
+
+ @After
+ public void tearDown() {
+ ShadowPrivateStorageInfo.reset();
+ }
+
+ @Test
+ @Config(shadows = ShadowPrivateStorageInfo.class)
+ public void getSlice_hasLowStorage_shouldBeCorrectSliceContent() {
+ ShadowPrivateStorageInfo.setPrivateStorageInfo(new PrivateStorageInfo(10L, 100L));
+
+ final Slice slice = mLowStorageSlice.getSlice();
+
+ final List sliceItems = slice.getItems();
+ SliceTester.assertTitle(sliceItems, mContext.getString(R.string.storage_menu_free));
+ }
+
+ @Test
+ @Config(shadows = ShadowPrivateStorageInfo.class)
+ public void getSlice_hasNoLowStorage_shouldBeNull() {
+ ShadowPrivateStorageInfo.setPrivateStorageInfo(new PrivateStorageInfo(100L, 100L));
+
+ final Slice slice = mLowStorageSlice.getSlice();
+
+ assertThat(slice).isNull();
+ }
+
+ @Implements(PrivateStorageInfo.class)
+ public static class ShadowPrivateStorageInfo {
+
+ private static PrivateStorageInfo sPrivateStorageInfo = null;
+
+ @Resetter
+ public static void reset() {
+ sPrivateStorageInfo = null;
+ }
+
+ @Implementation
+ public static PrivateStorageInfo getPrivateStorageInfo(
+ StorageVolumeProvider storageVolumeProvider) {
+ return sPrivateStorageInfo;
+ }
+
+ public static void setPrivateStorageInfo(
+ PrivateStorageInfo privateStorageInfo) {
+ sPrivateStorageInfo = privateStorageInfo;
+ }
+ }
+}
\ No newline at end of file
diff --git a/tests/robotests/src/com/android/settings/network/ApnEditorTest.java b/tests/robotests/src/com/android/settings/network/ApnEditorTest.java
index b6242c38ec7..db970fb4d33 100644
--- a/tests/robotests/src/com/android/settings/network/ApnEditorTest.java
+++ b/tests/robotests/src/com/android/settings/network/ApnEditorTest.java
@@ -57,6 +57,7 @@ import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import org.robolectric.Robolectric;
+import org.robolectric.RuntimeEnvironment;
@RunWith(SettingsRobolectricTestRunner.class)
public class ApnEditorTest {
@@ -113,6 +114,7 @@ public class ApnEditorTest {
doReturn(mResources).when(mApnEditorUT).getResources();
doNothing().when(mApnEditorUT).finish();
doNothing().when(mApnEditorUT).showError();
+ when(mApnEditorUT.getContext()).thenReturn(RuntimeEnvironment.application);
setMockPreference(mActivity);
mApnEditorUT.mApnData = new FakeApnData(APN_DATA);
diff --git a/tests/robotests/src/com/android/settings/notification/ZenModeAllBypassingAppsPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/ZenModeAllBypassingAppsPreferenceControllerTest.java
new file mode 100644
index 00000000000..45f42102e7a
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/notification/ZenModeAllBypassingAppsPreferenceControllerTest.java
@@ -0,0 +1,116 @@
+/*
+ * 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.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyString;
+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.NotificationChannel;
+import android.app.NotificationManager;
+import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.ParceledListSlice;
+
+import com.android.settings.testutils.SettingsRobolectricTestRunner;
+import com.android.settingslib.applications.ApplicationsState;
+
+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.util.ReflectionHelpers;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import androidx.fragment.app.Fragment;
+import androidx.preference.PreferenceScreen;
+
+@RunWith(SettingsRobolectricTestRunner.class)
+public class ZenModeAllBypassingAppsPreferenceControllerTest {
+ private ZenModeAllBypassingAppsPreferenceController mController;
+
+ private Context mContext;
+ @Mock
+ private NotificationBackend mBackend;
+ @Mock
+ private PreferenceScreen mPreferenceScreen;
+ @Mock
+ private ApplicationsState mApplicationState;
+
+ @Before
+ public void setup() {
+ MockitoAnnotations.initMocks(this);
+ mContext = RuntimeEnvironment.application;
+
+ mController = new ZenModeAllBypassingAppsPreferenceController(
+ mContext, null, mock(Fragment.class));
+ mController.mPreferenceScreen = mPreferenceScreen;
+ mController.mApplicationsState = mApplicationState;
+ mController.mPrefContext = mContext;
+ ReflectionHelpers.setField(mController, "mNotificationBackend", mBackend);
+ }
+
+ @Test
+ public void testIsAvailable() {
+ assertThat(mController.isAvailable()).isTrue();
+ }
+
+ @Test
+ public void testUpdateNotificationChannelList() {
+ ApplicationsState.AppEntry entry = mock(ApplicationsState.AppEntry.class);
+ entry.info = new ApplicationInfo();
+ entry.info.packageName = "test";
+ entry.info.uid = 0;
+
+ List appEntries = new ArrayList<>();
+ appEntries.add(entry);
+
+ List channelsBypassing = new ArrayList<>();
+ channelsBypassing.add(mock(NotificationChannel.class));
+ channelsBypassing.add(mock(NotificationChannel.class));
+ channelsBypassing.add(mock(NotificationChannel.class));
+
+ when(mBackend.getNotificationChannelsBypassingDnd(entry.info.packageName,
+ entry.info.uid)).thenReturn(new ParceledListSlice<>(channelsBypassing));
+
+ mController.updateNotificationChannelList(appEntries);
+ verify(mPreferenceScreen, times(3)).addPreference(any());
+ }
+
+ @Test
+ public void testUpdateNotificationChannelList_nullChannels() {
+ mController.updateNotificationChannelList(null);
+ verify(mPreferenceScreen, never()).addPreference(any());
+ }
+
+ @Test
+ public void testUpdateNotificationChannelList_emptyChannelsList() {
+ mController.updateNotificationChannelList(new ArrayList());
+ verify(mPreferenceScreen, never()).addPreference(any());
+ }
+}
diff --git a/tests/robotests/src/com/android/settings/notification/ZenModeBypassingAppsPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/ZenModeBypassingAppsPreferenceControllerTest.java
new file mode 100644
index 00000000000..0bdf6f58aea
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/notification/ZenModeBypassingAppsPreferenceControllerTest.java
@@ -0,0 +1,72 @@
+/*
+ * 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.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+
+import com.android.settings.testutils.SettingsRobolectricTestRunner;
+import com.android.settingslib.core.lifecycle.Lifecycle;
+
+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.util.ReflectionHelpers;
+
+@RunWith(SettingsRobolectricTestRunner.class)
+public class ZenModeBypassingAppsPreferenceControllerTest {
+
+ private ZenModeBypassingAppsPreferenceController mController;
+
+ private Context mContext;
+ @Mock
+ private NotificationBackend mBackend;
+
+ @Before
+ public void setup() {
+ MockitoAnnotations.initMocks(this);
+ mContext = RuntimeEnvironment.application;
+
+ mController = new ZenModeBypassingAppsPreferenceController(mContext, mock(Lifecycle.class));
+ ReflectionHelpers.setField(mController, "mNotificationBackend", mBackend);
+ }
+
+ @Test
+ public void testIsAvailable() {
+ when(mBackend.getNumAppsBypassingDnd(anyInt())).thenReturn(5);
+ assertThat(mController.isAvailable()).isTrue();
+ }
+
+ @Test
+ public void testNotAvailable() {
+ when(mBackend.getNumAppsBypassingDnd(anyInt())).thenReturn(0);
+ assertThat(mController.isAvailable()).isFalse();
+ }
+
+ @Test
+ public void testHasSummary() {
+ assertThat(mController.getSummary()).isNotNull();
+ }
+}
diff --git a/tests/robotests/src/com/android/settings/search/SearchFeatureProviderImplTest.java b/tests/robotests/src/com/android/settings/search/SearchFeatureProviderImplTest.java
index bcb9372308b..b0e40255622 100644
--- a/tests/robotests/src/com/android/settings/search/SearchFeatureProviderImplTest.java
+++ b/tests/robotests/src/com/android/settings/search/SearchFeatureProviderImplTest.java
@@ -19,14 +19,15 @@ package com.android.settings.search;
import static com.google.common.truth.Truth.assertThat;
-import static org.mockito.Mockito.spy;
-
import android.app.Activity;
import android.content.ComponentName;
import android.content.Intent;
+import android.content.pm.ActivityInfo;
+import android.content.pm.ResolveInfo;
import android.provider.Settings;
import android.widget.Toolbar;
+import com.android.settings.R;
import com.android.settings.testutils.FakeFeatureFactory;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
import com.android.settings.testutils.shadow.ShadowUtils;
@@ -37,25 +38,34 @@ import org.junit.runner.RunWith;
import org.robolectric.Robolectric;
import org.robolectric.Shadows;
import org.robolectric.annotation.Config;
+import org.robolectric.shadows.ShadowPackageManager;
@RunWith(SettingsRobolectricTestRunner.class)
public class SearchFeatureProviderImplTest {
private SearchFeatureProviderImpl mProvider;
private Activity mActivity;
+ private ShadowPackageManager mPackageManager;
@Before
public void setUp() {
FakeFeatureFactory.setupForTest();
mActivity = Robolectric.setupActivity(Activity.class);
- mProvider = spy(new SearchFeatureProviderImpl());
+ mProvider = new SearchFeatureProviderImpl();
+ mPackageManager = Shadows.shadowOf(mActivity.getPackageManager());
}
@Test
@Config(shadows = ShadowUtils.class)
- public void initSearchToolbar_shouldInitWithOnClickListener() {
- mProvider.initSearchToolbar(mActivity, null);
+ public void initSearchToolbar_hasResolvedInfo_shouldStartCorrectIntent() {
+ final Intent searchIntent = new Intent(SearchFeatureProvider.SEARCH_UI_INTENT)
+ .setPackage(mActivity.getString(R.string.config_settingsintelligence_package_name));
+ final ResolveInfo info = new ResolveInfo();
+ info.activityInfo = new ActivityInfo();
+ mPackageManager.addResolveInfoForIntent(searchIntent, info);
+
// Should not crash.
+ mProvider.initSearchToolbar(mActivity, null);
final Toolbar toolbar = new Toolbar(mActivity);
// This ensures navigationView is created.
@@ -70,6 +80,21 @@ public class SearchFeatureProviderImplTest {
.isEqualTo(Settings.ACTION_APP_SEARCH_SETTINGS);
}
+ @Test
+ @Config(shadows = ShadowUtils.class)
+ public void initSearchToolbar_NotHaveResolvedInfo_shouldNotStartActivity() {
+ final Toolbar toolbar = new Toolbar(mActivity);
+ // This ensures navigationView is created.
+ toolbar.setNavigationContentDescription("test");
+ mProvider.initSearchToolbar(mActivity, toolbar);
+
+ toolbar.performClick();
+
+ final Intent launchIntent = Shadows.shadowOf(mActivity).getNextStartedActivity();
+
+ assertThat(launchIntent).isNull();
+ }
+
@Test(expected = IllegalArgumentException.class)
public void verifyLaunchSearchResultPageCaller_nullCaller_shouldCrash() {
mProvider.verifyLaunchSearchResultPageCaller(mActivity, null /* caller */);
diff --git a/tests/robotests/src/com/android/settings/widget/ActionButtonPreferenceTest.java b/tests/robotests/src/com/android/settings/widget/ActionButtonPreferenceTest.java
index a66f6d55ca0..2a15127d0ba 100644
--- a/tests/robotests/src/com/android/settings/widget/ActionButtonPreferenceTest.java
+++ b/tests/robotests/src/com/android/settings/widget/ActionButtonPreferenceTest.java
@@ -25,6 +25,7 @@ import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import android.content.Context;
+import android.graphics.drawable.Drawable;
import android.view.View;
import android.widget.Button;
@@ -59,41 +60,17 @@ public class ActionButtonPreferenceTest {
mPref.setButton1Visible(false).setButton2Visible(false);
mPref.onBindViewHolder(mHolder);
- assertThat(mRootView.findViewById(R.id.button1_positive).getVisibility())
- .isEqualTo(View.INVISIBLE);
- assertThat(mRootView.findViewById(R.id.button1_negative).getVisibility())
- .isEqualTo(View.INVISIBLE);
-
- assertThat(mRootView.findViewById(R.id.button2_positive).getVisibility())
- .isEqualTo(View.INVISIBLE);
- assertThat(mRootView.findViewById(R.id.button2_negative).getVisibility())
- .isEqualTo(View.INVISIBLE);
+ assertThat(mRootView.findViewById(R.id.button1).getVisibility())
+ .isEqualTo(View.GONE);
+ assertThat(mRootView.findViewById(R.id.button2).getVisibility())
+ .isEqualTo(View.GONE);
mPref.setButton1Visible(true).setButton2Visible(true);
mPref.onBindViewHolder(mHolder);
- assertThat(mRootView.findViewById(R.id.button1_positive).getVisibility())
+ assertThat(mRootView.findViewById(R.id.button1).getVisibility())
.isEqualTo(View.VISIBLE);
- assertThat(mRootView.findViewById(R.id.button1_negative).getVisibility())
- .isEqualTo(View.INVISIBLE);
- assertThat(mRootView.findViewById(R.id.button2_positive).getVisibility())
- .isEqualTo(View.VISIBLE);
- assertThat(mRootView.findViewById(R.id.button2_negative).getVisibility())
- .isEqualTo(View.INVISIBLE);
- }
-
- @Test
- public void setPositiveNegative_shouldHideOppositeButton() {
- mPref.setButton1Positive(true).setButton2Positive(false);
- mPref.onBindViewHolder(mHolder);
-
- assertThat(mRootView.findViewById(R.id.button1_positive).getVisibility())
- .isEqualTo(View.VISIBLE);
- assertThat(mRootView.findViewById(R.id.button1_negative).getVisibility())
- .isEqualTo(View.INVISIBLE);
- assertThat(mRootView.findViewById(R.id.button2_positive).getVisibility())
- .isEqualTo(View.INVISIBLE);
- assertThat(mRootView.findViewById(R.id.button2_negative).getVisibility())
+ assertThat(mRootView.findViewById(R.id.button2).getVisibility())
.isEqualTo(View.VISIBLE);
}
@@ -102,36 +79,69 @@ public class ActionButtonPreferenceTest {
mPref.setButton1Enabled(true).setButton2Enabled(false);
mPref.onBindViewHolder(mHolder);
- assertThat(mRootView.findViewById(R.id.button1_positive).isEnabled()).isTrue();
- assertThat(mRootView.findViewById(R.id.button1_negative).isEnabled()).isTrue();
- assertThat(mRootView.findViewById(R.id.button2_positive).isEnabled()).isFalse();
- assertThat(mRootView.findViewById(R.id.button2_negative).isEnabled()).isFalse();
+ assertThat(mRootView.findViewById(R.id.button1).isEnabled()).isTrue();
+ assertThat(mRootView.findViewById(R.id.button2).isEnabled()).isFalse();
}
@Test
- public void setText() {
+ public void setText_shouldShowSameText() {
mPref.setButton1Text(R.string.settings_label);
mPref.onBindViewHolder(mHolder);
- assertThat(((Button) mRootView.findViewById(R.id.button1_positive)).getText())
- .isEqualTo(mContext.getText(R.string.settings_label));
- assertThat(((Button) mRootView.findViewById(R.id.button1_negative)).getText())
+ assertThat(((Button) mRootView.findViewById(R.id.button1)).getText())
.isEqualTo(mContext.getText(R.string.settings_label));
}
+ @Test
+ public void setButtonIcon_iconMustDisplayAboveText() {
+ mPref.setButton1Text(R.string.settings_label);
+ mPref.setButton1Icon(R.drawable.ic_settings);
+ mPref.onBindViewHolder(mHolder);
+ final Drawable[] drawablesAroundText =
+ ((Button) mRootView.findViewById(R.id.button1))
+ .getCompoundDrawables();
+
+ assertThat(drawablesAroundText[1 /* top */]).isNotNull();
+ }
+
+ @Test
+ public void setButtonIcon_iconResourceIdIsZero_shouldNotDisplayIcon() {
+ mPref.setButton1Text(R.string.settings_label);
+ mPref.setButton1Icon(0);
+ mPref.onBindViewHolder(mHolder);
+ final Drawable[] drawablesAroundText =
+ ((Button) mRootView.findViewById(R.id.button1))
+ .getCompoundDrawables();
+
+ assertThat(drawablesAroundText[1 /* top */]).isNull();
+ }
+
+ @Test
+ public void setButtonIcon_iconResourceIdNotExisting_shouldNotDisplayIconAndCrash() {
+ mPref.setButton1Text(R.string.settings_label);
+ mPref.setButton1Icon(999999999 /* not existing id */);
+ // Should not crash here
+ mPref.onBindViewHolder(mHolder);
+ final Drawable[] drawablesAroundText =
+ ((Button) mRootView.findViewById(R.id.button1))
+ .getCompoundDrawables();
+
+ assertThat(drawablesAroundText[1 /* top */]).isNull();
+ }
+
public static ActionButtonPreference createMock() {
final ActionButtonPreference pref = mock(ActionButtonPreference.class);
when(pref.setButton1Text(anyInt())).thenReturn(pref);
- when(pref.setButton1Positive(anyBoolean())).thenReturn(pref);
+ when(pref.setButton1Icon(anyInt())).thenReturn(pref);
when(pref.setButton1Enabled(anyBoolean())).thenReturn(pref);
when(pref.setButton1Visible(anyBoolean())).thenReturn(pref);
when(pref.setButton1OnClickListener(any(View.OnClickListener.class))).thenReturn(pref);
when(pref.setButton2Text(anyInt())).thenReturn(pref);
- when(pref.setButton2Positive(anyBoolean())).thenReturn(pref);
+ when(pref.setButton2Icon(anyInt())).thenReturn(pref);
when(pref.setButton2Enabled(anyBoolean())).thenReturn(pref);
when(pref.setButton2Visible(anyBoolean())).thenReturn(pref);
when(pref.setButton2OnClickListener(any(View.OnClickListener.class))).thenReturn(pref);
return pref;
}
-}
+}
\ No newline at end of file