diff --git a/res/drawable/button_border_selected.xml b/res/drawable/button_border_selected.xml
index 65dfe1b67a3..29acbcea8e1 100644
--- a/res/drawable/button_border_selected.xml
+++ b/res/drawable/button_border_selected.xml
@@ -20,6 +20,6 @@
android:color="@color/notification_importance_selection_bg" />
+ android:color="?android:attr/colorAccent"/>
diff --git a/res/drawable/ic_bubble_all.xml b/res/drawable/ic_bubble_all.xml
new file mode 100644
index 00000000000..fdcf6dc803c
--- /dev/null
+++ b/res/drawable/ic_bubble_all.xml
@@ -0,0 +1,25 @@
+
+
+
+
+
diff --git a/res/drawable/ic_bubble_none.xml b/res/drawable/ic_bubble_none.xml
new file mode 100644
index 00000000000..e8fd7df3def
--- /dev/null
+++ b/res/drawable/ic_bubble_none.xml
@@ -0,0 +1,25 @@
+
+
+
+
+
diff --git a/res/drawable/ic_bubble_selected.xml b/res/drawable/ic_bubble_selected.xml
new file mode 100644
index 00000000000..f9533283b5e
--- /dev/null
+++ b/res/drawable/ic_bubble_selected.xml
@@ -0,0 +1,25 @@
+
+
+
+
+
diff --git a/res/drawable/ic_create_bubble.xml b/res/drawable/ic_create_bubble.xml
index e9433553163..82d5db81210 100644
--- a/res/drawable/ic_create_bubble.xml
+++ b/res/drawable/ic_create_bubble.xml
@@ -14,17 +14,13 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-
-
-
-
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?android:attr/colorControlNormal">
+
+
\ No newline at end of file
diff --git a/res/layout/accessibility_edit_magnification_mode.xml b/res/layout/accessibility_edit_magnification_mode.xml
index bdc355d2551..e4f31328fae 100644
--- a/res/layout/accessibility_edit_magnification_mode.xml
+++ b/res/layout/accessibility_edit_magnification_mode.xml
@@ -28,12 +28,19 @@
android:padding="24dp">
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/accessibility_magnification_area_settings_message"
+ android:textAppearance="?android:attr/textAppearanceListItemSecondary"
+ android:textColor="?android:attr/textColorSecondary"
+ android:layout_marginBottom="24dp"/>
+ layout="@layout/accessibility_edit_shortcut_component"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginBottom="32dp" />
+ android:scaleType="fitCenter" />
diff --git a/res/layout/bubble_preference.xml b/res/layout/bubble_preference.xml
new file mode 100644
index 00000000000..8a64716b757
--- /dev/null
+++ b/res/layout/bubble_preference.xml
@@ -0,0 +1,128 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/res/layout/contextual_slice_full_tile.xml b/res/layout/contextual_slice_full_tile.xml
index 4b1155e3e97..b6ab410f341 100644
--- a/res/layout/contextual_slice_full_tile.xml
+++ b/res/layout/contextual_slice_full_tile.xml
@@ -19,7 +19,8 @@
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- style="@style/ContextualCardStyle">
+ style="@style/ContextualCardStyle"
+ android:importantForAccessibility="no">
@@ -28,10 +29,9 @@
android:theme="@style/Theme.Settings.ContextualCard"
style="@style/ContextualCardSliceViewStyle"
android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:importantForAccessibility="no"/>
+ android:layout_height="wrap_content"/>
-
+
\ No newline at end of file
diff --git a/res/layout/contextual_slice_sticky_tile.xml b/res/layout/contextual_slice_sticky_tile.xml
index 5991068dfc6..2e7a2befa63 100644
--- a/res/layout/contextual_slice_sticky_tile.xml
+++ b/res/layout/contextual_slice_sticky_tile.xml
@@ -19,14 +19,14 @@
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- style="@style/ContextualCardStyle">
+ style="@style/ContextualCardStyle"
+ android:importantForAccessibility="no">
+ android:layout_height="wrap_content"/>
diff --git a/res/raw-night/bubble_notification_animation.mp4 b/res/raw-night/bubble_notification_animation.mp4
new file mode 100644
index 00000000000..1a25e9378ad
Binary files /dev/null and b/res/raw-night/bubble_notification_animation.mp4 differ
diff --git a/res/raw/bubble_notification_animation.mp4 b/res/raw/bubble_notification_animation.mp4
new file mode 100644
index 00000000000..299454850e4
Binary files /dev/null and b/res/raw/bubble_notification_animation.mp4 differ
diff --git a/res/xml/app_bubble_notification_settings.xml b/res/xml/app_bubble_notification_settings.xml
index 8d97f8fda7a..3f52ad38153 100644
--- a/res/xml/app_bubble_notification_settings.xml
+++ b/res/xml/app_bubble_notification_settings.xml
@@ -13,22 +13,18 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-
+
-
-
-
+ android:title="@string/notification_bubbles_title"
+ settings:allowDividerBelow="false"/>
diff --git a/res/xml/app_notification_settings.xml b/res/xml/app_notification_settings.xml
index ceb08a26e32..f0200ce46b5 100644
--- a/res/xml/app_notification_settings.xml
+++ b/res/xml/app_notification_settings.xml
@@ -29,6 +29,14 @@
+
+
+
+
-
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/res/xml/configure_notification_settings.xml b/res/xml/configure_notification_settings.xml
index 3dcddc8eb19..cb8357bdb0e 100644
--- a/res/xml/configure_notification_settings.xml
+++ b/res/xml/configure_notification_settings.xml
@@ -50,15 +50,23 @@
-
-
-
+ settings:allowDividerAbove="true"
+ android:summary="@string/manage_conversations"
+ android:order="6"
+ android:fragment="com.android.settings.notification.app.ConversationListSettings"
+ />
+
+
+ settings:controller="com.android.settings.network.telephony.NetworkPreferenceCategoryController">
updatePreference());
+ }
+
+ private void updatePreference() {
+ if (mPreferenceScreen != null) {
+ displayPreference(mPreferenceScreen);
+ }
+ if (mPreference != null) {
+ updateState(mPreference);
+ }
}
@Override
@@ -94,20 +100,18 @@ public class EnabledNetworkModePreferenceController extends
@OnLifecycleEvent(ON_START)
public void onStart() {
- mContext.getContentResolver().registerContentObserver(
- Settings.Global.getUriFor(Settings.Global.PREFERRED_NETWORK_MODE + mSubId),
- true,
- mPreferredNetworkModeObserver);
+ mPreferredNetworkModeObserver.register(mContext, mSubId);
}
@OnLifecycleEvent(ON_STOP)
public void onStop() {
- mContext.getContentResolver().unregisterContentObserver(mPreferredNetworkModeObserver);
+ mPreferredNetworkModeObserver.unregister(mContext);
}
@Override
public void displayPreference(PreferenceScreen screen) {
super.displayPreference(screen);
+ mPreferenceScreen = screen;
mPreference = screen.findPreference(getPreferenceKey());
}
diff --git a/src/com/android/settings/network/telephony/Enhanced4gBasePreferenceController.java b/src/com/android/settings/network/telephony/Enhanced4gBasePreferenceController.java
index d3fb437a36c..cbe0912f0e9 100644
--- a/src/com/android/settings/network/telephony/Enhanced4gBasePreferenceController.java
+++ b/src/com/android/settings/network/telephony/Enhanced4gBasePreferenceController.java
@@ -17,6 +17,7 @@
package com.android.settings.network.telephony;
import android.content.Context;
+import android.os.Looper;
import android.os.PersistableBundle;
import android.telephony.CarrierConfigManager;
import android.telephony.PhoneStateListener;
@@ -187,7 +188,7 @@ public class Enhanced4gBasePreferenceController extends TelephonyTogglePreferenc
private class PhoneCallStateListener extends PhoneStateListener {
PhoneCallStateListener() {
- super();
+ super(Looper.getMainLooper());
}
private TelephonyManager mTelephonyManager;
diff --git a/src/com/android/settings/network/telephony/MobileNetworkSettings.java b/src/com/android/settings/network/telephony/MobileNetworkSettings.java
index 6ca556ade6a..4103447f642 100644
--- a/src/com/android/settings/network/telephony/MobileNetworkSettings.java
+++ b/src/com/android/settings/network/telephony/MobileNetworkSettings.java
@@ -44,7 +44,6 @@ import com.android.settings.network.telephony.cdma.CdmaSystemSelectPreferenceCon
import com.android.settings.network.telephony.gsm.AutoSelectPreferenceController;
import com.android.settings.network.telephony.gsm.OpenNetworkSelectPagePreferenceController;
import com.android.settings.search.BaseSearchIndexProvider;
-import com.android.settings.widget.PreferenceCategoryController;
import com.android.settingslib.core.AbstractPreferenceController;
import com.android.settingslib.search.SearchIndexable;
@@ -155,14 +154,13 @@ public class MobileNetworkSettings extends RestrictedDashboardFragment {
use(WifiCallingPreferenceController.class).init(mSubId);
final OpenNetworkSelectPagePreferenceController openNetworkSelectPagePreferenceController =
- use(OpenNetworkSelectPagePreferenceController.class).init(mSubId);
+ use(OpenNetworkSelectPagePreferenceController.class).init(getLifecycle(), mSubId);
final AutoSelectPreferenceController autoSelectPreferenceController =
use(AutoSelectPreferenceController.class)
- .init(mSubId)
+ .init(getLifecycle(), mSubId)
.addListener(openNetworkSelectPagePreferenceController);
- use(PreferenceCategoryController.class).setChildren(
- Arrays.asList(autoSelectPreferenceController));
-
+ use(NetworkPreferenceCategoryController.class).init(getLifecycle(), mSubId)
+ .setChildren(Arrays.asList(autoSelectPreferenceController));
mCdmaSystemSelectPreferenceController = use(CdmaSystemSelectPreferenceController.class);
mCdmaSystemSelectPreferenceController.init(getPreferenceManager(), mSubId);
mCdmaSubscriptionPreferenceController = use(CdmaSubscriptionPreferenceController.class);
diff --git a/src/com/android/settings/network/telephony/NetworkPreferenceCategoryController.java b/src/com/android/settings/network/telephony/NetworkPreferenceCategoryController.java
new file mode 100644
index 00000000000..042eb5fc088
--- /dev/null
+++ b/src/com/android/settings/network/telephony/NetworkPreferenceCategoryController.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2020 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.network.telephony;
+
+import static androidx.lifecycle.Lifecycle.Event.ON_START;
+import static androidx.lifecycle.Lifecycle.Event.ON_STOP;
+
+import android.content.Context;
+import android.os.Handler;
+import android.os.Looper;
+import android.telephony.SubscriptionManager;
+
+import androidx.lifecycle.Lifecycle;
+import androidx.lifecycle.LifecycleObserver;
+import androidx.lifecycle.OnLifecycleEvent;
+import androidx.preference.PreferenceScreen;
+
+import com.android.settings.network.PreferredNetworkModeContentObserver;
+import com.android.settings.widget.PreferenceCategoryController;
+
+/**
+ * Preference controller for "Network" category
+ */
+public class NetworkPreferenceCategoryController extends PreferenceCategoryController
+ implements LifecycleObserver {
+
+ private PreferenceScreen mPreferenceScreen;
+ private PreferredNetworkModeContentObserver mPreferredNetworkModeObserver;
+ protected int mSubId;
+
+ public NetworkPreferenceCategoryController(Context context, String key) {
+ super(context, key);
+ mSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
+ mPreferredNetworkModeObserver = new PreferredNetworkModeContentObserver(
+ new Handler(Looper.getMainLooper()));
+ mPreferredNetworkModeObserver.setPreferredNetworkModeChangedListener(
+ () -> updatePreference());
+ }
+
+ private void updatePreference() {
+ displayPreference(mPreferenceScreen);
+ }
+
+ @OnLifecycleEvent(ON_START)
+ public void onStart() {
+ mPreferredNetworkModeObserver.register(mContext, mSubId);
+ }
+
+ @OnLifecycleEvent(ON_STOP)
+ public void onStop() {
+ mPreferredNetworkModeObserver.unregister(mContext);
+ }
+
+ @Override
+ public void displayPreference(PreferenceScreen screen) {
+ super.displayPreference(screen);
+ mPreferenceScreen = screen;
+ }
+
+ public NetworkPreferenceCategoryController init(Lifecycle lifecycle, int subId) {
+ mSubId = subId;
+
+ lifecycle.addObserver(this);
+ return this;
+ }
+}
diff --git a/src/com/android/settings/network/telephony/VideoCallingPreferenceController.java b/src/com/android/settings/network/telephony/VideoCallingPreferenceController.java
index eed40467c84..d235a9ac36a 100644
--- a/src/com/android/settings/network/telephony/VideoCallingPreferenceController.java
+++ b/src/com/android/settings/network/telephony/VideoCallingPreferenceController.java
@@ -17,6 +17,7 @@
package com.android.settings.network.telephony;
import android.content.Context;
+import android.os.Looper;
import android.os.PersistableBundle;
import android.telephony.CarrierConfigManager;
import android.telephony.PhoneStateListener;
@@ -164,7 +165,7 @@ public class VideoCallingPreferenceController extends TelephonyTogglePreferenceC
private class PhoneCallStateListener extends PhoneStateListener {
PhoneCallStateListener() {
- super();
+ super(Looper.getMainLooper());
}
private TelephonyManager mTelephonyManager;
diff --git a/src/com/android/settings/network/telephony/WifiCallingPreferenceController.java b/src/com/android/settings/network/telephony/WifiCallingPreferenceController.java
index e928dba734c..bec8a51adda 100644
--- a/src/com/android/settings/network/telephony/WifiCallingPreferenceController.java
+++ b/src/com/android/settings/network/telephony/WifiCallingPreferenceController.java
@@ -20,6 +20,7 @@ import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
+import android.os.Looper;
import android.os.PersistableBundle;
import android.provider.Settings;
import android.telecom.PhoneAccountHandle;
@@ -194,7 +195,7 @@ public class WifiCallingPreferenceController extends TelephonyBasePreferenceCont
private class PhoneCallStateListener extends PhoneStateListener {
PhoneCallStateListener() {
- super();
+ super(Looper.getMainLooper());
}
private TelephonyManager mTelephonyManager;
diff --git a/src/com/android/settings/network/telephony/gsm/AutoSelectPreferenceController.java b/src/com/android/settings/network/telephony/gsm/AutoSelectPreferenceController.java
index 2eda9d94598..361f58e4172 100644
--- a/src/com/android/settings/network/telephony/gsm/AutoSelectPreferenceController.java
+++ b/src/com/android/settings/network/telephony/gsm/AutoSelectPreferenceController.java
@@ -16,6 +16,9 @@
package com.android.settings.network.telephony.gsm;
+import static androidx.lifecycle.Lifecycle.Event.ON_START;
+import static androidx.lifecycle.Lifecycle.Event.ON_STOP;
+
import android.app.ProgressDialog;
import android.app.settings.SettingsEnums;
import android.content.Context;
@@ -30,12 +33,16 @@ import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
import androidx.annotation.VisibleForTesting;
+import androidx.lifecycle.Lifecycle;
+import androidx.lifecycle.LifecycleObserver;
+import androidx.lifecycle.OnLifecycleEvent;
import androidx.preference.Preference;
import androidx.preference.PreferenceScreen;
import androidx.preference.SwitchPreference;
import com.android.settings.R;
import com.android.settings.core.SubSettingLauncher;
+import com.android.settings.network.PreferredNetworkModeContentObserver;
import com.android.settings.network.telephony.MobileNetworkUtils;
import com.android.settings.network.telephony.NetworkSelectSettings;
import com.android.settings.network.telephony.TelephonyTogglePreferenceController;
@@ -48,10 +55,13 @@ import java.util.concurrent.TimeUnit;
/**
* Preference controller for "Auto Select Network"
*/
-public class AutoSelectPreferenceController extends TelephonyTogglePreferenceController {
+public class AutoSelectPreferenceController extends TelephonyTogglePreferenceController
+ implements LifecycleObserver{
private static final long MINIMUM_DIALOG_TIME_MILLIS = TimeUnit.SECONDS.toMillis(1);
private final Handler mUiHandler;
+ private PreferenceScreen mPreferenceScreen;
+ private PreferredNetworkModeContentObserver mPreferredNetworkModeObserver;
private TelephonyManager mTelephonyManager;
private boolean mOnlyAutoSelectInHome;
private List mListeners;
@@ -66,6 +76,28 @@ public class AutoSelectPreferenceController extends TelephonyTogglePreferenceCon
mSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
mListeners = new ArrayList<>();
mUiHandler = new Handler(Looper.getMainLooper());
+ mPreferredNetworkModeObserver = new PreferredNetworkModeContentObserver(mUiHandler);
+ mPreferredNetworkModeObserver.setPreferredNetworkModeChangedListener(
+ () -> updatePreference());
+ }
+
+ private void updatePreference() {
+ if (mPreferenceScreen != null) {
+ displayPreference(mPreferenceScreen);
+ }
+ if (mSwitchPreference != null) {
+ updateState(mSwitchPreference);
+ }
+ }
+
+ @OnLifecycleEvent(ON_START)
+ public void onStart() {
+ mPreferredNetworkModeObserver.register(mContext, mSubId);
+ }
+
+ @OnLifecycleEvent(ON_STOP)
+ public void onStop() {
+ mPreferredNetworkModeObserver.unregister(mContext);
}
@Override
@@ -78,6 +110,7 @@ public class AutoSelectPreferenceController extends TelephonyTogglePreferenceCon
@Override
public void displayPreference(PreferenceScreen screen) {
super.displayPreference(screen);
+ mPreferenceScreen = screen;
mSwitchPreference = screen.findPreference(getPreferenceKey());
}
@@ -142,7 +175,7 @@ public class AutoSelectPreferenceController extends TelephonyTogglePreferenceCon
}
}
- public AutoSelectPreferenceController init(int subId) {
+ public AutoSelectPreferenceController init(Lifecycle lifecycle, int subId) {
mSubId = subId;
mTelephonyManager = mContext.getSystemService(TelephonyManager.class)
.createForSubscriptionId(mSubId);
@@ -153,6 +186,7 @@ public class AutoSelectPreferenceController extends TelephonyTogglePreferenceCon
CarrierConfigManager.KEY_ONLY_AUTO_SELECT_IN_HOME_NETWORK_BOOL)
: false;
+ lifecycle.addObserver(this);
return this;
}
diff --git a/src/com/android/settings/network/telephony/gsm/OpenNetworkSelectPagePreferenceController.java b/src/com/android/settings/network/telephony/gsm/OpenNetworkSelectPagePreferenceController.java
index 8c3928d7d50..2cc5bf1bbef 100644
--- a/src/com/android/settings/network/telephony/gsm/OpenNetworkSelectPagePreferenceController.java
+++ b/src/com/android/settings/network/telephony/gsm/OpenNetworkSelectPagePreferenceController.java
@@ -16,38 +16,64 @@
package com.android.settings.network.telephony.gsm;
+import static androidx.lifecycle.Lifecycle.Event.ON_START;
+import static androidx.lifecycle.Lifecycle.Event.ON_STOP;
+
import android.app.settings.SettingsEnums;
import android.content.Context;
import android.os.Bundle;
+import android.os.Handler;
+import android.os.Looper;
import android.provider.Settings;
import android.telephony.ServiceState;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
import android.text.TextUtils;
+import androidx.lifecycle.Lifecycle;
+import androidx.lifecycle.LifecycleObserver;
+import androidx.lifecycle.OnLifecycleEvent;
import androidx.preference.Preference;
import androidx.preference.PreferenceScreen;
import com.android.settings.R;
import com.android.settings.core.SubSettingLauncher;
+import com.android.settings.network.PreferredNetworkModeContentObserver;
import com.android.settings.network.telephony.MobileNetworkUtils;
import com.android.settings.network.telephony.NetworkSelectSettings;
import com.android.settings.network.telephony.TelephonyBasePreferenceController;
+
/**
* Preference controller for "Open network select"
*/
public class OpenNetworkSelectPagePreferenceController extends
TelephonyBasePreferenceController implements
- AutoSelectPreferenceController.OnNetworkSelectModeListener {
+ AutoSelectPreferenceController.OnNetworkSelectModeListener, LifecycleObserver {
private TelephonyManager mTelephonyManager;
private Preference mPreference;
+ private PreferenceScreen mPreferenceScreen;
+ private PreferredNetworkModeContentObserver mPreferredNetworkModeObserver;
public OpenNetworkSelectPagePreferenceController(Context context, String key) {
super(context, key);
mTelephonyManager = context.getSystemService(TelephonyManager.class);
mSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
+ mPreferredNetworkModeObserver = new PreferredNetworkModeContentObserver(
+ new Handler(Looper.getMainLooper()));
+ mPreferredNetworkModeObserver.setPreferredNetworkModeChangedListener(
+ () -> updatePreference());
+
+ }
+
+ private void updatePreference() {
+ if (mPreferenceScreen != null) {
+ displayPreference(mPreferenceScreen);
+ }
+ if (mPreference != null) {
+ updateState(mPreference);
+ }
}
@Override
@@ -57,9 +83,20 @@ public class OpenNetworkSelectPagePreferenceController extends
: CONDITIONALLY_UNAVAILABLE;
}
+ @OnLifecycleEvent(ON_START)
+ public void onStart() {
+ mPreferredNetworkModeObserver.register(mContext, mSubId);
+ }
+
+ @OnLifecycleEvent(ON_STOP)
+ public void onStop() {
+ mPreferredNetworkModeObserver.unregister(mContext);
+ }
+
@Override
public void displayPreference(PreferenceScreen screen) {
super.displayPreference(screen);
+ mPreferenceScreen = screen;
mPreference = screen.findPreference(getPreferenceKey());
}
@@ -97,10 +134,11 @@ public class OpenNetworkSelectPagePreferenceController extends
return false;
}
- public OpenNetworkSelectPagePreferenceController init(int subId) {
+ public OpenNetworkSelectPagePreferenceController init(Lifecycle lifecycle, int subId) {
mSubId = subId;
mTelephonyManager = mContext.getSystemService(TelephonyManager.class)
.createForSubscriptionId(mSubId);
+ lifecycle.addObserver(this);
return this;
}
diff --git a/src/com/android/settings/notification/BubbleNotificationPreferenceController.java b/src/com/android/settings/notification/BubbleNotificationPreferenceController.java
new file mode 100644
index 00000000000..0fa480cb64a
--- /dev/null
+++ b/src/com/android/settings/notification/BubbleNotificationPreferenceController.java
@@ -0,0 +1,132 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.notification;
+
+import static android.provider.Settings.Global.NOTIFICATION_BUBBLES;
+
+import android.content.ContentResolver;
+import android.content.Context;
+import android.database.ContentObserver;
+import android.net.Uri;
+import android.os.Handler;
+import android.provider.Settings;
+
+import androidx.annotation.VisibleForTesting;
+import androidx.preference.Preference;
+import androidx.preference.PreferenceScreen;
+
+import com.android.settings.core.PreferenceControllerMixin;
+import com.android.settings.core.TogglePreferenceController;
+import com.android.settingslib.core.lifecycle.LifecycleObserver;
+import com.android.settingslib.core.lifecycle.events.OnPause;
+import com.android.settingslib.core.lifecycle.events.OnResume;
+
+/**
+ * Feature level screen for bubbles, available through notification menu.
+ * Allows user to turn bubbles on or off for the device.
+ */
+public class BubbleNotificationPreferenceController extends TogglePreferenceController
+ implements PreferenceControllerMixin, Preference.OnPreferenceChangeListener,
+ LifecycleObserver, OnResume, OnPause {
+
+ private static final String TAG = "BubbleNotifPrefContr";
+
+ @VisibleForTesting
+ static final int ON = 1;
+ @VisibleForTesting
+ static final int OFF = 0;
+
+ private SettingObserver mSettingObserver;
+
+ public BubbleNotificationPreferenceController(Context context, String preferenceKey) {
+ super(context, preferenceKey);
+ }
+
+ @Override
+ public void displayPreference(PreferenceScreen screen) {
+ super.displayPreference(screen);
+ Preference preference = screen.findPreference(getPreferenceKey());
+ if (preference != null) {
+ mSettingObserver = new SettingObserver(preference);
+ }
+ }
+
+ @Override
+ public void onResume() {
+ if (mSettingObserver != null) {
+ mSettingObserver.register(mContext.getContentResolver(), true /* register */);
+ }
+ }
+
+ @Override
+ public void onPause() {
+ if (mSettingObserver != null) {
+ mSettingObserver.register(mContext.getContentResolver(), false /* register */);
+ }
+ }
+
+ @Override
+ public int getAvailabilityStatus() {
+ return AVAILABLE;
+ }
+
+ @Override
+ public boolean isChecked() {
+ return Settings.Global.getInt(mContext.getContentResolver(),
+ NOTIFICATION_BUBBLES, ON) == ON;
+ }
+
+ @Override
+ public boolean setChecked(boolean isChecked) {
+ return Settings.Global.putInt(mContext.getContentResolver(),
+ NOTIFICATION_BUBBLES, isChecked ? ON : OFF);
+ }
+
+ @Override
+ public boolean isSliceable() {
+ return false;
+ }
+
+ class SettingObserver extends ContentObserver {
+
+ private final Uri NOTIFICATION_BUBBLES_URI =
+ Settings.Global.getUriFor(NOTIFICATION_BUBBLES);
+
+ private final Preference mPreference;
+
+ SettingObserver(Preference preference) {
+ super(new Handler());
+ mPreference = preference;
+ }
+
+ public void register(ContentResolver cr, boolean register) {
+ if (register) {
+ cr.registerContentObserver(NOTIFICATION_BUBBLES_URI, false, this);
+ } else {
+ cr.unregisterContentObserver(this);
+ }
+ }
+
+ @Override
+ public void onChange(boolean selfChange, Uri uri) {
+ super.onChange(selfChange, uri);
+ if (NOTIFICATION_BUBBLES_URI.equals(uri)) {
+ updateState(mPreference);
+ }
+ }
+ }
+}
diff --git a/src/com/android/settings/notification/BubbleNotificationSettings.java b/src/com/android/settings/notification/BubbleNotificationSettings.java
new file mode 100644
index 00000000000..6e04683c4cd
--- /dev/null
+++ b/src/com/android/settings/notification/BubbleNotificationSettings.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2020 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.settings.SettingsEnums;
+
+import com.android.settings.R;
+import com.android.settings.core.OnActivityResultListener;
+import com.android.settings.dashboard.DashboardFragment;
+import com.android.settings.search.BaseSearchIndexProvider;
+import com.android.settingslib.search.SearchIndexable;
+
+@SearchIndexable
+public class BubbleNotificationSettings extends DashboardFragment implements
+ OnActivityResultListener {
+ private static final String TAG = "BubbleNotiSettings";
+
+ @Override
+ public int getMetricsCategory() {
+ return SettingsEnums.BUBBLE_SETTINGS;
+ }
+
+ @Override
+ protected String getLogTag() {
+ return TAG;
+ }
+
+ @Override
+ protected int getPreferenceScreenResId() {
+ return R.xml.bubble_notification_settings;
+ }
+
+ /**
+ * For Search.
+ */
+ public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
+ new BaseSearchIndexProvider(R.xml.bubble_notification_settings);
+}
diff --git a/src/com/android/settings/notification/BubbleSummaryNotificationPreferenceController.java b/src/com/android/settings/notification/BubbleSummaryNotificationPreferenceController.java
new file mode 100644
index 00000000000..f123c51fbdc
--- /dev/null
+++ b/src/com/android/settings/notification/BubbleSummaryNotificationPreferenceController.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.notification;
+
+import static android.provider.Settings.Global.NOTIFICATION_BUBBLES;
+
+import android.content.Context;
+import android.provider.Settings;
+
+import androidx.annotation.VisibleForTesting;
+
+import com.android.settings.R;
+import com.android.settings.core.BasePreferenceController;
+
+/**
+ * Summary of the feature setting for bubbles, available through notification menu.
+ */
+public class BubbleSummaryNotificationPreferenceController extends BasePreferenceController {
+
+ @VisibleForTesting
+ static final int ON = 1;
+
+ public BubbleSummaryNotificationPreferenceController(Context context, String preferenceKey) {
+ super(context, preferenceKey);
+ }
+
+ @Override
+ public CharSequence getSummary() {
+ return mContext.getString(
+ areBubblesEnabled()
+ ? R.string.notifications_bubble_setting_on_summary
+ : R.string.switch_off_text);
+ }
+
+ @Override
+ public int getAvailabilityStatus() {
+ return AVAILABLE;
+ }
+
+ private boolean areBubblesEnabled() {
+ return Settings.Global.getInt(mContext.getContentResolver(),
+ NOTIFICATION_BUBBLES, ON) == ON;
+ }
+}
diff --git a/src/com/android/settings/notification/NotificationBackend.java b/src/com/android/settings/notification/NotificationBackend.java
index fb0a438843f..b172879b64e 100644
--- a/src/com/android/settings/notification/NotificationBackend.java
+++ b/src/com/android/settings/notification/NotificationBackend.java
@@ -24,6 +24,7 @@ import android.app.INotificationManager;
import android.app.NotificationChannel;
import android.app.NotificationChannelGroup;
import android.app.NotificationHistory;
+import android.app.NotificationManager;
import android.app.role.RoleManager;
import android.app.usage.IUsageStatsManager;
import android.app.usage.UsageEvents;
@@ -81,7 +82,7 @@ public class NotificationBackend {
row.icon = IconDrawableFactory.newInstance(context).getBadgedIcon(app);
row.banned = getNotificationsBanned(row.pkg, row.uid);
row.showBadge = canShowBadge(row.pkg, row.uid);
- row.allowBubbles = canBubble(row.pkg, row.uid);
+ row.bubblePreference = getBubblePreference(row.pkg, row.uid);
row.userId = UserHandle.getUserId(row.uid);
row.blockedChannelCount = getBlockedChannelCount(row.pkg, row.uid);
row.channelCount = getChannelCount(row.pkg, row.uid);
@@ -192,18 +193,18 @@ public class NotificationBackend {
}
}
- public boolean canBubble(String pkg, int uid) {
+ public int getBubblePreference(String pkg, int uid) {
try {
- return sINM.areBubblesAllowedForPackage(pkg, uid);
+ return sINM.getBubblePreferenceForPackage(pkg, uid);
} catch (Exception e) {
Log.w(TAG, "Error calling NoMan", e);
- return false;
+ return -1;
}
}
- public boolean setAllowBubbles(String pkg, int uid, boolean allow) {
+ public boolean setAllowBubbles(String pkg, int uid, int preference) {
try {
- sINM.setBubblesAllowed(pkg, uid, allow);
+ sINM.setBubblesAllowed(pkg, uid, preference);
return true;
} catch (Exception e) {
Log.w(TAG, "Error calling NoMan", e);
@@ -563,7 +564,7 @@ public class NotificationBackend {
public boolean systemApp;
public boolean lockedImportance;
public boolean showBadge;
- public boolean allowBubbles;
+ public int bubblePreference = NotificationManager.BUBBLE_PREFERENCE_NONE;
public int userId;
public int blockedChannelCount;
public int channelCount;
diff --git a/src/com/android/settings/notification/app/AppBubbleNotificationSettings.java b/src/com/android/settings/notification/app/AppBubbleNotificationSettings.java
index 0ed1b84bdc5..5026a26a52a 100644
--- a/src/com/android/settings/notification/app/AppBubbleNotificationSettings.java
+++ b/src/com/android/settings/notification/app/AppBubbleNotificationSettings.java
@@ -30,6 +30,9 @@ import com.android.settingslib.search.SearchIndexable;
import java.util.ArrayList;
import java.util.List;
+/**
+ * App level settings for bubbles.
+ */
@SearchIndexable
public class AppBubbleNotificationSettings extends NotificationSettings implements
GlobalBubblePermissionObserverMixin.Listener {
diff --git a/src/com/android/settings/notification/app/AppNotificationSettings.java b/src/com/android/settings/notification/app/AppNotificationSettings.java
index d9f42393597..a4228411a72 100644
--- a/src/com/android/settings/notification/app/AppNotificationSettings.java
+++ b/src/com/android/settings/notification/app/AppNotificationSettings.java
@@ -22,6 +22,10 @@ import android.os.Bundle;
import android.text.TextUtils;
import android.util.Log;
+import androidx.preference.Preference;
+import androidx.preference.PreferenceGroup;
+import androidx.preference.PreferenceScreen;
+
import com.android.internal.widget.LockPatternUtils;
import com.android.settings.R;
import com.android.settingslib.core.AbstractPreferenceController;
@@ -29,10 +33,6 @@ import com.android.settingslib.core.AbstractPreferenceController;
import java.util.ArrayList;
import java.util.List;
-import androidx.preference.Preference;
-import androidx.preference.PreferenceGroup;
-import androidx.preference.PreferenceScreen;
-
/** These settings are per app, so should not be returned in global search results. */
public class AppNotificationSettings extends NotificationSettings {
private static final String TAG = "AppNotificationSettings";
@@ -41,8 +41,7 @@ public class AppNotificationSettings extends NotificationSettings {
private static String KEY_ADVANCED_CATEGORY = "app_advanced";
private static String KEY_BADGE = "badge";
private static String KEY_APP_LINK = "app_link";
- private static String KEY_BUBBLE = "bubble_link_pref";
- private static String[] LEGACY_NON_ADVANCED_KEYS = {KEY_BADGE, KEY_APP_LINK, KEY_BUBBLE};
+ private static String[] LEGACY_NON_ADVANCED_KEYS = {KEY_BADGE, KEY_APP_LINK};
@Override
public int getMetricsCategory() {
@@ -121,9 +120,9 @@ public class AppNotificationSettings extends NotificationSettings {
mControllers.add(new DescriptionPreferenceController(context));
mControllers.add(new NotificationsOffPreferenceController(context));
mControllers.add(new DeletedChannelsPreferenceController(context, mBackend));
- mControllers.add(new BubbleSummaryPreferenceController(context, mBackend));
mControllers.add(new ChannelListPreferenceController(context, mBackend));
mControllers.add(new AppConversationListPreferenceController(context, mBackend));
+ mControllers.add(new BubbleSummaryPreferenceController(context, mBackend));
return new ArrayList<>(mControllers);
}
}
diff --git a/src/com/android/settings/notification/app/BubblePreference.java b/src/com/android/settings/notification/app/BubblePreference.java
new file mode 100644
index 00000000000..679b663c8dd
--- /dev/null
+++ b/src/com/android/settings/notification/app/BubblePreference.java
@@ -0,0 +1,172 @@
+/*
+ * Copyright (C) 2020 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.app;
+
+import static android.app.NotificationManager.BUBBLE_PREFERENCE_ALL;
+import static android.app.NotificationManager.BUBBLE_PREFERENCE_NONE;
+import static android.app.NotificationManager.BUBBLE_PREFERENCE_SELECTED;
+
+import android.content.Context;
+import android.content.res.ColorStateList;
+import android.graphics.drawable.Drawable;
+import android.util.AttributeSet;
+import android.view.View;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import androidx.preference.Preference;
+import androidx.preference.PreferenceViewHolder;
+
+import com.android.settings.Utils;
+import com.android.settingslib.R;
+import com.android.settingslib.RestrictedLockUtils;
+import com.android.settingslib.RestrictedPreferenceHelper;
+
+/**
+ * A tri-state preference allowing a user to specify what gets to bubble.
+ */
+public class BubblePreference extends Preference implements View.OnClickListener {
+ RestrictedPreferenceHelper mHelper;
+
+ private int mSelectedPreference;
+
+ private Context mContext;
+ private Drawable mSelectedBackground;
+ private Drawable mUnselectedBackground;
+
+ private ButtonViewHolder mBubbleAllButton;
+ private ButtonViewHolder mBubbleSelectedButton;
+ private ButtonViewHolder mBubbleNoneButton;
+
+ public BubblePreference(Context context) {
+ this(context, null);
+ }
+
+ public BubblePreference(Context context, AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public BubblePreference(Context context, AttributeSet attrs, int defStyleAttr) {
+ this(context, attrs, defStyleAttr, 0);
+ }
+
+ public BubblePreference(Context context, AttributeSet attrs,
+ int defStyleAttr, int defStyleRes) {
+ super(context, attrs, defStyleAttr, defStyleRes);
+ mHelper = new RestrictedPreferenceHelper(context, this, attrs);
+ mHelper.useAdminDisabledSummary(true);
+ mContext = context;
+ mSelectedBackground = mContext.getDrawable(R.drawable.button_border_selected);
+ mUnselectedBackground = mContext.getDrawable(R.drawable.button_border_unselected);
+ setLayoutResource(R.layout.bubble_preference);
+ }
+
+ public void setSelectedPreference(int preference) {
+ mSelectedPreference = preference;
+ }
+
+ public int getSelectedPreference() {
+ return mSelectedPreference;
+ }
+
+ public void setDisabledByAdmin(RestrictedLockUtils.EnforcedAdmin admin) {
+ if (mHelper.setDisabledByAdmin(admin)) {
+ notifyChanged();
+ }
+ }
+
+ @Override
+ public void onBindViewHolder(final PreferenceViewHolder holder) {
+ super.onBindViewHolder(holder);
+
+ final boolean disabledByAdmin = mHelper.isDisabledByAdmin();
+ View summary = holder.findViewById(android.R.id.summary);
+ if (disabledByAdmin) {
+ mHelper.onBindViewHolder(holder);
+ summary.setVisibility(View.VISIBLE);
+ } else {
+ summary.setVisibility(View.GONE);
+ }
+ holder.itemView.setClickable(false);
+
+ View bubbleAll = holder.findViewById(R.id.bubble_all);
+ ImageView bubbleAllImage = (ImageView) holder.findViewById(R.id.bubble_all_icon);
+ TextView bubbleAllText = (TextView) holder.findViewById(R.id.bubble_all_label);
+ mBubbleAllButton = new ButtonViewHolder(bubbleAll, bubbleAllImage, bubbleAllText,
+ BUBBLE_PREFERENCE_ALL);
+ mBubbleAllButton.setSelected(mContext, mSelectedPreference == BUBBLE_PREFERENCE_ALL);
+ bubbleAll.setTag(BUBBLE_PREFERENCE_ALL);
+ bubbleAll.setOnClickListener(this);
+ bubbleAll.setVisibility(disabledByAdmin ? View.GONE : View.VISIBLE);
+
+ View bubbleSelected = holder.findViewById(R.id.bubble_selected);
+ ImageView bubbleSelectedImage = (ImageView) holder.findViewById(R.id.bubble_selected_icon);
+ TextView bubbleSelectedText = (TextView) holder.findViewById(R.id.bubble_selected_label);
+ mBubbleSelectedButton = new ButtonViewHolder(bubbleSelected, bubbleSelectedImage,
+ bubbleSelectedText, BUBBLE_PREFERENCE_SELECTED);
+ mBubbleSelectedButton.setSelected(mContext,
+ mSelectedPreference == BUBBLE_PREFERENCE_SELECTED);
+ bubbleSelected.setTag(BUBBLE_PREFERENCE_SELECTED);
+ bubbleSelected.setOnClickListener(this);
+ bubbleSelected.setVisibility(disabledByAdmin ? View.GONE : View.VISIBLE);
+
+ View bubbleNone = holder.findViewById(R.id.bubble_none);
+ ImageView bubbleNoneImage = (ImageView) holder.findViewById(R.id.bubble_none_icon);
+ TextView bubbleNoneText = (TextView) holder.findViewById(R.id.bubble_none_label);
+ mBubbleNoneButton = new ButtonViewHolder(bubbleNone, bubbleNoneImage, bubbleNoneText,
+ BUBBLE_PREFERENCE_NONE);
+ mBubbleNoneButton.setSelected(mContext, mSelectedPreference == BUBBLE_PREFERENCE_NONE);
+ bubbleNone.setTag(BUBBLE_PREFERENCE_NONE);
+ bubbleNone.setOnClickListener(this);
+ bubbleNone.setVisibility(disabledByAdmin ? View.GONE : View.VISIBLE);
+ }
+
+ @Override
+ public void onClick(View v) {
+ final int selected = (int) v.getTag();
+ callChangeListener(selected);
+
+ mBubbleAllButton.setSelected(mContext, selected == BUBBLE_PREFERENCE_ALL);
+ mBubbleSelectedButton.setSelected(mContext, selected == BUBBLE_PREFERENCE_SELECTED);
+ mBubbleNoneButton.setSelected(mContext, selected == BUBBLE_PREFERENCE_NONE);
+ }
+
+ private class ButtonViewHolder {
+ private View mView;
+ private ImageView mImageView;
+ private TextView mTextView;
+ private int mId;
+
+ ButtonViewHolder(View v, ImageView iv, TextView tv, int identifier) {
+ mView = v;
+ mImageView = iv;
+ mTextView = tv;
+ mId = identifier;
+ }
+
+ void setSelected(Context context, boolean selected) {
+ mView.setBackground(selected ? mSelectedBackground : mUnselectedBackground);
+ mView.setSelected(selected);
+
+ ColorStateList stateList = selected
+ ? Utils.getColorAccent(context)
+ : Utils.getColorAttr(context, android.R.attr.textColorPrimary);
+ mImageView.setImageTintList(stateList);
+ mTextView.setTextColor(stateList);
+ }
+ }
+}
diff --git a/src/com/android/settings/notification/app/BubblePreferenceController.java b/src/com/android/settings/notification/app/BubblePreferenceController.java
index d33ba7e1aa3..3255192a912 100644
--- a/src/com/android/settings/notification/app/BubblePreferenceController.java
+++ b/src/com/android/settings/notification/app/BubblePreferenceController.java
@@ -16,6 +16,7 @@
package com.android.settings.notification.app;
+import static android.app.NotificationManager.BUBBLE_PREFERENCE_NONE;
import static android.provider.Settings.Global.NOTIFICATION_BUBBLES;
import android.annotation.Nullable;
@@ -26,11 +27,14 @@ import androidx.annotation.VisibleForTesting;
import androidx.fragment.app.FragmentManager;
import androidx.preference.Preference;
-import com.android.settings.R;
import com.android.settings.core.PreferenceControllerMixin;
import com.android.settings.notification.NotificationBackend;
import com.android.settingslib.RestrictedSwitchPreference;
+/**
+ * Preference controller for Bubbles. This is used as the app-specific page and conversation
+ * settings.
+ */
public class BubblePreferenceController extends NotificationPreferenceController
implements PreferenceControllerMixin, Preference.OnPreferenceChangeListener {
@@ -74,40 +78,49 @@ public class BubblePreferenceController extends NotificationPreferenceController
return true;
}
+ @Override
public void updateState(Preference preference) {
- if (mAppRow != null) {
- RestrictedSwitchPreference pref = (RestrictedSwitchPreference) preference;
+ if (mIsAppPage && mAppRow != null) {
+ // We're on the app specific bubble page which displays a tri-state
+ int backEndPref = mAppRow.bubblePreference;
+ BubblePreference pref = (BubblePreference) preference;
pref.setDisabledByAdmin(mAdmin);
- if (mChannel != null) {
- pref.setChecked(mChannel.canBubble() && isGloballyEnabled());
- pref.setEnabled(!pref.isDisabledByAdmin());
+ if (!isGloballyEnabled()) {
+ pref.setSelectedPreference(BUBBLE_PREFERENCE_NONE);
} else {
- pref.setChecked(mAppRow.allowBubbles && isGloballyEnabled());
- pref.setSummary(mContext.getString(
- R.string.bubbles_app_toggle_summary, mAppRow.label));
+ pref.setSelectedPreference(backEndPref);
}
+ } else if (mChannel != null) {
+ // We're on the channel specific notification page which displays a toggle.
+ RestrictedSwitchPreference switchpref = (RestrictedSwitchPreference) preference;
+ switchpref.setDisabledByAdmin(mAdmin);
+ switchpref.setChecked(mChannel.canBubble() && isGloballyEnabled());
}
}
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
- final boolean value = (Boolean) newValue && isGloballyEnabled();
if (mChannel != null) {
- mChannel.setAllowBubbles(value);
+ // Channel page is toggle
+ mChannel.setAllowBubbles((boolean) newValue);
saveChannel();
- return true;
- } else if (mAppRow != null && mFragmentManager != null) {
- RestrictedSwitchPreference pref = (RestrictedSwitchPreference) preference;
- // if the global setting is off, toggling app level permission requires extra
- // confirmation
- if (!isGloballyEnabled() && !pref.isChecked()) {
- new BubbleWarningDialogFragment()
- .setPkgInfo(mAppRow.pkg, mAppRow.uid)
- .show(mFragmentManager, "dialog");
- return false;
- } else {
- mAppRow.allowBubbles = value;
- mBackend.setAllowBubbles(mAppRow.pkg, mAppRow.uid, value);
+ } else if (mIsAppPage) {
+ // App page is bubble preference
+ BubblePreference pref = (BubblePreference) preference;
+ if (mAppRow != null && mFragmentManager != null) {
+ final int value = (int) newValue;
+ if (!isGloballyEnabled()
+ && pref.getSelectedPreference() == BUBBLE_PREFERENCE_NONE) {
+ // if the global setting is off, toggling app level permission requires extra
+ // confirmation
+ new BubbleWarningDialogFragment()
+ .setPkgPrefInfo(mAppRow.pkg, mAppRow.uid, value)
+ .show(mFragmentManager, "dialog");
+ return false;
+ } else {
+ mAppRow.bubblePreference = value;
+ mBackend.setAllowBubbles(mAppRow.pkg, mAppRow.uid, value);
+ }
}
}
return true;
@@ -118,21 +131,26 @@ public class BubblePreferenceController extends NotificationPreferenceController
NOTIFICATION_BUBBLES, SYSTEM_WIDE_OFF) == SYSTEM_WIDE_ON;
}
- // Used in app level prompt that confirms the user is ok with turning on bubbles
- // globally. If they aren't, undo what
+ /**
+ * Used in app level prompt that confirms the user is ok with turning on bubbles
+ * globally. If they aren't, undo that.
+ */
public static void revertBubblesApproval(Context mContext, String pkg, int uid) {
NotificationBackend backend = new NotificationBackend();
- backend.setAllowBubbles(pkg, uid, false);
+ backend.setAllowBubbles(pkg, uid, BUBBLE_PREFERENCE_NONE);
+
// changing the global settings will cause the observer on the host page to reload
// correct preference state
Settings.Global.putInt(mContext.getContentResolver(),
NOTIFICATION_BUBBLES, SYSTEM_WIDE_OFF);
}
- // Apply global bubbles approval
- public static void applyBubblesApproval(Context mContext, String pkg, int uid) {
+ /**
+ * Apply global bubbles approval
+ */
+ public static void applyBubblesApproval(Context mContext, String pkg, int uid, int pref) {
NotificationBackend backend = new NotificationBackend();
- backend.setAllowBubbles(pkg, uid, true);
+ backend.setAllowBubbles(pkg, uid, pref);
// changing the global settings will cause the observer on the host page to reload
// correct preference state
Settings.Global.putInt(mContext.getContentResolver(),
diff --git a/src/com/android/settings/notification/app/BubbleSummaryPreferenceController.java b/src/com/android/settings/notification/app/BubbleSummaryPreferenceController.java
index f13613c4daf..06c6f3a1a84 100644
--- a/src/com/android/settings/notification/app/BubbleSummaryPreferenceController.java
+++ b/src/com/android/settings/notification/app/BubbleSummaryPreferenceController.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2019 The Android Open Source Project
+ * Copyright (C) 2020 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.
@@ -16,38 +16,34 @@
package com.android.settings.notification.app;
+import static android.app.NotificationManager.BUBBLE_PREFERENCE_ALL;
+import static android.app.NotificationManager.BUBBLE_PREFERENCE_NONE;
import static android.provider.Settings.Global.NOTIFICATION_BUBBLES;
-import android.app.settings.SettingsEnums;
import android.content.Context;
-import android.os.Bundle;
+import android.content.Intent;
+import android.content.res.Resources;
import android.provider.Settings;
-import com.android.settings.R;
-import com.android.settings.applications.AppInfoBase;
-import com.android.settings.core.SubSettingLauncher;
-import com.android.settings.notification.NotificationBackend;
-
import androidx.annotation.VisibleForTesting;
import androidx.preference.Preference;
-public class BubbleSummaryPreferenceController extends NotificationPreferenceController {
+import com.android.settings.R;
+import com.android.settings.notification.NotificationBackend;
+
+/**
+ * Summary of the app setting for bubbles, available through app notification settings.
+ */
+public class BubbleSummaryPreferenceController extends NotificationPreferenceController {
+ private static final String KEY = "bubble_pref_link";
- private static final String KEY = "bubble_link_pref";
@VisibleForTesting
- static final int SYSTEM_WIDE_ON = 1;
- @VisibleForTesting
- static final int SYSTEM_WIDE_OFF = 0;
+ static final int ON = 1;
public BubbleSummaryPreferenceController(Context context, NotificationBackend backend) {
super(context, backend);
}
- @Override
- public String getPreferenceKey() {
- return KEY;
- }
-
@Override
public boolean isAvailable() {
if (!super.isAvailable()) {
@@ -63,45 +59,47 @@ public class BubbleSummaryPreferenceController extends NotificationPreferenceCon
if (isDefaultChannel()) {
return true;
} else {
- return mAppRow != null && mAppRow.allowBubbles;
+ return mAppRow != null;
}
}
return isGloballyEnabled();
}
+ @Override
+ public String getPreferenceKey() {
+ return KEY;
+ }
+
@Override
public void updateState(Preference preference) {
super.updateState(preference);
if (mAppRow != null) {
- Bundle args = new Bundle();
- args.putString(AppInfoBase.ARG_PACKAGE_NAME, mAppRow.pkg);
- args.putInt(AppInfoBase.ARG_PACKAGE_UID, mAppRow.uid);
-
- preference.setIntent(new SubSettingLauncher(mContext)
- .setDestination(AppBubbleNotificationSettings.class.getName())
- .setArguments(args)
- .setSourceMetricsCategory(
- SettingsEnums.NOTIFICATION_APP_NOTIFICATION)
- .toIntent());
+ final Intent intent = new Intent(Settings.ACTION_APP_NOTIFICATION_BUBBLE_SETTINGS);
+ intent.putExtra(Settings.EXTRA_APP_PACKAGE, mAppRow.pkg);
+ intent.putExtra(Settings.EXTRA_APP_UID, mAppRow.uid);
+ preference.setIntent(intent);
}
}
@Override
public CharSequence getSummary() {
- boolean canBubble = false;
- if (mAppRow != null) {
- if (mChannel != null) {
- canBubble |= mChannel.canBubble() && isGloballyEnabled();
- } else {
- canBubble |= mAppRow.allowBubbles && isGloballyEnabled();
- }
+ if (mAppRow == null) {
+ return null;
+ }
+ int backEndPref = mAppRow.bubblePreference;
+ Resources res = mContext.getResources();
+ if (backEndPref == BUBBLE_PREFERENCE_NONE || !isGloballyEnabled()) {
+ return res.getString(R.string.bubble_app_setting_none);
+ } else if (backEndPref == BUBBLE_PREFERENCE_ALL) {
+ return res.getString(R.string.bubble_app_setting_all);
+ } else {
+ return res.getString(R.string.bubble_app_setting_selected);
}
- return mContext.getString(canBubble ? R.string.switch_on_text : R.string.switch_off_text);
}
private boolean isGloballyEnabled() {
return Settings.Global.getInt(mContext.getContentResolver(),
- NOTIFICATION_BUBBLES, SYSTEM_WIDE_OFF) == SYSTEM_WIDE_ON;
+ NOTIFICATION_BUBBLES, ON) == ON;
}
}
diff --git a/src/com/android/settings/notification/app/BubbleWarningDialogFragment.java b/src/com/android/settings/notification/app/BubbleWarningDialogFragment.java
index d3aa7585260..7d5b24a3050 100644
--- a/src/com/android/settings/notification/app/BubbleWarningDialogFragment.java
+++ b/src/com/android/settings/notification/app/BubbleWarningDialogFragment.java
@@ -27,6 +27,7 @@ import com.android.settings.core.instrumentation.InstrumentedDialogFragment;
public class BubbleWarningDialogFragment extends InstrumentedDialogFragment {
static final String KEY_PKG = "p";
static final String KEY_UID = "u";
+ static final String KEY_SELECTED_PREFERENCE = "pref";
@Override
@@ -34,10 +35,11 @@ public class BubbleWarningDialogFragment extends InstrumentedDialogFragment {
return SettingsEnums.DIALOG_APP_BUBBLE_SETTINGS;
}
- public BubbleWarningDialogFragment setPkgInfo(String pkg, int uid) {
+ public BubbleWarningDialogFragment setPkgPrefInfo(String pkg, int uid, int preference) {
Bundle args = new Bundle();
args.putString(KEY_PKG, pkg);
args.putInt(KEY_UID, uid);
+ args.putInt(KEY_SELECTED_PREFERENCE, preference);
setArguments(args);
return this;
}
@@ -48,6 +50,7 @@ public class BubbleWarningDialogFragment extends InstrumentedDialogFragment {
final Bundle args = getArguments();
final String pkg = args.getString(KEY_PKG);
final int uid = args.getInt(KEY_UID);
+ final int pref = args.getInt(KEY_SELECTED_PREFERENCE);
final String title =
getResources().getString(R.string.bubbles_feature_disabled_dialog_title);
@@ -60,7 +63,7 @@ public class BubbleWarningDialogFragment extends InstrumentedDialogFragment {
.setPositiveButton(R.string.bubbles_feature_disabled_button_approve,
(dialog, id) ->
BubblePreferenceController.applyBubblesApproval(
- getContext(), pkg, uid))
+ getContext(), pkg, uid, pref))
.setNegativeButton(R.string.bubbles_feature_disabled_button_cancel,
(dialog, id) ->
BubblePreferenceController.revertBubblesApproval(
diff --git a/src/com/android/settings/slices/SlicesIndexer.java b/src/com/android/settings/slices/SlicesIndexer.java
index 3a68a322853..e527fd657ab 100644
--- a/src/com/android/settings/slices/SlicesIndexer.java
+++ b/src/com/android/settings/slices/SlicesIndexer.java
@@ -104,7 +104,10 @@ class SlicesIndexer implements Runnable {
values.put(IndexColumns.SLICE_URI, dataRow.getUri().toSafeString());
values.put(IndexColumns.TITLE, dataRow.getTitle());
values.put(IndexColumns.SUMMARY, dataRow.getSummary());
- values.put(IndexColumns.SCREENTITLE, dataRow.getScreenTitle().toString());
+ final CharSequence screenTitle = dataRow.getScreenTitle();
+ if (screenTitle != null) {
+ values.put(IndexColumns.SCREENTITLE, screenTitle.toString());
+ }
values.put(IndexColumns.KEYWORDS, dataRow.getKeywords());
values.put(IndexColumns.ICON_RESOURCE, dataRow.getIconResource());
values.put(IndexColumns.FRAGMENT, dataRow.getFragmentClassName());
diff --git a/tests/perftests/Android.bp b/tests/perftests/Android.bp
index 1ba5d9c432a..7708bbe2569 100644
--- a/tests/perftests/Android.bp
+++ b/tests/perftests/Android.bp
@@ -19,4 +19,4 @@ android_test {
test_suites: ["device-tests"],
instrumentation_for: "Settings",
-}
+}
\ No newline at end of file
diff --git a/tests/perftests/AndroidManifest.xml b/tests/perftests/AndroidManifest.xml
index 4ce6a54048c..972467f5fe6 100644
--- a/tests/perftests/AndroidManifest.xml
+++ b/tests/perftests/AndroidManifest.xml
@@ -15,15 +15,15 @@
-->
+ package="com.android.settings.tests.perf">
-
+
+ android:targetPackage="com.android.settings.tests.perf"
+ android:label="Settings Performance Test Cases">
diff --git a/tests/perftests/src/com/android/settings/tests/perf/LaunchSettingsTest.java b/tests/perftests/src/com/android/settings/tests/perf/LaunchSettingsTest.java
index 5140be2db91..f55598cb998 100644
--- a/tests/perftests/src/com/android/settings/tests/perf/LaunchSettingsTest.java
+++ b/tests/perftests/src/com/android/settings/tests/perf/LaunchSettingsTest.java
@@ -15,8 +15,15 @@
*/
package com.android.settings.tests.perf;
+import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
+
+import static junit.framework.TestCase.fail;
+
import android.app.Instrumentation;
import android.os.Bundle;
+import android.support.test.uiautomator.By;
+import android.support.test.uiautomator.UiDevice;
+import android.support.test.uiautomator.Until;
import androidx.test.InstrumentationRegistry;
import androidx.test.runner.AndroidJUnit4;
@@ -26,23 +33,119 @@ import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
@RunWith(AndroidJUnit4.class)
public class LaunchSettingsTest {
+ private static class Page {
+ String action;
+ String displayName;
+ String title;
+
+ Page(String action, String displayName, String title) {
+ this.action = action;
+ this.displayName = displayName;
+ this.title = title;
+ }
+ }
+
+ private static final int TIME_OUT = 5000;
+ private static final int TEST_TIME = 10;
+ private static final Pattern PATTERN = Pattern.compile("TotalTime:\\s[0-9]*");
+ private static final Page[] PAGES;
+
+ static {
+ PAGES = new Page[]{
+ new Page("android.settings.SETTINGS", "Search settings", "Settings"),
+ new Page("android.settings.WIFI_SETTINGS", "Use Wi‑Fi", "Wi-Fi"),
+ new Page("android.settings.BLUETOOTH_SETTINGS", "Connected devices", "BlueTooth"),
+ new Page("android.settings.APPLICATION_SETTINGS", "App info", "Application"),
+ new Page("android.intent.action.POWER_USAGE_SUMMARY", "Battery", "Battery")
+ };
+ }
+
+ private Bundle mBundle;
+ private UiDevice mDevice;
+ private Instrumentation mInstrumentation;
+ private Map> mResult;
@Before
public void setUp() throws Exception {
+ mBundle = new Bundle();
+ mDevice = UiDevice.getInstance(getInstrumentation());
+ mInstrumentation = InstrumentationRegistry.getInstrumentation();
+ mResult = new LinkedHashMap<>();
+ mDevice.pressHome();
+ mDevice.waitForIdle(TIME_OUT);
+
+ for (Page page : PAGES) {
+ mResult.put(page.title, new ArrayList());
+ }
}
@After
public void tearDown() throws Exception {
+ putResultToBundle();
+ mInstrumentation.sendStatus(0, mBundle);
}
@Test
- public void testReportMetrics() throws Exception {
- Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
- final Bundle result = new Bundle();
- result.putString("LaunchSettingsTest_metric_key1", "1000");
- result.putString("LaunchSettingsTest_metric_key2", "5000");
- instrumentation.sendStatus(0, result);
+ public void settingsPerformanceTest() throws Exception {
+ for (int i = 0; i < TEST_TIME; i++) {
+ for (Page page : PAGES) {
+ executePreformanceTest(page.action, page.displayName, page.title);
+ }
+ }
}
-}
+
+ private void executePreformanceTest(String action, String displayName, String title)
+ throws Exception {
+ final String mString = mDevice.executeShellCommand("am start -W -a" + action);
+ mDevice.wait(Until.findObject(By.text(displayName)), TIME_OUT);
+ handleLaunchResult(title, mString);
+ closeApp();
+ mDevice.waitForIdle(TIME_OUT);
+ }
+
+ private void handleLaunchResult(String title, String s) {
+ Matcher mMatcher = PATTERN.matcher(s);
+ if (mMatcher.find()) {
+ mResult.get(title).add(Integer.valueOf(mMatcher.group().split("\\s")[1]));
+ } else {
+ fail("Some pages can't be found");
+ }
+ }
+
+ private void closeApp() throws Exception {
+ mDevice.executeShellCommand("am force-stop com.android.settings");
+ Thread.sleep(1000);
+ }
+
+ private void putResultToBundle() {
+ for (String string : mResult.keySet()) {
+ mBundle.putString(String.format("LaunchSettingsTest_%s_%s", string, "max"),
+ getMax(mResult.get(string)));
+ mBundle.putString(String.format("LaunchSettingsTest_%s_%s", string, "min"),
+ getMin(mResult.get(string)));
+ mBundle.putString(String.format("LaunchSettingsTest_%s_%s", string, "avg"),
+ getAvg(mResult.get(string)));
+ }
+ }
+
+ private String getMax(ArrayList launchResult) {
+ return String.format("%s", launchResult.isEmpty() ? "null" : Collections.max(launchResult));
+ }
+
+ private String getMin(ArrayList launchResult) {
+ return String.format("%s", launchResult.isEmpty() ? "null" : Collections.min(launchResult));
+ }
+
+ private String getAvg(ArrayList launchResult) {
+ return String.valueOf((int) launchResult.stream().mapToInt(i -> i).average().orElse(0));
+ }
+}
\ No newline at end of file
diff --git a/tests/robotests/src/com/android/settings/AirplaneModeEnablerTest.java b/tests/robotests/src/com/android/settings/AirplaneModeEnablerTest.java
index 24abac9f258..6c5b9f2323f 100644
--- a/tests/robotests/src/com/android/settings/AirplaneModeEnablerTest.java
+++ b/tests/robotests/src/com/android/settings/AirplaneModeEnablerTest.java
@@ -53,7 +53,7 @@ public final class AirplaneModeEnablerTest {
@Test
public void onRadioPowerStateChanged_beenInvoke_invokeOnAirplaneModeChanged() {
- mAirplaneModeEnabler.resume();
+ mAirplaneModeEnabler.start();
ShadowSettings.setAirplaneMode(true);
diff --git a/tests/robotests/src/com/android/settings/development/BubbleGlobalPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/development/BubbleGlobalPreferenceControllerTest.java
deleted file mode 100644
index 9e52a8829c9..00000000000
--- a/tests/robotests/src/com/android/settings/development/BubbleGlobalPreferenceControllerTest.java
+++ /dev/null
@@ -1,111 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.settings.development;
-
-import static android.provider.Settings.Global.NOTIFICATION_BUBBLES;
-
-import static com.android.settings.development.BubbleGlobalPreferenceController.OFF;
-import static com.android.settings.development.BubbleGlobalPreferenceController.ON;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import android.content.Context;
-import android.provider.Settings;
-
-import androidx.preference.PreferenceScreen;
-import androidx.preference.SwitchPreference;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-import org.robolectric.RobolectricTestRunner;
-import org.robolectric.RuntimeEnvironment;
-
-@RunWith(RobolectricTestRunner.class)
-public class BubbleGlobalPreferenceControllerTest {
- private Context mContext;
-
- @Mock
- private SwitchPreference mPreference;
- @Mock
- private PreferenceScreen mPreferenceScreen;
-
- private BubbleGlobalPreferenceController mController;
-
- @Before
- public void setUp() {
- MockitoAnnotations.initMocks(this);
- mContext = RuntimeEnvironment.application;
- mController = new BubbleGlobalPreferenceController(mContext);
- when(mPreferenceScreen.findPreference(mController.getPreferenceKey()))
- .thenReturn(mPreference);
- mController.displayPreference(mPreferenceScreen);
- }
-
- @Test
- public void onPreferenceChange_settingEnabled_allowBubbles_shouldBeOn() {
- mController.onPreferenceChange(mPreference, true /* new value */);
-
- assertThat(isSettingEnabled()).isTrue();
- }
-
- @Test
- public void onPreferenceChange_settingDisabled_allowBubbles_shouldBeOff() {
- mController.onPreferenceChange(mPreference, false /* new value */);
-
- assertThat(isSettingEnabled()).isFalse();
- }
-
- @Test
- public void updateState_settingEnabled_preferenceShouldBeChecked() {
- Settings.Global.putInt(mContext.getContentResolver(),
- NOTIFICATION_BUBBLES, 1 /* enabled */);
- mController.updateState(mPreference);
-
- verify(mPreference).setChecked(true);
- }
-
- @Test
- public void updateState_settingReset_defaultDisabled_preferenceShouldNotBeChecked() {
- Settings.Global.putInt(mContext.getContentResolver(),
- NOTIFICATION_BUBBLES, 0 /* enabled */);
- mController.updateState(mPreference);
-
- verify(mPreference).setChecked(false);
- }
-
- @Test
- public void onDeveloperOptionsSwitchDisabled_shouldDisable() {
- mController.onDeveloperOptionsSwitchDisabled();
-
- verify(mPreference).setChecked(false);
- verify(mPreference).setEnabled(false);
-
- assertThat(isSettingEnabled()).isFalse();
- }
-
- private boolean isSettingEnabled() {
- return Settings.Global.getInt(mContext.getContentResolver(), NOTIFICATION_BUBBLES,
- OFF /* default off */) == ON;
- }
-
-}
diff --git a/tests/robotests/src/com/android/settings/network/AirplaneModePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/network/AirplaneModePreferenceControllerTest.java
index 54c36833d45..cb68e2a6aa9 100644
--- a/tests/robotests/src/com/android/settings/network/AirplaneModePreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/network/AirplaneModePreferenceControllerTest.java
@@ -102,8 +102,8 @@ public class AirplaneModePreferenceControllerTest {
mController.displayPreference(mScreen);
// This should not crash
- mController.onResume();
- mController.onPause();
+ mController.onStart();
+ mController.onStop();
}
@Test
@@ -115,8 +115,8 @@ public class AirplaneModePreferenceControllerTest {
mController.displayPreference(mScreen);
// This should not crash
- mController.onResume();
- mController.onPause();
+ mController.onStart();
+ mController.onStop();
}
@Test
@@ -147,7 +147,7 @@ public class AirplaneModePreferenceControllerTest {
Settings.Global.putInt(mResolver, Settings.Global.AIRPLANE_MODE_ON, ON);
mController.displayPreference(mScreen);
- mController.onResume();
+ mController.onStart();
assertThat(mController.isChecked()).isTrue();
@@ -161,7 +161,7 @@ public class AirplaneModePreferenceControllerTest {
Settings.Global.putInt(mResolver, Settings.Global.AIRPLANE_MODE_ON, OFF);
mController.displayPreference(mScreen);
- mController.onResume();
+ mController.onStop();
assertThat(mPreference.isChecked()).isFalse();
diff --git a/tests/robotests/src/com/android/settings/network/PreferredNetworkModeContentObserverTest.java b/tests/robotests/src/com/android/settings/network/PreferredNetworkModeContentObserverTest.java
new file mode 100644
index 00000000000..657b8b3dc9d
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/network/PreferredNetworkModeContentObserverTest.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2020 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.network;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
+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 org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
+
+@RunWith(RobolectricTestRunner.class)
+public class PreferredNetworkModeContentObserverTest {
+
+ private static final int SUB_ID = 1;
+
+ @Mock
+ private ContentResolver mResolver;
+ @Mock
+ private Context mContext;
+ @Mock
+ private PreferredNetworkModeContentObserver.OnPreferredNetworkModeChangedListener mListener;
+
+ private PreferredNetworkModeContentObserver mPreferredNetworkModeContentObserver;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ when(mContext.getContentResolver()).thenReturn(mResolver);
+ mPreferredNetworkModeContentObserver =
+ spy(new PreferredNetworkModeContentObserver(null));
+ }
+
+ @Test
+ public void onChange_shouldCallListener() {
+ mPreferredNetworkModeContentObserver.mListener = mListener;
+ mPreferredNetworkModeContentObserver.onChange(true);
+
+ verify(mListener).onPreferredNetworkModeChanged();
+ }
+
+ @Test
+ public void register_shouldRegisterContentObserver() {
+ mPreferredNetworkModeContentObserver.register(mContext, SUB_ID);
+
+ verify(mResolver).registerContentObserver(
+ Settings.Global.getUriFor(Settings.Global.PREFERRED_NETWORK_MODE + SUB_ID), false,
+ mPreferredNetworkModeContentObserver);
+ }
+
+ @Test
+ public void unregister_shouldUnregisterContentObserver() {
+ mPreferredNetworkModeContentObserver.unregister(mContext);
+
+ verify(mResolver).unregisterContentObserver(mPreferredNetworkModeContentObserver);
+ }
+
+}
diff --git a/tests/robotests/src/com/android/settings/network/telephony/gsm/AutoSelectPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/network/telephony/gsm/AutoSelectPreferenceControllerTest.java
index 0ae2dc6ec6e..d1a794d079d 100644
--- a/tests/robotests/src/com/android/settings/network/telephony/gsm/AutoSelectPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/network/telephony/gsm/AutoSelectPreferenceControllerTest.java
@@ -30,9 +30,11 @@ import android.telephony.CarrierConfigManager;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
+import androidx.lifecycle.LifecycleOwner;
import androidx.preference.SwitchPreference;
import com.android.settings.R;
+import com.android.settingslib.core.lifecycle.Lifecycle;
import org.junit.Before;
import org.junit.Test;
@@ -62,12 +64,16 @@ public class AutoSelectPreferenceControllerTest {
private AutoSelectPreferenceController mController;
private SwitchPreference mSwitchPreference;
private Context mContext;
+ private LifecycleOwner mLifecycleOwner;
+ private Lifecycle mLifecycle;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mContext = spy(RuntimeEnvironment.application);
+ mLifecycleOwner = () -> mLifecycle;
+ mLifecycle = new Lifecycle(mLifecycleOwner);
when(mContext.getSystemService(Context.TELEPHONY_SERVICE)).thenReturn(mTelephonyManager);
when(mContext.getSystemService(SubscriptionManager.class)).thenReturn(mSubscriptionManager);
when(mContext.getSystemService(CarrierConfigManager.class)).thenReturn(
@@ -83,7 +89,7 @@ public class AutoSelectPreferenceControllerTest {
mController = new AutoSelectPreferenceController(mContext, "auto_select");
mController.mProgressDialog = mProgressDialog;
mController.mSwitchPreference = mSwitchPreference;
- mController.init(SUB_ID);
+ mController.init(mLifecycle, SUB_ID);
}
@Test
@@ -125,6 +131,6 @@ public class AutoSelectPreferenceControllerTest {
when(mCarrierConfigManager.getConfigForSubId(SUB_ID)).thenReturn(null);
// Should not crash
- mController.init(SUB_ID);
+ mController.init(mLifecycle, SUB_ID);
}
}
diff --git a/tests/robotests/src/com/android/settings/network/telephony/gsm/OpenNetworkSelectPagePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/network/telephony/gsm/OpenNetworkSelectPagePreferenceControllerTest.java
index 5c182208d79..60de5aa146c 100644
--- a/tests/robotests/src/com/android/settings/network/telephony/gsm/OpenNetworkSelectPagePreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/network/telephony/gsm/OpenNetworkSelectPagePreferenceControllerTest.java
@@ -17,7 +17,7 @@
package com.android.settings.network.telephony.gsm;
import static com.google.common.truth.Truth.assertThat;
-import static org.mockito.Mockito.doReturn;
+
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;
@@ -29,11 +29,11 @@ import android.telephony.SubscriptionInfo;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
+import androidx.lifecycle.LifecycleOwner;
import androidx.preference.Preference;
import com.android.settings.R;
-import com.android.settings.network.telephony.MobileNetworkUtils;
-import java.util.Arrays;
+import com.android.settingslib.core.lifecycle.Lifecycle;
import org.junit.Before;
import org.junit.Test;
@@ -43,6 +43,8 @@ import org.mockito.MockitoAnnotations;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
+import java.util.Arrays;
+
@RunWith(RobolectricTestRunner.class)
public class OpenNetworkSelectPagePreferenceControllerTest {
private static final int SUB_ID = 2;
@@ -63,12 +65,16 @@ public class OpenNetworkSelectPagePreferenceControllerTest {
private OpenNetworkSelectPagePreferenceController mController;
private Preference mPreference;
private Context mContext;
+ private LifecycleOwner mLifecycleOwner;
+ private Lifecycle mLifecycle;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mContext = spy(RuntimeEnvironment.application);
+ mLifecycleOwner = () -> mLifecycle;
+ mLifecycle = new Lifecycle(mLifecycleOwner);
when(mContext.getSystemService(Context.TELEPHONY_SERVICE)).thenReturn(mTelephonyManager);
when(mContext.getSystemService(SubscriptionManager.class)).thenReturn(mSubscriptionManager);
when(mContext.getSystemService(CarrierConfigManager.class)).thenReturn(
@@ -92,7 +98,7 @@ public class OpenNetworkSelectPagePreferenceControllerTest {
mPreference = new Preference(mContext);
mController = new OpenNetworkSelectPagePreferenceController(mContext,
"open_network_select");
- mController.init(SUB_ID);
+ mController.init(mLifecycle, SUB_ID);
}
@Test
diff --git a/tests/robotests/src/com/android/settings/notification/BubbleNotificationPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/BubbleNotificationPreferenceControllerTest.java
new file mode 100644
index 00000000000..b2cf55b97b2
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/notification/BubbleNotificationPreferenceControllerTest.java
@@ -0,0 +1,138 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.notification;
+
+import static android.provider.Settings.Global.NOTIFICATION_BUBBLES;
+
+import static com.android.settings.core.BasePreferenceController.AVAILABLE;
+import static com.android.settings.notification.BadgingNotificationPreferenceController.OFF;
+import static com.android.settings.notification.BadgingNotificationPreferenceController.ON;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.provider.Settings;
+
+import androidx.preference.Preference;
+import androidx.preference.PreferenceScreen;
+import androidx.preference.TwoStatePreference;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Answers;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
+
+@RunWith(RobolectricTestRunner.class)
+public class BubbleNotificationPreferenceControllerTest {
+
+ private Context mContext;
+ @Mock(answer = Answers.RETURNS_DEEP_STUBS)
+ private PreferenceScreen mScreen;
+
+ private BubbleNotificationPreferenceController mController;
+ private Preference mPreference;
+
+ private static final String KEY_NOTIFICATION_BUBBLES = "notification_bubbles";
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ mContext = RuntimeEnvironment.application;
+ mController = new BubbleNotificationPreferenceController(mContext,
+ KEY_NOTIFICATION_BUBBLES);
+ mPreference = new Preference(RuntimeEnvironment.application);
+ mPreference.setKey(mController.getPreferenceKey());
+ when(mScreen.findPreference(mPreference.getKey())).thenReturn(mPreference);
+ }
+
+ @Test
+ public void getAvilabilityStatus_returnsAvailable() {
+ assertEquals(AVAILABLE, mController.getAvailabilityStatus());
+ }
+
+ @Test
+ public void updateState_settingIsOn_preferenceSetChecked() {
+ final TwoStatePreference preference = mock(TwoStatePreference.class);
+ Settings.Global.putInt(mContext.getContentResolver(), NOTIFICATION_BUBBLES, ON);
+
+ mController.updateState(preference);
+
+ verify(preference).setChecked(true);
+ }
+
+ @Test
+ public void updateState_settingIsOff_preferenceSetUnchecked() {
+ final TwoStatePreference preference = mock(TwoStatePreference.class);
+ Settings.Global.putInt(mContext.getContentResolver(), NOTIFICATION_BUBBLES, OFF);
+ assertThat(Settings.Global.getInt(mContext.getContentResolver(),
+ NOTIFICATION_BUBBLES, ON)).isEqualTo(OFF);
+
+ mController.updateState(preference);
+
+ verify(preference).setChecked(false);
+ }
+
+ @Test
+ public void isChecked_settingIsOff_shouldReturnFalse() {
+ Settings.Global.putInt(mContext.getContentResolver(), NOTIFICATION_BUBBLES, OFF);
+
+ assertThat(mController.isChecked()).isFalse();
+ }
+
+ @Test
+ public void isChecked_settingIsOn_shouldReturnTrue() {
+ Settings.Global.putInt(mContext.getContentResolver(), NOTIFICATION_BUBBLES, ON);
+
+ assertThat(mController.isChecked()).isTrue();
+ }
+
+ @Test
+ public void setChecked_setFalse_disablesSetting() {
+ Settings.Global.putInt(mContext.getContentResolver(), NOTIFICATION_BUBBLES, ON);
+
+ mController.setChecked(false);
+ int updatedValue = Settings.Global.getInt(mContext.getContentResolver(),
+ NOTIFICATION_BUBBLES, -1);
+
+ assertThat(updatedValue).isEqualTo(OFF);
+ }
+
+ @Test
+ public void setChecked_setTrue_enablesSetting() {
+ Settings.Global.putInt(mContext.getContentResolver(), NOTIFICATION_BUBBLES, OFF);
+
+ mController.setChecked(true);
+ int updatedValue = Settings.Global.getInt(mContext.getContentResolver(),
+ NOTIFICATION_BUBBLES, -1);
+
+ assertThat(updatedValue).isEqualTo(ON);
+ }
+
+ @Test
+ public void isSliceable_returnsFalse() {
+ assertThat(mController.isSliceable()).isFalse();
+ }
+}
diff --git a/tests/robotests/src/com/android/settings/notification/BubbleSummaryNotificationPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/BubbleSummaryNotificationPreferenceControllerTest.java
new file mode 100644
index 00000000000..b5f505b6e82
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/notification/BubbleSummaryNotificationPreferenceControllerTest.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.notification;
+
+import static android.provider.Settings.Global.NOTIFICATION_BUBBLES;
+
+import static com.android.settings.notification.BadgingNotificationPreferenceController.OFF;
+import static com.android.settings.notification.BadgingNotificationPreferenceController.ON;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.content.Context;
+import android.provider.Settings;
+
+import androidx.preference.Preference;
+
+import com.android.settings.R;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
+
+@RunWith(RobolectricTestRunner.class)
+public class BubbleSummaryNotificationPreferenceControllerTest {
+
+ private Context mContext;
+
+ private BubbleSummaryNotificationPreferenceController mController;
+ private Preference mPreference;
+
+ private static final String KEY_NOTIFICATION_BUBBLES = "notification_bubbles";
+
+ @Before
+ public void setUp() {
+ mContext = RuntimeEnvironment.application;
+ mController = new BubbleSummaryNotificationPreferenceController(mContext,
+ KEY_NOTIFICATION_BUBBLES);
+ mPreference = new Preference(RuntimeEnvironment.application);
+ }
+
+ @Test
+ public void getSummary_NOTIFICATION_BUBBLESIsOff_returnOffString() {
+ Settings.Global.putInt(mContext.getContentResolver(), NOTIFICATION_BUBBLES, OFF);
+
+ assertThat(mController.getSummary()).isEqualTo("Off");
+ }
+
+ @Test
+ public void getSummary_NOTIFICATION_BUBBLESIsOff_returnOnString() {
+ Settings.Global.putInt(mContext.getContentResolver(), NOTIFICATION_BUBBLES, ON);
+
+ String onString = mContext.getString(R.string.notifications_bubble_setting_on_summary);
+ assertThat(mController.getSummary()).isEqualTo(onString);
+ }
+}
diff --git a/tests/robotests/src/com/android/settings/notification/app/BubblePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/app/BubblePreferenceControllerTest.java
index c2c45cb1707..0cf6dc67829 100644
--- a/tests/robotests/src/com/android/settings/notification/app/BubblePreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/notification/app/BubblePreferenceControllerTest.java
@@ -17,6 +17,9 @@
package com.android.settings.notification.app;
import static android.app.NotificationChannel.DEFAULT_CHANNEL_ID;
+import static android.app.NotificationManager.BUBBLE_PREFERENCE_ALL;
+import static android.app.NotificationManager.BUBBLE_PREFERENCE_NONE;
+import static android.app.NotificationManager.BUBBLE_PREFERENCE_SELECTED;
import static android.app.NotificationManager.IMPORTANCE_HIGH;
import static android.app.NotificationManager.IMPORTANCE_LOW;
import static android.app.NotificationManager.IMPORTANCE_NONE;
@@ -25,8 +28,8 @@ import static android.provider.Settings.Global.NOTIFICATION_BUBBLES;
import static com.android.settings.notification.app.BubblePreferenceController.SYSTEM_WIDE_OFF;
import static com.android.settings.notification.app.BubblePreferenceController.SYSTEM_WIDE_ON;
+import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
@@ -44,6 +47,11 @@ import android.content.Context;
import android.os.UserManager;
import android.provider.Settings;
+import androidx.fragment.app.FragmentManager;
+import androidx.fragment.app.FragmentTransaction;
+import androidx.preference.Preference;
+import androidx.preference.PreferenceScreen;
+
import com.android.settings.notification.NotificationBackend;
import com.android.settingslib.RestrictedLockUtils;
import com.android.settingslib.RestrictedSwitchPreference;
@@ -58,11 +66,6 @@ import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.shadows.ShadowApplication;
-import androidx.fragment.app.FragmentManager;
-import androidx.fragment.app.FragmentTransaction;
-import androidx.preference.Preference;
-import androidx.preference.PreferenceScreen;
-
@RunWith(RobolectricTestRunner.class)
public class BubblePreferenceControllerTest {
@@ -125,7 +128,7 @@ public class BubblePreferenceControllerTest {
public void testIsAvailable_channel_yesIfAppOff() {
Settings.Global.putInt(mContext.getContentResolver(), NOTIFICATION_BUBBLES, SYSTEM_WIDE_ON);
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
- appRow.allowBubbles = false;
+ appRow.bubblePreference = BUBBLE_PREFERENCE_NONE;
NotificationChannel channel = mock(NotificationChannel.class);
when(channel.getImportance()).thenReturn(IMPORTANCE_HIGH);
mController.onResume(appRow, channel, null, null, null, null);
@@ -177,7 +180,7 @@ public class BubblePreferenceControllerTest {
@Test
public void testIsAvailable_defaultChannel() {
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
- appRow.allowBubbles = true;
+ appRow.bubblePreference = BUBBLE_PREFERENCE_ALL;
NotificationChannel channel = mock(NotificationChannel.class);
when(channel.getImportance()).thenReturn(IMPORTANCE_HIGH);
when(channel.getId()).thenReturn(DEFAULT_CHANNEL_ID);
@@ -190,7 +193,7 @@ public class BubblePreferenceControllerTest {
@Test
public void testIsAvailable_channel() {
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
- appRow.allowBubbles = true;
+ appRow.bubblePreference = BUBBLE_PREFERENCE_ALL;
NotificationChannel channel = mock(NotificationChannel.class);
when(channel.getImportance()).thenReturn(IMPORTANCE_HIGH);
mController.onResume(appRow, channel, null, null, null, null);
@@ -213,7 +216,20 @@ public class BubblePreferenceControllerTest {
}
@Test
- public void testUpdateState_channelNotBlockable() {
+ public void testUpdateState_app_disabledByAdmin() {
+ NotificationChannel channel = mock(NotificationChannel.class);
+ when(channel.getId()).thenReturn("something");
+ mAppPageController.onResume(new NotificationBackend.AppRow(), channel, null,
+ null, null, mock(RestrictedLockUtils.EnforcedAdmin.class));
+
+ BubblePreference pref = new BubblePreference(mContext);
+ mAppPageController.updateState(pref);
+
+ assertFalse(pref.isEnabled());
+ }
+
+ @Test
+ public void testUpdateState_channel_channelNotBlockable() {
Settings.Global.putInt(mContext.getContentResolver(), NOTIFICATION_BUBBLES, SYSTEM_WIDE_ON);
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
NotificationChannel channel = mock(NotificationChannel.class);
@@ -251,21 +267,24 @@ public class BubblePreferenceControllerTest {
Settings.Global.putInt(mContext.getContentResolver(), NOTIFICATION_BUBBLES, SYSTEM_WIDE_ON);
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
appRow.label = "App!";
- appRow.allowBubbles = true;
- mController.onResume(appRow, null, null, null, null, null);
+ appRow.bubblePreference = BUBBLE_PREFERENCE_ALL;
+ mAppPageController.onResume(appRow, null, null, null, null, null);
- RestrictedSwitchPreference pref = new RestrictedSwitchPreference(mContext);
- mController.updateState(pref);
- assertTrue(pref.isChecked());
+ BubblePreference pref = new BubblePreference(mContext);
+ mAppPageController.updateState(pref);
+ assertEquals(BUBBLE_PREFERENCE_ALL, pref.getSelectedPreference());
- appRow.allowBubbles = false;
- mController.onResume(appRow, null, null, null, null, null);
+ appRow.bubblePreference = BUBBLE_PREFERENCE_NONE;
+ mAppPageController.onResume(appRow, null, null, null, null, null);
- mController.updateState(pref);
- assertFalse(pref.isChecked());
+ mAppPageController.updateState(pref);
+ assertEquals(BUBBLE_PREFERENCE_NONE, pref.getSelectedPreference());
- assertNotNull(pref.getSummary());
- assertTrue(pref.getSummary().toString().contains(appRow.label));
+ appRow.bubblePreference = BUBBLE_PREFERENCE_SELECTED;
+ mAppPageController.onResume(appRow, null, null, null, null, null);
+
+ mAppPageController.updateState(pref);
+ assertEquals(BUBBLE_PREFERENCE_SELECTED, pref.getSelectedPreference());
}
@Test
@@ -274,22 +293,21 @@ public class BubblePreferenceControllerTest {
NOTIFICATION_BUBBLES, SYSTEM_WIDE_OFF);
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
appRow.label = "App!";
- appRow.allowBubbles = true;
- mController.onResume(appRow, null, null, null, null, null);
+ appRow.bubblePreference = BUBBLE_PREFERENCE_ALL;
+ mAppPageController.onResume(appRow, null, null, null, null, null);
- RestrictedSwitchPreference pref = new RestrictedSwitchPreference(mContext);
- mController.updateState(pref);
- assertFalse(pref.isChecked());
+ BubblePreference pref = new BubblePreference(mContext);
+ mAppPageController.updateState(pref);
+ assertEquals(BUBBLE_PREFERENCE_NONE, pref.getSelectedPreference());
}
@Test
public void testOnPreferenceChange_on_channel() {
Settings.Global.putInt(mContext.getContentResolver(), NOTIFICATION_BUBBLES, SYSTEM_WIDE_ON);
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
- appRow.allowBubbles = true;
+ appRow.bubblePreference = BUBBLE_PREFERENCE_SELECTED;
NotificationChannel channel =
new NotificationChannel(DEFAULT_CHANNEL_ID, "a", IMPORTANCE_LOW);
- channel.setAllowBubbles(false);
mController.onResume(appRow, channel, null, null, null, null);
RestrictedSwitchPreference pref = new RestrictedSwitchPreference(mContext);
@@ -306,10 +324,9 @@ public class BubblePreferenceControllerTest {
public void testOnPreferenceChange_off_channel() {
Settings.Global.putInt(mContext.getContentResolver(), NOTIFICATION_BUBBLES, SYSTEM_WIDE_ON);
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
- appRow.allowBubbles = true;
+ appRow.bubblePreference = BUBBLE_PREFERENCE_SELECTED;
NotificationChannel channel =
new NotificationChannel(DEFAULT_CHANNEL_ID, "a", IMPORTANCE_HIGH);
- channel.setAllowBubbles(true);
mController.onResume(appRow, channel, null, null, null, null);
RestrictedSwitchPreference pref = new RestrictedSwitchPreference(mContext);
@@ -322,59 +339,78 @@ public class BubblePreferenceControllerTest {
assertFalse(channel.canBubble());
}
+
@Test
- public void testOnPreferenceChange_on_app() {
+ public void testOnPreferenceChange_app_all() {
Settings.Global.putInt(mContext.getContentResolver(), NOTIFICATION_BUBBLES, SYSTEM_WIDE_ON);
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
- appRow.allowBubbles = false;
- mController.onResume(appRow, null, null, null, null, null);
+ appRow.bubblePreference = BUBBLE_PREFERENCE_NONE;
+ mAppPageController.onResume(appRow, null, null, null, null, null);
- RestrictedSwitchPreference pref = new RestrictedSwitchPreference(mContext);
+ BubblePreference pref = new BubblePreference(mContext);
when(mScreen.findPreference(mController.getPreferenceKey())).thenReturn(pref);
- mController.displayPreference(mScreen);
- mController.updateState(pref);
+ mAppPageController.displayPreference(mScreen);
+ mAppPageController.updateState(pref);
- mController.onPreferenceChange(pref, true);
+ mAppPageController.onPreferenceChange(pref, BUBBLE_PREFERENCE_ALL);
- assertTrue(appRow.allowBubbles);
- verify(mBackend, times(1)).setAllowBubbles(any(), anyInt(), eq(true));
+ assertEquals(appRow.bubblePreference, BUBBLE_PREFERENCE_ALL);
+ verify(mBackend, times(1)).setAllowBubbles(any(), anyInt(), eq(BUBBLE_PREFERENCE_ALL));
}
@Test
- public void testOnPreferenceChange_off_app() {
- Settings.Global.putInt(mContext.getContentResolver(), NOTIFICATION_BUBBLES, SYSTEM_WIDE_ON);
- NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
- appRow.allowBubbles = true;
- mController.onResume(appRow, null, null, null, null, null);
-
- RestrictedSwitchPreference pref = new RestrictedSwitchPreference(mContext);
- when(mScreen.findPreference(mController.getPreferenceKey())).thenReturn(pref);
- mController.displayPreference(mScreen);
- mController.updateState(pref);
-
- mController.onPreferenceChange(pref, false);
-
- assertFalse(appRow.allowBubbles);
- verify(mBackend, times(1)).setAllowBubbles(any(), anyInt(), eq(false));
- }
-
- @Test
- public void testOnPreferenceChange_on_app_offGlobally() {
+ public void testOnPreferenceChange_app_all_offGlobally() {
Settings.Global.putInt(mContext.getContentResolver(), NOTIFICATION_BUBBLES,
SYSTEM_WIDE_OFF);
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
- appRow.allowBubbles = false;
- mController.onResume(appRow, null, null, null, null, null);
+ appRow.bubblePreference = BUBBLE_PREFERENCE_NONE;
+ mAppPageController.onResume(appRow, null, null, null, null, null);
- RestrictedSwitchPreference pref = new RestrictedSwitchPreference(mContext);
+ BubblePreference pref = new BubblePreference(mContext);
when(mScreen.findPreference(mController.getPreferenceKey())).thenReturn(pref);
- mController.displayPreference(mScreen);
- mController.updateState(pref);
+ mAppPageController.displayPreference(mScreen);
+ mAppPageController.updateState(pref);
- mController.onPreferenceChange(pref, true);
+ mAppPageController.onPreferenceChange(pref, BUBBLE_PREFERENCE_ALL);
- assertFalse(appRow.allowBubbles);
- verify(mBackend, never()).setAllowBubbles(any(), anyInt(), eq(true));
+ assertEquals(appRow.bubblePreference, BUBBLE_PREFERENCE_NONE);
+ verify(mBackend, never()).setAllowBubbles(any(), anyInt(), eq(BUBBLE_PREFERENCE_ALL));
verify(mFragmentManager, times(1)).beginTransaction();
}
+
+ @Test
+ public void testOnPreferenceChange_app_selected() {
+ Settings.Global.putInt(mContext.getContentResolver(), NOTIFICATION_BUBBLES, SYSTEM_WIDE_ON);
+ NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
+ appRow.bubblePreference = BUBBLE_PREFERENCE_ALL;
+ mAppPageController.onResume(appRow, null, null, null, null, null);
+
+ BubblePreference pref = new BubblePreference(mContext);
+ when(mScreen.findPreference(mController.getPreferenceKey())).thenReturn(pref);
+ mAppPageController.displayPreference(mScreen);
+ mAppPageController.updateState(pref);
+
+ mAppPageController.onPreferenceChange(pref, BUBBLE_PREFERENCE_NONE);
+
+ assertEquals(BUBBLE_PREFERENCE_NONE, appRow.bubblePreference);
+ verify(mBackend, times(1)).setAllowBubbles(any(), anyInt(), eq(BUBBLE_PREFERENCE_NONE));
+ }
+
+ @Test
+ public void testOnPreferenceChange_app_none() {
+ Settings.Global.putInt(mContext.getContentResolver(), NOTIFICATION_BUBBLES, SYSTEM_WIDE_ON);
+ NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
+ appRow.bubblePreference = BUBBLE_PREFERENCE_ALL;
+ mAppPageController.onResume(appRow, null, null, null, null, null);
+
+ BubblePreference pref = new BubblePreference(mContext);
+ when(mScreen.findPreference(mController.getPreferenceKey())).thenReturn(pref);
+ mAppPageController.displayPreference(mScreen);
+ mAppPageController.updateState(pref);
+
+ mAppPageController.onPreferenceChange(pref, BUBBLE_PREFERENCE_NONE);
+
+ assertEquals(BUBBLE_PREFERENCE_NONE, appRow.bubblePreference);
+ verify(mBackend, times(1)).setAllowBubbles(any(), anyInt(), eq(BUBBLE_PREFERENCE_NONE));
+ }
}
diff --git a/tests/robotests/src/com/android/settings/notification/app/BubbleSummaryPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/app/BubbleSummaryPreferenceControllerTest.java
index 80abfbb5f20..9d664ac02c8 100644
--- a/tests/robotests/src/com/android/settings/notification/app/BubbleSummaryPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/notification/app/BubbleSummaryPreferenceControllerTest.java
@@ -17,28 +17,31 @@
package com.android.settings.notification.app;
import static android.app.NotificationChannel.DEFAULT_CHANNEL_ID;
+import static android.app.NotificationManager.BUBBLE_PREFERENCE_ALL;
+import static android.app.NotificationManager.BUBBLE_PREFERENCE_NONE;
+import static android.app.NotificationManager.BUBBLE_PREFERENCE_SELECTED;
import static android.app.NotificationManager.IMPORTANCE_HIGH;
import static android.provider.Settings.Global.NOTIFICATION_BUBBLES;
-import static com.android.settings.notification.app.BubbleSummaryPreferenceController.SYSTEM_WIDE_OFF;
-import static com.android.settings.notification.app.BubbleSummaryPreferenceController.SYSTEM_WIDE_ON;
+import static com.android.settings.notification.app.BubblePreferenceController.SYSTEM_WIDE_OFF;
+import static com.android.settings.notification.app.BubblePreferenceController.SYSTEM_WIDE_ON;
import static junit.framework.TestCase.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.app.NotificationChannel;
import android.content.Context;
import android.provider.Settings;
+import androidx.preference.Preference;
+
+import com.android.settings.R;
import com.android.settings.notification.NotificationBackend;
import org.junit.Before;
@@ -50,8 +53,6 @@ import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.shadows.ShadowApplication;
-import androidx.preference.Preference;
-
@RunWith(RobolectricTestRunner.class)
public class BubbleSummaryPreferenceControllerTest {
@@ -70,13 +71,13 @@ public class BubbleSummaryPreferenceControllerTest {
}
@Test
- public void testNoCrashIfNoOnResume() {
+ public void isAvailable_noOnResume_shouldNotCrash() {
mController.isAvailable();
mController.updateState(mock(Preference.class));
}
@Test
- public void testIsAvailable_notIfAppBlocked() {
+ public void isAvailable_appBlocked_shouldReturnFalse() {
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
appRow.banned = true;
mController.onResume(appRow, mock(NotificationChannel.class), null, null, null, null);
@@ -84,53 +85,52 @@ public class BubbleSummaryPreferenceControllerTest {
}
@Test
- public void testIsAvailable_notIfOffGlobally() {
- NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
- NotificationChannel channel = mock(NotificationChannel.class);
- when(channel.getImportance()).thenReturn(IMPORTANCE_HIGH);
- mController.onResume(appRow, channel, null, null, null, null);
- Settings.Global.putInt(mContext.getContentResolver(), NOTIFICATION_BUBBLES,
- SYSTEM_WIDE_OFF);
-
- assertFalse(mController.isAvailable());
- }
-
- @Test
- public void testIsAvailable_app() {
+ public void isAvailable_nullChannelNOTIFICATION_BUBBLESisOn_shouldReturnTrue() {
+ Settings.Global.putInt(mContext.getContentResolver(), NOTIFICATION_BUBBLES, SYSTEM_WIDE_ON);
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
mController.onResume(appRow, null, null, null, null, null);
- Settings.Global.putInt(mContext.getContentResolver(), NOTIFICATION_BUBBLES, SYSTEM_WIDE_ON);
assertTrue(mController.isAvailable());
}
@Test
- public void testIsNotAvailable_app_globalOff() {
- NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
- mController.onResume(appRow, null, null, null, null, null);
+ public void isAvailable_nullChannelNOTIFICATION_BUBBLESisOff_shouldReturnFalse() {
Settings.Global.putInt(mContext.getContentResolver(), NOTIFICATION_BUBBLES,
SYSTEM_WIDE_OFF);
+ NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
+ mController.onResume(appRow, null, null, null, null, null);
assertFalse(mController.isAvailable());
}
@Test
- public void testIsAvailable_defaultChannel() {
+ public void isAvailable_nonNullChannelNOTIFICATION_BUBBLESisOff_shouldReturnFalse() {
+ Settings.Global.putInt(mContext.getContentResolver(), NOTIFICATION_BUBBLES,
+ SYSTEM_WIDE_OFF);
+ NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
+ NotificationChannel channel = mock(NotificationChannel.class);
+ when(channel.getImportance()).thenReturn(IMPORTANCE_HIGH);
+ mController.onResume(appRow, channel, null, null, null, null);
+
+ assertFalse(mController.isAvailable());
+ }
+
+ @Test
+ public void isAvailable_defaultChannelNOTIFICATION_BUBBLESisOn_shouldReturnTrue() {
+ Settings.Global.putInt(mContext.getContentResolver(), NOTIFICATION_BUBBLES, SYSTEM_WIDE_ON);
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
- appRow.allowBubbles = true;
NotificationChannel channel = mock(NotificationChannel.class);
when(channel.getImportance()).thenReturn(IMPORTANCE_HIGH);
when(channel.getId()).thenReturn(DEFAULT_CHANNEL_ID);
mController.onResume(appRow, channel, null, null, null, null);
- Settings.Global.putInt(mContext.getContentResolver(), NOTIFICATION_BUBBLES, SYSTEM_WIDE_ON);
assertTrue(mController.isAvailable());
}
@Test
- public void testUpdateState() {
+ public void updateState_setsIntent() {
NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
- appRow.allowBubbles = true;
+ appRow.bubblePreference = BUBBLE_PREFERENCE_ALL;
mController.onResume(appRow, null, null, null, null, null);
Preference pref = new Preference(mContext);
@@ -139,22 +139,53 @@ public class BubbleSummaryPreferenceControllerTest {
}
@Test
- public void testGetSummary() {
- Settings.Global.putInt(mContext.getContentResolver(), NOTIFICATION_BUBBLES, SYSTEM_WIDE_ON);
- NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
- appRow.allowBubbles = true;
- mController.onResume(appRow, null, null, null, null, null);
-
- assertEquals("On", mController.getSummary());
-
+ public void getSummary_NOTIFICATION_BUBBLESIsOff_returnsNoneString() {
Settings.Global.putInt(mContext.getContentResolver(), NOTIFICATION_BUBBLES,
SYSTEM_WIDE_OFF);
- assertEquals("Off", mController.getSummary());
- Settings.Global.putInt(mContext.getContentResolver(), NOTIFICATION_BUBBLES, SYSTEM_WIDE_ON);
- appRow.allowBubbles = false;
+ NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
mController.onResume(appRow, null, null, null, null, null);
- assertEquals("Off", mController.getSummary());
+ String noneString = mContext.getString(R.string.bubble_app_setting_none);
+ assertEquals(noneString, mController.getSummary());
+ }
+
+ @Test
+ public void getSummary_BUBBLE_PREFERENCE_NONEisSelected_returnsNoneString() {
+ Settings.Global.putInt(mContext.getContentResolver(), NOTIFICATION_BUBBLES,
+ SYSTEM_WIDE_ON);
+
+ NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
+ appRow.bubblePreference = BUBBLE_PREFERENCE_NONE;
+ mController.onResume(appRow, null, null, null, null, null);
+
+ String noneString = mContext.getString(R.string.bubble_app_setting_none);
+ assertEquals(noneString, mController.getSummary());
+ }
+
+ @Test
+ public void getSummary_BUBBLE_PREFERENCE_ALLisSelected_returnsAllString() {
+ Settings.Global.putInt(mContext.getContentResolver(), NOTIFICATION_BUBBLES,
+ SYSTEM_WIDE_ON);
+
+ NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
+ appRow.bubblePreference = BUBBLE_PREFERENCE_ALL;
+ mController.onResume(appRow, null, null, null, null, null);
+
+ String allString = mContext.getString(R.string.bubble_app_setting_all);
+ assertEquals(allString, mController.getSummary());
+ }
+
+ @Test
+ public void getSummary_BUBBLE_PREFERENCE_SELECTEDisSelected_returnsSelectedString() {
+ Settings.Global.putInt(mContext.getContentResolver(), NOTIFICATION_BUBBLES,
+ SYSTEM_WIDE_ON);
+
+ NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
+ appRow.bubblePreference = BUBBLE_PREFERENCE_SELECTED;
+ mController.onResume(appRow, null, null, null, null, null);
+
+ String selectedString = mContext.getString(R.string.bubble_app_setting_selected);
+ assertEquals(selectedString, mController.getSummary());
}
}