diff options
12 files changed, 138 insertions, 5 deletions
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index fef6495e5c88..8ab8361086d7 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -12134,6 +12134,12 @@ public final class Settings { * @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 d66322c3aa89..171d4d938beb 100644 --- a/core/java/android/service/notification/ZenModeConfig.java +++ b/core/java/android/service/notification/ZenModeConfig.java @@ -94,7 +94,7 @@ public class ZenModeConfig implements Parcelable { 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 class ZenModeConfig implements Parcelable { 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 @@ public class ZenModeConfig implements Parcelable { 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 4a181b27b2e3..44adbb22eb7e 100644 --- a/core/java/com/android/internal/notification/SystemNotificationChannels.java +++ b/core/java/com/android/internal/notification/SystemNotificationChannels.java @@ -49,6 +49,7 @@ public class SystemNotificationChannels { 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 @@ public class SystemNotificationChannels { .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 f2b7ab297e20..52ee9e82646f 100644 --- a/core/proto/android/providers/settings.proto +++ b/core/proto/android/providers/settings.proto @@ -426,10 +426,11 @@ message GlobalSettingsProto { 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 ec81df7b89e2..0efb6f91fce0 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 a86f58a52685..5a9dc7fa92be 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -3103,6 +3103,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" /> @@ -3258,4 +3259,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 a446088fb93d..7849a2ace638 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 a0b6297db235..c36026c5b1e5 100644 --- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java +++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java @@ -354,6 +354,7 @@ public class SettingsBackupTest { 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 1551b8e2eea9..6cf5eef6469c 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 @@ class SettingsProtoDumpUtil { 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 08fdb9775d0a..608970f59a66 100644 --- a/proto/src/system_messages.proto +++ b/proto/src/system_messages.proto @@ -204,6 +204,10 @@ message SystemMessage { // 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 @@ message SystemMessage { // 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 7e3b5516b8cc..44b83d8cf759 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 @@ package com.android.server.notification; 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.Message; 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 android.util.proto.ProtoOutputStream; 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 @@ public class ZenModeHelper { 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 @@ public class ZenModeHelper { 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 @@ public class ZenModeHelper { mHandler.postMetricsTimer(); cleanUpZenRules(); evaluateZenMode("onSystemReady", true); + mIsBootComplete = true; + showZenUpgradeNotification(mZenMode); } public void onUserSwitched(int user) { @@ -612,6 +622,10 @@ public class ZenModeHelper { 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 @@ public class ZenModeHelper { 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 @@ public class ZenModeHelper { } } + 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 c532a8a25bda..6144c516750d 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 @@ import org.mockito.MockitoAnnotations; 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 @@ public class ZenModeHelperTest extends UiServiceTestCase { 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()); + } } |