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

Commit 8a7b7899 authored by Julia Reynolds's avatar Julia Reynolds Committed by Android (Google) Code Review
Browse files

Merge "Log when audio attributes are corrected" into main

parents db3f9172 b92621bb
Loading
Loading
Loading
Loading
+30 −0
Original line number Original line Diff line number Diff line
@@ -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
@@ -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");
@@ -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)
@@ -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;
+2 −6
Original line number Original line Diff line number Diff line
@@ -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;
+3 −0
Original line number Original line Diff line number Diff line
@@ -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
@@ -52,4 +53,6 @@ public interface NotificationSignalExtractor {
     *               DND.
     *               DND.
     */
     */
    void setZenHelper(ZenModeHelper helper);
    void setZenHelper(ZenModeHelper helper);

    default void setCompatChangeLogger(IPlatformCompat platformCompat){};
}
}
+10 −1
Original line number Original line Diff line number Diff line
@@ -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;
@@ -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;
@@ -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()) {
@@ -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);
+24 −9
Original line number Original line 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_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;
@@ -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;
@@ -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);
@@ -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) {
@@ -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")
@@ -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")
@@ -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")
@@ -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)
@@ -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)
@@ -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)
@@ -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)
@@ -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)
@@ -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)
@@ -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