Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b92621bb authored by Julia Reynolds's avatar Julia Reynolds
Browse files

Log when audio attributes are corrected

Test: NotificationChannelExtractorTest
Bug: 331793339
Flag: android.app.restrict_audio_attributes_media,
android.app.restrict_audio_attributes_call,
android.app.restrict_audio_attributes_alarm STAGING

Change-Id: I82e3b4a9a5783e11196b2c1eca08039da10b6d79
parent c96af15b
Loading
Loading
Loading
Loading
+30 −0
Original line number Diff line number Diff line
@@ -23,9 +23,15 @@ import static android.media.AudioAttributes.USAGE_NOTIFICATION;

import android.app.Notification;
import android.app.NotificationChannel;
import android.compat.annotation.ChangeId;
import android.compat.annotation.LoggingOnly;
import android.content.Context;
import android.media.AudioAttributes;
import android.os.Binder;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.util.Slog;
import com.android.internal.compat.IPlatformCompat;

/**
 * Stores the latest notification channel information for this notification
@@ -34,14 +40,26 @@ public class NotificationChannelExtractor implements NotificationSignalExtractor
    private static final String TAG = "ChannelExtractor";
    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 Context mContext;
    private IPlatformCompat mPlatformCompat;

    public void initialize(Context ctx, NotificationUsageStats usageStats) {
        mContext = ctx;
        if (DBG) Slog.d(TAG, "Initializing  " + getClass().getSimpleName() + ".");
    }

    public void setCompatChangeLogger(IPlatformCompat platformCompat) {
        mPlatformCompat = platformCompat;
    }

    public RankingReconsideration process(NotificationRecord record) {
        if (record == null || record.getNotification() == null) {
            if (DBG) Slog.d(TAG, "skipping empty notification");
@@ -80,6 +98,7 @@ public class NotificationChannelExtractor implements NotificationSignalExtractor
            }

            if (updateAttributes) {
                reportAudioAttributesChanged(record.getUid());
                NotificationChannel clone = record.getChannel().copy();
                clone.setSound(clone.getSound(), new AudioAttributes.Builder(attributes)
                        .setUsage(USAGE_NOTIFICATION)
@@ -91,6 +110,17 @@ public class NotificationChannelExtractor implements NotificationSignalExtractor
        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
    public void setConfig(RankingConfig config) {
        mConfig = config;
+2 −6
Original line number Diff line number Diff line
@@ -2508,12 +2508,8 @@ public class NotificationManagerService extends SystemService {
                mAppOps,
                mUserProfiles,
                mShowReviewPermissionsNotification);
        mRankingHelper = new RankingHelper(getContext(),
                mRankingHandler,
                mPreferencesHelper,
                mZenModeHelper,
                mUsageStats,
                extractorNames);
        mRankingHelper = new RankingHelper(getContext(), mRankingHandler, mPreferencesHelper,
                mZenModeHelper, mUsageStats, extractorNames, mPlatformCompat);
        mSnoozeHelper = snoozeHelper;
        mGroupHelper = groupHelper;
        mHistoryManager = historyManager;
+3 −0
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
package com.android.server.notification;

import android.content.Context;
import com.android.internal.compat.IPlatformCompat;

/**
 * Extracts signals that will be useful to the {@link NotificationComparator} and caches them
@@ -52,4 +53,6 @@ public interface NotificationSignalExtractor {
     *               DND.
     */
    void setZenHelper(ZenModeHelper helper);

    default void setCompatChangeLogger(IPlatformCompat platformCompat){};
}
+10 −1
Original line number Diff line number Diff line
@@ -15,6 +15,9 @@
 */
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.NotificationManager.IMPORTANCE_MIN;
import static android.text.TextUtils.formatSimple;
@@ -27,6 +30,7 @@ import android.util.ArrayMap;
import android.util.Slog;
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.KeepTarget;
import com.android.tools.r8.keepanno.annotations.UsesReflection;
@@ -56,7 +60,8 @@ public class RankingHelper {
                        methodName = "<init>")
            })
    public RankingHelper(Context context, RankingHandler rankingHandler, RankingConfig config,
            ZenModeHelper zenHelper, NotificationUsageStats usageStats, String[] extractorNames) {
            ZenModeHelper zenHelper, NotificationUsageStats usageStats, String[] extractorNames,
            IPlatformCompat platformCompat) {
        mContext = context;
        mRankingHandler = rankingHandler;
        if (sortSectionByTime()) {
@@ -75,6 +80,10 @@ public class RankingHelper {
                extractor.initialize(mContext, usageStats);
                extractor.setConfig(config);
                extractor.setZenHelper(zenHelper);
                if (restrictAudioAttributesAlarm() || restrictAudioAttributesMedia()
                        || restrictAudioAttributesCall()) {
                    extractor.setCompatChangeLogger(platformCompat);
                }
                mSignalExtractors[i] = extractor;
            } catch (ClassNotFoundException e) {
                Slog.w(TAG, "Couldn't find extractor " + extractorNames[i] + ".", e);
+24 −9
Original line number Diff line number Diff line
@@ -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_UNKNOWN;
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 junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertNull;

import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.eq;
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 android.app.Flags;
@@ -43,12 +47,14 @@ import android.app.PendingIntent;
import android.app.Person;
import android.media.AudioAttributes;
import android.net.Uri;
import android.os.RemoteException;
import android.os.UserHandle;
import android.platform.test.annotations.EnableFlags;
import android.platform.test.flag.junit.SetFlagsRule;
import android.provider.Settings;
import android.service.notification.StatusBarNotification;

import com.android.internal.compat.IPlatformCompat;
import com.android.server.UiServiceTestCase;

import org.junit.Before;
@@ -60,6 +66,8 @@ import org.mockito.MockitoAnnotations;
public class NotificationChannelExtractorTest extends UiServiceTestCase {

    @Mock RankingConfig mConfig;
    @Mock
    IPlatformCompat mPlatformCompat;

    @Rule
    public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(DEVICE_DEFAULT);
@@ -73,6 +81,7 @@ public class NotificationChannelExtractorTest extends UiServiceTestCase {
        mExtractor = new NotificationChannelExtractor();
        mExtractor.setConfig(mConfig);
        mExtractor.initialize(mContext, null);
        mExtractor.setCompatChangeLogger(mPlatformCompat);
    }

    private NotificationRecord getRecord(NotificationChannel channel, Notification n) {
@@ -82,7 +91,7 @@ public class NotificationChannelExtractorTest extends UiServiceTestCase {
    }

    @Test
    public void testExtractsUpdatedConversationChannel() {
    public void testExtractsUpdatedConversationChannel() throws RemoteException {
        NotificationChannel channel = new NotificationChannel("a", "a", IMPORTANCE_LOW);
        final Notification n = new Notification.Builder(getContext())
                .setContentTitle("foo")
@@ -101,7 +110,7 @@ public class NotificationChannelExtractorTest extends UiServiceTestCase {
    }

    @Test
    public void testInvalidShortcutFlagEnabled_looksUpCorrectNonChannel() {
    public void testInvalidShortcutFlagEnabled_looksUpCorrectNonChannel() throws RemoteException {
        NotificationChannel channel = new NotificationChannel("a", "a", IMPORTANCE_LOW);
        final Notification n = new Notification.Builder(getContext())
                .setContentTitle("foo")
@@ -122,7 +131,7 @@ public class NotificationChannelExtractorTest extends UiServiceTestCase {
    }

    @Test
    public void testInvalidShortcutFlagDisabled_looksUpCorrectChannel() {
    public void testInvalidShortcutFlagDisabled_looksUpCorrectChannel() throws RemoteException {
        NotificationChannel channel = new NotificationChannel("a", "a", IMPORTANCE_LOW);
        final Notification n = new Notification.Builder(getContext())
                .setContentTitle("foo")
@@ -143,7 +152,7 @@ public class NotificationChannelExtractorTest extends UiServiceTestCase {

    @Test
    @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);
        channel.setSound(Uri.EMPTY, new AudioAttributes.Builder()
                .setUsage(USAGE_NOTIFICATION_RINGTONE)
@@ -162,11 +171,12 @@ public class NotificationChannelExtractorTest extends UiServiceTestCase {
        assertThat(mExtractor.process(r)).isNull();
        assertThat(r.getAudioAttributes().getUsage()).isEqualTo(USAGE_NOTIFICATION_RINGTONE);
        assertThat(r.getChannel()).isEqualTo(channel);
        verify(mPlatformCompat, never()).reportChangeByUid(anyLong(), anyInt());
    }

    @Test
    @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);
        channel.setSound(Uri.EMPTY, new AudioAttributes.Builder()
                .setUsage(USAGE_NOTIFICATION_RINGTONE)
@@ -180,13 +190,14 @@ public class NotificationChannelExtractorTest extends UiServiceTestCase {
        assertThat(mExtractor.process(r)).isNull();
        // instance updated
        assertThat(r.getAudioAttributes().getUsage()).isEqualTo(USAGE_NOTIFICATION);
        verify(mPlatformCompat).reportChangeByUid(RESTRICT_AUDIO_ATTRIBUTES, r.getUid());
        // in-memory channel unchanged
        assertThat(channel.getAudioAttributes().getUsage()).isEqualTo(USAGE_NOTIFICATION_RINGTONE);
    }

    @Test
    @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);
        channel.setSound(Uri.EMPTY, new AudioAttributes.Builder()
                .setUsage(USAGE_ALARM)
@@ -201,11 +212,12 @@ public class NotificationChannelExtractorTest extends UiServiceTestCase {
        assertThat(mExtractor.process(r)).isNull();
        assertThat(r.getAudioAttributes().getUsage()).isEqualTo(USAGE_ALARM);
        assertThat(r.getChannel()).isEqualTo(channel);
        verify(mPlatformCompat, never()).reportChangeByUid(anyLong(), anyInt());
    }

    @Test
    @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);
        channel.setSound(Uri.EMPTY, new AudioAttributes.Builder()
                .setUsage(USAGE_ALARM)
@@ -219,13 +231,14 @@ public class NotificationChannelExtractorTest extends UiServiceTestCase {
        assertThat(mExtractor.process(r)).isNull();
        // instance updated
        assertThat(r.getAudioAttributes().getUsage()).isEqualTo(USAGE_NOTIFICATION);
        verify(mPlatformCompat).reportChangeByUid(RESTRICT_AUDIO_ATTRIBUTES, r.getUid());
        // in-memory channel unchanged
        assertThat(channel.getAudioAttributes().getUsage()).isEqualTo(USAGE_ALARM);
    }

    @Test
    @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);
        channel.setSound(Uri.EMPTY, new AudioAttributes.Builder()
                .setUsage(USAGE_MEDIA)
@@ -239,13 +252,14 @@ public class NotificationChannelExtractorTest extends UiServiceTestCase {
        assertThat(mExtractor.process(r)).isNull();
        // instance updated
        assertThat(r.getAudioAttributes().getUsage()).isEqualTo(USAGE_NOTIFICATION);
        verify(mPlatformCompat).reportChangeByUid(RESTRICT_AUDIO_ATTRIBUTES, r.getUid());
        // in-memory channel unchanged
        assertThat(channel.getAudioAttributes().getUsage()).isEqualTo(USAGE_MEDIA);
    }

    @Test
    @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);
        channel.setSound(Uri.EMPTY, new AudioAttributes.Builder()
                .setUsage(USAGE_UNKNOWN)
@@ -259,6 +273,7 @@ public class NotificationChannelExtractorTest extends UiServiceTestCase {
        assertThat(mExtractor.process(r)).isNull();
        // instance updated
        assertThat(r.getAudioAttributes().getUsage()).isEqualTo(USAGE_NOTIFICATION);
        verify(mPlatformCompat).reportChangeByUid(RESTRICT_AUDIO_ATTRIBUTES, r.getUid());
        // in-memory channel unchanged
        assertThat(channel.getAudioAttributes().getUsage()).isEqualTo(USAGE_UNKNOWN);
    }
Loading