Loading services/core/java/com/android/server/notification/NotificationChannelExtractor.java +30 −0 Original line number Original line Diff line number Diff line Loading @@ -23,9 +23,15 @@ import static android.media.AudioAttributes.USAGE_NOTIFICATION; import android.app.Notification; import android.app.Notification; import android.app.NotificationChannel; import android.app.NotificationChannel; import android.compat.annotation.ChangeId; import android.compat.annotation.LoggingOnly; import android.content.Context; import android.content.Context; import android.media.AudioAttributes; import android.media.AudioAttributes; import android.os.Binder; import android.os.RemoteException; import android.os.ServiceManager; import android.util.Slog; import android.util.Slog; import com.android.internal.compat.IPlatformCompat; /** /** * Stores the latest notification channel information for this notification * Stores the latest notification channel information for this notification Loading @@ -34,14 +40,26 @@ public class NotificationChannelExtractor implements NotificationSignalExtractor private static final String TAG = "ChannelExtractor"; private static final String TAG = "ChannelExtractor"; private static final boolean DBG = false; private static final boolean DBG = false; /** * Corrects audio attributes for notifications based on characteristics of the notifications. */ @ChangeId @LoggingOnly static final long RESTRICT_AUDIO_ATTRIBUTES = 331793339L; private RankingConfig mConfig; private RankingConfig mConfig; private Context mContext; private Context mContext; private IPlatformCompat mPlatformCompat; public void initialize(Context ctx, NotificationUsageStats usageStats) { public void initialize(Context ctx, NotificationUsageStats usageStats) { mContext = ctx; mContext = ctx; if (DBG) Slog.d(TAG, "Initializing " + getClass().getSimpleName() + "."); if (DBG) Slog.d(TAG, "Initializing " + getClass().getSimpleName() + "."); } } public void setCompatChangeLogger(IPlatformCompat platformCompat) { mPlatformCompat = platformCompat; } public RankingReconsideration process(NotificationRecord record) { public RankingReconsideration process(NotificationRecord record) { if (record == null || record.getNotification() == null) { if (record == null || record.getNotification() == null) { if (DBG) Slog.d(TAG, "skipping empty notification"); if (DBG) Slog.d(TAG, "skipping empty notification"); Loading Loading @@ -80,6 +98,7 @@ public class NotificationChannelExtractor implements NotificationSignalExtractor } } if (updateAttributes) { if (updateAttributes) { reportAudioAttributesChanged(record.getUid()); NotificationChannel clone = record.getChannel().copy(); NotificationChannel clone = record.getChannel().copy(); clone.setSound(clone.getSound(), new AudioAttributes.Builder(attributes) clone.setSound(clone.getSound(), new AudioAttributes.Builder(attributes) .setUsage(USAGE_NOTIFICATION) .setUsage(USAGE_NOTIFICATION) Loading @@ -91,6 +110,17 @@ public class NotificationChannelExtractor implements NotificationSignalExtractor return null; return null; } } private void reportAudioAttributesChanged(int uid) { final long id = Binder.clearCallingIdentity(); try { mPlatformCompat.reportChangeByUid(RESTRICT_AUDIO_ATTRIBUTES, uid); } catch (RemoteException e) { Slog.e(TAG, "Unexpected exception while reporting to changecompat", e); } finally { Binder.restoreCallingIdentity(id); } } @Override @Override public void setConfig(RankingConfig config) { public void setConfig(RankingConfig config) { mConfig = config; mConfig = config; Loading services/core/java/com/android/server/notification/NotificationManagerService.java +2 −6 Original line number Original line Diff line number Diff line Loading @@ -2508,12 +2508,8 @@ public class NotificationManagerService extends SystemService { mAppOps, mAppOps, mUserProfiles, mUserProfiles, mShowReviewPermissionsNotification); mShowReviewPermissionsNotification); mRankingHelper = new RankingHelper(getContext(), mRankingHelper = new RankingHelper(getContext(), mRankingHandler, mPreferencesHelper, mRankingHandler, mZenModeHelper, mUsageStats, extractorNames, mPlatformCompat); mPreferencesHelper, mZenModeHelper, mUsageStats, extractorNames); mSnoozeHelper = snoozeHelper; mSnoozeHelper = snoozeHelper; mGroupHelper = groupHelper; mGroupHelper = groupHelper; mHistoryManager = historyManager; mHistoryManager = historyManager; Loading services/core/java/com/android/server/notification/NotificationSignalExtractor.java +3 −0 Original line number Original line Diff line number Diff line Loading @@ -17,6 +17,7 @@ package com.android.server.notification; package com.android.server.notification; import android.content.Context; import android.content.Context; import com.android.internal.compat.IPlatformCompat; /** /** * Extracts signals that will be useful to the {@link NotificationComparator} and caches them * Extracts signals that will be useful to the {@link NotificationComparator} and caches them Loading Loading @@ -52,4 +53,6 @@ public interface NotificationSignalExtractor { * DND. * DND. */ */ void setZenHelper(ZenModeHelper helper); void setZenHelper(ZenModeHelper helper); default void setCompatChangeLogger(IPlatformCompat platformCompat){}; } } services/core/java/com/android/server/notification/RankingHelper.java +10 −1 Original line number Original line Diff line number Diff line Loading @@ -15,6 +15,9 @@ */ */ package com.android.server.notification; package com.android.server.notification; import static android.app.Flags.restrictAudioAttributesAlarm; import static android.app.Flags.restrictAudioAttributesCall; import static android.app.Flags.restrictAudioAttributesMedia; import static android.app.Flags.sortSectionByTime; import static android.app.Flags.sortSectionByTime; import static android.app.NotificationManager.IMPORTANCE_MIN; import static android.app.NotificationManager.IMPORTANCE_MIN; import static android.text.TextUtils.formatSimple; import static android.text.TextUtils.formatSimple; Loading @@ -27,6 +30,7 @@ import android.util.ArrayMap; import android.util.Slog; import android.util.Slog; import android.util.proto.ProtoOutputStream; import android.util.proto.ProtoOutputStream; import com.android.internal.compat.IPlatformCompat; import com.android.tools.r8.keepanno.annotations.KeepItemKind; import com.android.tools.r8.keepanno.annotations.KeepItemKind; import com.android.tools.r8.keepanno.annotations.KeepTarget; import com.android.tools.r8.keepanno.annotations.KeepTarget; import com.android.tools.r8.keepanno.annotations.UsesReflection; import com.android.tools.r8.keepanno.annotations.UsesReflection; Loading Loading @@ -56,7 +60,8 @@ public class RankingHelper { methodName = "<init>") methodName = "<init>") }) }) public RankingHelper(Context context, RankingHandler rankingHandler, RankingConfig config, public RankingHelper(Context context, RankingHandler rankingHandler, RankingConfig config, ZenModeHelper zenHelper, NotificationUsageStats usageStats, String[] extractorNames) { ZenModeHelper zenHelper, NotificationUsageStats usageStats, String[] extractorNames, IPlatformCompat platformCompat) { mContext = context; mContext = context; mRankingHandler = rankingHandler; mRankingHandler = rankingHandler; if (sortSectionByTime()) { if (sortSectionByTime()) { Loading @@ -75,6 +80,10 @@ public class RankingHelper { extractor.initialize(mContext, usageStats); extractor.initialize(mContext, usageStats); extractor.setConfig(config); extractor.setConfig(config); extractor.setZenHelper(zenHelper); extractor.setZenHelper(zenHelper); if (restrictAudioAttributesAlarm() || restrictAudioAttributesMedia() || restrictAudioAttributesCall()) { extractor.setCompatChangeLogger(platformCompat); } mSignalExtractors[i] = extractor; mSignalExtractors[i] = extractor; } catch (ClassNotFoundException e) { } catch (ClassNotFoundException e) { Slog.w(TAG, "Couldn't find extractor " + extractorNames[i] + ".", e); Slog.w(TAG, "Couldn't find extractor " + extractorNames[i] + ".", e); Loading services/tests/uiservicestests/src/com/android/server/notification/NotificationChannelExtractorTest.java +24 −9 Original line number Original line Diff line number Diff line Loading @@ -26,14 +26,18 @@ import static android.media.AudioAttributes.USAGE_NOTIFICATION; import static android.media.AudioAttributes.USAGE_NOTIFICATION_RINGTONE; import static android.media.AudioAttributes.USAGE_NOTIFICATION_RINGTONE; import static android.media.AudioAttributes.USAGE_UNKNOWN; import static android.media.AudioAttributes.USAGE_UNKNOWN; import static android.platform.test.flag.junit.SetFlagsRule.DefaultInitValueType.DEVICE_DEFAULT; import static android.platform.test.flag.junit.SetFlagsRule.DefaultInitValueType.DEVICE_DEFAULT; import static com.android.server.notification.NotificationChannelExtractor.RESTRICT_AUDIO_ATTRIBUTES; import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertThat; import static junit.framework.Assert.assertEquals; import static junit.framework.Assert.assertEquals; import static junit.framework.Assert.assertNull; import static junit.framework.Assert.assertNull; import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.Matchers.any; import static org.mockito.Matchers.any; import static org.mockito.Matchers.anyInt; import static org.mockito.Matchers.anyInt; import static org.mockito.Matchers.eq; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import static org.mockito.Mockito.when; import android.app.Flags; import android.app.Flags; Loading @@ -43,12 +47,14 @@ import android.app.PendingIntent; import android.app.Person; import android.app.Person; import android.media.AudioAttributes; import android.media.AudioAttributes; import android.net.Uri; import android.net.Uri; import android.os.RemoteException; import android.os.UserHandle; import android.os.UserHandle; import android.platform.test.annotations.EnableFlags; import android.platform.test.annotations.EnableFlags; import android.platform.test.flag.junit.SetFlagsRule; import android.platform.test.flag.junit.SetFlagsRule; import android.provider.Settings; import android.provider.Settings; import android.service.notification.StatusBarNotification; import android.service.notification.StatusBarNotification; import com.android.internal.compat.IPlatformCompat; import com.android.server.UiServiceTestCase; import com.android.server.UiServiceTestCase; import org.junit.Before; import org.junit.Before; Loading @@ -60,6 +66,8 @@ import org.mockito.MockitoAnnotations; public class NotificationChannelExtractorTest extends UiServiceTestCase { public class NotificationChannelExtractorTest extends UiServiceTestCase { @Mock RankingConfig mConfig; @Mock RankingConfig mConfig; @Mock IPlatformCompat mPlatformCompat; @Rule @Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(DEVICE_DEFAULT); public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(DEVICE_DEFAULT); Loading @@ -73,6 +81,7 @@ public class NotificationChannelExtractorTest extends UiServiceTestCase { mExtractor = new NotificationChannelExtractor(); mExtractor = new NotificationChannelExtractor(); mExtractor.setConfig(mConfig); mExtractor.setConfig(mConfig); mExtractor.initialize(mContext, null); mExtractor.initialize(mContext, null); mExtractor.setCompatChangeLogger(mPlatformCompat); } } private NotificationRecord getRecord(NotificationChannel channel, Notification n) { private NotificationRecord getRecord(NotificationChannel channel, Notification n) { Loading @@ -82,7 +91,7 @@ public class NotificationChannelExtractorTest extends UiServiceTestCase { } } @Test @Test public void testExtractsUpdatedConversationChannel() { public void testExtractsUpdatedConversationChannel() throws RemoteException { NotificationChannel channel = new NotificationChannel("a", "a", IMPORTANCE_LOW); NotificationChannel channel = new NotificationChannel("a", "a", IMPORTANCE_LOW); final Notification n = new Notification.Builder(getContext()) final Notification n = new Notification.Builder(getContext()) .setContentTitle("foo") .setContentTitle("foo") Loading @@ -101,7 +110,7 @@ public class NotificationChannelExtractorTest extends UiServiceTestCase { } } @Test @Test public void testInvalidShortcutFlagEnabled_looksUpCorrectNonChannel() { public void testInvalidShortcutFlagEnabled_looksUpCorrectNonChannel() throws RemoteException { NotificationChannel channel = new NotificationChannel("a", "a", IMPORTANCE_LOW); NotificationChannel channel = new NotificationChannel("a", "a", IMPORTANCE_LOW); final Notification n = new Notification.Builder(getContext()) final Notification n = new Notification.Builder(getContext()) .setContentTitle("foo") .setContentTitle("foo") Loading @@ -122,7 +131,7 @@ public class NotificationChannelExtractorTest extends UiServiceTestCase { } } @Test @Test public void testInvalidShortcutFlagDisabled_looksUpCorrectChannel() { public void testInvalidShortcutFlagDisabled_looksUpCorrectChannel() throws RemoteException { NotificationChannel channel = new NotificationChannel("a", "a", IMPORTANCE_LOW); NotificationChannel channel = new NotificationChannel("a", "a", IMPORTANCE_LOW); final Notification n = new Notification.Builder(getContext()) final Notification n = new Notification.Builder(getContext()) .setContentTitle("foo") .setContentTitle("foo") Loading @@ -143,7 +152,7 @@ public class NotificationChannelExtractorTest extends UiServiceTestCase { @Test @Test @EnableFlags(Flags.FLAG_RESTRICT_AUDIO_ATTRIBUTES_CALL) @EnableFlags(Flags.FLAG_RESTRICT_AUDIO_ATTRIBUTES_CALL) public void testAudioAttributes_callStyleCanUseCallUsage() { public void testAudioAttributes_callStyleCanUseCallUsage() throws RemoteException { NotificationChannel channel = new NotificationChannel("a", "a", IMPORTANCE_HIGH); NotificationChannel channel = new NotificationChannel("a", "a", IMPORTANCE_HIGH); channel.setSound(Uri.EMPTY, new AudioAttributes.Builder() channel.setSound(Uri.EMPTY, new AudioAttributes.Builder() .setUsage(USAGE_NOTIFICATION_RINGTONE) .setUsage(USAGE_NOTIFICATION_RINGTONE) Loading @@ -162,11 +171,12 @@ public class NotificationChannelExtractorTest extends UiServiceTestCase { assertThat(mExtractor.process(r)).isNull(); assertThat(mExtractor.process(r)).isNull(); assertThat(r.getAudioAttributes().getUsage()).isEqualTo(USAGE_NOTIFICATION_RINGTONE); assertThat(r.getAudioAttributes().getUsage()).isEqualTo(USAGE_NOTIFICATION_RINGTONE); assertThat(r.getChannel()).isEqualTo(channel); assertThat(r.getChannel()).isEqualTo(channel); verify(mPlatformCompat, never()).reportChangeByUid(anyLong(), anyInt()); } } @Test @Test @EnableFlags(Flags.FLAG_RESTRICT_AUDIO_ATTRIBUTES_CALL) @EnableFlags(Flags.FLAG_RESTRICT_AUDIO_ATTRIBUTES_CALL) public void testAudioAttributes_nonCallStyleCannotUseCallUsage() { public void testAudioAttributes_nonCallStyleCannotUseCallUsage() throws RemoteException { NotificationChannel channel = new NotificationChannel("a", "a", IMPORTANCE_HIGH); NotificationChannel channel = new NotificationChannel("a", "a", IMPORTANCE_HIGH); channel.setSound(Uri.EMPTY, new AudioAttributes.Builder() channel.setSound(Uri.EMPTY, new AudioAttributes.Builder() .setUsage(USAGE_NOTIFICATION_RINGTONE) .setUsage(USAGE_NOTIFICATION_RINGTONE) Loading @@ -180,13 +190,14 @@ public class NotificationChannelExtractorTest extends UiServiceTestCase { assertThat(mExtractor.process(r)).isNull(); assertThat(mExtractor.process(r)).isNull(); // instance updated // instance updated assertThat(r.getAudioAttributes().getUsage()).isEqualTo(USAGE_NOTIFICATION); assertThat(r.getAudioAttributes().getUsage()).isEqualTo(USAGE_NOTIFICATION); verify(mPlatformCompat).reportChangeByUid(RESTRICT_AUDIO_ATTRIBUTES, r.getUid()); // in-memory channel unchanged // in-memory channel unchanged assertThat(channel.getAudioAttributes().getUsage()).isEqualTo(USAGE_NOTIFICATION_RINGTONE); assertThat(channel.getAudioAttributes().getUsage()).isEqualTo(USAGE_NOTIFICATION_RINGTONE); } } @Test @Test @EnableFlags(Flags.FLAG_RESTRICT_AUDIO_ATTRIBUTES_ALARM) @EnableFlags(Flags.FLAG_RESTRICT_AUDIO_ATTRIBUTES_ALARM) public void testAudioAttributes_alarmCategoryCanUseAlarmUsage() { public void testAudioAttributes_alarmCategoryCanUseAlarmUsage() throws RemoteException { NotificationChannel channel = new NotificationChannel("a", "a", IMPORTANCE_HIGH); NotificationChannel channel = new NotificationChannel("a", "a", IMPORTANCE_HIGH); channel.setSound(Uri.EMPTY, new AudioAttributes.Builder() channel.setSound(Uri.EMPTY, new AudioAttributes.Builder() .setUsage(USAGE_ALARM) .setUsage(USAGE_ALARM) Loading @@ -201,11 +212,12 @@ public class NotificationChannelExtractorTest extends UiServiceTestCase { assertThat(mExtractor.process(r)).isNull(); assertThat(mExtractor.process(r)).isNull(); assertThat(r.getAudioAttributes().getUsage()).isEqualTo(USAGE_ALARM); assertThat(r.getAudioAttributes().getUsage()).isEqualTo(USAGE_ALARM); assertThat(r.getChannel()).isEqualTo(channel); assertThat(r.getChannel()).isEqualTo(channel); verify(mPlatformCompat, never()).reportChangeByUid(anyLong(), anyInt()); } } @Test @Test @EnableFlags(Flags.FLAG_RESTRICT_AUDIO_ATTRIBUTES_ALARM) @EnableFlags(Flags.FLAG_RESTRICT_AUDIO_ATTRIBUTES_ALARM) public void testAudioAttributes_nonAlarmCategoryCannotUseAlarmUsage() { public void testAudioAttributes_nonAlarmCategoryCannotUseAlarmUsage() throws RemoteException { NotificationChannel channel = new NotificationChannel("a", "a", IMPORTANCE_HIGH); NotificationChannel channel = new NotificationChannel("a", "a", IMPORTANCE_HIGH); channel.setSound(Uri.EMPTY, new AudioAttributes.Builder() channel.setSound(Uri.EMPTY, new AudioAttributes.Builder() .setUsage(USAGE_ALARM) .setUsage(USAGE_ALARM) Loading @@ -219,13 +231,14 @@ public class NotificationChannelExtractorTest extends UiServiceTestCase { assertThat(mExtractor.process(r)).isNull(); assertThat(mExtractor.process(r)).isNull(); // instance updated // instance updated assertThat(r.getAudioAttributes().getUsage()).isEqualTo(USAGE_NOTIFICATION); assertThat(r.getAudioAttributes().getUsage()).isEqualTo(USAGE_NOTIFICATION); verify(mPlatformCompat).reportChangeByUid(RESTRICT_AUDIO_ATTRIBUTES, r.getUid()); // in-memory channel unchanged // in-memory channel unchanged assertThat(channel.getAudioAttributes().getUsage()).isEqualTo(USAGE_ALARM); assertThat(channel.getAudioAttributes().getUsage()).isEqualTo(USAGE_ALARM); } } @Test @Test @EnableFlags(Flags.FLAG_RESTRICT_AUDIO_ATTRIBUTES_MEDIA) @EnableFlags(Flags.FLAG_RESTRICT_AUDIO_ATTRIBUTES_MEDIA) public void testAudioAttributes_noMediaUsage() { public void testAudioAttributes_noMediaUsage() throws RemoteException { NotificationChannel channel = new NotificationChannel("a", "a", IMPORTANCE_HIGH); NotificationChannel channel = new NotificationChannel("a", "a", IMPORTANCE_HIGH); channel.setSound(Uri.EMPTY, new AudioAttributes.Builder() channel.setSound(Uri.EMPTY, new AudioAttributes.Builder() .setUsage(USAGE_MEDIA) .setUsage(USAGE_MEDIA) Loading @@ -239,13 +252,14 @@ public class NotificationChannelExtractorTest extends UiServiceTestCase { assertThat(mExtractor.process(r)).isNull(); assertThat(mExtractor.process(r)).isNull(); // instance updated // instance updated assertThat(r.getAudioAttributes().getUsage()).isEqualTo(USAGE_NOTIFICATION); assertThat(r.getAudioAttributes().getUsage()).isEqualTo(USAGE_NOTIFICATION); verify(mPlatformCompat).reportChangeByUid(RESTRICT_AUDIO_ATTRIBUTES, r.getUid()); // in-memory channel unchanged // in-memory channel unchanged assertThat(channel.getAudioAttributes().getUsage()).isEqualTo(USAGE_MEDIA); assertThat(channel.getAudioAttributes().getUsage()).isEqualTo(USAGE_MEDIA); } } @Test @Test @EnableFlags(Flags.FLAG_RESTRICT_AUDIO_ATTRIBUTES_MEDIA) @EnableFlags(Flags.FLAG_RESTRICT_AUDIO_ATTRIBUTES_MEDIA) public void testAudioAttributes_noUnknownUsage() { public void testAudioAttributes_noUnknownUsage() throws RemoteException { NotificationChannel channel = new NotificationChannel("a", "a", IMPORTANCE_HIGH); NotificationChannel channel = new NotificationChannel("a", "a", IMPORTANCE_HIGH); channel.setSound(Uri.EMPTY, new AudioAttributes.Builder() channel.setSound(Uri.EMPTY, new AudioAttributes.Builder() .setUsage(USAGE_UNKNOWN) .setUsage(USAGE_UNKNOWN) Loading @@ -259,6 +273,7 @@ public class NotificationChannelExtractorTest extends UiServiceTestCase { assertThat(mExtractor.process(r)).isNull(); assertThat(mExtractor.process(r)).isNull(); // instance updated // instance updated assertThat(r.getAudioAttributes().getUsage()).isEqualTo(USAGE_NOTIFICATION); assertThat(r.getAudioAttributes().getUsage()).isEqualTo(USAGE_NOTIFICATION); verify(mPlatformCompat).reportChangeByUid(RESTRICT_AUDIO_ATTRIBUTES, r.getUid()); // in-memory channel unchanged // in-memory channel unchanged assertThat(channel.getAudioAttributes().getUsage()).isEqualTo(USAGE_UNKNOWN); assertThat(channel.getAudioAttributes().getUsage()).isEqualTo(USAGE_UNKNOWN); } } Loading Loading
services/core/java/com/android/server/notification/NotificationChannelExtractor.java +30 −0 Original line number Original line Diff line number Diff line Loading @@ -23,9 +23,15 @@ import static android.media.AudioAttributes.USAGE_NOTIFICATION; import android.app.Notification; import android.app.Notification; import android.app.NotificationChannel; import android.app.NotificationChannel; import android.compat.annotation.ChangeId; import android.compat.annotation.LoggingOnly; import android.content.Context; import android.content.Context; import android.media.AudioAttributes; import android.media.AudioAttributes; import android.os.Binder; import android.os.RemoteException; import android.os.ServiceManager; import android.util.Slog; import android.util.Slog; import com.android.internal.compat.IPlatformCompat; /** /** * Stores the latest notification channel information for this notification * Stores the latest notification channel information for this notification Loading @@ -34,14 +40,26 @@ public class NotificationChannelExtractor implements NotificationSignalExtractor private static final String TAG = "ChannelExtractor"; private static final String TAG = "ChannelExtractor"; private static final boolean DBG = false; private static final boolean DBG = false; /** * Corrects audio attributes for notifications based on characteristics of the notifications. */ @ChangeId @LoggingOnly static final long RESTRICT_AUDIO_ATTRIBUTES = 331793339L; private RankingConfig mConfig; private RankingConfig mConfig; private Context mContext; private Context mContext; private IPlatformCompat mPlatformCompat; public void initialize(Context ctx, NotificationUsageStats usageStats) { public void initialize(Context ctx, NotificationUsageStats usageStats) { mContext = ctx; mContext = ctx; if (DBG) Slog.d(TAG, "Initializing " + getClass().getSimpleName() + "."); if (DBG) Slog.d(TAG, "Initializing " + getClass().getSimpleName() + "."); } } public void setCompatChangeLogger(IPlatformCompat platformCompat) { mPlatformCompat = platformCompat; } public RankingReconsideration process(NotificationRecord record) { public RankingReconsideration process(NotificationRecord record) { if (record == null || record.getNotification() == null) { if (record == null || record.getNotification() == null) { if (DBG) Slog.d(TAG, "skipping empty notification"); if (DBG) Slog.d(TAG, "skipping empty notification"); Loading Loading @@ -80,6 +98,7 @@ public class NotificationChannelExtractor implements NotificationSignalExtractor } } if (updateAttributes) { if (updateAttributes) { reportAudioAttributesChanged(record.getUid()); NotificationChannel clone = record.getChannel().copy(); NotificationChannel clone = record.getChannel().copy(); clone.setSound(clone.getSound(), new AudioAttributes.Builder(attributes) clone.setSound(clone.getSound(), new AudioAttributes.Builder(attributes) .setUsage(USAGE_NOTIFICATION) .setUsage(USAGE_NOTIFICATION) Loading @@ -91,6 +110,17 @@ public class NotificationChannelExtractor implements NotificationSignalExtractor return null; return null; } } private void reportAudioAttributesChanged(int uid) { final long id = Binder.clearCallingIdentity(); try { mPlatformCompat.reportChangeByUid(RESTRICT_AUDIO_ATTRIBUTES, uid); } catch (RemoteException e) { Slog.e(TAG, "Unexpected exception while reporting to changecompat", e); } finally { Binder.restoreCallingIdentity(id); } } @Override @Override public void setConfig(RankingConfig config) { public void setConfig(RankingConfig config) { mConfig = config; mConfig = config; Loading
services/core/java/com/android/server/notification/NotificationManagerService.java +2 −6 Original line number Original line Diff line number Diff line Loading @@ -2508,12 +2508,8 @@ public class NotificationManagerService extends SystemService { mAppOps, mAppOps, mUserProfiles, mUserProfiles, mShowReviewPermissionsNotification); mShowReviewPermissionsNotification); mRankingHelper = new RankingHelper(getContext(), mRankingHelper = new RankingHelper(getContext(), mRankingHandler, mPreferencesHelper, mRankingHandler, mZenModeHelper, mUsageStats, extractorNames, mPlatformCompat); mPreferencesHelper, mZenModeHelper, mUsageStats, extractorNames); mSnoozeHelper = snoozeHelper; mSnoozeHelper = snoozeHelper; mGroupHelper = groupHelper; mGroupHelper = groupHelper; mHistoryManager = historyManager; mHistoryManager = historyManager; Loading
services/core/java/com/android/server/notification/NotificationSignalExtractor.java +3 −0 Original line number Original line Diff line number Diff line Loading @@ -17,6 +17,7 @@ package com.android.server.notification; package com.android.server.notification; import android.content.Context; import android.content.Context; import com.android.internal.compat.IPlatformCompat; /** /** * Extracts signals that will be useful to the {@link NotificationComparator} and caches them * Extracts signals that will be useful to the {@link NotificationComparator} and caches them Loading Loading @@ -52,4 +53,6 @@ public interface NotificationSignalExtractor { * DND. * DND. */ */ void setZenHelper(ZenModeHelper helper); void setZenHelper(ZenModeHelper helper); default void setCompatChangeLogger(IPlatformCompat platformCompat){}; } }
services/core/java/com/android/server/notification/RankingHelper.java +10 −1 Original line number Original line Diff line number Diff line Loading @@ -15,6 +15,9 @@ */ */ package com.android.server.notification; package com.android.server.notification; import static android.app.Flags.restrictAudioAttributesAlarm; import static android.app.Flags.restrictAudioAttributesCall; import static android.app.Flags.restrictAudioAttributesMedia; import static android.app.Flags.sortSectionByTime; import static android.app.Flags.sortSectionByTime; import static android.app.NotificationManager.IMPORTANCE_MIN; import static android.app.NotificationManager.IMPORTANCE_MIN; import static android.text.TextUtils.formatSimple; import static android.text.TextUtils.formatSimple; Loading @@ -27,6 +30,7 @@ import android.util.ArrayMap; import android.util.Slog; import android.util.Slog; import android.util.proto.ProtoOutputStream; import android.util.proto.ProtoOutputStream; import com.android.internal.compat.IPlatformCompat; import com.android.tools.r8.keepanno.annotations.KeepItemKind; import com.android.tools.r8.keepanno.annotations.KeepItemKind; import com.android.tools.r8.keepanno.annotations.KeepTarget; import com.android.tools.r8.keepanno.annotations.KeepTarget; import com.android.tools.r8.keepanno.annotations.UsesReflection; import com.android.tools.r8.keepanno.annotations.UsesReflection; Loading Loading @@ -56,7 +60,8 @@ public class RankingHelper { methodName = "<init>") methodName = "<init>") }) }) public RankingHelper(Context context, RankingHandler rankingHandler, RankingConfig config, public RankingHelper(Context context, RankingHandler rankingHandler, RankingConfig config, ZenModeHelper zenHelper, NotificationUsageStats usageStats, String[] extractorNames) { ZenModeHelper zenHelper, NotificationUsageStats usageStats, String[] extractorNames, IPlatformCompat platformCompat) { mContext = context; mContext = context; mRankingHandler = rankingHandler; mRankingHandler = rankingHandler; if (sortSectionByTime()) { if (sortSectionByTime()) { Loading @@ -75,6 +80,10 @@ public class RankingHelper { extractor.initialize(mContext, usageStats); extractor.initialize(mContext, usageStats); extractor.setConfig(config); extractor.setConfig(config); extractor.setZenHelper(zenHelper); extractor.setZenHelper(zenHelper); if (restrictAudioAttributesAlarm() || restrictAudioAttributesMedia() || restrictAudioAttributesCall()) { extractor.setCompatChangeLogger(platformCompat); } mSignalExtractors[i] = extractor; mSignalExtractors[i] = extractor; } catch (ClassNotFoundException e) { } catch (ClassNotFoundException e) { Slog.w(TAG, "Couldn't find extractor " + extractorNames[i] + ".", e); Slog.w(TAG, "Couldn't find extractor " + extractorNames[i] + ".", e); Loading
services/tests/uiservicestests/src/com/android/server/notification/NotificationChannelExtractorTest.java +24 −9 Original line number Original line Diff line number Diff line Loading @@ -26,14 +26,18 @@ import static android.media.AudioAttributes.USAGE_NOTIFICATION; import static android.media.AudioAttributes.USAGE_NOTIFICATION_RINGTONE; import static android.media.AudioAttributes.USAGE_NOTIFICATION_RINGTONE; import static android.media.AudioAttributes.USAGE_UNKNOWN; import static android.media.AudioAttributes.USAGE_UNKNOWN; import static android.platform.test.flag.junit.SetFlagsRule.DefaultInitValueType.DEVICE_DEFAULT; import static android.platform.test.flag.junit.SetFlagsRule.DefaultInitValueType.DEVICE_DEFAULT; import static com.android.server.notification.NotificationChannelExtractor.RESTRICT_AUDIO_ATTRIBUTES; import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertThat; import static junit.framework.Assert.assertEquals; import static junit.framework.Assert.assertEquals; import static junit.framework.Assert.assertNull; import static junit.framework.Assert.assertNull; import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.Matchers.any; import static org.mockito.Matchers.any; import static org.mockito.Matchers.anyInt; import static org.mockito.Matchers.anyInt; import static org.mockito.Matchers.eq; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import static org.mockito.Mockito.when; import android.app.Flags; import android.app.Flags; Loading @@ -43,12 +47,14 @@ import android.app.PendingIntent; import android.app.Person; import android.app.Person; import android.media.AudioAttributes; import android.media.AudioAttributes; import android.net.Uri; import android.net.Uri; import android.os.RemoteException; import android.os.UserHandle; import android.os.UserHandle; import android.platform.test.annotations.EnableFlags; import android.platform.test.annotations.EnableFlags; import android.platform.test.flag.junit.SetFlagsRule; import android.platform.test.flag.junit.SetFlagsRule; import android.provider.Settings; import android.provider.Settings; import android.service.notification.StatusBarNotification; import android.service.notification.StatusBarNotification; import com.android.internal.compat.IPlatformCompat; import com.android.server.UiServiceTestCase; import com.android.server.UiServiceTestCase; import org.junit.Before; import org.junit.Before; Loading @@ -60,6 +66,8 @@ import org.mockito.MockitoAnnotations; public class NotificationChannelExtractorTest extends UiServiceTestCase { public class NotificationChannelExtractorTest extends UiServiceTestCase { @Mock RankingConfig mConfig; @Mock RankingConfig mConfig; @Mock IPlatformCompat mPlatformCompat; @Rule @Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(DEVICE_DEFAULT); public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(DEVICE_DEFAULT); Loading @@ -73,6 +81,7 @@ public class NotificationChannelExtractorTest extends UiServiceTestCase { mExtractor = new NotificationChannelExtractor(); mExtractor = new NotificationChannelExtractor(); mExtractor.setConfig(mConfig); mExtractor.setConfig(mConfig); mExtractor.initialize(mContext, null); mExtractor.initialize(mContext, null); mExtractor.setCompatChangeLogger(mPlatformCompat); } } private NotificationRecord getRecord(NotificationChannel channel, Notification n) { private NotificationRecord getRecord(NotificationChannel channel, Notification n) { Loading @@ -82,7 +91,7 @@ public class NotificationChannelExtractorTest extends UiServiceTestCase { } } @Test @Test public void testExtractsUpdatedConversationChannel() { public void testExtractsUpdatedConversationChannel() throws RemoteException { NotificationChannel channel = new NotificationChannel("a", "a", IMPORTANCE_LOW); NotificationChannel channel = new NotificationChannel("a", "a", IMPORTANCE_LOW); final Notification n = new Notification.Builder(getContext()) final Notification n = new Notification.Builder(getContext()) .setContentTitle("foo") .setContentTitle("foo") Loading @@ -101,7 +110,7 @@ public class NotificationChannelExtractorTest extends UiServiceTestCase { } } @Test @Test public void testInvalidShortcutFlagEnabled_looksUpCorrectNonChannel() { public void testInvalidShortcutFlagEnabled_looksUpCorrectNonChannel() throws RemoteException { NotificationChannel channel = new NotificationChannel("a", "a", IMPORTANCE_LOW); NotificationChannel channel = new NotificationChannel("a", "a", IMPORTANCE_LOW); final Notification n = new Notification.Builder(getContext()) final Notification n = new Notification.Builder(getContext()) .setContentTitle("foo") .setContentTitle("foo") Loading @@ -122,7 +131,7 @@ public class NotificationChannelExtractorTest extends UiServiceTestCase { } } @Test @Test public void testInvalidShortcutFlagDisabled_looksUpCorrectChannel() { public void testInvalidShortcutFlagDisabled_looksUpCorrectChannel() throws RemoteException { NotificationChannel channel = new NotificationChannel("a", "a", IMPORTANCE_LOW); NotificationChannel channel = new NotificationChannel("a", "a", IMPORTANCE_LOW); final Notification n = new Notification.Builder(getContext()) final Notification n = new Notification.Builder(getContext()) .setContentTitle("foo") .setContentTitle("foo") Loading @@ -143,7 +152,7 @@ public class NotificationChannelExtractorTest extends UiServiceTestCase { @Test @Test @EnableFlags(Flags.FLAG_RESTRICT_AUDIO_ATTRIBUTES_CALL) @EnableFlags(Flags.FLAG_RESTRICT_AUDIO_ATTRIBUTES_CALL) public void testAudioAttributes_callStyleCanUseCallUsage() { public void testAudioAttributes_callStyleCanUseCallUsage() throws RemoteException { NotificationChannel channel = new NotificationChannel("a", "a", IMPORTANCE_HIGH); NotificationChannel channel = new NotificationChannel("a", "a", IMPORTANCE_HIGH); channel.setSound(Uri.EMPTY, new AudioAttributes.Builder() channel.setSound(Uri.EMPTY, new AudioAttributes.Builder() .setUsage(USAGE_NOTIFICATION_RINGTONE) .setUsage(USAGE_NOTIFICATION_RINGTONE) Loading @@ -162,11 +171,12 @@ public class NotificationChannelExtractorTest extends UiServiceTestCase { assertThat(mExtractor.process(r)).isNull(); assertThat(mExtractor.process(r)).isNull(); assertThat(r.getAudioAttributes().getUsage()).isEqualTo(USAGE_NOTIFICATION_RINGTONE); assertThat(r.getAudioAttributes().getUsage()).isEqualTo(USAGE_NOTIFICATION_RINGTONE); assertThat(r.getChannel()).isEqualTo(channel); assertThat(r.getChannel()).isEqualTo(channel); verify(mPlatformCompat, never()).reportChangeByUid(anyLong(), anyInt()); } } @Test @Test @EnableFlags(Flags.FLAG_RESTRICT_AUDIO_ATTRIBUTES_CALL) @EnableFlags(Flags.FLAG_RESTRICT_AUDIO_ATTRIBUTES_CALL) public void testAudioAttributes_nonCallStyleCannotUseCallUsage() { public void testAudioAttributes_nonCallStyleCannotUseCallUsage() throws RemoteException { NotificationChannel channel = new NotificationChannel("a", "a", IMPORTANCE_HIGH); NotificationChannel channel = new NotificationChannel("a", "a", IMPORTANCE_HIGH); channel.setSound(Uri.EMPTY, new AudioAttributes.Builder() channel.setSound(Uri.EMPTY, new AudioAttributes.Builder() .setUsage(USAGE_NOTIFICATION_RINGTONE) .setUsage(USAGE_NOTIFICATION_RINGTONE) Loading @@ -180,13 +190,14 @@ public class NotificationChannelExtractorTest extends UiServiceTestCase { assertThat(mExtractor.process(r)).isNull(); assertThat(mExtractor.process(r)).isNull(); // instance updated // instance updated assertThat(r.getAudioAttributes().getUsage()).isEqualTo(USAGE_NOTIFICATION); assertThat(r.getAudioAttributes().getUsage()).isEqualTo(USAGE_NOTIFICATION); verify(mPlatformCompat).reportChangeByUid(RESTRICT_AUDIO_ATTRIBUTES, r.getUid()); // in-memory channel unchanged // in-memory channel unchanged assertThat(channel.getAudioAttributes().getUsage()).isEqualTo(USAGE_NOTIFICATION_RINGTONE); assertThat(channel.getAudioAttributes().getUsage()).isEqualTo(USAGE_NOTIFICATION_RINGTONE); } } @Test @Test @EnableFlags(Flags.FLAG_RESTRICT_AUDIO_ATTRIBUTES_ALARM) @EnableFlags(Flags.FLAG_RESTRICT_AUDIO_ATTRIBUTES_ALARM) public void testAudioAttributes_alarmCategoryCanUseAlarmUsage() { public void testAudioAttributes_alarmCategoryCanUseAlarmUsage() throws RemoteException { NotificationChannel channel = new NotificationChannel("a", "a", IMPORTANCE_HIGH); NotificationChannel channel = new NotificationChannel("a", "a", IMPORTANCE_HIGH); channel.setSound(Uri.EMPTY, new AudioAttributes.Builder() channel.setSound(Uri.EMPTY, new AudioAttributes.Builder() .setUsage(USAGE_ALARM) .setUsage(USAGE_ALARM) Loading @@ -201,11 +212,12 @@ public class NotificationChannelExtractorTest extends UiServiceTestCase { assertThat(mExtractor.process(r)).isNull(); assertThat(mExtractor.process(r)).isNull(); assertThat(r.getAudioAttributes().getUsage()).isEqualTo(USAGE_ALARM); assertThat(r.getAudioAttributes().getUsage()).isEqualTo(USAGE_ALARM); assertThat(r.getChannel()).isEqualTo(channel); assertThat(r.getChannel()).isEqualTo(channel); verify(mPlatformCompat, never()).reportChangeByUid(anyLong(), anyInt()); } } @Test @Test @EnableFlags(Flags.FLAG_RESTRICT_AUDIO_ATTRIBUTES_ALARM) @EnableFlags(Flags.FLAG_RESTRICT_AUDIO_ATTRIBUTES_ALARM) public void testAudioAttributes_nonAlarmCategoryCannotUseAlarmUsage() { public void testAudioAttributes_nonAlarmCategoryCannotUseAlarmUsage() throws RemoteException { NotificationChannel channel = new NotificationChannel("a", "a", IMPORTANCE_HIGH); NotificationChannel channel = new NotificationChannel("a", "a", IMPORTANCE_HIGH); channel.setSound(Uri.EMPTY, new AudioAttributes.Builder() channel.setSound(Uri.EMPTY, new AudioAttributes.Builder() .setUsage(USAGE_ALARM) .setUsage(USAGE_ALARM) Loading @@ -219,13 +231,14 @@ public class NotificationChannelExtractorTest extends UiServiceTestCase { assertThat(mExtractor.process(r)).isNull(); assertThat(mExtractor.process(r)).isNull(); // instance updated // instance updated assertThat(r.getAudioAttributes().getUsage()).isEqualTo(USAGE_NOTIFICATION); assertThat(r.getAudioAttributes().getUsage()).isEqualTo(USAGE_NOTIFICATION); verify(mPlatformCompat).reportChangeByUid(RESTRICT_AUDIO_ATTRIBUTES, r.getUid()); // in-memory channel unchanged // in-memory channel unchanged assertThat(channel.getAudioAttributes().getUsage()).isEqualTo(USAGE_ALARM); assertThat(channel.getAudioAttributes().getUsage()).isEqualTo(USAGE_ALARM); } } @Test @Test @EnableFlags(Flags.FLAG_RESTRICT_AUDIO_ATTRIBUTES_MEDIA) @EnableFlags(Flags.FLAG_RESTRICT_AUDIO_ATTRIBUTES_MEDIA) public void testAudioAttributes_noMediaUsage() { public void testAudioAttributes_noMediaUsage() throws RemoteException { NotificationChannel channel = new NotificationChannel("a", "a", IMPORTANCE_HIGH); NotificationChannel channel = new NotificationChannel("a", "a", IMPORTANCE_HIGH); channel.setSound(Uri.EMPTY, new AudioAttributes.Builder() channel.setSound(Uri.EMPTY, new AudioAttributes.Builder() .setUsage(USAGE_MEDIA) .setUsage(USAGE_MEDIA) Loading @@ -239,13 +252,14 @@ public class NotificationChannelExtractorTest extends UiServiceTestCase { assertThat(mExtractor.process(r)).isNull(); assertThat(mExtractor.process(r)).isNull(); // instance updated // instance updated assertThat(r.getAudioAttributes().getUsage()).isEqualTo(USAGE_NOTIFICATION); assertThat(r.getAudioAttributes().getUsage()).isEqualTo(USAGE_NOTIFICATION); verify(mPlatformCompat).reportChangeByUid(RESTRICT_AUDIO_ATTRIBUTES, r.getUid()); // in-memory channel unchanged // in-memory channel unchanged assertThat(channel.getAudioAttributes().getUsage()).isEqualTo(USAGE_MEDIA); assertThat(channel.getAudioAttributes().getUsage()).isEqualTo(USAGE_MEDIA); } } @Test @Test @EnableFlags(Flags.FLAG_RESTRICT_AUDIO_ATTRIBUTES_MEDIA) @EnableFlags(Flags.FLAG_RESTRICT_AUDIO_ATTRIBUTES_MEDIA) public void testAudioAttributes_noUnknownUsage() { public void testAudioAttributes_noUnknownUsage() throws RemoteException { NotificationChannel channel = new NotificationChannel("a", "a", IMPORTANCE_HIGH); NotificationChannel channel = new NotificationChannel("a", "a", IMPORTANCE_HIGH); channel.setSound(Uri.EMPTY, new AudioAttributes.Builder() channel.setSound(Uri.EMPTY, new AudioAttributes.Builder() .setUsage(USAGE_UNKNOWN) .setUsage(USAGE_UNKNOWN) Loading @@ -259,6 +273,7 @@ public class NotificationChannelExtractorTest extends UiServiceTestCase { assertThat(mExtractor.process(r)).isNull(); assertThat(mExtractor.process(r)).isNull(); // instance updated // instance updated assertThat(r.getAudioAttributes().getUsage()).isEqualTo(USAGE_NOTIFICATION); assertThat(r.getAudioAttributes().getUsage()).isEqualTo(USAGE_NOTIFICATION); verify(mPlatformCompat).reportChangeByUid(RESTRICT_AUDIO_ATTRIBUTES, r.getUid()); // in-memory channel unchanged // in-memory channel unchanged assertThat(channel.getAudioAttributes().getUsage()).isEqualTo(USAGE_UNKNOWN); assertThat(channel.getAudioAttributes().getUsage()).isEqualTo(USAGE_UNKNOWN); } } Loading