diff options
| author | 2019-01-11 10:38:08 -0500 | |
|---|---|---|
| committer | 2019-01-14 14:03:55 +0000 | |
| commit | 413ba846b377a1dd094ce94fa6ded78104de8b51 (patch) | |
| tree | 7355c732139116c21ddf91bb91dae26accd81809 | |
| parent | 5ca575ae71493aedfbd93da032692ad5a1d50f27 (diff) | |
Don't allow importance updates for oem locked channels
Test: atest, make sure missed call notifications are no
longer demoted by aosp notification assistant
Change-Id: I80728bae67501d64359e0dac02dca928c34a7e95
Fixes: 122657004
7 files changed, 273 insertions, 21 deletions
diff --git a/api/test-current.txt b/api/test-current.txt index 957f957d21a3..89ab8028686a 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -219,6 +219,11 @@ package android.app { method public abstract void onOpActiveChanged(int, int, java.lang.String, boolean); } + public final class NotificationChannel implements android.os.Parcelable { + method public boolean isImportanceLockedByOEM(); + method public void setImportanceLockedByOEM(boolean); + } + public final class NotificationChannelGroup implements android.os.Parcelable { method public int getUserLockedFields(); method public void lockFields(int); diff --git a/core/java/android/app/NotificationChannel.java b/core/java/android/app/NotificationChannel.java index 41ceaafa56a9..950e9aa939f8 100644 --- a/core/java/android/app/NotificationChannel.java +++ b/core/java/android/app/NotificationChannel.java @@ -19,6 +19,7 @@ import static android.app.NotificationManager.IMPORTANCE_HIGH; import android.annotation.Nullable; import android.annotation.SystemApi; +import android.annotation.TestApi; import android.annotation.UnsupportedAppUsage; import android.app.NotificationManager.Importance; import android.content.ContentResolver; @@ -168,6 +169,7 @@ public final class NotificationChannel implements Parcelable { // If this is a blockable system notification channel. private boolean mBlockableSystem = false; private boolean mAllowAppOverlay = DEFAULT_ALLOW_APP_OVERLAY; + private boolean mImportanceLockedByOEM; /** * Creates a notification channel. @@ -230,6 +232,7 @@ public final class NotificationChannel implements Parcelable { mLightColor = in.readInt(); mBlockableSystem = in.readBoolean(); mAllowAppOverlay = in.readBoolean(); + mImportanceLockedByOEM = in.readBoolean(); } @Override @@ -283,6 +286,7 @@ public final class NotificationChannel implements Parcelable { dest.writeInt(mLightColor); dest.writeBoolean(mBlockableSystem); dest.writeBoolean(mAllowAppOverlay); + dest.writeBoolean(mImportanceLockedByOEM); } /** @@ -649,6 +653,22 @@ public final class NotificationChannel implements Parcelable { } /** + * @hide + */ + @TestApi + public void setImportanceLockedByOEM(boolean locked) { + mImportanceLockedByOEM = locked; + } + + /** + * @hide + */ + @TestApi + public boolean isImportanceLockedByOEM() { + return mImportanceLockedByOEM; + } + + /** * Returns whether the user has chosen the importance of this channel, either to affirm the * initial selection from the app, or changed it to be higher or lower. * @see #getImportance() @@ -952,25 +972,26 @@ public final class NotificationChannel implements Parcelable { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; NotificationChannel that = (NotificationChannel) o; - return getImportance() == that.getImportance() && - mBypassDnd == that.mBypassDnd && - getLockscreenVisibility() == that.getLockscreenVisibility() && - mLights == that.mLights && - getLightColor() == that.getLightColor() && - getUserLockedFields() == that.getUserLockedFields() && - isFgServiceShown() == that.isFgServiceShown() && - mVibrationEnabled == that.mVibrationEnabled && - mShowBadge == that.mShowBadge && - isDeleted() == that.isDeleted() && - isBlockableSystem() == that.isBlockableSystem() && - mAllowAppOverlay == that.mAllowAppOverlay && - Objects.equals(getId(), that.getId()) && - Objects.equals(getName(), that.getName()) && - Objects.equals(mDesc, that.mDesc) && - Objects.equals(getSound(), that.getSound()) && - Arrays.equals(mVibration, that.mVibration) && - Objects.equals(getGroup(), that.getGroup()) && - Objects.equals(getAudioAttributes(), that.getAudioAttributes()); + return getImportance() == that.getImportance() + && mBypassDnd == that.mBypassDnd + && getLockscreenVisibility() == that.getLockscreenVisibility() + && mLights == that.mLights + && getLightColor() == that.getLightColor() + && getUserLockedFields() == that.getUserLockedFields() + && isFgServiceShown() == that.isFgServiceShown() + && mVibrationEnabled == that.mVibrationEnabled + && mShowBadge == that.mShowBadge + && isDeleted() == that.isDeleted() + && isBlockableSystem() == that.isBlockableSystem() + && mAllowAppOverlay == that.mAllowAppOverlay + && Objects.equals(getId(), that.getId()) + && Objects.equals(getName(), that.getName()) + && Objects.equals(mDesc, that.mDesc) + && Objects.equals(getSound(), that.getSound()) + && Arrays.equals(mVibration, that.mVibration) + && Objects.equals(getGroup(), that.getGroup()) + && Objects.equals(getAudioAttributes(), that.getAudioAttributes()) + && mImportanceLockedByOEM == that.mImportanceLockedByOEM; } @Override @@ -979,7 +1000,8 @@ public final class NotificationChannel implements Parcelable { getLockscreenVisibility(), getSound(), mLights, getLightColor(), getUserLockedFields(), isFgServiceShown(), mVibrationEnabled, mShowBadge, isDeleted(), getGroup(), - getAudioAttributes(), isBlockableSystem(), mAllowAppOverlay); + getAudioAttributes(), isBlockableSystem(), mAllowAppOverlay, + mImportanceLockedByOEM); result = 31 * result + Arrays.hashCode(mVibration); return result; } @@ -1007,6 +1029,7 @@ public final class NotificationChannel implements Parcelable { + ", mAudioAttributes=" + mAudioAttributes + ", mBlockableSystem=" + mBlockableSystem + ", mAllowAppOverlay=" + mAllowAppOverlay + + ", mImportanceLockedByOEM=" + mImportanceLockedByOEM + '}'; pw.println(prefix + output); } @@ -1033,6 +1056,7 @@ public final class NotificationChannel implements Parcelable { + ", mAudioAttributes=" + mAudioAttributes + ", mBlockableSystem=" + mBlockableSystem + ", mAllowAppOverlay=" + mAllowAppOverlay + + ", mImportanceLockedByOEM=" + mImportanceLockedByOEM + '}'; } diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index 7ecdad27c505..7b7a3ec9809d 100644 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -1581,6 +1581,9 @@ public class NotificationManagerService extends SystemService { mIsAutomotive = mPackageManagerClient.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE, 0); + + mPreferencesHelper.lockChannelsForOEM(getContext().getResources().getStringArray( + com.android.internal.R.array.config_nonBlockableNotificationPackages)); } @Override diff --git a/services/core/java/com/android/server/notification/NotificationRecord.java b/services/core/java/com/android/server/notification/NotificationRecord.java index 2ec7773dfdb1..559874167429 100644 --- a/services/core/java/com/android/server/notification/NotificationRecord.java +++ b/services/core/java/com/android/server/notification/NotificationRecord.java @@ -785,7 +785,8 @@ public final class NotificationRecord { mImportanceExplanation = "user"; } if (!getChannel().hasUserSetImportance() - && mAssistantImportance != IMPORTANCE_UNSPECIFIED) { + && mAssistantImportance != IMPORTANCE_UNSPECIFIED + && !getChannel().isImportanceLockedByOEM()) { mImportance = mAssistantImportance; mImportanceExplanation = "asst"; } diff --git a/services/core/java/com/android/server/notification/PreferencesHelper.java b/services/core/java/com/android/server/notification/PreferencesHelper.java index 7c0e0b0983fb..28f6972636be 100644 --- a/services/core/java/com/android/server/notification/PreferencesHelper.java +++ b/services/core/java/com/android/server/notification/PreferencesHelper.java @@ -68,6 +68,7 @@ public class PreferencesHelper implements RankingConfig { private static final String TAG = "NotificationPrefHelper"; private static final int XML_VERSION = 1; private static final int UNKNOWN_UID = UserHandle.USER_NULL; + private static final String NON_BLOCKABLE_CHANNEL_DELIM = ":"; @VisibleForTesting static final String TAG_RANKING = "ranking"; @@ -94,6 +95,7 @@ public class PreferencesHelper implements RankingConfig { private static final int DEFAULT_IMPORTANCE = NotificationManager.IMPORTANCE_UNSPECIFIED; private static final boolean DEFAULT_SHOW_BADGE = true; private static final boolean DEFAULT_ALLOW_APP_OVERLAY = true; + private static final boolean DEFAULT_OEM_LOCKED_IMPORTANCE = false; /** * Default value for what fields are user locked. See {@link LockableAppFields} for all lockable * fields. @@ -621,6 +623,12 @@ public class PreferencesHelper implements RankingConfig { channel.setLockscreenVisibility(r.visibility); } clearLockedFields(channel); + channel.setImportanceLockedByOEM(r.oemLockedImportance); + if (!channel.isImportanceLockedByOEM()) { + if (r.futureOemLockedChannels.remove(channel.getId())) { + channel.setImportanceLockedByOEM(true); + } + } if (channel.getLockscreenVisibility() == Notification.VISIBILITY_PUBLIC) { channel.setLockscreenVisibility( NotificationListenerService.Ranking.VISIBILITY_NO_OVERRIDE); @@ -664,6 +672,12 @@ public class PreferencesHelper implements RankingConfig { } else { updatedChannel.unlockFields(updatedChannel.getUserLockedFields()); } + // no importance updates are allowed if OEM blocked it + updatedChannel.setImportanceLockedByOEM(channel.isImportanceLockedByOEM()); + if (updatedChannel.isImportanceLockedByOEM()) { + updatedChannel.setImportance(channel.getImportance()); + } + r.channels.put(updatedChannel.getId(), updatedChannel); if (onlyHasDefaultChannel(pkg, uid)) { @@ -753,6 +767,44 @@ public class PreferencesHelper implements RankingConfig { } } + public void lockChannelsForOEM(String[] appOrChannelList) { + if (appOrChannelList == null) { + return; + } + for (String appOrChannel : appOrChannelList) { + if (!TextUtils.isEmpty(appOrChannel)) { + String[] appSplit = appOrChannel.split(NON_BLOCKABLE_CHANNEL_DELIM); + if (appSplit != null && appSplit.length > 0) { + String appName = appSplit[0]; + String channelId = appSplit.length == 2 ? appSplit[1] : null; + + synchronized (mPackagePreferences) { + for (PackagePreferences r : mPackagePreferences.values()) { + if (r.pkg.equals(appName)) { + if (channelId == null) { + // lock all channels for the app + r.oemLockedImportance = true; + for (NotificationChannel channel : r.channels.values()) { + channel.setImportanceLockedByOEM(true); + } + } else { + NotificationChannel channel = r.channels.get(channelId); + if (channel != null) { + channel.setImportanceLockedByOEM(true); + } else { + // if this channel shows up in the future, make sure it'll + // be locked immediately + r.futureOemLockedChannels.add(channelId); + } + } + } + } + } + } + } + } + } + public NotificationChannelGroup getNotificationChannelGroupWithChannels(String pkg, int uid, String groupId, boolean includeDeleted) { Preconditions.checkNotNull(pkg); @@ -1604,6 +1656,8 @@ public class PreferencesHelper implements RankingConfig { boolean showBadge = DEFAULT_SHOW_BADGE; boolean appOverlay = DEFAULT_ALLOW_APP_OVERLAY; int lockedAppFields = DEFAULT_LOCKED_APP_FIELDS; + boolean oemLockedImportance = DEFAULT_OEM_LOCKED_IMPORTANCE; + List<String> futureOemLockedChannels = new ArrayList<>(); Delegate delegate = null; ArrayMap<String, NotificationChannel> channels = new ArrayMap<>(); diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordTest.java index 9bcbcd5777d2..b9ae7d5e3f93 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordTest.java @@ -792,4 +792,52 @@ public class NotificationRecordTest extends UiServiceTestCase { assertFalse(record.isNewEnoughForAlerting(record.mUpdateTimeMs + (1000 * 60 * 60))); } + + @Test + public void testIgnoreImportanceAdjustmentsForOemLockedChannels() { + NotificationChannel channel = new NotificationChannel("a", "a", IMPORTANCE_DEFAULT); + channel.setImportanceLockedByOEM(true); + + StatusBarNotification sbn = getNotification(PKG_O, true /* noisy */, + true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */, + false /* lights */, false /* defaultLights */, groupId /* group */); + NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel); + + assertEquals(IMPORTANCE_DEFAULT, record.getImportance()); + + Bundle bundle = new Bundle(); + bundle.putInt(Adjustment.KEY_IMPORTANCE, IMPORTANCE_LOW); + Adjustment adjustment = new Adjustment( + PKG_O, record.getKey(), bundle, "", record.getUserId()); + + record.addAdjustment(adjustment); + record.applyAdjustments(); + record.calculateImportance(); + + assertEquals(IMPORTANCE_DEFAULT, record.getImportance()); + } + + @Test + public void testApplyImportanceAdjustmentsForNonOemLockedChannels() { + NotificationChannel channel = new NotificationChannel("a", "a", IMPORTANCE_DEFAULT); + channel.setImportanceLockedByOEM(false); + + StatusBarNotification sbn = getNotification(PKG_O, true /* noisy */, + true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */, + false /* lights */, false /* defaultLights */, groupId /* group */); + NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel); + + assertEquals(IMPORTANCE_DEFAULT, record.getImportance()); + + Bundle bundle = new Bundle(); + bundle.putInt(Adjustment.KEY_IMPORTANCE, IMPORTANCE_LOW); + Adjustment adjustment = new Adjustment( + PKG_O, record.getKey(), bundle, "", record.getUserId()); + + record.addAdjustment(adjustment); + record.applyAdjustments(); + record.calculateImportance(); + + assertEquals(IMPORTANCE_LOW, record.getImportance()); + } } 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 0b7348194b26..0fcfea716e8f 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java @@ -2187,4 +2187,121 @@ public class PreferencesHelperTest extends UiServiceTestCase { assertEquals(PreferencesHelper.LockableAppFields.USER_LOCKED_APP_OVERLAY, mHelper.getAppLockedFields(PKG_O, UID_O)); } + + @Test + public void testLockChannelsForOEM_emptyList() { + mHelper.lockChannelsForOEM(null); + mHelper.lockChannelsForOEM(new String[0]); + // no exception + } + + @Test + public void testLockChannelsForOEM_appWide() { + NotificationChannel a = new NotificationChannel("a", "a", IMPORTANCE_HIGH); + NotificationChannel b = new NotificationChannel("b", "b", IMPORTANCE_LOW); + NotificationChannel c = new NotificationChannel("c", "c", IMPORTANCE_DEFAULT); + // different uids, same package + mHelper.createNotificationChannel(PKG_O, 3, a, true, false); + mHelper.createNotificationChannel(PKG_O, 3, b, false, false); + mHelper.createNotificationChannel(PKG_O, 30, c, true, true); + + mHelper.lockChannelsForOEM(new String[] {PKG_O}); + + assertTrue(mHelper.getNotificationChannel(PKG_O, 3, a.getId(), false) + .isImportanceLockedByOEM()); + assertTrue(mHelper.getNotificationChannel(PKG_O, 3, b.getId(), false) + .isImportanceLockedByOEM()); + assertTrue(mHelper.getNotificationChannel(PKG_O, 30, c.getId(), false) + .isImportanceLockedByOEM()); + } + + @Test + public void testLockChannelsForOEM_onlyGivenPkg() { + NotificationChannel a = new NotificationChannel("a", "a", IMPORTANCE_HIGH); + NotificationChannel b = new NotificationChannel("b", "b", IMPORTANCE_LOW); + mHelper.createNotificationChannel(PKG_O, 3, a, true, false); + mHelper.createNotificationChannel(PKG_N_MR1, 30, b, false, false); + + mHelper.lockChannelsForOEM(new String[] {PKG_O}); + + assertTrue(mHelper.getNotificationChannel(PKG_O, 3, a.getId(), false) + .isImportanceLockedByOEM()); + assertFalse(mHelper.getNotificationChannel(PKG_N_MR1, 30, b.getId(), false) + .isImportanceLockedByOEM()); + } + + @Test + public void testLockChannelsForOEM_channelSpecific() { + NotificationChannel a = new NotificationChannel("a", "a", IMPORTANCE_HIGH); + NotificationChannel b = new NotificationChannel("b", "b", IMPORTANCE_LOW); + NotificationChannel c = new NotificationChannel("c", "c", IMPORTANCE_DEFAULT); + // different uids, same package + mHelper.createNotificationChannel(PKG_O, 3, a, true, false); + mHelper.createNotificationChannel(PKG_O, 3, b, false, false); + mHelper.createNotificationChannel(PKG_O, 30, c, true, true); + + mHelper.lockChannelsForOEM(new String[] {PKG_O + ":b", PKG_O + ":c"}); + + assertFalse(mHelper.getNotificationChannel(PKG_O, 3, a.getId(), false) + .isImportanceLockedByOEM()); + assertTrue(mHelper.getNotificationChannel(PKG_O, 3, b.getId(), false) + .isImportanceLockedByOEM()); + assertTrue(mHelper.getNotificationChannel(PKG_O, 30, c.getId(), false) + .isImportanceLockedByOEM()); + } + + @Test + public void testLockChannelsForOEM_channelDoesNotExistYet_appWide() { + NotificationChannel a = new NotificationChannel("a", "a", IMPORTANCE_HIGH); + NotificationChannel b = new NotificationChannel("b", "b", IMPORTANCE_LOW); + mHelper.createNotificationChannel(PKG_O, 3, a, true, false); + + mHelper.lockChannelsForOEM(new String[] {PKG_O}); + + assertTrue(mHelper.getNotificationChannel(PKG_O, 3, a.getId(), false) + .isImportanceLockedByOEM()); + + mHelper.createNotificationChannel(PKG_O, 3, b, true, false); + assertTrue(mHelper.getNotificationChannel(PKG_O, 3, b.getId(), false) + .isImportanceLockedByOEM()); + } + + @Test + public void testLockChannelsForOEM_channelDoesNotExistYet_channelSpecific() { + NotificationChannel a = new NotificationChannel("a", "a", IMPORTANCE_HIGH); + NotificationChannel b = new NotificationChannel("b", "b", IMPORTANCE_LOW); + mHelper.createNotificationChannel(PKG_O, UID_O, a, true, false); + + mHelper.lockChannelsForOEM(new String[] {PKG_O + ":a", PKG_O + ":b"}); + + assertTrue(mHelper.getNotificationChannel(PKG_O, UID_O, a.getId(), false) + .isImportanceLockedByOEM()); + + mHelper.createNotificationChannel(PKG_O, UID_O, b, true, false); + assertTrue(mHelper.getNotificationChannel(PKG_O, UID_O, b.getId(), false) + .isImportanceLockedByOEM()); + } + + @Test + public void testUpdateNotificationChannel_oemLockedImportance() { + NotificationChannel a = new NotificationChannel("a", "a", IMPORTANCE_HIGH); + mHelper.createNotificationChannel(PKG_O, UID_O, a, true, false); + + mHelper.lockChannelsForOEM(new String[] {PKG_O}); + + NotificationChannel update = new NotificationChannel("a", "a", IMPORTANCE_NONE); + update.setAllowAppOverlay(false); + + mHelper.updateNotificationChannel(PKG_O, UID_O, update, true); + + assertEquals(IMPORTANCE_HIGH, + mHelper.getNotificationChannel(PKG_O, UID_O, a.getId(), false).getImportance()); + assertEquals(false, + mHelper.getNotificationChannel(PKG_O, UID_O, a.getId(), false).canOverlayApps()); + + mHelper.updateNotificationChannel(PKG_O, UID_O, update, true); + + assertEquals(IMPORTANCE_HIGH, + mHelper.getNotificationChannel(PKG_O, UID_O, a.getId(), false).getImportance()); + } } |