Zen upgrade notification
Test: runtest --path /extra/master/frameworks/base/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
Change-Id: Ia31f89af74d9bcee40e050bd6cc13f1e6a9a15d9
Fixes: 73000503
Fixes: 72876890
Fixes: 73110052
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index fef6495..8ab8361 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -12134,6 +12134,12 @@
* @hide
*/
public static final String SHOW_MUTE_IN_CRASH_DIALOG = "show_mute_in_crash_dialog";
+
+ /**
+ * If nonzero, will show the zen upgrade notification when the user toggles DND on/off.
+ * @hide
+ */
+ public static final String SHOW_ZEN_UPGRADE_NOTIFICATION = "show_zen_upgrade_notification";
}
/**
diff --git a/core/java/android/service/notification/ZenModeConfig.java b/core/java/android/service/notification/ZenModeConfig.java
index d66322c..171d4d9 100644
--- a/core/java/android/service/notification/ZenModeConfig.java
+++ b/core/java/android/service/notification/ZenModeConfig.java
@@ -94,7 +94,7 @@
private static final boolean DEFAULT_ALLOW_SCREEN_OFF = true;
private static final boolean DEFAULT_ALLOW_SCREEN_ON = true;
- private static final int XML_VERSION = 2;
+ public static final int XML_VERSION = 3;
public static final String ZEN_TAG = "zen";
private static final String ZEN_ATT_VERSION = "version";
private static final String ZEN_ATT_USER = "user";
@@ -145,6 +145,7 @@
public int user = UserHandle.USER_SYSTEM;
public boolean allowWhenScreenOff = DEFAULT_ALLOW_SCREEN_OFF;
public boolean allowWhenScreenOn = DEFAULT_ALLOW_SCREEN_ON;
+ public int version;
public ZenRule manualRule;
public ArrayMap<String, ZenRule> automaticRules = new ArrayMap<>();
@@ -431,6 +432,7 @@
String tag = parser.getName();
if (!ZEN_TAG.equals(tag)) return null;
final ZenModeConfig rt = new ZenModeConfig();
+ rt.version = safeInt(parser, ZEN_ATT_VERSION, XML_VERSION);
rt.user = safeInt(parser, ZEN_ATT_USER, rt.user);
while ((type = parser.next()) != XmlPullParser.END_DOCUMENT) {
tag = parser.getName();
diff --git a/core/java/com/android/internal/notification/SystemNotificationChannels.java b/core/java/com/android/internal/notification/SystemNotificationChannels.java
index 4a181b2..44adbb2 100644
--- a/core/java/com/android/internal/notification/SystemNotificationChannels.java
+++ b/core/java/com/android/internal/notification/SystemNotificationChannels.java
@@ -49,6 +49,7 @@
public static String USB = "USB";
public static String FOREGROUND_SERVICE = "FOREGROUND_SERVICE";
public static String HEAVY_WEIGHT_APP = "HEAVY_WEIGHT_APP";
+ public static String SYSTEM_CHANGES = "SYSTEM_CHANGES";
public static void createAll(Context context) {
final NotificationManager nm = context.getSystemService(NotificationManager.class);
@@ -152,6 +153,11 @@
.build());
channelsList.add(heavyWeightChannel);
+ NotificationChannel systemChanges = new NotificationChannel(SYSTEM_CHANGES,
+ context.getString(R.string.notification_channel_system_changes),
+ NotificationManager.IMPORTANCE_LOW);
+ channelsList.add(systemChanges);
+
nm.createNotificationChannels(channelsList);
}
diff --git a/core/proto/android/providers/settings.proto b/core/proto/android/providers/settings.proto
index f2b7ab2..52ee9e8 100644
--- a/core/proto/android/providers/settings.proto
+++ b/core/proto/android/providers/settings.proto
@@ -426,10 +426,11 @@
optional SettingProto show_first_crash_dialog = 349 [ (android.privacy).dest = DEST_AUTOMATIC ];
optional SettingProto show_restart_in_crash_dialog = 351 [ (android.privacy).dest = DEST_AUTOMATIC ];
optional SettingProto show_mute_in_crash_dialog = 352 [ (android.privacy).dest = DEST_AUTOMATIC ];
+ optional SettingsProto show_zen_upgrade_notification = 354 [ (android.privacy).dest = DEST_AUTOMATIC ];
// Please insert fields in the same order as in
// frameworks/base/core/java/android/provider/Settings.java.
- // Next tag = 354;
+ // Next tag = 355;
}
message SecureSettingsProto {
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index ec81df7..0efb6f9 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -4854,4 +4854,11 @@
<!-- Notification action for editing a screenshot (drawing on it, cropping it, etc) -->
<string name="screenshot_edit">Edit</string>
+
+ <!-- Title for the notification channel notifying user of settings system changes (i.e. Do Not Disturb has changed). [CHAR LIMIT=NONE] -->
+ <string name="notification_channel_system_changes">System changes</string>
+ <!-- Title of notification indicating do not disturb settings have changed when upgrading to P -->
+ <string name="zen_upgrade_notification_title">Do Not Disturb has changed</string>
+ <!-- Content of notification indicating users can tap on the notification to go to dnd behavior settings -->
+ <string name="zen_upgrade_notification_content">Tap to check your behavior settings for interruptions</string>
</resources>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index af25398..cbe0c69 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -3102,6 +3102,7 @@
<java-symbol type="string" name="notification_channel_retail_mode" />
<java-symbol type="string" name="notification_channel_usb" />
<java-symbol type="string" name="notification_channel_heavy_weight_app" />
+ <java-symbol type="string" name="notification_channel_system_changes" />
<java-symbol type="string" name="config_defaultAutofillService" />
<java-symbol type="string" name="config_defaultTextClassifierService" />
@@ -3257,4 +3258,7 @@
<!-- For Wear devices -->
<java-symbol type="array" name="config_wearActivityModeRadios" />
+
+ <java-symbol type="string" name="zen_upgrade_notification_title" />
+ <java-symbol type="string" name="zen_upgrade_notification_content" />
</resources>
diff --git a/core/res/res/xml/default_zen_mode_config.xml b/core/res/res/xml/default_zen_mode_config.xml
index a446088..7849a2a 100644
--- a/core/res/res/xml/default_zen_mode_config.xml
+++ b/core/res/res/xml/default_zen_mode_config.xml
@@ -18,7 +18,7 @@
-->
<!-- Default configuration for zen mode. See android.service.notification.ZenModeConfig. -->
-<zen version="2">
+<zen version="3">
<allow alarms="true" media_system_other="true" calls="false" messages="false" reminders="false"
events="false" />
</zen>
diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
index a0b6297..c36026c 100644
--- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java
+++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
@@ -354,6 +354,7 @@
Settings.Global.SHOW_NOTIFICATION_CHANNEL_WARNINGS,
Settings.Global.SHOW_RESTART_IN_CRASH_DIALOG,
Settings.Global.SHOW_TEMPERATURE_WARNING,
+ Settings.Global.SHOW_ZEN_UPGRADE_NOTIFICATION,
Settings.Global.SMART_SELECTION_UPDATE_CONTENT_URL,
Settings.Global.SMART_SELECTION_UPDATE_METADATA_URL,
Settings.Global.SMS_OUTGOING_CHECK_INTERVAL_MS,
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
index 1551b8e..6cf5eef 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
@@ -1123,6 +1123,9 @@
dumpSetting(s, p,
Settings.Global.SHOW_MUTE_IN_CRASH_DIALOG,
GlobalSettingsProto.SHOW_MUTE_IN_CRASH_DIALOG);
+ dumpSetting(s, p,
+ Settings.Global.SHOW_ZEN_UPGRADE_NOTIFICATION,
+ GlobalSettingsProto.SHOW_ZEN_UPGRADE_NOTIFICATION);
// Please insert new settings using the same order as in Settings.Global.
}
diff --git a/proto/src/system_messages.proto b/proto/src/system_messages.proto
index 08fdb97..608970f 100644
--- a/proto/src/system_messages.proto
+++ b/proto/src/system_messages.proto
@@ -204,6 +204,10 @@
// Package: android
NOTE_USB_TETHER = 47;
+ // Inform that DND settings have changed on OS upgrade
+ // Package: android
+ NOTE_ZEN_UPGRADE = 48;
+
// ADD_NEW_IDS_ABOVE_THIS_LINE
// Legacy IDs with arbitrary values appear below
// Legacy IDs existed as stable non-conflicting constants prior to the O release
@@ -253,6 +257,7 @@
// Notify the user about public volume state changes..
// Package: com.android.systemui
+
NOTE_STORAGE_PUBLIC = 0x53505542; // 1397773634
// Notify the user about private volume state changes.
diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java
index 7e3b551..44b83d8 100644
--- a/services/core/java/com/android/server/notification/ZenModeHelper.java
+++ b/services/core/java/com/android/server/notification/ZenModeHelper.java
@@ -18,8 +18,10 @@
import android.app.AppOpsManager;
import android.app.AutomaticZenRule;
+import android.app.Notification;
import android.app.NotificationManager;
import android.app.NotificationManager.Policy;
+import android.app.PendingIntent;
import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.Context;
@@ -44,6 +46,7 @@
import android.os.Process;
import android.os.SystemClock;
import android.os.UserHandle;
+import android.provider.Settings;
import android.provider.Settings.Global;
import android.service.notification.Condition;
import android.service.notification.ConditionProviderService;
@@ -61,6 +64,8 @@
import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.logging.MetricsLogger;
+import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
+import com.android.internal.notification.SystemNotificationChannels;
import com.android.server.LocalServices;
import libcore.io.IoUtils;
@@ -89,6 +94,7 @@
private final H mHandler;
private final SettingsObserver mSettingsObserver;
@VisibleForTesting protected final AppOpsManager mAppOps;
+ @VisibleForTesting protected final NotificationManager mNotificationManager;
protected ZenModeConfig mDefaultConfig;
private final ArrayList<Callback> mCallbacks = new ArrayList<Callback>();
private final ZenModeFiltering mFiltering;
@@ -112,12 +118,14 @@
protected String mDefaultRuleEveryNightName;
protected String mDefaultRuleEventsName;
+ @VisibleForTesting protected boolean mIsBootComplete;
public ZenModeHelper(Context context, Looper looper, ConditionProviders conditionProviders) {
mContext = context;
mHandler = new H(looper);
addCallback(mMetrics);
mAppOps = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
+ mNotificationManager = context.getSystemService(NotificationManager.class);
mDefaultConfig = new ZenModeConfig();
setDefaultZenRules(mContext);
@@ -197,6 +205,8 @@
mHandler.postMetricsTimer();
cleanUpZenRules();
evaluateZenMode("onSystemReady", true);
+ mIsBootComplete = true;
+ showZenUpgradeNotification(mZenMode);
}
public void onUserSwitched(int user) {
@@ -612,6 +622,10 @@
throws XmlPullParserException, IOException {
final ZenModeConfig config = ZenModeConfig.readXml(parser);
if (config != null) {
+ if (config.version < ZenModeConfig.XML_VERSION) {
+ Settings.Global.putInt(mContext.getContentResolver(),
+ Global.SHOW_ZEN_UPGRADE_NOTIFICATION, 1);
+ }
if (forRestore) {
//TODO: http://b/22388012
if (config.user != UserHandle.USER_SYSTEM) {
@@ -755,8 +769,10 @@
return Global.getInt(mContext.getContentResolver(), Global.ZEN_MODE, Global.ZEN_MODE_OFF);
}
- private void setZenModeSetting(int zen) {
+ @VisibleForTesting
+ protected void setZenModeSetting(int zen) {
Global.putInt(mContext.getContentResolver(), Global.ZEN_MODE, zen);
+ showZenUpgradeNotification(zen);
}
private int getPreviousRingerModeSetting() {
@@ -1139,6 +1155,41 @@
}
}
+ private void showZenUpgradeNotification(int zen) {
+ final boolean showNotification = mIsBootComplete
+ && zen == Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS
+ && Settings.Global.getInt(mContext.getContentResolver(),
+ Settings.Global.SHOW_ZEN_UPGRADE_NOTIFICATION, 0) != 0;
+
+ if (showNotification) {
+ mNotificationManager.notify(TAG, SystemMessage.NOTE_ZEN_UPGRADE,
+ createZenUpgradeNotification());
+ Settings.Global.putInt(mContext.getContentResolver(),
+ Global.SHOW_ZEN_UPGRADE_NOTIFICATION, 0);
+ }
+ }
+
+ @VisibleForTesting
+ protected Notification createZenUpgradeNotification() {
+ Intent intent = new Intent(Settings.ACTION_ZEN_MODE_PRIORITY_SETTINGS)
+ .setPackage("com.android.settings")
+ .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ final Bundle extras = new Bundle();
+ extras.putString(Notification.EXTRA_SUBSTITUTE_APP_NAME,
+ mContext.getResources().getString(R.string.global_action_settings));
+ return new Notification.Builder(mContext, SystemNotificationChannels.SYSTEM_CHANGES)
+ .setSmallIcon(R.drawable.ic_settings)
+ .setContentTitle(mContext.getResources().getString(
+ R.string.zen_upgrade_notification_title))
+ .setContentText(mContext.getResources().getString(
+ R.string.zen_upgrade_notification_content))
+ .setAutoCancel(true)
+ .setLocalOnly(true)
+ .addExtras(extras)
+ .setContentIntent(PendingIntent.getActivity(mContext, 0, intent, 0, null))
+ .build();
+ }
+
private final class Metrics extends Callback {
private static final String COUNTER_PREFIX = "dnd_mode_";
private static final long MINIMUM_LOG_PERIOD_MS = 60 * 1000;
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
index c532a8a..6144c51 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
@@ -17,21 +17,32 @@
package com.android.server.notification;
import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertEquals;
import static junit.framework.TestCase.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+import android.app.NotificationManager;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.res.Resources;
import android.media.AudioAttributes;
import android.provider.Settings;
import android.test.suitebuilder.annotation.SmallTest;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
+import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
import com.android.server.UiServiceTestCase;
import org.junit.Before;
@@ -46,15 +57,24 @@
public class ZenModeHelperTest extends UiServiceTestCase {
@Mock ConditionProviders mConditionProviders;
+ @Mock NotificationManager mNotificationManager;
+ @Mock private Resources mResources;
private TestableLooper mTestableLooper;
private ZenModeHelper mZenModeHelperSpy;
+ private Context mContext;
+ private ContentResolver mContentResolver;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mTestableLooper = TestableLooper.get(this);
- mZenModeHelperSpy = spy(new ZenModeHelper(getContext(), mTestableLooper.getLooper(),
+ mContext = spy(getContext());
+ mContentResolver = mContext.getContentResolver();
+ when(mContext.getResources()).thenReturn(mResources);
+ when(mContext.getSystemService(NotificationManager.class)).thenReturn(mNotificationManager);
+
+ mZenModeHelperSpy = spy(new ZenModeHelper(mContext, mTestableLooper.getLooper(),
mConditionProviders));
}
@@ -194,4 +214,31 @@
verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(shouldMute, usage);
}
}
+
+ @Test
+ public void testZenUpgradeNotification() {
+ // shows zen upgrade notification if stored settings says to shows, boot is completed
+ // and we're setting zen mode on
+ Settings.Global.putInt(mContentResolver, Settings.Global.SHOW_ZEN_UPGRADE_NOTIFICATION, 1);
+ mZenModeHelperSpy.mIsBootComplete = true;
+ mZenModeHelperSpy.setZenModeSetting(Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS);
+
+ verify(mZenModeHelperSpy, times(1)).createZenUpgradeNotification();
+ verify(mNotificationManager, times(1)).notify(eq(ZenModeHelper.TAG),
+ eq(SystemMessage.NOTE_ZEN_UPGRADE), any());
+ assertEquals(0, Settings.Global.getInt(mContentResolver,
+ Settings.Global.SHOW_ZEN_UPGRADE_NOTIFICATION, -1));
+ }
+
+ @Test
+ public void testNoZenUpgradeNotification() {
+ // doesn't show upgrade notification if stored settings says don't show
+ Settings.Global.putInt(mContentResolver, Settings.Global.SHOW_ZEN_UPGRADE_NOTIFICATION, 0);
+ mZenModeHelperSpy.mIsBootComplete = true;
+ mZenModeHelperSpy.setZenModeSetting(Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS);
+
+ verify(mZenModeHelperSpy, never()).createZenUpgradeNotification();
+ verify(mNotificationManager, never()).notify(eq(ZenModeHelper.TAG),
+ eq(SystemMessage.NOTE_ZEN_UPGRADE), any());
+ }
}