diff options
3 files changed, 129 insertions, 23 deletions
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index 54efe543a29f..d76e1b40ee71 100755 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -1959,7 +1959,8 @@ public class NotificationManagerService extends SystemService { mPackageManagerClient, mRankingHandler, mZenModeHelper, - new NotificationChannelLoggerImpl()); + new NotificationChannelLoggerImpl(), + mAppOps); mRankingHelper = new RankingHelper(getContext(), mRankingHandler, mPreferencesHelper, diff --git a/services/core/java/com/android/server/notification/PreferencesHelper.java b/services/core/java/com/android/server/notification/PreferencesHelper.java index b3d373ffab3a..d432fc83b52a 100644 --- a/services/core/java/com/android/server/notification/PreferencesHelper.java +++ b/services/core/java/com/android/server/notification/PreferencesHelper.java @@ -16,7 +16,9 @@ package com.android.server.notification; +import static android.app.AppOpsManager.OP_SYSTEM_ALERT_WINDOW; import static android.app.NotificationChannel.PLACEHOLDER_CONVERSATION_ID; +import static android.app.NotificationManager.BUBBLE_PREFERENCE_ALL; import static android.app.NotificationManager.BUBBLE_PREFERENCE_NONE; import static android.app.NotificationManager.IMPORTANCE_NONE; import static android.app.NotificationManager.IMPORTANCE_UNSPECIFIED; @@ -30,6 +32,7 @@ import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.UserIdInt; +import android.app.AppOpsManager; import android.app.Notification; import android.app.NotificationChannel; import android.app.NotificationChannelGroup; @@ -79,7 +82,9 @@ import java.util.concurrent.ConcurrentHashMap; public class PreferencesHelper implements RankingConfig { private static final String TAG = "NotificationPrefHelper"; - private static final int XML_VERSION = 1; + private static final int XML_VERSION = 2; + /** What version to check to do the upgrade for bubbles. */ + private static final int XML_VERSION_BUBBLES_UPGRADE = 1; private static final int UNKNOWN_UID = UserHandle.USER_NULL; private static final String NON_BLOCKABLE_CHANNEL_DELIM = ":"; @@ -151,6 +156,7 @@ public class PreferencesHelper implements RankingConfig { private final RankingHandler mRankingHandler; private final ZenModeHelper mZenModeHelper; private final NotificationChannelLogger mNotificationChannelLogger; + private final AppOpsManager mAppOps; private SparseBooleanArray mBadgingEnabled; private boolean mBubblesEnabledGlobally = DEFAULT_GLOBAL_ALLOW_BUBBLE; @@ -167,12 +173,14 @@ public class PreferencesHelper implements RankingConfig { } public PreferencesHelper(Context context, PackageManager pm, RankingHandler rankingHandler, - ZenModeHelper zenHelper, NotificationChannelLogger notificationChannelLogger) { + ZenModeHelper zenHelper, NotificationChannelLogger notificationChannelLogger, + AppOpsManager appOpsManager) { mContext = context; mZenModeHelper = zenHelper; mRankingHandler = rankingHandler; mPm = pm; mNotificationChannelLogger = notificationChannelLogger; + mAppOps = appOpsManager; // STOPSHIP (b/142218092) this should be removed before ship if (!wasBadgingForcedTrue(context)) { @@ -195,6 +203,15 @@ public class PreferencesHelper implements RankingConfig { if (type != XmlPullParser.START_TAG) return; String tag = parser.getName(); if (!TAG_RANKING.equals(tag)) return; + + boolean upgradeForBubbles = false; + if (parser.getAttributeCount() > 0) { + String attribute = parser.getAttributeName(0); + if (ATT_VERSION.equals(attribute)) { + int xmlVersion = Integer.parseInt(parser.getAttributeValue(0)); + upgradeForBubbles = xmlVersion == XML_VERSION_BUBBLES_UPGRADE; + } + } synchronized (mPackagePreferences) { while ((type = parser.next()) != XmlPullParser.END_DOCUMENT) { tag = parser.getName(); @@ -220,6 +237,16 @@ public class PreferencesHelper implements RankingConfig { } } boolean skipWarningLogged = false; + boolean hasSAWPermission = false; + if (upgradeForBubbles) { + hasSAWPermission = mAppOps.noteOpNoThrow( + OP_SYSTEM_ALERT_WINDOW, uid, name, null, + "check-notif-bubble") == AppOpsManager.MODE_ALLOWED; + } + int bubblePref = hasSAWPermission + ? BUBBLE_PREFERENCE_ALL + : XmlUtils.readIntAttribute(parser, ATT_ALLOW_BUBBLE, + DEFAULT_BUBBLE_PREFERENCE); PackagePreferences r = getOrCreatePackagePreferencesLocked( name, userId, uid, @@ -231,8 +258,7 @@ public class PreferencesHelper implements RankingConfig { parser, ATT_VISIBILITY, DEFAULT_VISIBILITY), XmlUtils.readBooleanAttribute( parser, ATT_SHOW_BADGE, DEFAULT_SHOW_BADGE), - XmlUtils.readIntAttribute( - parser, ATT_ALLOW_BUBBLE, DEFAULT_BUBBLE_PREFERENCE)); + bubblePref); r.importance = XmlUtils.readIntAttribute( parser, ATT_IMPORTANCE, DEFAULT_IMPORTANCE); r.priority = XmlUtils.readIntAttribute( diff --git a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java index 427237c4be0f..ac51750f23f8 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java @@ -15,6 +15,9 @@ */ package com.android.server.notification; +import static android.app.AppOpsManager.MODE_ALLOWED; +import static android.app.AppOpsManager.MODE_DEFAULT; +import static android.app.AppOpsManager.OP_SYSTEM_ALERT_WINDOW; import static android.app.NotificationChannel.CONVERSATION_CHANNEL_ID_FORMAT; import static android.app.NotificationManager.BUBBLE_PREFERENCE_ALL; import static android.app.NotificationManager.BUBBLE_PREFERENCE_NONE; @@ -50,6 +53,7 @@ import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import android.app.AppOpsManager; import android.app.Notification; import android.app.NotificationChannel; import android.app.NotificationChannelGroup; @@ -132,6 +136,7 @@ public class PreferencesHelperTest extends UiServiceTestCase { @Spy IContentProvider mTestIContentProvider = new MockIContentProvider(); @Mock Context mContext; @Mock ZenModeHelper mMockZenModeHelper; + @Mock AppOpsManager mAppOpsManager; private NotificationManager.Policy mTestNotificationPolicy; @@ -187,7 +192,10 @@ public class PreferencesHelperTest extends UiServiceTestCase { mTestNotificationPolicy = new NotificationManager.Policy(0, 0, 0, 0, NotificationManager.Policy.STATE_CHANNELS_BYPASSING_DND, 0); when(mMockZenModeHelper.getNotificationPolicy()).thenReturn(mTestNotificationPolicy); - mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper, mLogger); + when(mAppOpsManager.noteOpNoThrow(anyInt(), anyInt(), + anyString(), eq(null), anyString())).thenReturn(MODE_DEFAULT); + mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper, mLogger, + mAppOpsManager); resetZenModeHelper(); mAudioAttributes = new AudioAttributes.Builder() @@ -1464,7 +1472,8 @@ public class PreferencesHelperTest extends UiServiceTestCase { mTestNotificationPolicy = new NotificationManager.Policy(0, 0, 0, 0, NotificationManager.Policy.STATE_CHANNELS_BYPASSING_DND, 0); when(mMockZenModeHelper.getNotificationPolicy()).thenReturn(mTestNotificationPolicy); - mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper, mLogger); + mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper, mLogger, + mAppOpsManager); assertFalse(mHelper.areChannelsBypassingDnd()); verify(mMockZenModeHelper, times(1)).setNotificationPolicy(any()); resetZenModeHelper(); @@ -1475,7 +1484,8 @@ public class PreferencesHelperTest extends UiServiceTestCase { // start notification policy off with mAreChannelsBypassingDnd = false mTestNotificationPolicy = new NotificationManager.Policy(0, 0, 0, 0, 0, 0); when(mMockZenModeHelper.getNotificationPolicy()).thenReturn(mTestNotificationPolicy); - mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper, mLogger); + mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper, mLogger, + mAppOpsManager); assertFalse(mHelper.areChannelsBypassingDnd()); verify(mMockZenModeHelper, never()).setNotificationPolicy(any()); resetZenModeHelper(); @@ -2241,7 +2251,8 @@ public class PreferencesHelperTest extends UiServiceTestCase { + "content_type=\"4\" flags=\"0\" show_badge=\"true\" />\n" + "</package>\n" + "</ranking>\n"; - mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper, mLogger); + mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper, mLogger, + mAppOpsManager); loadByteArrayXml(preQXml.getBytes(), true, UserHandle.USER_SYSTEM); assertEquals(PreferencesHelper.DEFAULT_HIDE_SILENT_STATUS_BAR_ICONS, @@ -2253,7 +2264,8 @@ public class PreferencesHelperTest extends UiServiceTestCase { mHelper.setHideSilentStatusIcons(!PreferencesHelper.DEFAULT_HIDE_SILENT_STATUS_BAR_ICONS); ByteArrayOutputStream baos = writeXmlAndPurge(PKG_O, UID_O, false, UserHandle.USER_ALL); - mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper, mLogger); + mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper, mLogger, + mAppOpsManager); loadStreamXml(baos, false, UserHandle.USER_ALL); assertEquals(!PreferencesHelper.DEFAULT_HIDE_SILENT_STATUS_BAR_ICONS, @@ -2349,7 +2361,8 @@ public class PreferencesHelperTest extends UiServiceTestCase { mHelper.setImportance(PKG_O, UID_O, IMPORTANCE_UNSPECIFIED); ByteArrayOutputStream baos = writeXmlAndPurge(PKG_O, UID_O, false, UserHandle.USER_ALL); - mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper, mLogger); + mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper, mLogger, + mAppOpsManager); loadStreamXml(baos, false, UserHandle.USER_ALL); assertNull(mHelper.getNotificationDelegate(PKG_O, UID_O)); @@ -2360,7 +2373,8 @@ public class PreferencesHelperTest extends UiServiceTestCase { mHelper.setNotificationDelegate(PKG_O, UID_O, "other", 53); ByteArrayOutputStream baos = writeXmlAndPurge(PKG_O, UID_O, false, UserHandle.USER_ALL); - mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper, mLogger); + mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper, mLogger, + mAppOpsManager); loadStreamXml(baos, false, UserHandle.USER_ALL); assertEquals("other", mHelper.getNotificationDelegate(PKG_O, UID_O)); @@ -2372,7 +2386,8 @@ public class PreferencesHelperTest extends UiServiceTestCase { mHelper.revokeNotificationDelegate(PKG_O, UID_O); ByteArrayOutputStream baos = writeXmlAndPurge(PKG_O, UID_O, false, UserHandle.USER_ALL); - mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper, mLogger); + mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper, mLogger, + mAppOpsManager); loadStreamXml(baos, false, UserHandle.USER_ALL); assertNull(mHelper.getNotificationDelegate(PKG_O, UID_O)); @@ -2384,7 +2399,8 @@ public class PreferencesHelperTest extends UiServiceTestCase { mHelper.toggleNotificationDelegate(PKG_O, UID_O, false); ByteArrayOutputStream baos = writeXmlAndPurge(PKG_O, UID_O, false, UserHandle.USER_ALL); - mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper, mLogger); + mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper, mLogger, + mAppOpsManager); loadStreamXml(baos, false, UserHandle.USER_ALL); // appears disabled @@ -2402,7 +2418,8 @@ public class PreferencesHelperTest extends UiServiceTestCase { mHelper.revokeNotificationDelegate(PKG_O, UID_O); ByteArrayOutputStream baos = writeXmlAndPurge(PKG_O, UID_O, false, UserHandle.USER_ALL); - mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper, mLogger); + mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper, mLogger, + mAppOpsManager); loadStreamXml(baos, false, UserHandle.USER_ALL); // appears disabled @@ -2417,14 +2434,71 @@ public class PreferencesHelperTest extends UiServiceTestCase { @Test public void testBubblePreference_defaults() throws Exception { - assertEquals(mHelper.getBubblePreference(PKG_O, UID_O), BUBBLE_PREFERENCE_NONE); + assertEquals(BUBBLE_PREFERENCE_NONE, mHelper.getBubblePreference(PKG_O, UID_O)); ByteArrayOutputStream baos = writeXmlAndPurge(PKG_O, UID_O, false, UserHandle.USER_ALL); - mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper, mLogger); + mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper, mLogger, + mAppOpsManager); loadStreamXml(baos, false, UserHandle.USER_ALL); - assertEquals(mHelper.getBubblePreference(PKG_O, UID_O), BUBBLE_PREFERENCE_NONE); + assertEquals(BUBBLE_PREFERENCE_NONE, mHelper.getBubblePreference(PKG_O, UID_O)); + assertEquals(0, mHelper.getAppLockedFields(PKG_O, UID_O)); + } + + @Test + public void testBubblePreference_upgradeWithSAWPermission() throws Exception { + when(mAppOpsManager.noteOpNoThrow(eq(OP_SYSTEM_ALERT_WINDOW), anyInt(), + anyString(), eq(null), anyString())).thenReturn(MODE_ALLOWED); + + final String xml = "<ranking version=\"1\">\n" + + "<package name=\"" + PKG_O + "\" uid=\"" + UID_O + "\">\n" + + "<channel id=\"someId\" name=\"hi\"" + + " importance=\"3\"/>" + + "</package>" + + "</ranking>"; + XmlPullParser parser = Xml.newPullParser(); + parser.setInput(new BufferedInputStream(new ByteArrayInputStream(xml.getBytes())), + null); + parser.nextTag(); + mHelper.readXml(parser, false, UserHandle.USER_ALL); + + assertEquals(BUBBLE_PREFERENCE_ALL, mHelper.getBubblePreference(PKG_O, UID_O)); + assertEquals(0, mHelper.getAppLockedFields(PKG_O, UID_O)); + } + + @Test + public void testBubblePreference_upgradeWithSAWThenUserOverride() throws Exception { + when(mAppOpsManager.noteOpNoThrow(eq(OP_SYSTEM_ALERT_WINDOW), anyInt(), + anyString(), eq(null), anyString())).thenReturn(MODE_ALLOWED); + + final String xml = "<ranking version=\"1\">\n" + + "<package name=\"" + PKG_O + "\" uid=\"" + UID_O + "\">\n" + + "<channel id=\"someId\" name=\"hi\"" + + " importance=\"3\"/>" + + "</package>" + + "</ranking>"; + XmlPullParser parser = Xml.newPullParser(); + parser.setInput(new BufferedInputStream(new ByteArrayInputStream(xml.getBytes())), + null); + parser.nextTag(); + mHelper.readXml(parser, false, UserHandle.USER_ALL); + + assertEquals(BUBBLE_PREFERENCE_ALL, mHelper.getBubblePreference(PKG_O, UID_O)); assertEquals(0, mHelper.getAppLockedFields(PKG_O, UID_O)); + + mHelper.setBubblesAllowed(PKG_O, UID_O, BUBBLE_PREFERENCE_SELECTED); + assertEquals(BUBBLE_PREFERENCE_SELECTED, mHelper.getBubblePreference(PKG_O, UID_O)); + assertEquals(PreferencesHelper.LockableAppFields.USER_LOCKED_BUBBLE, + mHelper.getAppLockedFields(PKG_O, UID_O)); + + ByteArrayOutputStream baos = writeXmlAndPurge(PKG_O, UID_O, false, UserHandle.USER_ALL); + mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper, mLogger, + mAppOpsManager); + loadStreamXml(baos, false, UserHandle.USER_ALL); + + assertEquals(BUBBLE_PREFERENCE_SELECTED, mHelper.getBubblePreference(PKG_O, UID_O)); + assertEquals(PreferencesHelper.LockableAppFields.USER_LOCKED_BUBBLE, + mHelper.getAppLockedFields(PKG_O, UID_O)); } @Test @@ -2435,7 +2509,8 @@ public class PreferencesHelperTest extends UiServiceTestCase { mHelper.getAppLockedFields(PKG_O, UID_O)); ByteArrayOutputStream baos = writeXmlAndPurge(PKG_O, UID_O, false, UserHandle.USER_ALL); - mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper, mLogger); + mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper, mLogger, + mAppOpsManager); loadStreamXml(baos, false, UserHandle.USER_ALL); assertEquals(mHelper.getBubblePreference(PKG_O, UID_O), BUBBLE_PREFERENCE_NONE); @@ -2949,7 +3024,8 @@ public class PreferencesHelperTest extends UiServiceTestCase { Settings.Global.putInt(mContext.getContentResolver(), Settings.Global.REQUIRE_SHORTCUTS_FOR_CONVERSATIONS, 0); - mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper, mLogger); + mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper, mLogger, + mAppOpsManager); final String xml = "<ranking version=\"1\">\n" + "<package name=\"" + PKG_O + "\" uid=\"" + UID_O + "\" >\n" @@ -2969,7 +3045,8 @@ public class PreferencesHelperTest extends UiServiceTestCase { public void testPlaceholderConversationId_shortcutRequired() throws Exception { Settings.Global.putInt(mContext.getContentResolver(), Settings.Global.REQUIRE_SHORTCUTS_FOR_CONVERSATIONS, 1); - mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper, mLogger); + mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper, mLogger, + mAppOpsManager); final String xml = "<ranking version=\"1\">\n" + "<package name=\"" + PKG_O + "\" uid=\"" + UID_O + "\" >\n" @@ -2989,7 +3066,8 @@ public class PreferencesHelperTest extends UiServiceTestCase { public void testNormalConversationId_shortcutRequired() throws Exception { Settings.Global.putInt(mContext.getContentResolver(), Settings.Global.REQUIRE_SHORTCUTS_FOR_CONVERSATIONS, 1); - mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper, mLogger); + mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper, mLogger, + mAppOpsManager); final String xml = "<ranking version=\"1\">\n" + "<package name=\"" + PKG_O + "\" uid=\"" + UID_O + "\" >\n" @@ -3009,7 +3087,8 @@ public class PreferencesHelperTest extends UiServiceTestCase { public void testNoConversationId_shortcutRequired() throws Exception { Settings.Global.putInt(mContext.getContentResolver(), Settings.Global.REQUIRE_SHORTCUTS_FOR_CONVERSATIONS, 1); - mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper, mLogger); + mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper, mLogger, + mAppOpsManager); final String xml = "<ranking version=\"1\">\n" + "<package name=\"" + PKG_O + "\" uid=\"" + UID_O + "\" >\n" |