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

Commit 8655879e authored by Android Build Merger (Role)'s avatar Android Build Merger (Role) Committed by Android (Google) Code Review
Browse files

Merge "Merge "Allow system apps to make channels that bypass DND" into pi-dev...

Merge "Merge "Allow system apps to make channels that bypass DND" into pi-dev am: a4a76af3" into pi-dev-plus-aosp
parents e3190757 c570c01f
Loading
Loading
Loading
Loading
+83 −2
Original line number Diff line number Diff line
@@ -29,18 +29,23 @@ import android.app.NotificationChannelGroup;
import android.app.NotificationManager;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.ParceledListSlice;
import android.content.pm.Signature;
import android.content.res.Resources;
import android.metrics.LogMaker;
import android.os.Build;
import android.os.UserHandle;
import android.print.PrintManager;
import android.provider.Settings.Secure;
import android.service.notification.NotificationListenerService.Ranking;
import android.service.notification.RankingHelperProto;
import android.service.notification.RankingHelperProto.RecordProto;
import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.Pair;
import android.util.Slog;
import android.util.SparseBooleanArray;
import android.util.proto.ProtoOutputStream;
@@ -95,12 +100,18 @@ public class RankingHelper implements RankingConfig {
    private final ArrayMap<String, Record> mRecords = new ArrayMap<>(); // pkg|uid => Record
    private final ArrayMap<String, NotificationRecord> mProxyByGroupTmp = new ArrayMap<>();
    private final ArrayMap<String, Record> mRestoredWithoutUids = new ArrayMap<>(); // pkg => Record
    private final ArrayMap<Pair<String, Integer>, Boolean> mSystemAppCache = new ArrayMap<>();

    private final Context mContext;
    private final RankingHandler mRankingHandler;
    private final PackageManager mPm;
    private SparseBooleanArray mBadgingEnabled;

    private Signature[] mSystemSignature;
    private String mPermissionControllerPackageName;
    private String mServicesSystemSharedLibPackageName;
    private String mSharedSystemSharedLibPackageName;

    public RankingHelper(Context context, PackageManager pm, RankingHandler rankingHandler,
            ZenModeHelper zenHelper, NotificationUsageStats usageStats, String[] extractorNames) {
        mContext = context;
@@ -130,6 +141,8 @@ public class RankingHelper implements RankingConfig {
                Slog.w(TAG, "Problem accessing extractor " + extractorNames[i] + ".", e);
            }
        }

        getSignatures();
    }

    @SuppressWarnings("unchecked")
@@ -571,7 +584,7 @@ public class RankingHelper implements RankingConfig {
        if (NotificationChannel.DEFAULT_CHANNEL_ID.equals(channel.getId())) {
            throw new IllegalArgumentException("Reserved id");
        }

        final boolean isSystemApp = isSystemPackage(pkg, uid);
        NotificationChannel existing = r.channels.get(channel.getId());
        // Keep most of the existing settings
        if (existing != null && fromTargetApp) {
@@ -597,6 +610,11 @@ public class RankingHelper implements RankingConfig {
                existing.setImportance(channel.getImportance());
            }

            // system apps can bypass dnd if the user hasn't changed any fields on the channel yet
            if (existing.getUserLockedFields() == 0 & isSystemApp) {
                existing.setBypassDnd(channel.canBypassDnd());
            }

            updateConfig();
            return;
        }
@@ -604,9 +622,12 @@ public class RankingHelper implements RankingConfig {
                || channel.getImportance() > NotificationManager.IMPORTANCE_MAX) {
            throw new IllegalArgumentException("Invalid importance level");
        }

        // Reset fields that apps aren't allowed to set.
        if (fromTargetApp) {
        if (fromTargetApp && !isSystemApp) {
            channel.setBypassDnd(r.priority == Notification.PRIORITY_MAX);
        }
        if (fromTargetApp) {
            channel.setLockscreenVisibility(r.visibility);
        }
        clearLockedFields(channel);
@@ -616,6 +637,7 @@ public class RankingHelper implements RankingConfig {
        if (!r.showBadge) {
            channel.setShowBadge(false);
        }

        r.channels.put(channel.getId(), channel);
        MetricsLogger.action(getChannelLog(channel, pkg).setType(
                MetricsProto.MetricsEvent.TYPE_OPEN));
@@ -625,6 +647,65 @@ public class RankingHelper implements RankingConfig {
        channel.unlockFields(channel.getUserLockedFields());
    }

    /**
     * Determine whether a package is a "system package", in which case certain things (like
     * bypassing DND) should be allowed.
     */
    private boolean isSystemPackage(String pkg, int uid) {
        Pair<String, Integer> app = new Pair(pkg, uid);
        if (mSystemAppCache.containsKey(app)) {
            return mSystemAppCache.get(app);
        }

        PackageInfo pi;
        try {
            pi = mPm.getPackageInfoAsUser(
                    pkg, PackageManager.GET_SIGNATURES, UserHandle.getUserId(uid));
        } catch (NameNotFoundException e) {
            Slog.w(TAG, "Can't find pkg", e);
            return false;
        }
        boolean isSystem = (mSystemSignature[0] != null
                && mSystemSignature[0].equals(getFirstSignature(pi)))
                || pkg.equals(mPermissionControllerPackageName)
                || pkg.equals(mServicesSystemSharedLibPackageName)
                || pkg.equals(mSharedSystemSharedLibPackageName)
                || pkg.equals(PrintManager.PRINT_SPOOLER_PACKAGE_NAME)
                || isDeviceProvisioningPackage(pkg);
        mSystemAppCache.put(app, isSystem);
        return isSystem;
    }

    private Signature getFirstSignature(PackageInfo pkg) {
        if (pkg != null && pkg.signatures != null && pkg.signatures.length > 0) {
            return pkg.signatures[0];
        }
        return null;
    }

    private Signature getSystemSignature() {
        try {
            final PackageInfo sys = mPm.getPackageInfoAsUser(
                    "android", PackageManager.GET_SIGNATURES, UserHandle.USER_SYSTEM);
            return getFirstSignature(sys);
        } catch (NameNotFoundException e) {
        }
        return null;
    }

    private boolean isDeviceProvisioningPackage(String packageName) {
        String deviceProvisioningPackage = mContext.getResources().getString(
                com.android.internal.R.string.config_deviceProvisioningPackage);
        return deviceProvisioningPackage != null && deviceProvisioningPackage.equals(packageName);
    }

    private void getSignatures() {
        mSystemSignature = new Signature[]{getSystemSignature()};
        mPermissionControllerPackageName = mPm.getPermissionControllerPackageName();
        mServicesSystemSharedLibPackageName = mPm.getServicesSystemSharedLibraryPackageName();
        mSharedSystemSharedLibPackageName = mPm.getSharedSystemSharedLibraryPackageName();
    }

    @Override
    public void updateNotificationChannel(String pkg, int uid, NotificationChannel updatedChannel,
            boolean fromUser) {
+59 −0
Original line number Diff line number Diff line
@@ -47,7 +47,9 @@ import android.content.ContentProvider;
import android.content.Context;
import android.content.IContentProvider;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.Signature;
import android.content.res.Resources;
import android.graphics.Color;
import android.media.AudioAttributes;
@@ -97,6 +99,8 @@ public class RankingHelperTest extends UiServiceTestCase {
    private static final UserHandle USER = UserHandle.of(0);
    private static final String UPDATED_PKG = "updatedPkg";
    private static final int UID2 = 1111;
    private static final String SYSTEM_PKG = "android";
    private static final int SYSTEM_UID= 1000;
    private static final UserHandle USER2 = UserHandle.of(10);
    private static final String TEST_CHANNEL_ID = "test_channel_id";
    private static final String TEST_AUTHORITY = "test";
@@ -136,8 +140,15 @@ public class RankingHelperTest extends UiServiceTestCase {
        upgrade.targetSdkVersion = Build.VERSION_CODES.O;
        when(mPm.getApplicationInfoAsUser(eq(PKG), anyInt(), anyInt())).thenReturn(legacy);
        when(mPm.getApplicationInfoAsUser(eq(UPDATED_PKG), anyInt(), anyInt())).thenReturn(upgrade);
        when(mPm.getApplicationInfoAsUser(eq(SYSTEM_PKG), anyInt(), anyInt())).thenReturn(upgrade);
        when(mPm.getPackageUidAsUser(eq(PKG), anyInt())).thenReturn(UID);
        when(mPm.getPackageUidAsUser(eq(UPDATED_PKG), anyInt())).thenReturn(UID2);
        when(mPm.getPackageUidAsUser(eq(SYSTEM_PKG), anyInt())).thenReturn(SYSTEM_UID);
        PackageInfo info = mock(PackageInfo.class);
        info.signatures = new Signature[] {mock(Signature.class)};
        when(mPm.getPackageInfoAsUser(eq(SYSTEM_PKG), anyInt(), anyInt())).thenReturn(info);
        when(mPm.getPackageInfoAsUser(eq(PKG), anyInt(), anyInt()))
                .thenReturn(mock(PackageInfo.class));
        when(mContext.getResources()).thenReturn(
                InstrumentationRegistry.getContext().getResources());
        when(mContext.getContentResolver()).thenReturn(
@@ -1627,4 +1638,52 @@ public class RankingHelperTest extends UiServiceTestCase {
        assertEquals(1, retrieved.getChannels().size());
        compareChannels(a, findChannel(retrieved.getChannels(), a.getId()));
    }

    @Test
    public void testAndroidPkgCanBypassDnd_creation() {

        NotificationChannel test = new NotificationChannel("A", "a", IMPORTANCE_LOW);
        test.setBypassDnd(true);

        mHelper.createNotificationChannel(SYSTEM_PKG, SYSTEM_UID, test, true);

        assertTrue(mHelper.getNotificationChannel(SYSTEM_PKG, SYSTEM_UID, "A", false)
                .canBypassDnd());
    }

    @Test
    public void testNormalPkgCannotBypassDnd_creation() {
        NotificationChannel test = new NotificationChannel("A", "a", IMPORTANCE_LOW);
        test.setBypassDnd(true);

        mHelper.createNotificationChannel(PKG, 1000, test, true);

        assertFalse(mHelper.getNotificationChannel(PKG, 1000, "A", false).canBypassDnd());
    }

    @Test
    public void testAndroidPkgCanBypassDnd_update() throws Exception {
        NotificationChannel test = new NotificationChannel("A", "a", IMPORTANCE_LOW);
        mHelper.createNotificationChannel(SYSTEM_PKG, SYSTEM_UID, test, true);

        NotificationChannel update = new NotificationChannel("A", "a", IMPORTANCE_LOW);
        update.setBypassDnd(true);
        mHelper.createNotificationChannel(SYSTEM_PKG, SYSTEM_UID, update, true);

        assertTrue(mHelper.getNotificationChannel(SYSTEM_PKG, SYSTEM_UID, "A", false)
                .canBypassDnd());

        // setup + 1st check
        verify(mPm, times(2)).getPackageInfoAsUser(any(), anyInt(), anyInt());
    }

    @Test
    public void testNormalPkgCannotBypassDnd_update() {
        NotificationChannel test = new NotificationChannel("A", "a", IMPORTANCE_LOW);
        mHelper.createNotificationChannel(PKG, 1000, test, true);
        NotificationChannel update = new NotificationChannel("A", "a", IMPORTANCE_LOW);
        update.setBypassDnd(true);
        mHelper.createNotificationChannel(PKG, 1000, update, true);
        assertFalse(mHelper.getNotificationChannel(PKG, 1000, "A", false).canBypassDnd());
    }
}