1 /* 2 * Copyright (C) 2018 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.systemui.statusbar.notification; 18 19 import android.Manifest; 20 import android.app.AppGlobals; 21 import android.app.Notification; 22 import android.content.pm.IPackageManager; 23 import android.content.pm.PackageManager; 24 import android.os.RemoteException; 25 import android.service.notification.StatusBarNotification; 26 27 import com.android.internal.annotations.VisibleForTesting; 28 import com.android.systemui.Dependency; 29 import com.android.systemui.ForegroundServiceController; 30 import com.android.systemui.statusbar.NotificationLockscreenUserManager; 31 import com.android.systemui.statusbar.notification.collection.NotificationData; 32 import com.android.systemui.statusbar.notification.collection.NotificationEntry; 33 import com.android.systemui.statusbar.phone.NotificationGroupManager; 34 import com.android.systemui.statusbar.phone.ShadeController; 35 import com.android.systemui.statusbar.phone.StatusBar; 36 37 import javax.inject.Inject; 38 import javax.inject.Singleton; 39 40 /** Component which manages the various reasons a notification might be filtered out. */ 41 @Singleton 42 public class NotificationFilter { 43 44 private final NotificationGroupManager mGroupManager = Dependency.get( 45 NotificationGroupManager.class); 46 47 private NotificationData.KeyguardEnvironment mEnvironment; 48 private ShadeController mShadeController; 49 private ForegroundServiceController mFsc; 50 private NotificationLockscreenUserManager mUserManager; 51 52 @Inject NotificationFilter()53 public NotificationFilter() {} 54 getEnvironment()55 private NotificationData.KeyguardEnvironment getEnvironment() { 56 if (mEnvironment == null) { 57 mEnvironment = Dependency.get(NotificationData.KeyguardEnvironment.class); 58 } 59 return mEnvironment; 60 } 61 getShadeController()62 private ShadeController getShadeController() { 63 if (mShadeController == null) { 64 mShadeController = Dependency.get(ShadeController.class); 65 } 66 return mShadeController; 67 } 68 getFsc()69 private ForegroundServiceController getFsc() { 70 if (mFsc == null) { 71 mFsc = Dependency.get(ForegroundServiceController.class); 72 } 73 return mFsc; 74 } 75 getUserManager()76 private NotificationLockscreenUserManager getUserManager() { 77 if (mUserManager == null) { 78 mUserManager = Dependency.get(NotificationLockscreenUserManager.class); 79 } 80 return mUserManager; 81 } 82 83 84 /** 85 * @return true if the provided notification should NOT be shown right now. 86 */ shouldFilterOut(NotificationEntry entry)87 public boolean shouldFilterOut(NotificationEntry entry) { 88 final StatusBarNotification sbn = entry.notification; 89 if (!(getEnvironment().isDeviceProvisioned() 90 || showNotificationEvenIfUnprovisioned(sbn))) { 91 return true; 92 } 93 94 if (!getEnvironment().isNotificationForCurrentProfiles(sbn)) { 95 return true; 96 } 97 98 if (getUserManager().isLockscreenPublicMode(sbn.getUserId()) 99 && (sbn.getNotification().visibility == Notification.VISIBILITY_SECRET 100 || getUserManager().shouldHideNotifications(sbn.getUserId()) 101 || getUserManager().shouldHideNotifications(sbn.getKey()))) { 102 return true; 103 } 104 105 if (getShadeController().isDozing() && entry.shouldSuppressAmbient()) { 106 return true; 107 } 108 109 if (!getShadeController().isDozing() && entry.shouldSuppressNotificationList()) { 110 return true; 111 } 112 113 if (entry.suspended) { 114 return true; 115 } 116 117 if (!StatusBar.ENABLE_CHILD_NOTIFICATIONS 118 && mGroupManager.isChildInGroupWithSummary(sbn)) { 119 return true; 120 } 121 122 if (getFsc().isDisclosureNotification(sbn) 123 && !getFsc().isDisclosureNeededForUser(sbn.getUserId())) { 124 // this is a foreground-service disclosure for a user that does not need to show one 125 return true; 126 } 127 if (getFsc().isSystemAlertNotification(sbn)) { 128 final String[] apps = sbn.getNotification().extras.getStringArray( 129 Notification.EXTRA_FOREGROUND_APPS); 130 if (apps != null && apps.length >= 1) { 131 if (!getFsc().isSystemAlertWarningNeeded(sbn.getUserId(), apps[0])) { 132 return true; 133 } 134 } 135 } 136 return false; 137 } 138 139 // Q: What kinds of notifications should show during setup? 140 // A: Almost none! Only things coming from packages with permission 141 // android.permission.NOTIFICATION_DURING_SETUP that also have special "kind" tags marking them 142 // as relevant for setup (see below). showNotificationEvenIfUnprovisioned(StatusBarNotification sbn)143 private static boolean showNotificationEvenIfUnprovisioned(StatusBarNotification sbn) { 144 return showNotificationEvenIfUnprovisioned(AppGlobals.getPackageManager(), sbn); 145 } 146 147 @VisibleForTesting showNotificationEvenIfUnprovisioned(IPackageManager packageManager, StatusBarNotification sbn)148 static boolean showNotificationEvenIfUnprovisioned(IPackageManager packageManager, 149 StatusBarNotification sbn) { 150 return checkUidPermission(packageManager, Manifest.permission.NOTIFICATION_DURING_SETUP, 151 sbn.getUid()) == PackageManager.PERMISSION_GRANTED 152 && sbn.getNotification().extras.getBoolean(Notification.EXTRA_ALLOW_DURING_SETUP); 153 } 154 checkUidPermission(IPackageManager packageManager, String permission, int uid)155 private static int checkUidPermission(IPackageManager packageManager, String permission, 156 int uid) { 157 try { 158 return packageManager.checkUidPermission(permission, uid); 159 } catch (RemoteException e) { 160 throw e.rethrowFromSystemServer(); 161 } 162 } 163 } 164