| /* |
| * Copyright (C) 2018 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package com.android.systemui.statusbar.notification; |
| |
| import android.Manifest; |
| import android.app.AppGlobals; |
| import android.app.Notification; |
| import android.content.pm.IPackageManager; |
| import android.content.pm.PackageManager; |
| import android.os.RemoteException; |
| import android.service.notification.StatusBarNotification; |
| |
| import com.android.internal.annotations.VisibleForTesting; |
| import com.android.systemui.Dependency; |
| import com.android.systemui.ForegroundServiceController; |
| import com.android.systemui.statusbar.NotificationLockscreenUserManager; |
| import com.android.systemui.statusbar.notification.collection.NotificationData; |
| import com.android.systemui.statusbar.notification.collection.NotificationEntry; |
| import com.android.systemui.statusbar.phone.NotificationGroupManager; |
| import com.android.systemui.statusbar.phone.ShadeController; |
| import com.android.systemui.statusbar.phone.StatusBar; |
| |
| import javax.inject.Inject; |
| import javax.inject.Singleton; |
| |
| /** Component which manages the various reasons a notification might be filtered out. */ |
| @Singleton |
| public class NotificationFilter { |
| |
| private final NotificationGroupManager mGroupManager = Dependency.get( |
| NotificationGroupManager.class); |
| |
| private NotificationData.KeyguardEnvironment mEnvironment; |
| private ShadeController mShadeController; |
| private ForegroundServiceController mFsc; |
| private NotificationLockscreenUserManager mUserManager; |
| |
| @Inject |
| public NotificationFilter() {} |
| |
| private NotificationData.KeyguardEnvironment getEnvironment() { |
| if (mEnvironment == null) { |
| mEnvironment = Dependency.get(NotificationData.KeyguardEnvironment.class); |
| } |
| return mEnvironment; |
| } |
| |
| private ShadeController getShadeController() { |
| if (mShadeController == null) { |
| mShadeController = Dependency.get(ShadeController.class); |
| } |
| return mShadeController; |
| } |
| |
| private ForegroundServiceController getFsc() { |
| if (mFsc == null) { |
| mFsc = Dependency.get(ForegroundServiceController.class); |
| } |
| return mFsc; |
| } |
| |
| private NotificationLockscreenUserManager getUserManager() { |
| if (mUserManager == null) { |
| mUserManager = Dependency.get(NotificationLockscreenUserManager.class); |
| } |
| return mUserManager; |
| } |
| |
| |
| /** |
| * @return true if the provided notification should NOT be shown right now. |
| */ |
| public boolean shouldFilterOut(NotificationEntry entry) { |
| final StatusBarNotification sbn = entry.notification; |
| if (!(getEnvironment().isDeviceProvisioned() |
| || showNotificationEvenIfUnprovisioned(sbn))) { |
| return true; |
| } |
| |
| if (!getEnvironment().isNotificationForCurrentProfiles(sbn)) { |
| return true; |
| } |
| |
| if (getUserManager().isLockscreenPublicMode(sbn.getUserId()) |
| && (sbn.getNotification().visibility == Notification.VISIBILITY_SECRET |
| || getUserManager().shouldHideNotifications(sbn.getUserId()) |
| || getUserManager().shouldHideNotifications(sbn.getKey()))) { |
| return true; |
| } |
| |
| if (getShadeController().isDozing() && entry.shouldSuppressAmbient()) { |
| return true; |
| } |
| |
| if (!getShadeController().isDozing() && entry.shouldSuppressNotificationList()) { |
| return true; |
| } |
| |
| if (entry.suspended) { |
| return true; |
| } |
| |
| if (!StatusBar.ENABLE_CHILD_NOTIFICATIONS |
| && mGroupManager.isChildInGroupWithSummary(sbn)) { |
| return true; |
| } |
| |
| if (getFsc().isDisclosureNotification(sbn) |
| && !getFsc().isDisclosureNeededForUser(sbn.getUserId())) { |
| // this is a foreground-service disclosure for a user that does not need to show one |
| return true; |
| } |
| if (getFsc().isSystemAlertNotification(sbn)) { |
| final String[] apps = sbn.getNotification().extras.getStringArray( |
| Notification.EXTRA_FOREGROUND_APPS); |
| if (apps != null && apps.length >= 1) { |
| if (!getFsc().isSystemAlertWarningNeeded(sbn.getUserId(), apps[0])) { |
| return true; |
| } |
| } |
| } |
| |
| if (entry.isBubble() && !entry.showInShadeWhenBubble()) { |
| return true; |
| } |
| |
| return false; |
| } |
| |
| // Q: What kinds of notifications should show during setup? |
| // A: Almost none! Only things coming from packages with permission |
| // android.permission.NOTIFICATION_DURING_SETUP that also have special "kind" tags marking them |
| // as relevant for setup (see below). |
| private static boolean showNotificationEvenIfUnprovisioned(StatusBarNotification sbn) { |
| return showNotificationEvenIfUnprovisioned(AppGlobals.getPackageManager(), sbn); |
| } |
| |
| @VisibleForTesting |
| static boolean showNotificationEvenIfUnprovisioned(IPackageManager packageManager, |
| StatusBarNotification sbn) { |
| return checkUidPermission(packageManager, Manifest.permission.NOTIFICATION_DURING_SETUP, |
| sbn.getUid()) == PackageManager.PERMISSION_GRANTED |
| && sbn.getNotification().extras.getBoolean(Notification.EXTRA_ALLOW_DURING_SETUP); |
| } |
| |
| private static int checkUidPermission(IPackageManager packageManager, String permission, |
| int uid) { |
| try { |
| return packageManager.checkUidPermission(permission, uid); |
| } catch (RemoteException e) { |
| throw e.rethrowFromSystemServer(); |
| } |
| } |
| } |