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

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

Merge "Migrate DND related apis to permissionhelper"

parents f3da531c 84c44400
Loading
Loading
Loading
Loading
+0 −1
Original line number Diff line number Diff line
@@ -115,7 +115,6 @@ interface INotificationManager
    ParceledListSlice getNotificationChannelGroups(String pkg);
    boolean onlyHasDefaultChannel(String pkg, int uid);
    boolean areChannelsBypassingDnd();
    int getAppsBypassingDndCount(int uid);
    ParceledListSlice getNotificationChannelsBypassingDnd(String pkg, int userId);
    boolean isPackagePaused(String pkg);
    void deleteNotificationHistoryItem(String pkg, int uid, long postedTime);
+9 −8
Original line number Diff line number Diff line
@@ -479,6 +479,7 @@ public class NotificationManagerService extends SystemService {
    private ActivityManagerInternal mAmi;
    private IPackageManager mPackageManager;
    private PackageManager mPackageManagerClient;
    private PackageManagerInternal mPackageManagerInternal;
    AudioManager mAudioManager;
    AudioManagerInternal mAudioManagerInternal;
    // Can be null for wear
@@ -2212,6 +2213,7 @@ public class NotificationManagerService extends SystemService {
        mUgmInternal = ugmInternal;
        mPackageManager = packageManager;
        mPackageManagerClient = packageManagerClient;
        mPackageManagerInternal = LocalServices.getService(PackageManagerInternal.class);
        mAppOps = appOps;
        mAppOpsService = iAppOps;
        try {
@@ -2292,10 +2294,12 @@ public class NotificationManagerService extends SystemService {
                });
            }
        });
        mPermissionHelper = permissionHelper;
        mPreferencesHelper = new PreferencesHelper(getContext(),
                mPackageManagerClient,
                mRankingHandler,
                mZenModeHelper,
                mPermissionHelper,
                new NotificationChannelLoggerImpl(),
                mAppOps,
                new SysUiStatsEvent.BuilderFactory());
@@ -2309,7 +2313,6 @@ public class NotificationManagerService extends SystemService {
        mGroupHelper = groupHelper;
        mVibratorHelper = new VibratorHelper(getContext());
        mHistoryManager = historyManager;
        mPermissionHelper = permissionHelper;

        // This is a ManagedServices object that keeps track of the listeners.
        mListeners = notificationListeners;
@@ -3481,7 +3484,7 @@ public class NotificationManagerService extends SystemService {

                mPreferencesHelper.setEnabled(pkg, uid, enabled);
                // TODO (b/194833441): this is being ignored by app ops now that the permission
                // exists
                // exists, so send the broadcast manually
                mAppOps.setMode(AppOpsManager.OP_POST_NOTIFICATION, uid, pkg,
                        enabled ? MODE_ALLOWED : AppOpsManager.MODE_IGNORED);

@@ -4081,16 +4084,14 @@ public class NotificationManagerService extends SystemService {
                    + " cannot read channels for " + targetPkg + " in " + userId);
        }

        @Override
        public int getAppsBypassingDndCount(int userId) {
            checkCallerIsSystem();
            return mPreferencesHelper.getAppsBypassingDndCount(userId);
        }

        @Override
        public ParceledListSlice<NotificationChannel> getNotificationChannelsBypassingDnd(
                String pkg, int userId) {
            checkCallerIsSystem();
            if (!areNotificationsEnabledForPackage(pkg,
                    mPackageManagerInternal.getPackageUid(pkg, 0, userId))) {
                return ParceledListSlice.emptyList();
            }
            return mPreferencesHelper.getNotificationChannelsBypassingDnd(pkg, userId);
        }

+4 −0
Original line number Diff line number Diff line
@@ -58,6 +58,10 @@ public final class PermissionHelper {
        mMigrationEnabled = migrationEnabled;
    }

    public boolean isMigrationEnabled() {
        return mMigrationEnabled;
    }

    /**
     * Returns whether the given uid holds the notification permission. Must not be called
     * with a lock held.
+116 −106
Original line number Diff line number Diff line
@@ -169,6 +169,7 @@ public class PreferencesHelper implements RankingConfig {
    private final PackageManager mPm;
    private final RankingHandler mRankingHandler;
    private final ZenModeHelper mZenModeHelper;
    private final PermissionHelper mPermissionHelper;
    private final NotificationChannelLogger mNotificationChannelLogger;
    private final AppOpsManager mAppOps;

@@ -187,12 +188,14 @@ public class PreferencesHelper implements RankingConfig {
    private int mCurrentUserId = UserHandle.USER_NULL;

    public PreferencesHelper(Context context, PackageManager pm, RankingHandler rankingHandler,
            ZenModeHelper zenHelper, NotificationChannelLogger notificationChannelLogger,
            ZenModeHelper zenHelper, PermissionHelper permHelper,
            NotificationChannelLogger notificationChannelLogger,
            AppOpsManager appOpsManager,
            SysUiStatsEvent.BuilderFactory statsEventBuilderFactory) {
        mContext = context;
        mZenModeHelper = zenHelper;
        mRankingHandler = rankingHandler;
        mPermissionHelper = permHelper;
        mPm = pm;
        mNotificationChannelLogger = notificationChannelLogger;
        mAppOps = appOpsManager;
@@ -791,6 +794,7 @@ public class PreferencesHelper implements RankingConfig {
        Objects.requireNonNull(group);
        Objects.requireNonNull(group.getId());
        Objects.requireNonNull(!TextUtils.isEmpty(group.getName()));
        boolean needsDndChange = false;
        synchronized (mPackagePreferences) {
            PackagePreferences r = getOrCreatePackagePreferencesLocked(pkg, uid);
            if (r == null) {
@@ -809,7 +813,7 @@ public class PreferencesHelper implements RankingConfig {
                    // but the system can
                    if (group.isBlocked() != oldGroup.isBlocked()) {
                        group.lockFields(NotificationChannelGroup.USER_LOCKED_BLOCKED_STATE);
                        updateChannelsBypassingDnd();
                        needsDndChange = true;
                    }
                }
            }
@@ -822,6 +826,9 @@ public class PreferencesHelper implements RankingConfig {
            }
            r.groups.put(group.getId(), group);
        }
        if (needsDndChange) {
            updateChannelsBypassingDnd();
        }
    }

    @Override
@@ -831,7 +838,7 @@ public class PreferencesHelper implements RankingConfig {
        Objects.requireNonNull(channel);
        Objects.requireNonNull(channel.getId());
        Preconditions.checkArgument(!TextUtils.isEmpty(channel.getName()));
        boolean needsPolicyFileChange = false, wasUndeleted = false;
        boolean needsPolicyFileChange = false, wasUndeleted = false, needsDndChange = false;
        synchronized (mPackagePreferences) {
            PackagePreferences r = getOrCreatePackagePreferencesLocked(pkg, uid);
            if (r == null) {
@@ -897,7 +904,7 @@ public class PreferencesHelper implements RankingConfig {

                        if (bypassDnd != mAreChannelsBypassingDnd
                                || previousExistingImportance != existing.getImportance()) {
                            updateChannelsBypassingDnd();
                            needsDndChange = true;
                        }
                    }
                }
@@ -912,9 +919,7 @@ public class PreferencesHelper implements RankingConfig {
                    mNotificationChannelLogger.logNotificationChannelModified(existing, uid, pkg,
                            previousLoggingImportance, false);
                }
                return needsPolicyFileChange;
            }

            } else {
                if (r.channels.size() >= NOTIFICATION_CHANNEL_COUNT_LIMIT) {
                    throw new IllegalStateException("Limit exceed; cannot create more channels");
                }
@@ -955,18 +960,24 @@ public class PreferencesHelper implements RankingConfig {

                // validate parent
                if (channel.getParentChannelId() != null) {
                Preconditions.checkArgument(r.channels.containsKey(channel.getParentChannelId()),
                    Preconditions.checkArgument(
                            r.channels.containsKey(channel.getParentChannelId()),
                            "Tried to create a conversation channel without a preexisting parent");
                }

                r.channels.put(channel.getId(), channel);
                if (channel.canBypassDnd() != mAreChannelsBypassingDnd) {
                updateChannelsBypassingDnd();
                    needsDndChange = true;
                }
                MetricsLogger.action(getChannelLog(channel, pkg).setType(
                        com.android.internal.logging.nano.MetricsProto.MetricsEvent.TYPE_OPEN));
                mNotificationChannelLogger.logNotificationChannelCreated(channel, uid, pkg);
            }
        }

        if (needsDndChange) {
            updateChannelsBypassingDnd();
        }

        return needsPolicyFileChange;
    }
@@ -997,6 +1008,7 @@ public class PreferencesHelper implements RankingConfig {
            boolean fromUser) {
        Objects.requireNonNull(updatedChannel);
        Objects.requireNonNull(updatedChannel.getId());
        boolean needsDndChange = false;
        synchronized (mPackagePreferences) {
            PackagePreferences r = getOrCreatePackagePreferencesLocked(pkg, uid);
            if (r == null) {
@@ -1050,9 +1062,12 @@ public class PreferencesHelper implements RankingConfig {

            if (updatedChannel.canBypassDnd() != mAreChannelsBypassingDnd
                    || channel.getImportance() != updatedChannel.getImportance()) {
                updateChannelsBypassingDnd();
                needsDndChange = true;
            }
        }
        if (needsDndChange) {
            updateChannelsBypassingDnd();
        }
        updateConfig();
    }

@@ -1126,6 +1141,8 @@ public class PreferencesHelper implements RankingConfig {

    @Override
    public boolean deleteNotificationChannel(String pkg, int uid, String channelId) {
        boolean deletedChannel = false;
        boolean channelBypassedDnd = false;
        synchronized (mPackagePreferences) {
            PackagePreferences r = getPackagePreferencesLocked(pkg, uid);
            if (r == null) {
@@ -1133,13 +1150,18 @@ public class PreferencesHelper implements RankingConfig {
            }
            NotificationChannel channel = r.channels.get(channelId);
            if (channel != null) {
                return deleteNotificationChannelLocked(channel, pkg, uid);
                channelBypassedDnd = channel.canBypassDnd();
                deletedChannel = deleteNotificationChannelLocked(channel, pkg, uid);
            }
            return false;
        }
        if (channelBypassedDnd) {
            updateChannelsBypassingDnd();
        }
        return deletedChannel;
    }

    private boolean deleteNotificationChannelLocked(NotificationChannel channel, String pkg, int uid) {
    private boolean deleteNotificationChannelLocked(NotificationChannel channel, String pkg,
            int uid) {
        if (!channel.isDeleted()) {
            channel.setDeleted(true);
            channel.setDeletedTimeMs(System.currentTimeMillis());
@@ -1147,10 +1169,6 @@ public class PreferencesHelper implements RankingConfig {
            lm.setType(com.android.internal.logging.nano.MetricsProto.MetricsEvent.TYPE_CLOSE);
            MetricsLogger.action(lm);
            mNotificationChannelLogger.logNotificationChannelDeleted(channel, uid, pkg);

            if (mAreChannelsBypassingDnd && channel.canBypassDnd()) {
                updateChannelsBypassingDnd();
            }
            return true;
        }
        return false;
@@ -1352,6 +1370,7 @@ public class PreferencesHelper implements RankingConfig {
    public List<NotificationChannel> deleteNotificationChannelGroup(String pkg, int uid,
            String groupId) {
        List<NotificationChannel> deletedChannels = new ArrayList<>();
        boolean groupBypassedDnd = false;
        synchronized (mPackagePreferences) {
            PackagePreferences r = getPackagePreferencesLocked(pkg, uid);
            if (r == null || TextUtils.isEmpty(groupId)) {
@@ -1368,11 +1387,15 @@ public class PreferencesHelper implements RankingConfig {
            for (int i = 0; i < N; i++) {
                final NotificationChannel nc = r.channels.valueAt(i);
                if (groupId.equals(nc.getGroup())) {
                    groupBypassedDnd |= nc.canBypassDnd();
                    deleteNotificationChannelLocked(nc, pkg, uid);
                    deletedChannels.add(nc);
                }
            }
        }
        if (groupBypassedDnd) {
            updateChannelsBypassingDnd();
        }
        return deletedChannels;
    }

@@ -1495,8 +1518,8 @@ public class PreferencesHelper implements RankingConfig {

    public @NonNull List<String> deleteConversations(String pkg, int uid,
            Set<String> conversationIds) {
        synchronized (mPackagePreferences) {
        List<String> deletedChannelIds = new ArrayList<>();
        synchronized (mPackagePreferences) {
            PackagePreferences r = getPackagePreferencesLocked(pkg, uid);
            if (r == null) {
                return deletedChannelIds;
@@ -1517,12 +1540,12 @@ public class PreferencesHelper implements RankingConfig {
                    deletedChannelIds.add(nc.getId());
                }
            }
        }
        if (!deletedChannelIds.isEmpty() && mAreChannelsBypassingDnd) {
            updateChannelsBypassingDnd();
        }
        return deletedChannelIds;
    }
    }

    @Override
    public ParceledListSlice<NotificationChannel> getNotificationChannels(String pkg, int uid,
@@ -1554,8 +1577,7 @@ public class PreferencesHelper implements RankingConfig {
        synchronized (mPackagePreferences) {
            final PackagePreferences r = mPackagePreferences.get(
                    packagePreferencesKey(pkg, userId));
            // notifications from this package aren't blocked
            if (r != null && r.importance != IMPORTANCE_NONE) {
            if (r != null) {
                for (NotificationChannel channel : r.channels.values()) {
                    if (channelIsLiveLocked(r, channel) && channel.canBypassDnd()) {
                        channels.add(channel);
@@ -1621,33 +1643,6 @@ public class PreferencesHelper implements RankingConfig {
        }
    }

    /**
     * Returns the number of apps that have at least one notification channel that can bypass DND
     * for given particular user
     */
    public int getAppsBypassingDndCount(int userId) {
        int count = 0;
        synchronized (mPackagePreferences) {
            final int numPackagePreferences = mPackagePreferences.size();
            for (int i = 0; i < numPackagePreferences; i++) {
                final PackagePreferences r = mPackagePreferences.valueAt(i);
                // Package isn't associated with this userId or notifications from this package are
                // blocked
                if (userId != UserHandle.getUserId(r.uid) || r.importance == IMPORTANCE_NONE) {
                    continue;
                }

                for (NotificationChannel channel : r.channels.values()) {
                    if (channelIsLiveLocked(r, channel) && channel.canBypassDnd()) {
                        count++;
                        break;
                    }
                }
            }
        }
        return count;
    }

    /**
     * Syncs {@link #mAreChannelsBypassingDnd} with the current user's notification policy before
     * updating
@@ -1655,41 +1650,56 @@ public class PreferencesHelper implements RankingConfig {
    private void syncChannelsBypassingDnd() {
        mAreChannelsBypassingDnd = (mZenModeHelper.getNotificationPolicy().state
                & NotificationManager.Policy.STATE_CHANNELS_BYPASSING_DND) == 1;

        updateChannelsBypassingDnd();
    }

    /**
     * Updates the user's NotificationPolicy based on whether the current userId
     * has channels bypassing DND
     * @param userId
     */
    private void updateChannelsBypassingDnd() {
        ArraySet<Pair<String, Integer>> candidatePkgs = new ArraySet<>();

        synchronized (mPackagePreferences) {
            final int numPackagePreferences = mPackagePreferences.size();
            for (int i = 0; i < numPackagePreferences; i++) {
                final PackagePreferences r = mPackagePreferences.valueAt(i);
                // Package isn't associated with the current userId or notifications from this
                // package are blocked
                if (mCurrentUserId != UserHandle.getUserId(r.uid)
                        || r.importance == IMPORTANCE_NONE) {
                // Package isn't associated with the current userId
                if (mCurrentUserId != UserHandle.getUserId(r.uid)) {
                    continue;
                }

                for (NotificationChannel channel : r.channels.values()) {
                    if (channelIsLiveLocked(r, channel) && channel.canBypassDnd()) {
                        if (!mAreChannelsBypassingDnd) {
                            mAreChannelsBypassingDnd = true;
                            updateZenPolicy(true);
                        candidatePkgs.add(new Pair(r.pkg, r.uid));
                        break;
                    }
                        return;
                }
            }
        }
        for (int i = candidatePkgs.size() - 1; i >= 0; i--) {
            Pair<String, Integer> app = candidatePkgs.valueAt(i);
            if (mPermissionHelper.isMigrationEnabled()) {
                if (!mPermissionHelper.hasPermission(app.second)) {
                    candidatePkgs.removeAt(i);
                }
            } else {
                synchronized (mPackagePreferences) {
                    PackagePreferences r = getPackagePreferencesLocked(app.first, app.second);
                    if (r == null) {
                        continue;
                    }
                    if (r.importance == IMPORTANCE_NONE) {
                        candidatePkgs.removeAt(i);
                    }
                }
            }
        }
        // If no channels bypass DND, update the zen policy once to disable DND bypass.
        if (mAreChannelsBypassingDnd) {
            mAreChannelsBypassingDnd = false;
            updateZenPolicy(false);
        boolean haveBypassingApps = candidatePkgs.size() > 0;
        if (mAreChannelsBypassingDnd != haveBypassingApps) {
            mAreChannelsBypassingDnd = haveBypassingApps;
            updateZenPolicy(mAreChannelsBypassingDnd);
        }
    }

+16 −0
Original line number Diff line number Diff line
@@ -132,6 +132,7 @@ import android.content.pm.ApplicationInfo;
import android.content.pm.IPackageManager;
import android.content.pm.LauncherApps;
import android.content.pm.PackageManager;
import android.content.pm.PackageManagerInternal;
import android.content.pm.ParceledListSlice;
import android.content.pm.ShortcutInfo;
import android.content.pm.ShortcutServiceInternal;
@@ -248,6 +249,8 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
    @Mock
    private PackageManager mPackageManagerClient;
    @Mock
    private PackageManagerInternal mPackageManagerInternal;
    @Mock
    private WindowManagerInternal mWindowManagerInternal;
    @Mock
    private PermissionHelper mPermissionHelper;
@@ -375,6 +378,8 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
        LocalServices.addService(DeviceIdleInternal.class, deviceIdleInternal);
        LocalServices.removeServiceForTest(ActivityManagerInternal.class);
        LocalServices.addService(ActivityManagerInternal.class, mAmi);
        LocalServices.removeServiceForTest(PackageManagerInternal.class);
        LocalServices.addService(PackageManagerInternal.class, mPackageManagerInternal);
        mContext.addMockSystemService(Context.ALARM_SERVICE, mAlarmManager);

        doNothing().when(mContext).sendBroadcastAsUser(any(), any(), any());
@@ -8307,4 +8312,15 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
    public void testMigrationDisabledByDefault() {
        assertThat(mService.mEnableAppSettingMigration).isFalse();
    }

    @Test
    public void testGetNotificationChannelsBypassingDnd_blocked() throws RemoteException {
        mService.setPreferencesHelper(mPreferencesHelper);
        when(mPreferencesHelper.getImportance(PKG, mUid)).thenReturn(IMPORTANCE_NONE);

        assertThat(mBinderService.getNotificationChannelsBypassingDnd(PKG, mUid).getList())
                .isEmpty();
        verify(mPermissionHelper, never()).hasPermission(anyInt());
        verify(mPreferencesHelper, never()).getNotificationChannelsBypassingDnd(PKG, mUid);
    }
}
Loading