Merge "Remove notification permission feature flag" into tm-dev am: af7982277b
Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/18164160 Change-Id: Ib8aaa5d29fb04be54d2378d68ca42a8a46d332f0 Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
@@ -314,7 +314,6 @@ package android.app {
|
||||
public final class NotificationChannel implements android.os.Parcelable {
|
||||
method public int getOriginalImportance();
|
||||
method public boolean isImportanceLockedByCriticalDeviceFunction();
|
||||
method public boolean isImportanceLockedByOEM();
|
||||
method public void lockFields(int);
|
||||
method public void setDeleted(boolean);
|
||||
method public void setDeletedTimeMs(long);
|
||||
|
||||
@@ -863,14 +863,6 @@ public final class NotificationChannel implements Parcelable {
|
||||
mImportanceLockedDefaultApp = locked;
|
||||
}
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
@TestApi
|
||||
public boolean isImportanceLockedByOEM() {
|
||||
return mImportanceLockedByOEM;
|
||||
}
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
|
||||
@@ -10154,15 +10154,6 @@ public final class Settings {
|
||||
@Readable
|
||||
public static final String NOTIFICATION_DISMISS_RTL = "notification_dismiss_rtl";
|
||||
|
||||
/**
|
||||
* Whether the app-level notification setting is represented by a manifest permission.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@Readable
|
||||
public static final String NOTIFICATION_PERMISSION_ENABLED =
|
||||
"notification_permission_enabled";
|
||||
|
||||
/**
|
||||
* Comma separated list of QS tiles that have been auto-added already.
|
||||
* @hide
|
||||
|
||||
@@ -5509,16 +5509,7 @@ public class SettingsProvider extends ContentProvider {
|
||||
currentVersion = 209;
|
||||
}
|
||||
if (currentVersion == 209) {
|
||||
// Version 209: Enable enforcement of
|
||||
// android.Manifest.permission#POST_NOTIFICATIONS in order for applications
|
||||
// to post notifications.
|
||||
final SettingsState secureSettings = getSecureSettingsLocked(userId);
|
||||
secureSettings.insertSettingLocked(
|
||||
Secure.NOTIFICATION_PERMISSION_ENABLED,
|
||||
/* enabled= */ "1",
|
||||
/* tag= */ null,
|
||||
/* makeDefault= */ false,
|
||||
SettingsState.SYSTEM_PACKAGE_NAME);
|
||||
// removed now that feature is enabled for everyone
|
||||
currentVersion = 210;
|
||||
}
|
||||
|
||||
|
||||
@@ -160,8 +160,7 @@ class ChannelEditorDialogController @Inject constructor(
|
||||
val channels = groupList
|
||||
.flatMap { group ->
|
||||
group.channels.asSequence().filterNot { channel ->
|
||||
channel.isImportanceLockedByOEM ||
|
||||
channel.importance == IMPORTANCE_NONE ||
|
||||
channel.importance == IMPORTANCE_NONE ||
|
||||
channel.isImportanceLockedByCriticalDeviceFunction
|
||||
}
|
||||
}
|
||||
|
||||
@@ -376,44 +376,24 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
|
||||
* calls.
|
||||
*/
|
||||
private static Boolean isSystemNotification(Context context, StatusBarNotification sbn) {
|
||||
// TODO (b/194833441): clean up before launch
|
||||
if (Settings.Secure.getIntForUser(context.getContentResolver(),
|
||||
Settings.Secure.NOTIFICATION_PERMISSION_ENABLED, 0, USER_SYSTEM) == 1) {
|
||||
INotificationManager iNm = INotificationManager.Stub.asInterface(
|
||||
ServiceManager.getService(Context.NOTIFICATION_SERVICE));
|
||||
INotificationManager iNm = INotificationManager.Stub.asInterface(
|
||||
ServiceManager.getService(Context.NOTIFICATION_SERVICE));
|
||||
|
||||
boolean isSystem = false;
|
||||
try {
|
||||
isSystem = iNm.isPermissionFixed(sbn.getPackageName(), sbn.getUserId());
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "cannot reach NMS");
|
||||
}
|
||||
RoleManager rm = context.getSystemService(RoleManager.class);
|
||||
List<String> fixedRoleHolders = new ArrayList<>();
|
||||
fixedRoleHolders.addAll(rm.getRoleHolders(RoleManager.ROLE_DIALER));
|
||||
fixedRoleHolders.addAll(rm.getRoleHolders(RoleManager.ROLE_EMERGENCY));
|
||||
if (fixedRoleHolders.contains(sbn.getPackageName())) {
|
||||
isSystem = true;
|
||||
}
|
||||
|
||||
return isSystem;
|
||||
} else {
|
||||
PackageManager packageManager = CentralSurfaces.getPackageManagerForUser(
|
||||
context, sbn.getUser().getIdentifier());
|
||||
Boolean isSystemNotification = null;
|
||||
|
||||
try {
|
||||
PackageInfo packageInfo = packageManager.getPackageInfo(
|
||||
sbn.getPackageName(), PackageManager.GET_SIGNATURES);
|
||||
|
||||
isSystemNotification =
|
||||
com.android.settingslib.Utils.isSystemPackage(
|
||||
context.getResources(), packageManager, packageInfo);
|
||||
} catch (PackageManager.NameNotFoundException e) {
|
||||
Log.e(TAG, "cacheIsSystemNotification: Could not find package info");
|
||||
}
|
||||
return isSystemNotification;
|
||||
boolean isSystem = false;
|
||||
try {
|
||||
isSystem = iNm.isPermissionFixed(sbn.getPackageName(), sbn.getUserId());
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "cannot reach NMS");
|
||||
}
|
||||
RoleManager rm = context.getSystemService(RoleManager.class);
|
||||
List<String> fixedRoleHolders = new ArrayList<>();
|
||||
fixedRoleHolders.addAll(rm.getRoleHolders(RoleManager.ROLE_DIALER));
|
||||
fixedRoleHolders.addAll(rm.getRoleHolders(RoleManager.ROLE_EMERGENCY));
|
||||
if (fixedRoleHolders.contains(sbn.getPackageName())) {
|
||||
isSystem = true;
|
||||
}
|
||||
|
||||
return isSystem;
|
||||
}
|
||||
|
||||
public NotificationContentView[] getLayouts() {
|
||||
@@ -567,9 +547,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
|
||||
mEntry.mIsSystemNotification = isSystemNotification(mContext, mEntry.getSbn());
|
||||
}
|
||||
|
||||
// TODO (b/194833441): remove when we've migrated to permission
|
||||
boolean isNonblockable = mEntry.getChannel().isImportanceLockedByOEM()
|
||||
|| mEntry.getChannel().isImportanceLockedByCriticalDeviceFunction();
|
||||
boolean isNonblockable = mEntry.getChannel().isImportanceLockedByCriticalDeviceFunction();
|
||||
|
||||
if (!isNonblockable && mEntry != null && mEntry.mIsSystemNotification != null) {
|
||||
if (mEntry.mIsSystemNotification) {
|
||||
|
||||
@@ -317,15 +317,6 @@ public class ExpandableNotificationRowTest extends SysuiTestCase {
|
||||
assertFalse(row.getIsNonblockable());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetIsNonblockable_oemLocked() throws Exception {
|
||||
ExpandableNotificationRow row =
|
||||
mNotificationTestHelper.createRow(mNotificationTestHelper.createNotification());
|
||||
row.getEntry().getChannel().setImportanceLockedByOEM(true);
|
||||
|
||||
assertTrue(row.getIsNonblockable());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetIsNonblockable_criticalDeviceFunction() throws Exception {
|
||||
ExpandableNotificationRow row =
|
||||
|
||||
@@ -656,10 +656,10 @@ public class NotificationManagerService extends SystemService {
|
||||
|
||||
private int mWarnRemoteViewsSizeBytes;
|
||||
private int mStripRemoteViewsSizeBytes;
|
||||
final boolean mEnableAppSettingMigration;
|
||||
private boolean mForceUserSetOnUpgrade;
|
||||
|
||||
private MetricsLogger mMetricsLogger;
|
||||
private NotificationChannelLogger mNotificationChannelLogger;
|
||||
private TriPredicate<String, Integer, String> mAllowedManagedServicePackages;
|
||||
|
||||
private final SavePolicyFileRunnable mSavePolicyFile = new SavePolicyFileRunnable();
|
||||
@@ -1999,12 +1999,6 @@ public class NotificationManagerService extends SystemService {
|
||||
mNotificationRecordLogger = notificationRecordLogger;
|
||||
mNotificationInstanceIdSequence = notificationInstanceIdSequence;
|
||||
Notification.processAllowlistToken = ALLOWLIST_TOKEN;
|
||||
// TODO (b/194833441): remove when OS is ready for migration. This flag is checked once
|
||||
// rather than having a settings observer because some of the behaviors (e.g. readXml) only
|
||||
// happen on reboot
|
||||
mEnableAppSettingMigration = Settings.Secure.getIntForUser(
|
||||
getContext().getContentResolver(),
|
||||
Settings.Secure.NOTIFICATION_PERMISSION_ENABLED, 0, USER_SYSTEM) == 1;
|
||||
}
|
||||
|
||||
// TODO - replace these methods with new fields in the VisibleForTesting constructor
|
||||
@@ -2184,7 +2178,7 @@ public class NotificationManagerService extends SystemService {
|
||||
TelephonyManager telephonyManager, ActivityManagerInternal ami,
|
||||
MultiRateLimiter toastRateLimiter, PermissionHelper permissionHelper,
|
||||
UsageStatsManagerInternal usageStatsManagerInternal,
|
||||
TelecomManager telecomManager) {
|
||||
TelecomManager telecomManager, NotificationChannelLogger channelLogger) {
|
||||
mHandler = handler;
|
||||
Resources resources = getContext().getResources();
|
||||
mMaxPackageEnqueueRate = Settings.Global.getFloat(getContext().getContentResolver(),
|
||||
@@ -2281,12 +2275,13 @@ public class NotificationManagerService extends SystemService {
|
||||
}
|
||||
});
|
||||
mPermissionHelper = permissionHelper;
|
||||
mNotificationChannelLogger = channelLogger;
|
||||
mPreferencesHelper = new PreferencesHelper(getContext(),
|
||||
mPackageManagerClient,
|
||||
mRankingHandler,
|
||||
mZenModeHelper,
|
||||
mPermissionHelper,
|
||||
new NotificationChannelLoggerImpl(),
|
||||
mNotificationChannelLogger,
|
||||
mAppOps,
|
||||
new SysUiStatsEvent.BuilderFactory());
|
||||
mRankingHelper = new RankingHelper(getContext(),
|
||||
@@ -2368,9 +2363,6 @@ public class NotificationManagerService extends SystemService {
|
||||
mNotificationEffectsEnabledForAutomotive =
|
||||
resources.getBoolean(R.bool.config_enableServerNotificationEffectsForAutomotive);
|
||||
|
||||
mPreferencesHelper.lockChannelsForOEM(getContext().getResources().getStringArray(
|
||||
com.android.internal.R.array.config_nonBlockableNotificationPackages));
|
||||
|
||||
mZenModeHelper.setPriorityOnlyDndExemptPackages(getContext().getResources().getStringArray(
|
||||
com.android.internal.R.array.config_priorityOnlyDndExemptPackages));
|
||||
|
||||
@@ -2510,10 +2502,11 @@ public class NotificationManagerService extends SystemService {
|
||||
LocalServices.getService(ActivityManagerInternal.class),
|
||||
createToastRateLimiter(), new PermissionHelper(LocalServices.getService(
|
||||
PermissionManagerServiceInternal.class), AppGlobals.getPackageManager(),
|
||||
AppGlobals.getPermissionManager(), mEnableAppSettingMigration,
|
||||
AppGlobals.getPermissionManager(),
|
||||
mForceUserSetOnUpgrade),
|
||||
LocalServices.getService(UsageStatsManagerInternal.class),
|
||||
getContext().getSystemService(TelecomManager.class));
|
||||
getContext().getSystemService(TelecomManager.class),
|
||||
new NotificationChannelLoggerImpl());
|
||||
|
||||
publishBinderService(Context.NOTIFICATION_SERVICE, mService, /* allowIsolated= */ false,
|
||||
DUMP_FLAG_PRIORITY_CRITICAL | DUMP_FLAG_PRIORITY_NORMAL);
|
||||
@@ -2805,7 +2798,7 @@ public class NotificationManagerService extends SystemService {
|
||||
}
|
||||
}
|
||||
|
||||
private void updateNotificationChannelInt(String pkg, int uid, NotificationChannel channel,
|
||||
void updateNotificationChannelInt(String pkg, int uid, NotificationChannel channel,
|
||||
boolean fromListener) {
|
||||
if (channel.getImportance() == NotificationManager.IMPORTANCE_NONE) {
|
||||
// cancel
|
||||
@@ -2827,11 +2820,9 @@ public class NotificationManagerService extends SystemService {
|
||||
mPreferencesHelper.getNotificationChannel(pkg, uid, channel.getId(), true);
|
||||
|
||||
mPreferencesHelper.updateNotificationChannel(pkg, uid, channel, true);
|
||||
if (mEnableAppSettingMigration) {
|
||||
if (mPreferencesHelper.onlyHasDefaultChannel(pkg, uid)) {
|
||||
mPermissionHelper.setNotificationPermission(pkg, UserHandle.getUserId(uid),
|
||||
channel.getImportance() != IMPORTANCE_NONE, true);
|
||||
}
|
||||
if (mPreferencesHelper.onlyHasDefaultChannel(pkg, uid)) {
|
||||
mPermissionHelper.setNotificationPermission(pkg, UserHandle.getUserId(uid),
|
||||
channel.getImportance() != IMPORTANCE_NONE, true);
|
||||
}
|
||||
maybeNotifyChannelOwner(pkg, uid, preUpdate, channel);
|
||||
|
||||
@@ -3480,36 +3471,19 @@ public class NotificationManagerService extends SystemService {
|
||||
@Override
|
||||
public void setNotificationsEnabledForPackage(String pkg, int uid, boolean enabled) {
|
||||
enforceSystemOrSystemUI("setNotificationsEnabledForPackage");
|
||||
if (mEnableAppSettingMigration) {
|
||||
boolean wasEnabled = mPermissionHelper.hasPermission(uid);
|
||||
if (wasEnabled == enabled) {
|
||||
return;
|
||||
}
|
||||
mPermissionHelper.setNotificationPermission(
|
||||
pkg, UserHandle.getUserId(uid), enabled, true);
|
||||
sendAppBlockStateChangedBroadcast(pkg, uid, !enabled);
|
||||
} else {
|
||||
synchronized (mNotificationLock) {
|
||||
boolean wasEnabled = mPreferencesHelper.getImportance(pkg, uid)
|
||||
!= NotificationManager.IMPORTANCE_NONE;
|
||||
|
||||
if (wasEnabled == enabled) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
mPreferencesHelper.setEnabled(pkg, uid, enabled);
|
||||
// TODO (b/194833441): this is being ignored by app ops now that the permission
|
||||
// exists, so send the broadcast manually
|
||||
mAppOps.setMode(AppOpsManager.OP_POST_NOTIFICATION, uid, pkg,
|
||||
enabled ? MODE_ALLOWED : AppOpsManager.MODE_IGNORED);
|
||||
|
||||
sendAppBlockStateChangedBroadcast(pkg, uid, !enabled);
|
||||
boolean wasEnabled = mPermissionHelper.hasPermission(uid);
|
||||
if (wasEnabled == enabled) {
|
||||
return;
|
||||
}
|
||||
mPermissionHelper.setNotificationPermission(
|
||||
pkg, UserHandle.getUserId(uid), enabled, true);
|
||||
sendAppBlockStateChangedBroadcast(pkg, uid, !enabled);
|
||||
|
||||
mMetricsLogger.write(new LogMaker(MetricsEvent.ACTION_BAN_APP_NOTES)
|
||||
.setType(MetricsEvent.TYPE_ACTION)
|
||||
.setPackageName(pkg)
|
||||
.setSubtype(enabled ? 1 : 0));
|
||||
mNotificationChannelLogger.logAppNotificationsAllowed(uid, pkg, enabled);
|
||||
// Now, cancel any outstanding notifications that are part of a just-disabled app
|
||||
if (!enabled) {
|
||||
cancelAllNotificationsInt(MY_UID, MY_PID, pkg, null, 0, 0, true,
|
||||
@@ -3535,8 +3509,6 @@ public class NotificationManagerService extends SystemService {
|
||||
public void setNotificationsEnabledWithImportanceLockForPackage(
|
||||
String pkg, int uid, boolean enabled) {
|
||||
setNotificationsEnabledForPackage(pkg, uid, enabled);
|
||||
|
||||
mPreferencesHelper.setAppImportanceLocked(pkg, uid);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -3652,14 +3624,10 @@ public class NotificationManagerService extends SystemService {
|
||||
@Override
|
||||
public int getPackageImportance(String pkg) {
|
||||
checkCallerIsSystemOrSameApp(pkg);
|
||||
if (mEnableAppSettingMigration) {
|
||||
if (mPermissionHelper.hasPermission(Binder.getCallingUid())) {
|
||||
return IMPORTANCE_DEFAULT;
|
||||
} else {
|
||||
return IMPORTANCE_NONE;
|
||||
}
|
||||
if (mPermissionHelper.hasPermission(Binder.getCallingUid())) {
|
||||
return IMPORTANCE_DEFAULT;
|
||||
} else {
|
||||
return mPreferencesHelper.getImportance(pkg, Binder.getCallingUid());
|
||||
return IMPORTANCE_NONE;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5891,8 +5859,7 @@ public class NotificationManagerService extends SystemService {
|
||||
NotificationRecord createAutoGroupSummary(int userId, String pkg, String triggeringKey,
|
||||
boolean needsOngoingFlag) {
|
||||
NotificationRecord summaryRecord = null;
|
||||
boolean isPermissionFixed = mPermissionHelper.isMigrationEnabled()
|
||||
? mPermissionHelper.isPermissionFixed(pkg, userId) : false;
|
||||
boolean isPermissionFixed = mPermissionHelper.isPermissionFixed(pkg, userId);
|
||||
synchronized (mNotificationLock) {
|
||||
NotificationRecord notificationRecord = mNotificationsByKey.get(triggeringKey);
|
||||
if (notificationRecord == null) {
|
||||
@@ -5901,10 +5868,6 @@ public class NotificationManagerService extends SystemService {
|
||||
return null;
|
||||
}
|
||||
NotificationChannel channel = notificationRecord.getChannel();
|
||||
boolean isImportanceFixed = mPermissionHelper.isMigrationEnabled()
|
||||
? isPermissionFixed
|
||||
: (channel.isImportanceLockedByOEM()
|
||||
|| channel.isImportanceLockedByCriticalDeviceFunction());
|
||||
final StatusBarNotification adjustedSbn = notificationRecord.getSbn();
|
||||
userId = adjustedSbn.getUser().getIdentifier();
|
||||
int uid = adjustedSbn.getUid();
|
||||
@@ -5950,7 +5913,7 @@ public class NotificationManagerService extends SystemService {
|
||||
System.currentTimeMillis());
|
||||
summaryRecord = new NotificationRecord(getContext(), summarySbn,
|
||||
notificationRecord.getChannel());
|
||||
summaryRecord.setImportanceFixed(isImportanceFixed);
|
||||
summaryRecord.setImportanceFixed(isPermissionFixed);
|
||||
summaryRecord.setIsAppImportanceLocked(
|
||||
notificationRecord.getIsAppImportanceLocked());
|
||||
summaries.put(pkg, summarySbn.getKey());
|
||||
@@ -5998,10 +5961,6 @@ public class NotificationManagerService extends SystemService {
|
||||
@VisibleForTesting
|
||||
protected ArrayMap<Pair<Integer, String>, Pair<Boolean, Boolean>>
|
||||
getAllUsersNotificationPermissions() {
|
||||
// don't bother if migration is not enabled
|
||||
if (!mEnableAppSettingMigration) {
|
||||
return null;
|
||||
}
|
||||
ArrayMap<Pair<Integer, String>, Pair<Boolean, Boolean>> allPermissions = new ArrayMap<>();
|
||||
final List<UserInfo> allUsers = mUm.getUsers();
|
||||
// for each of these, get the package notification permissions that are associated
|
||||
@@ -6515,13 +6474,8 @@ public class NotificationManagerService extends SystemService {
|
||||
+ ", notificationUid=" + notificationUid
|
||||
+ ", notification=" + notification;
|
||||
Slog.e(TAG, noChannelStr);
|
||||
boolean appNotificationsOff;
|
||||
if (mEnableAppSettingMigration) {
|
||||
appNotificationsOff = !mPermissionHelper.hasPermission(notificationUid);
|
||||
} else {
|
||||
appNotificationsOff = mPreferencesHelper.getImportance(pkg, notificationUid)
|
||||
== NotificationManager.IMPORTANCE_NONE;
|
||||
}
|
||||
boolean appNotificationsOff = !mPermissionHelper.hasPermission(notificationUid);
|
||||
|
||||
|
||||
if (!appNotificationsOff) {
|
||||
doChannelWarningToast(notificationUid,
|
||||
@@ -6533,14 +6487,11 @@ public class NotificationManagerService extends SystemService {
|
||||
}
|
||||
|
||||
final NotificationRecord r = new NotificationRecord(getContext(), n, channel);
|
||||
r.setIsAppImportanceLocked(mPreferencesHelper.getIsAppImportanceLocked(pkg, callingUid));
|
||||
r.setIsAppImportanceLocked(mPermissionHelper.isPermissionUserSet(pkg, userId));
|
||||
r.setPostSilently(postSilently);
|
||||
r.setFlagBubbleRemoved(false);
|
||||
r.setPkgAllowedAsConvo(mMsgPkgsAllowedAsConvos.contains(pkg));
|
||||
boolean isImportanceFixed = mPermissionHelper.isMigrationEnabled()
|
||||
? mPermissionHelper.isPermissionFixed(pkg, userId)
|
||||
: (channel.isImportanceLockedByOEM()
|
||||
|| channel.isImportanceLockedByCriticalDeviceFunction());
|
||||
boolean isImportanceFixed = mPermissionHelper.isPermissionFixed(pkg, userId);
|
||||
r.setImportanceFixed(isImportanceFixed);
|
||||
|
||||
if ((notification.flags & Notification.FLAG_FOREGROUND_SERVICE) != 0) {
|
||||
@@ -6997,11 +6948,7 @@ public class NotificationManagerService extends SystemService {
|
||||
}
|
||||
|
||||
private boolean areNotificationsEnabledForPackageInt(String pkg, int uid) {
|
||||
if (mEnableAppSettingMigration) {
|
||||
return mPermissionHelper.hasPermission(uid);
|
||||
} else {
|
||||
return mPreferencesHelper.getImportance(pkg, uid) != IMPORTANCE_NONE;
|
||||
}
|
||||
return mPermissionHelper.hasPermission(uid);
|
||||
}
|
||||
|
||||
protected int getNotificationCount(String pkg, int userId, int excludedId,
|
||||
|
||||
@@ -1089,7 +1089,7 @@ public final class NotificationRecord {
|
||||
}
|
||||
|
||||
/**
|
||||
* @see PreferencesHelper#getIsAppImportanceLocked(String, int)
|
||||
* @see PermissionHelper#isPermissionUserSet(String, int)
|
||||
*/
|
||||
public boolean getIsAppImportanceLocked() {
|
||||
return mIsAppImportanceLocked;
|
||||
|
||||
@@ -55,30 +55,21 @@ public final class PermissionHelper {
|
||||
private final PermissionManagerServiceInternal mPmi;
|
||||
private final IPackageManager mPackageManager;
|
||||
private final IPermissionManager mPermManager;
|
||||
// TODO (b/194833441): Remove when the migration is enabled
|
||||
private final boolean mMigrationEnabled;
|
||||
private final boolean mForceUserSetOnUpgrade;
|
||||
|
||||
public PermissionHelper(PermissionManagerServiceInternal pmi, IPackageManager packageManager,
|
||||
IPermissionManager permManager, boolean migrationEnabled,
|
||||
boolean forceUserSetOnUpgrade) {
|
||||
IPermissionManager permManager, boolean forceUserSetOnUpgrade) {
|
||||
mPmi = pmi;
|
||||
mPackageManager = packageManager;
|
||||
mPermManager = permManager;
|
||||
mMigrationEnabled = migrationEnabled;
|
||||
mForceUserSetOnUpgrade = forceUserSetOnUpgrade;
|
||||
}
|
||||
|
||||
public boolean isMigrationEnabled() {
|
||||
return mMigrationEnabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the given uid holds the notification permission. Must not be called
|
||||
* with a lock held.
|
||||
*/
|
||||
public boolean hasPermission(int uid) {
|
||||
assertFlag();
|
||||
final long callingId = Binder.clearCallingIdentity();
|
||||
try {
|
||||
return mPmi.checkPostNotificationsPermissionGrantedOrLegacyAccess(uid)
|
||||
@@ -93,7 +84,6 @@ public final class PermissionHelper {
|
||||
* Must not be called with a lock held. Format: uid, packageName
|
||||
*/
|
||||
Set<Pair<Integer, String>> getAppsRequestingPermission(int userId) {
|
||||
assertFlag();
|
||||
Set<Pair<Integer, String>> requested = new HashSet<>();
|
||||
List<PackageInfo> pkgs = getInstalledPackages(userId);
|
||||
for (PackageInfo pi : pkgs) {
|
||||
@@ -131,7 +121,6 @@ public final class PermissionHelper {
|
||||
* with a lock held. Format: uid, packageName.
|
||||
*/
|
||||
Set<Pair<Integer, String>> getAppsGrantedPermission(int userId) {
|
||||
assertFlag();
|
||||
Set<Pair<Integer, String>> granted = new HashSet<>();
|
||||
ParceledListSlice<PackageInfo> parceledList = null;
|
||||
try {
|
||||
@@ -153,7 +142,6 @@ public final class PermissionHelper {
|
||||
public @NonNull
|
||||
ArrayMap<Pair<Integer, String>, Pair<Boolean, Boolean>>
|
||||
getNotificationPermissionValues(int userId) {
|
||||
assertFlag();
|
||||
ArrayMap<Pair<Integer, String>, Pair<Boolean, Boolean>> notifPermissions = new ArrayMap<>();
|
||||
Set<Pair<Integer, String>> allRequestingUids = getAppsRequestingPermission(userId);
|
||||
Set<Pair<Integer, String>> allApprovedUids = getAppsGrantedPermission(userId);
|
||||
@@ -180,7 +168,6 @@ public final class PermissionHelper {
|
||||
*/
|
||||
public void setNotificationPermission(String packageName, @UserIdInt int userId, boolean grant,
|
||||
boolean userSet, boolean reviewRequired) {
|
||||
assertFlag();
|
||||
final long callingId = Binder.clearCallingIdentity();
|
||||
try {
|
||||
// Do not change the permission if the package doesn't request it, do not change fixed
|
||||
@@ -221,7 +208,6 @@ public final class PermissionHelper {
|
||||
* restoring a pre-T backup on a T+ device
|
||||
*/
|
||||
public void setNotificationPermission(PackagePermission pkgPerm) {
|
||||
assertFlag();
|
||||
if (pkgPerm == null || pkgPerm.packageName == null) {
|
||||
return;
|
||||
}
|
||||
@@ -233,7 +219,6 @@ public final class PermissionHelper {
|
||||
}
|
||||
|
||||
public boolean isPermissionFixed(String packageName, @UserIdInt int userId) {
|
||||
assertFlag();
|
||||
final long callingId = Binder.clearCallingIdentity();
|
||||
try {
|
||||
try {
|
||||
@@ -251,7 +236,6 @@ public final class PermissionHelper {
|
||||
}
|
||||
|
||||
boolean isPermissionUserSet(String packageName, @UserIdInt int userId) {
|
||||
assertFlag();
|
||||
final long callingId = Binder.clearCallingIdentity();
|
||||
try {
|
||||
try {
|
||||
@@ -269,7 +253,6 @@ public final class PermissionHelper {
|
||||
}
|
||||
|
||||
boolean isPermissionGrantedByDefaultOrRole(String packageName, @UserIdInt int userId) {
|
||||
assertFlag();
|
||||
final long callingId = Binder.clearCallingIdentity();
|
||||
try {
|
||||
try {
|
||||
@@ -288,7 +271,6 @@ public final class PermissionHelper {
|
||||
|
||||
private boolean packageRequestsNotificationPermission(String packageName,
|
||||
@UserIdInt int userId) {
|
||||
assertFlag();
|
||||
try {
|
||||
String[] permissions = mPackageManager.getPackageInfo(packageName, GET_PERMISSIONS,
|
||||
userId).requestedPermissions;
|
||||
@@ -299,12 +281,6 @@ public final class PermissionHelper {
|
||||
return false;
|
||||
}
|
||||
|
||||
private void assertFlag() {
|
||||
if (!mMigrationEnabled) {
|
||||
throw new IllegalStateException("Method called without checking flag value");
|
||||
}
|
||||
}
|
||||
|
||||
public static class PackagePermission {
|
||||
public final String packageName;
|
||||
public final @UserIdInt int userId;
|
||||
|
||||
@@ -209,11 +209,7 @@ public class PreferencesHelper implements RankingConfig {
|
||||
mAppOps = appOpsManager;
|
||||
mStatsEventBuilderFactory = statsEventBuilderFactory;
|
||||
|
||||
if (mPermissionHelper.isMigrationEnabled()) {
|
||||
XML_VERSION = 4;
|
||||
} else {
|
||||
XML_VERSION = 2;
|
||||
}
|
||||
XML_VERSION = 4;
|
||||
|
||||
updateBadgingEnabled();
|
||||
updateBubblesEnabled();
|
||||
@@ -230,8 +226,7 @@ public class PreferencesHelper implements RankingConfig {
|
||||
|
||||
final int xmlVersion = parser.getAttributeInt(null, ATT_VERSION, -1);
|
||||
boolean upgradeForBubbles = xmlVersion == XML_VERSION_BUBBLES_UPGRADE;
|
||||
boolean migrateToPermission = (xmlVersion < XML_VERSION_NOTIF_PERMISSION)
|
||||
&& mPermissionHelper.isMigrationEnabled();
|
||||
boolean migrateToPermission = (xmlVersion < XML_VERSION_NOTIF_PERMISSION);
|
||||
if (xmlVersion < XML_VERSION_REVIEW_PERMISSIONS_NOTIFICATION) {
|
||||
// make a note that we should show the notification at some point.
|
||||
// it shouldn't be possible for the user to already have seen it, as the XML version
|
||||
@@ -393,8 +388,6 @@ public class PreferencesHelper implements RankingConfig {
|
||||
hasUserConfiguredSettings(r));
|
||||
pkgPerms.add(pkgPerm);
|
||||
}
|
||||
} else if (!mPermissionHelper.isMigrationEnabled()) {
|
||||
r.importance = appImportance;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Slog.w(TAG, "Failed to restore pkg", e);
|
||||
@@ -417,16 +410,8 @@ public class PreferencesHelper implements RankingConfig {
|
||||
} else {
|
||||
channel.populateFromXml(parser);
|
||||
}
|
||||
if (!mPermissionHelper.isMigrationEnabled()) {
|
||||
channel.setImportanceLockedByCriticalDeviceFunction(
|
||||
r.defaultAppLockedImportance);
|
||||
channel.setImportanceLockedByOEM(r.oemLockedImportance);
|
||||
if (!channel.isImportanceLockedByOEM()) {
|
||||
if (r.oemLockedChannels.contains(channel.getId())) {
|
||||
channel.setImportanceLockedByOEM(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
channel.setImportanceLockedByCriticalDeviceFunction(
|
||||
r.defaultAppLockedImportance);
|
||||
|
||||
if (isShortcutOk(channel) && isDeletionOk(channel)) {
|
||||
r.channels.put(id, channel);
|
||||
@@ -604,7 +589,7 @@ public class PreferencesHelper implements RankingConfig {
|
||||
out.endTag(null, TAG_STATUS_ICONS);
|
||||
}
|
||||
ArrayMap<Pair<Integer, String>, Pair<Boolean, Boolean>> notifPermissions = new ArrayMap<>();
|
||||
if (mPermissionHelper.isMigrationEnabled() && forBackup) {
|
||||
if (forBackup) {
|
||||
notifPermissions = mPermissionHelper.getNotificationPermissionValues(userId);
|
||||
}
|
||||
|
||||
@@ -736,28 +721,6 @@ public class PreferencesHelper implements RankingConfig {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets importance.
|
||||
*/
|
||||
@Override
|
||||
public int getImportance(String packageName, int uid) {
|
||||
synchronized (mPackagePreferences) {
|
||||
return getOrCreatePackagePreferencesLocked(packageName, uid).importance;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the importance of the corresponding notification is user-locked and shouldn't
|
||||
* be adjusted by an assistant (via means of a blocking helper, for example). For the channel
|
||||
* locking field, see {@link NotificationChannel#USER_LOCKED_IMPORTANCE}.
|
||||
*/
|
||||
public boolean getIsAppImportanceLocked(String packageName, int uid) {
|
||||
synchronized (mPackagePreferences) {
|
||||
int userLockedFields = getOrCreatePackagePreferencesLocked(packageName, uid).lockedAppFields;
|
||||
return (userLockedFields & LockableAppFields.USER_LOCKED_IMPORTANCE) != 0;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canShowBadge(String packageName, int uid) {
|
||||
synchronized (mPackagePreferences) {
|
||||
@@ -1043,16 +1006,10 @@ public class PreferencesHelper implements RankingConfig {
|
||||
: NotificationChannel.DEFAULT_ALLOW_BUBBLE);
|
||||
}
|
||||
clearLockedFieldsLocked(channel);
|
||||
if (!mPermissionHelper.isMigrationEnabled()) {
|
||||
channel.setImportanceLockedByOEM(r.oemLockedImportance);
|
||||
if (!channel.isImportanceLockedByOEM()) {
|
||||
if (r.oemLockedChannels.contains(channel.getId())) {
|
||||
channel.setImportanceLockedByOEM(true);
|
||||
}
|
||||
}
|
||||
channel.setImportanceLockedByCriticalDeviceFunction(
|
||||
r.defaultAppLockedImportance);
|
||||
}
|
||||
|
||||
channel.setImportanceLockedByCriticalDeviceFunction(
|
||||
r.defaultAppLockedImportance);
|
||||
|
||||
if (channel.getLockscreenVisibility() == Notification.VISIBILITY_PUBLIC) {
|
||||
channel.setLockscreenVisibility(
|
||||
NotificationListenerService.Ranking.VISIBILITY_NO_OVERRIDE);
|
||||
@@ -1133,33 +1090,15 @@ public class PreferencesHelper implements RankingConfig {
|
||||
updatedChannel.unlockFields(updatedChannel.getUserLockedFields());
|
||||
}
|
||||
|
||||
if (mPermissionHelper.isMigrationEnabled()) {
|
||||
if (mPermissionHelper.isPermissionFixed(r.pkg, UserHandle.getUserId(r.uid))
|
||||
&& !(channel.isBlockable() || channel.getImportance() == IMPORTANCE_NONE)) {
|
||||
updatedChannel.setImportance(channel.getImportance());
|
||||
}
|
||||
} else {
|
||||
// no importance updates are allowed if OEM blocked it
|
||||
updatedChannel.setImportanceLockedByOEM(channel.isImportanceLockedByOEM());
|
||||
if (updatedChannel.isImportanceLockedByOEM()) {
|
||||
updatedChannel.setImportance(channel.getImportance());
|
||||
}
|
||||
updatedChannel.setImportanceLockedByCriticalDeviceFunction(
|
||||
r.defaultAppLockedImportance);
|
||||
if (updatedChannel.isImportanceLockedByCriticalDeviceFunction()
|
||||
&& updatedChannel.getImportance() == IMPORTANCE_NONE) {
|
||||
updatedChannel.setImportance(channel.getImportance());
|
||||
}
|
||||
if ((mPermissionHelper.isPermissionFixed(r.pkg, UserHandle.getUserId(r.uid))
|
||||
|| channel.isImportanceLockedByCriticalDeviceFunction())
|
||||
&& !(channel.isBlockable() || channel.getImportance() == IMPORTANCE_NONE)) {
|
||||
updatedChannel.setImportance(channel.getImportance());
|
||||
}
|
||||
|
||||
r.channels.put(updatedChannel.getId(), updatedChannel);
|
||||
|
||||
if (onlyHasDefaultChannel(pkg, uid)) {
|
||||
if (!mPermissionHelper.isMigrationEnabled()) {
|
||||
// copy settings to app level so they are inherited by new channels
|
||||
// when the app migrates
|
||||
r.importance = updatedChannel.getImportance();
|
||||
}
|
||||
r.priority = updatedChannel.canBypassDnd()
|
||||
? Notification.PRIORITY_MAX : Notification.PRIORITY_DEFAULT;
|
||||
r.visibility = updatedChannel.getLockscreenVisibility();
|
||||
@@ -1328,61 +1267,8 @@ public class PreferencesHelper implements RankingConfig {
|
||||
mHideSilentStatusBarIcons = hide;
|
||||
}
|
||||
|
||||
public void lockChannelsForOEM(String[] appOrChannelList) {
|
||||
if (mPermissionHelper.isMigrationEnabled()) {
|
||||
return;
|
||||
}
|
||||
if (appOrChannelList == null) {
|
||||
return;
|
||||
}
|
||||
for (String appOrChannel : appOrChannelList) {
|
||||
if (!TextUtils.isEmpty(appOrChannel)) {
|
||||
String[] appSplit = appOrChannel.split(NON_BLOCKABLE_CHANNEL_DELIM);
|
||||
if (appSplit != null && appSplit.length > 0) {
|
||||
String appName = appSplit[0];
|
||||
String channelId = appSplit.length == 2 ? appSplit[1] : null;
|
||||
|
||||
synchronized (mPackagePreferences) {
|
||||
boolean foundApp = false;
|
||||
for (PackagePreferences r : mPackagePreferences.values()) {
|
||||
if (r.pkg.equals(appName)) {
|
||||
foundApp = true;
|
||||
if (channelId == null) {
|
||||
// lock all channels for the app
|
||||
r.oemLockedImportance = true;
|
||||
for (NotificationChannel channel : r.channels.values()) {
|
||||
channel.setImportanceLockedByOEM(true);
|
||||
}
|
||||
} else {
|
||||
NotificationChannel channel = r.channels.get(channelId);
|
||||
if (channel != null) {
|
||||
channel.setImportanceLockedByOEM(true);
|
||||
}
|
||||
// Also store the locked channels on the record, so they aren't
|
||||
// temporarily lost when data is cleared on the package
|
||||
r.oemLockedChannels.add(channelId);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!foundApp) {
|
||||
List<String> channels =
|
||||
mOemLockedApps.getOrDefault(appName, new ArrayList<>());
|
||||
if (channelId != null) {
|
||||
channels.add(channelId);
|
||||
}
|
||||
mOemLockedApps.put(appName, channels);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void updateDefaultApps(int userId, ArraySet<String> toRemove,
|
||||
ArraySet<Pair<String, Integer>> toAdd) {
|
||||
if (mPermissionHelper.isMigrationEnabled()) {
|
||||
return;
|
||||
}
|
||||
synchronized (mPackagePreferences) {
|
||||
for (PackagePreferences p : mPackagePreferences.values()) {
|
||||
if (userId == UserHandle.getUserId(p.uid)) {
|
||||
@@ -1802,20 +1688,8 @@ public class PreferencesHelper implements RankingConfig {
|
||||
}
|
||||
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 (!mPermissionHelper.hasPermission(app.second)) {
|
||||
candidatePkgs.removeAt(i);
|
||||
}
|
||||
}
|
||||
boolean haveBypassingApps = candidatePkgs.size() > 0;
|
||||
@@ -1860,27 +1734,6 @@ public class PreferencesHelper implements RankingConfig {
|
||||
return mAreChannelsBypassingDnd;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets importance.
|
||||
*/
|
||||
@Override
|
||||
public void setImportance(String pkgName, int uid, int importance) {
|
||||
synchronized (mPackagePreferences) {
|
||||
getOrCreatePackagePreferencesLocked(pkgName, uid).importance = importance;
|
||||
}
|
||||
updateConfig();
|
||||
}
|
||||
|
||||
public void setEnabled(String packageName, int uid, boolean enabled) {
|
||||
boolean wasEnabled = getImportance(packageName, uid) != IMPORTANCE_NONE;
|
||||
if (wasEnabled == enabled) {
|
||||
return;
|
||||
}
|
||||
setImportance(packageName, uid,
|
||||
enabled ? DEFAULT_IMPORTANCE : IMPORTANCE_NONE);
|
||||
mNotificationChannelLogger.logAppNotificationsAllowed(uid, packageName, enabled);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether any notifications from the app, represented by the given {@code pkgName} and
|
||||
* {@code uid}, have their importance locked by the user. Locked notifications don't get
|
||||
@@ -2055,23 +1908,15 @@ public class PreferencesHelper implements RankingConfig {
|
||||
pw.print(" (");
|
||||
pw.print(r.uid == UNKNOWN_UID ? "UNKNOWN_UID" : Integer.toString(r.uid));
|
||||
pw.print(')');
|
||||
if (!mPermissionHelper.isMigrationEnabled()) {
|
||||
if (r.importance != DEFAULT_IMPORTANCE) {
|
||||
pw.print(" importance=");
|
||||
pw.print(NotificationListenerService.Ranking.importanceToString(
|
||||
r.importance));
|
||||
}
|
||||
} else {
|
||||
Pair<Integer, String> key = new Pair<>(r.uid, r.pkg);
|
||||
if (packagePermissions != null && pkgsWithPermissionsToHandle.contains(key)) {
|
||||
pw.print(" importance=");
|
||||
pw.print(NotificationListenerService.Ranking.importanceToString(
|
||||
packagePermissions.get(key).first
|
||||
? IMPORTANCE_DEFAULT : IMPORTANCE_NONE));
|
||||
pw.print(" userSet=");
|
||||
pw.print(packagePermissions.get(key).second);
|
||||
pkgsWithPermissionsToHandle.remove(key);
|
||||
}
|
||||
Pair<Integer, String> key = new Pair<>(r.uid, r.pkg);
|
||||
if (packagePermissions != null && pkgsWithPermissionsToHandle.contains(key)) {
|
||||
pw.print(" importance=");
|
||||
pw.print(NotificationListenerService.Ranking.importanceToString(
|
||||
packagePermissions.get(key).first
|
||||
? IMPORTANCE_DEFAULT : IMPORTANCE_NONE));
|
||||
pw.print(" userSet=");
|
||||
pw.print(packagePermissions.get(key).second);
|
||||
pkgsWithPermissionsToHandle.remove(key);
|
||||
}
|
||||
if (r.priority != DEFAULT_PRIORITY) {
|
||||
pw.print(" priority=");
|
||||
@@ -2111,7 +1956,7 @@ public class PreferencesHelper implements RankingConfig {
|
||||
}
|
||||
}
|
||||
// Handle any remaining packages with permissions
|
||||
if (mPermissionHelper.isMigrationEnabled() && pkgsWithPermissionsToHandle != null) {
|
||||
if (pkgsWithPermissionsToHandle != null) {
|
||||
for (Pair<Integer, String> p : pkgsWithPermissionsToHandle) {
|
||||
// p.first is the uid of this package; p.second is the package name
|
||||
if (filter.matches(p.second)) {
|
||||
@@ -2151,16 +1996,12 @@ public class PreferencesHelper implements RankingConfig {
|
||||
|
||||
proto.write(RankingHelperProto.RecordProto.PACKAGE, r.pkg);
|
||||
proto.write(RankingHelperProto.RecordProto.UID, r.uid);
|
||||
if (mPermissionHelper.isMigrationEnabled()) {
|
||||
Pair<Integer, String> key = new Pair<>(r.uid, r.pkg);
|
||||
if (packagePermissions != null && pkgsWithPermissionsToHandle.contains(key)) {
|
||||
proto.write(RankingHelperProto.RecordProto.IMPORTANCE,
|
||||
packagePermissions.get(key).first
|
||||
? IMPORTANCE_DEFAULT : IMPORTANCE_NONE);
|
||||
pkgsWithPermissionsToHandle.remove(key);
|
||||
}
|
||||
} else {
|
||||
proto.write(RankingHelperProto.RecordProto.IMPORTANCE, r.importance);
|
||||
Pair<Integer, String> key = new Pair<>(r.uid, r.pkg);
|
||||
if (packagePermissions != null && pkgsWithPermissionsToHandle.contains(key)) {
|
||||
proto.write(RankingHelperProto.RecordProto.IMPORTANCE,
|
||||
packagePermissions.get(key).first
|
||||
? IMPORTANCE_DEFAULT : IMPORTANCE_NONE);
|
||||
pkgsWithPermissionsToHandle.remove(key);
|
||||
}
|
||||
proto.write(RankingHelperProto.RecordProto.PRIORITY, r.priority);
|
||||
proto.write(RankingHelperProto.RecordProto.VISIBILITY, r.visibility);
|
||||
@@ -2177,7 +2018,7 @@ public class PreferencesHelper implements RankingConfig {
|
||||
}
|
||||
}
|
||||
|
||||
if (mPermissionHelper.isMigrationEnabled() && pkgsWithPermissionsToHandle != null) {
|
||||
if (pkgsWithPermissionsToHandle != null) {
|
||||
for (Pair<Integer, String> p : pkgsWithPermissionsToHandle) {
|
||||
if (filter.matches(p.second)) {
|
||||
fToken = proto.start(fieldId);
|
||||
@@ -2217,25 +2058,22 @@ public class PreferencesHelper implements RankingConfig {
|
||||
// collect whether this package's importance info was user-set for later, if needed
|
||||
// before the migration is enabled, this will simply default to false in all cases.
|
||||
boolean importanceIsUserSet = false;
|
||||
if (mPermissionHelper.isMigrationEnabled()) {
|
||||
// Even if this package's data is not present, we need to write something;
|
||||
// so default to IMPORTANCE_NONE, since if PM doesn't know about the package
|
||||
// for some reason, notifications are not allowed.
|
||||
int importance = IMPORTANCE_NONE;
|
||||
Pair<Integer, String> key = new Pair<>(r.uid, r.pkg);
|
||||
if (pkgPermissions != null && pkgsWithPermissionsToHandle.contains(key)) {
|
||||
Pair<Boolean, Boolean> permissionPair = pkgPermissions.get(key);
|
||||
importance = permissionPair.first
|
||||
? IMPORTANCE_DEFAULT : IMPORTANCE_NONE;
|
||||
// cache the second value for writing later
|
||||
importanceIsUserSet = permissionPair.second;
|
||||
// Even if this package's data is not present, we need to write something;
|
||||
// so default to IMPORTANCE_NONE, since if PM doesn't know about the package
|
||||
// for some reason, notifications are not allowed.
|
||||
int importance = IMPORTANCE_NONE;
|
||||
Pair<Integer, String> key = new Pair<>(r.uid, r.pkg);
|
||||
if (pkgPermissions != null && pkgsWithPermissionsToHandle.contains(key)) {
|
||||
Pair<Boolean, Boolean> permissionPair = pkgPermissions.get(key);
|
||||
importance = permissionPair.first
|
||||
? IMPORTANCE_DEFAULT : IMPORTANCE_NONE;
|
||||
// cache the second value for writing later
|
||||
importanceIsUserSet = permissionPair.second;
|
||||
|
||||
pkgsWithPermissionsToHandle.remove(key);
|
||||
}
|
||||
event.writeInt(importance);
|
||||
} else {
|
||||
event.writeInt(r.importance);
|
||||
pkgsWithPermissionsToHandle.remove(key);
|
||||
}
|
||||
event.writeInt(importance);
|
||||
|
||||
event.writeInt(r.visibility);
|
||||
event.writeInt(r.lockedAppFields);
|
||||
event.writeBoolean(importanceIsUserSet); // optional bool user_set_importance = 5;
|
||||
@@ -2244,7 +2082,7 @@ public class PreferencesHelper implements RankingConfig {
|
||||
}
|
||||
|
||||
// handle remaining packages with PackageManager permissions but not local settings
|
||||
if (mPermissionHelper.isMigrationEnabled() && pkgPermissions != null) {
|
||||
if (pkgPermissions != null) {
|
||||
for (Pair<Integer, String> p : pkgsWithPermissionsToHandle) {
|
||||
if (pulledEvents > NOTIFICATION_PREFERENCES_PULL_LIMIT) {
|
||||
break;
|
||||
@@ -2357,22 +2195,14 @@ public class PreferencesHelper implements RankingConfig {
|
||||
try {
|
||||
PackagePreferences.put("userId", UserHandle.getUserId(r.uid));
|
||||
PackagePreferences.put("packageName", r.pkg);
|
||||
if (mPermissionHelper.isMigrationEnabled()) {
|
||||
Pair<Integer, String> key = new Pair<>(r.uid, r.pkg);
|
||||
if (pkgPermissions != null
|
||||
&& pkgsWithPermissionsToHandle.contains(key)) {
|
||||
PackagePreferences.put("importance",
|
||||
NotificationListenerService.Ranking.importanceToString(
|
||||
pkgPermissions.get(key).first
|
||||
? IMPORTANCE_DEFAULT : IMPORTANCE_NONE));
|
||||
pkgsWithPermissionsToHandle.remove(key);
|
||||
}
|
||||
} else {
|
||||
if (r.importance != DEFAULT_IMPORTANCE) {
|
||||
PackagePreferences.put("importance",
|
||||
NotificationListenerService.Ranking.importanceToString(
|
||||
r.importance));
|
||||
}
|
||||
Pair<Integer, String> key = new Pair<>(r.uid, r.pkg);
|
||||
if (pkgPermissions != null
|
||||
&& pkgsWithPermissionsToHandle.contains(key)) {
|
||||
PackagePreferences.put("importance",
|
||||
NotificationListenerService.Ranking.importanceToString(
|
||||
pkgPermissions.get(key).first
|
||||
? IMPORTANCE_DEFAULT : IMPORTANCE_NONE));
|
||||
pkgsWithPermissionsToHandle.remove(key);
|
||||
}
|
||||
if (r.priority != DEFAULT_PRIORITY) {
|
||||
PackagePreferences.put("priority",
|
||||
@@ -2404,7 +2234,7 @@ public class PreferencesHelper implements RankingConfig {
|
||||
}
|
||||
|
||||
// handle packages for which there are permissions but no local settings
|
||||
if (mPermissionHelper.isMigrationEnabled() && pkgsWithPermissionsToHandle != null) {
|
||||
if (pkgsWithPermissionsToHandle != null) {
|
||||
for (Pair<Integer, String> p : pkgsWithPermissionsToHandle) {
|
||||
if (filter == null || filter.matches(p.second)) {
|
||||
JSONObject PackagePreferences = new JSONObject();
|
||||
@@ -2443,8 +2273,7 @@ public class PreferencesHelper implements RankingConfig {
|
||||
public JSONArray dumpBansJson(NotificationManagerService.DumpFilter filter,
|
||||
ArrayMap<Pair<Integer, String>, Pair<Boolean, Boolean>> pkgPermissions) {
|
||||
JSONArray bans = new JSONArray();
|
||||
Map<Integer, String> packageBans = mPermissionHelper.isMigrationEnabled()
|
||||
? getPermissionBasedPackageBans(pkgPermissions) : getPackageBans();
|
||||
Map<Integer, String> packageBans = getPermissionBasedPackageBans(pkgPermissions);
|
||||
for (Map.Entry<Integer, String> ban : packageBans.entrySet()) {
|
||||
final int userId = UserHandle.getUserId(ban.getKey());
|
||||
final String packageName = ban.getValue();
|
||||
@@ -2597,7 +2426,7 @@ public class PreferencesHelper implements RankingConfig {
|
||||
synchronized (mPackagePreferences) {
|
||||
mPackagePreferences.put(packagePreferencesKey(r.pkg, r.uid), r);
|
||||
}
|
||||
if (mPermissionHelper.isMigrationEnabled() && r.migrateToPm) {
|
||||
if (r.migrateToPm) {
|
||||
try {
|
||||
PackagePermission p = new PackagePermission(
|
||||
r.pkg, UserHandle.getUserId(r.uid),
|
||||
|
||||
@@ -24,8 +24,6 @@ import java.util.Collection;
|
||||
|
||||
public interface RankingConfig {
|
||||
|
||||
void setImportance(String packageName, int uid, int importance);
|
||||
int getImportance(String packageName, int uid);
|
||||
void setShowBadge(String packageName, int uid, boolean showBadge);
|
||||
boolean canShowBadge(String packageName, int uid);
|
||||
boolean badgingEnabled(UserHandle userHandle);
|
||||
|
||||
@@ -1453,16 +1453,6 @@ public final class PermissionPolicyService extends SystemService {
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
if (Settings.Secure.getIntForUser(mContext.getContentResolver(),
|
||||
Settings.Secure.NOTIFICATION_PERMISSION_ENABLED, UserHandle.USER_SYSTEM)
|
||||
== 0) {
|
||||
return false;
|
||||
}
|
||||
} catch (Settings.SettingNotFoundException e) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!pkg.getRequestedPermissions().contains(POST_NOTIFICATIONS)
|
||||
|| CompatChanges.isChangeEnabled(NOTIFICATION_PERM_CHANGE_ID, pkgName, user)
|
||||
|| mKeyguardManager.isKeyguardLocked()) {
|
||||
|
||||
@@ -82,8 +82,6 @@ public class ImportanceExtractorTest extends UiServiceTestCase {
|
||||
ImportanceExtractor extractor = new ImportanceExtractor();
|
||||
extractor.setConfig(mConfig);
|
||||
|
||||
when(mConfig.getImportance(anyString(), anyInt())).thenReturn(
|
||||
NotificationManager.IMPORTANCE_MIN);
|
||||
NotificationChannel channel =
|
||||
new NotificationChannel("a", "a", NotificationManager.IMPORTANCE_UNSPECIFIED);
|
||||
|
||||
@@ -101,8 +99,6 @@ public class ImportanceExtractorTest extends UiServiceTestCase {
|
||||
ImportanceExtractor extractor = new ImportanceExtractor();
|
||||
extractor.setConfig(mConfig);
|
||||
|
||||
when(mConfig.getImportance(anyString(), anyInt())).thenReturn(
|
||||
NotificationManager.IMPORTANCE_MIN);
|
||||
NotificationChannel channel =
|
||||
new NotificationChannel("a", "a", NotificationManager.IMPORTANCE_HIGH);
|
||||
|
||||
|
||||
@@ -28,6 +28,13 @@ public class NotificationChannelLoggerFake implements NotificationChannelLogger
|
||||
CallRecord(NotificationChannelEvent event) {
|
||||
this.event = event;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "CallRecord{" +
|
||||
"event=" + event +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
|
||||
private List<CallRecord> mCalls = new ArrayList<>();
|
||||
|
||||
@@ -188,6 +188,7 @@ import android.text.TextUtils;
|
||||
import android.util.ArrayMap;
|
||||
import android.util.ArraySet;
|
||||
import android.util.AtomicFile;
|
||||
import android.util.Pair;
|
||||
import android.util.TypedXmlPullParser;
|
||||
import android.util.TypedXmlSerializer;
|
||||
import android.util.Xml;
|
||||
@@ -221,6 +222,7 @@ import com.android.server.wm.WindowManagerInternal;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
@@ -273,6 +275,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
|
||||
private WindowManagerInternal mWindowManagerInternal;
|
||||
@Mock
|
||||
private PermissionHelper mPermissionHelper;
|
||||
private NotificationChannelLoggerFake mLogger = new NotificationChannelLoggerFake();
|
||||
private TestableContext mContext = spy(getContext());
|
||||
private final String PKG = mContext.getPackageName();
|
||||
private TestableLooper mTestableLooper;
|
||||
@@ -385,9 +388,6 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
|
||||
"android.permission.WRITE_DEVICE_CONFIG",
|
||||
"android.permission.READ_DEVICE_CONFIG",
|
||||
"android.permission.READ_CONTACTS");
|
||||
Settings.Secure.putIntForUser(
|
||||
getContext().getContentResolver(),
|
||||
Settings.Secure.NOTIFICATION_PERMISSION_ENABLED, 0, USER_SYSTEM);
|
||||
|
||||
MockitoAnnotations.initMocks(this);
|
||||
|
||||
@@ -509,7 +509,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
|
||||
mAppOpsManager, mAppOpsService, mUm, mHistoryManager, mStatsManager,
|
||||
mock(TelephonyManager.class),
|
||||
mAmi, mToastRateLimiter, mPermissionHelper, mock(UsageStatsManagerInternal.class),
|
||||
mTelecomManager);
|
||||
mTelecomManager, mLogger);
|
||||
// Return first true for RoleObserver main-thread check
|
||||
when(mMainLooper.isCurrentThread()).thenReturn(true).thenReturn(false);
|
||||
mService.onBootPhase(SystemService.PHASE_SYSTEM_SERVICES_READY, mMainLooper);
|
||||
@@ -585,6 +585,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
|
||||
assertNotNull(mBinderService.getNotificationChannel(
|
||||
PKG, mContext.getUserId(), PKG, TEST_CHANNEL_ID));
|
||||
clearInvocations(mRankingHandler);
|
||||
when(mPermissionHelper.hasPermission(mUid)).thenReturn(true);
|
||||
}
|
||||
|
||||
@After
|
||||
@@ -1237,8 +1238,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
|
||||
@Test
|
||||
public void testEnqueuedBlockedNotifications_blockedApp() throws Exception {
|
||||
when(mPackageManager.isPackageSuspendedForUser(anyString(), anyInt())).thenReturn(false);
|
||||
|
||||
mBinderService.setNotificationsEnabledForPackage(PKG, mUid, false);
|
||||
when(mPermissionHelper.hasPermission(mUid)).thenReturn(false);
|
||||
|
||||
final StatusBarNotification sbn = generateNotificationRecord(null).getSbn();
|
||||
mBinderService.enqueueNotificationWithTag(PKG, PKG,
|
||||
@@ -1251,8 +1251,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
|
||||
@Test
|
||||
public void testEnqueuedBlockedNotifications_blockedAppForegroundService() throws Exception {
|
||||
when(mPackageManager.isPackageSuspendedForUser(anyString(), anyInt())).thenReturn(false);
|
||||
|
||||
mBinderService.setNotificationsEnabledForPackage(PKG, mUid, false);
|
||||
when(mPermissionHelper.hasPermission(mUid)).thenReturn(false);
|
||||
|
||||
final StatusBarNotification sbn = generateNotificationRecord(null).getSbn();
|
||||
sbn.getNotification().flags |= FLAG_FOREGROUND_SERVICE;
|
||||
@@ -1344,6 +1343,30 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
|
||||
assertEquals(0, mBinderService.getActiveNotifications(PKG).length);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetNotificationsEnabledForPackage_noChange() throws Exception {
|
||||
when(mPermissionHelper.hasPermission(mUid)).thenReturn(true);
|
||||
mBinderService.setNotificationsEnabledForPackage(mContext.getPackageName(), mUid, true);
|
||||
|
||||
verify(mPermissionHelper, never()).setNotificationPermission(
|
||||
anyString(), anyInt(), anyBoolean(), anyBoolean());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetNotificationsEnabledForPackage() throws Exception {
|
||||
when(mPermissionHelper.hasPermission(mUid)).thenReturn(true);
|
||||
mBinderService.setNotificationsEnabledForPackage(mContext.getPackageName(), mUid, false);
|
||||
|
||||
verify(mPermissionHelper).setNotificationPermission(
|
||||
mContext.getPackageName(), UserHandle.getUserId(mUid), false, true);
|
||||
|
||||
verify(mAppOpsManager, never()).setMode(anyInt(), anyInt(), anyString(), anyInt());
|
||||
List<NotificationChannelLoggerFake.CallRecord> calls = mLogger.getCalls();
|
||||
Assert.assertEquals(
|
||||
NotificationChannelLogger.NotificationChannelEvent.APP_NOTIFICATIONS_BLOCKED,
|
||||
calls.get(calls.size() -1).event);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBlockedNotifications_blockedByAssistant() throws Exception {
|
||||
when(mPackageManager.isPackageSuspendedForUser(anyString(), anyInt())).thenReturn(false);
|
||||
@@ -1371,7 +1394,6 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
|
||||
|
||||
@Test
|
||||
public void testBlockedNotifications_blockedByUser() throws Exception {
|
||||
mService.setPreferencesHelper(mPreferencesHelper);
|
||||
when(mPackageManager.isPackageSuspendedForUser(anyString(), anyInt())).thenReturn(false);
|
||||
when(mAssistants.isSameUser(any(), anyInt())).thenReturn(true);
|
||||
|
||||
@@ -1380,7 +1402,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
|
||||
NotificationRecord r = generateNotificationRecord(channel);
|
||||
mService.addEnqueuedNotification(r);
|
||||
|
||||
when(mPreferencesHelper.getImportance(anyString(), anyInt())).thenReturn(IMPORTANCE_NONE);
|
||||
when(mPermissionHelper.hasPermission(anyInt())).thenReturn(false);
|
||||
|
||||
NotificationManagerService.PostNotificationRunnable runnable =
|
||||
mService.new PostNotificationRunnable(r.getKey(), r.getSbn().getPackageName(),
|
||||
@@ -1392,9 +1414,33 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
|
||||
verify(mUsageStats, never()).registerPostedByApp(any());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEnqueueNotificationInternal_noChannel() throws Exception {
|
||||
when(mPermissionHelper.hasPermission(mUid)).thenReturn(false);
|
||||
NotificationRecord nr = generateNotificationRecord(
|
||||
new NotificationChannel("did not create", "", IMPORTANCE_DEFAULT));
|
||||
|
||||
mBinderService.enqueueNotificationWithTag(PKG, PKG, nr.getSbn().getTag(),
|
||||
nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
|
||||
waitForIdle();
|
||||
|
||||
verify(mPermissionHelper).hasPermission(mUid);
|
||||
verify(mPermissionHelper, never()).hasPermission(Process.SYSTEM_UID);
|
||||
|
||||
reset(mPermissionHelper);
|
||||
when(mPermissionHelper.hasPermission(mUid)).thenReturn(true);
|
||||
|
||||
mBinderService.enqueueNotificationWithTag(PKG, PKG, nr.getSbn().getTag(),
|
||||
nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
|
||||
waitForIdle();
|
||||
|
||||
verify(mPermissionHelper).hasPermission(mUid);
|
||||
assertThat(mService.mChannelToastsSent).contains(mUid);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEnqueueNotification_appBlocked() throws Exception {
|
||||
mBinderService.setNotificationsEnabledForPackage(PKG, mUid, false);
|
||||
when(mPermissionHelper.hasPermission(mUid)).thenReturn(false);
|
||||
|
||||
mBinderService.enqueueNotificationWithTag(PKG, PKG,
|
||||
"testEnqueueNotification_appBlocked", 0,
|
||||
@@ -2688,6 +2734,49 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
|
||||
assertEquals(0, notifs.length);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDefaultChannelUpdatesApp_postMigrationToPermissions() throws Exception {
|
||||
final NotificationChannel defaultChannel = mBinderService.getNotificationChannel(
|
||||
PKG_N_MR1, ActivityManager.getCurrentUser(), PKG_N_MR1,
|
||||
NotificationChannel.DEFAULT_CHANNEL_ID);
|
||||
defaultChannel.setImportance(IMPORTANCE_NONE);
|
||||
|
||||
mBinderService.updateNotificationChannelForPackage(PKG_N_MR1, mUid, defaultChannel);
|
||||
|
||||
verify(mPermissionHelper).setNotificationPermission(
|
||||
PKG_N_MR1, ActivityManager.getCurrentUser(), false, true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPostNotification_appPermissionFixed() throws Exception {
|
||||
when(mPermissionHelper.hasPermission(mUid)).thenReturn(true);
|
||||
when(mPermissionHelper.isPermissionFixed(PKG, 0)).thenReturn(true);
|
||||
|
||||
NotificationRecord temp = generateNotificationRecord(mTestNotificationChannel);
|
||||
mBinderService.enqueueNotificationWithTag(PKG, PKG,
|
||||
"testPostNotification_appPermissionFixed", 0,
|
||||
temp.getNotification(), 0);
|
||||
waitForIdle();
|
||||
assertThat(mService.getNotificationRecordCount()).isEqualTo(1);
|
||||
StatusBarNotification[] notifs =
|
||||
mBinderService.getActiveNotifications(PKG);
|
||||
assertThat(mService.getNotificationRecord(notifs[0].getKey()).isImportanceFixed()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSummaryNotification_appPermissionFixed() {
|
||||
NotificationRecord temp = generateNotificationRecord(mTestNotificationChannel);
|
||||
mService.addNotification(temp);
|
||||
|
||||
when(mPermissionHelper.hasPermission(mUid)).thenReturn(true);
|
||||
when(mPermissionHelper.isPermissionFixed(PKG, temp.getUserId())).thenReturn(true);
|
||||
|
||||
NotificationRecord r = mService.createAutoGroupSummary(
|
||||
temp.getUserId(), temp.getSbn().getPackageName(), temp.getKey(), false);
|
||||
|
||||
assertThat(r.isImportanceFixed()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTvExtenderChannelOverride_onTv() throws Exception {
|
||||
mService.setIsTelevision(true);
|
||||
@@ -2721,13 +2810,12 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
|
||||
|
||||
@Test
|
||||
public void testUpdateAppNotifyCreatorBlock() throws Exception {
|
||||
mService.setPreferencesHelper(mPreferencesHelper);
|
||||
when(mPreferencesHelper.getImportance(PKG, mUid)).thenReturn(IMPORTANCE_DEFAULT);
|
||||
when(mPermissionHelper.hasPermission(mUid)).thenReturn(true);
|
||||
|
||||
// should trigger a broadcast
|
||||
mBinderService.setNotificationsEnabledForPackage(PKG, mUid, false);
|
||||
Thread.sleep(500);
|
||||
waitForIdle();
|
||||
|
||||
ArgumentCaptor<Intent> captor = ArgumentCaptor.forClass(Intent.class);
|
||||
verify(mContext, times(1)).sendBroadcastAsUser(captor.capture(), any(), eq(null));
|
||||
|
||||
@@ -2739,7 +2827,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
|
||||
|
||||
@Test
|
||||
public void testUpdateAppNotifyCreatorBlock_notIfMatchesExistingSetting() throws Exception {
|
||||
mService.setPreferencesHelper(mPreferencesHelper);
|
||||
when(mPermissionHelper.hasPermission(mUid)).thenReturn(false);
|
||||
|
||||
mBinderService.setNotificationsEnabledForPackage(PKG, 0, false);
|
||||
verify(mContext, never()).sendBroadcastAsUser(any(), any(), eq(null));
|
||||
@@ -2747,15 +2835,12 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
|
||||
|
||||
@Test
|
||||
public void testUpdateAppNotifyCreatorUnblock() throws Exception {
|
||||
mService.setPreferencesHelper(mPreferencesHelper);
|
||||
when(mPermissionHelper.hasPermission(mUid)).thenReturn(false);
|
||||
|
||||
// should not trigger a broadcast
|
||||
when(mAppOpsManager.checkOpNoThrow(anyInt(), eq(mUid), eq(PKG))).thenReturn(MODE_ALLOWED);
|
||||
|
||||
// should trigger a broadcast
|
||||
mBinderService.setNotificationsEnabledForPackage(PKG, 0, true);
|
||||
mBinderService.setNotificationsEnabledForPackage(PKG, mUid, true);
|
||||
Thread.sleep(500);
|
||||
waitForIdle();
|
||||
|
||||
ArgumentCaptor<Intent> captor = ArgumentCaptor.forClass(Intent.class);
|
||||
verify(mContext, times(1)).sendBroadcastAsUser(captor.capture(), any(), eq(null));
|
||||
|
||||
@@ -4347,7 +4432,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
|
||||
|
||||
assertEquals(IMPORTANCE_LOW,
|
||||
mService.getNotificationRecord(sbn.getKey()).getImportance());
|
||||
assertEquals(IMPORTANCE_UNSPECIFIED, mBinderService.getPackageImportance(
|
||||
assertEquals(IMPORTANCE_DEFAULT, mBinderService.getPackageImportance(
|
||||
sbn.getPackageName()));
|
||||
|
||||
nb = new Notification.Builder(mContext)
|
||||
@@ -4863,6 +4948,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
|
||||
|
||||
@Test
|
||||
public void testBackup() throws Exception {
|
||||
mService.setPreferencesHelper(mPreferencesHelper);
|
||||
int systemChecks = mService.countSystemChecks;
|
||||
when(mListeners.queryPackageForServices(anyString(), anyInt(), anyInt()))
|
||||
.thenReturn(new ArraySet<>());
|
||||
@@ -5966,8 +6052,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
|
||||
.thenReturn(false);
|
||||
|
||||
// notifications from this package are blocked by the user
|
||||
mService.setPreferencesHelper(mPreferencesHelper);
|
||||
when(mPreferencesHelper.getImportance(testPackage, mUid)).thenReturn(IMPORTANCE_NONE);
|
||||
when(mPermissionHelper.hasPermission(mUid)).thenReturn(false);
|
||||
|
||||
setAppInForegroundForToasts(mUid, true);
|
||||
|
||||
@@ -6263,8 +6348,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
|
||||
.thenReturn(false);
|
||||
|
||||
// notifications from this package are blocked by the user
|
||||
mService.setPreferencesHelper(mPreferencesHelper);
|
||||
when(mPreferencesHelper.getImportance(testPackage, mUid)).thenReturn(IMPORTANCE_NONE);
|
||||
when(mPermissionHelper.hasPermission(mUid)).thenReturn(false);
|
||||
|
||||
setAppInForegroundForToasts(mUid, false);
|
||||
|
||||
@@ -6350,8 +6434,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
|
||||
.thenReturn(true);
|
||||
|
||||
// notifications from this package are NOT blocked by the user
|
||||
mService.setPreferencesHelper(mPreferencesHelper);
|
||||
when(mPreferencesHelper.getImportance(testPackage, mUid)).thenReturn(IMPORTANCE_LOW);
|
||||
when(mPermissionHelper.hasPermission(mUid)).thenReturn(true);
|
||||
|
||||
// enqueue toast -> no toasts enqueued
|
||||
((INotificationManager) mService.mService).enqueueToast(testPackage, new Binder(),
|
||||
@@ -6372,8 +6455,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
|
||||
.thenReturn(false);
|
||||
|
||||
// notifications from this package are blocked by the user
|
||||
mService.setPreferencesHelper(mPreferencesHelper);
|
||||
when(mPreferencesHelper.getImportance(testPackage, mUid)).thenReturn(IMPORTANCE_NONE);
|
||||
when(mPermissionHelper.hasPermission(mUid)).thenReturn(true);
|
||||
|
||||
setAppInForegroundForToasts(mUid, false);
|
||||
|
||||
@@ -6396,8 +6478,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
|
||||
.thenReturn(true);
|
||||
|
||||
// notifications from this package ARE blocked by the user
|
||||
mService.setPreferencesHelper(mPreferencesHelper);
|
||||
when(mPreferencesHelper.getImportance(testPackage, mUid)).thenReturn(IMPORTANCE_NONE);
|
||||
when(mPermissionHelper.hasPermission(mUid)).thenReturn(true);
|
||||
|
||||
setAppInForegroundForToasts(mUid, false);
|
||||
|
||||
@@ -7305,6 +7386,14 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
|
||||
mBinderService.addAutomaticZenRule(rule, mContext.getPackageName());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAreNotificationsEnabledForPackage() throws Exception {
|
||||
mBinderService.areNotificationsEnabledForPackage(mContext.getPackageName(),
|
||||
mUid);
|
||||
|
||||
verify(mPermissionHelper).hasPermission(mUid);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAreNotificationsEnabledForPackage_crossUser() throws Exception {
|
||||
try {
|
||||
@@ -7314,21 +7403,31 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
|
||||
} catch (SecurityException e) {
|
||||
// pass
|
||||
}
|
||||
verify(mPermissionHelper, never()).hasPermission(anyInt());
|
||||
|
||||
// cross user, with permission, no problem
|
||||
enableInteractAcrossUsers();
|
||||
mBinderService.areNotificationsEnabledForPackage(mContext.getPackageName(),
|
||||
mUid + UserHandle.PER_USER_RANGE);
|
||||
|
||||
verify(mPermissionHelper, never()).hasPermission(anyInt());
|
||||
verify(mPermissionHelper).hasPermission(mUid + UserHandle.PER_USER_RANGE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAreNotificationsEnabledForPackage_viaInternalService() throws Exception {
|
||||
assertEquals(mInternalService.areNotificationsEnabledForPackage(
|
||||
mContext.getPackageName(), mUid),
|
||||
mBinderService.areNotificationsEnabledForPackage(mContext.getPackageName(), mUid));
|
||||
verify(mPermissionHelper, never()).hasPermission(anyInt());
|
||||
public void testAreNotificationsEnabledForPackage_viaInternalService() {
|
||||
mInternalService.areNotificationsEnabledForPackage(mContext.getPackageName(), mUid);
|
||||
verify(mPermissionHelper).hasPermission(mUid);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetPackageImportance() throws Exception {
|
||||
when(mPermissionHelper.hasPermission(mUid)).thenReturn(true);
|
||||
assertThat(mBinderService.getPackageImportance(mContext.getPackageName()))
|
||||
.isEqualTo(IMPORTANCE_DEFAULT);
|
||||
|
||||
when(mPermissionHelper.hasPermission(mUid)).thenReturn(false);
|
||||
assertThat(mBinderService.getPackageImportance(mContext.getPackageName()))
|
||||
.isEqualTo(IMPORTANCE_NONE);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -8977,49 +9076,14 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
|
||||
assertFalse(captor.getValue().isPackageAllowed(new VersionedPackage("test", 1002)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMigrationDisabledByDefault() {
|
||||
assertThat(mService.mEnableAppSettingMigration).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPostNotification_channelLockedFixed() throws Exception {
|
||||
mTestNotificationChannel.setImportanceLockedByOEM(true);
|
||||
|
||||
NotificationRecord temp = generateNotificationRecord(mTestNotificationChannel);
|
||||
mBinderService.enqueueNotificationWithTag(PKG, PKG,
|
||||
"testPostNotification_appPermissionFixed", 0,
|
||||
temp.getNotification(), 0);
|
||||
waitForIdle();
|
||||
assertThat(mService.getNotificationRecordCount()).isEqualTo(1);
|
||||
StatusBarNotification[] notifs =
|
||||
mBinderService.getActiveNotifications(PKG);
|
||||
assertThat(mService.getNotificationRecord(notifs[0].getKey()).isImportanceFixed()).isTrue();
|
||||
|
||||
mBinderService.cancelAllNotifications(PKG, 0);
|
||||
waitForIdle();
|
||||
|
||||
mTestNotificationChannel.setImportanceLockedByOEM(false);
|
||||
mTestNotificationChannel.setImportanceLockedByCriticalDeviceFunction(true);
|
||||
|
||||
temp = generateNotificationRecord(mTestNotificationChannel);
|
||||
mBinderService.enqueueNotificationWithTag(PKG, PKG,
|
||||
"testPostNotification_appPermissionFixed", 0,
|
||||
temp.getNotification(), 0);
|
||||
waitForIdle();
|
||||
assertThat(mService.getNotificationRecordCount()).isEqualTo(1);
|
||||
notifs = mBinderService.getActiveNotifications(PKG);
|
||||
assertThat(mService.getNotificationRecord(notifs[0].getKey()).isImportanceFixed()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetNotificationChannelsBypassingDnd_blocked() throws RemoteException {
|
||||
mService.setPreferencesHelper(mPreferencesHelper);
|
||||
when(mPreferencesHelper.getImportance(PKG, mUid)).thenReturn(IMPORTANCE_NONE);
|
||||
|
||||
when(mPermissionHelper.hasPermission(mUid)).thenReturn(false);
|
||||
|
||||
assertThat(mBinderService.getNotificationChannelsBypassingDnd(PKG, mUid).getList())
|
||||
.isEmpty();
|
||||
verify(mPermissionHelper, never()).hasPermission(anyInt());
|
||||
verify(mPreferencesHelper, never()).getNotificationChannelsBypassingDnd(PKG, mUid);
|
||||
}
|
||||
|
||||
@@ -9113,8 +9177,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
|
||||
nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
|
||||
NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
|
||||
|
||||
mBinderService.setNotificationsEnabledForPackage(
|
||||
r.getSbn().getPackageName(), r.getUid(), false);
|
||||
when(mPermissionHelper.hasPermission(mUid)).thenReturn(false);
|
||||
|
||||
// normal blocked notifications - blocked
|
||||
assertThat(mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(),
|
||||
@@ -9151,6 +9214,67 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
|
||||
r.getSbn().getId(), r.getSbn().getTag(), r, false)).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMediaNotificationsBypassBlock_atPost() throws Exception {
|
||||
when(mPackageManager.isPackageSuspendedForUser(anyString(), anyInt())).thenReturn(false);
|
||||
when(mAssistants.isSameUser(any(), anyInt())).thenReturn(true);
|
||||
|
||||
Notification.Builder nb = new Notification.Builder(
|
||||
mContext, mTestNotificationChannel.getId())
|
||||
.setContentTitle("foo")
|
||||
.setSmallIcon(android.R.drawable.sym_def_app_icon)
|
||||
.addAction(new Notification.Action.Builder(null, "test", null).build());
|
||||
StatusBarNotification sbn = new StatusBarNotification(PKG, PKG, 8, "tag", mUid, 0,
|
||||
nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
|
||||
NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
|
||||
|
||||
when(mPermissionHelper.hasPermission(anyInt())).thenReturn(false);
|
||||
|
||||
mService.addEnqueuedNotification(r);
|
||||
NotificationManagerService.PostNotificationRunnable runnable =
|
||||
mService.new PostNotificationRunnable(r.getKey(), r.getSbn().getPackageName(),
|
||||
r.getUid(), SystemClock.elapsedRealtime());
|
||||
runnable.run();
|
||||
waitForIdle();
|
||||
|
||||
verify(mUsageStats).registerBlocked(any());
|
||||
verify(mUsageStats, never()).registerPostedByApp(any());
|
||||
|
||||
// just using the style - blocked
|
||||
mService.clearNotifications();
|
||||
reset(mUsageStats);
|
||||
nb.setStyle(new Notification.MediaStyle());
|
||||
sbn = new StatusBarNotification(PKG, PKG, 8, "tag", mUid, 0,
|
||||
nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
|
||||
r = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
|
||||
|
||||
mService.addEnqueuedNotification(r);
|
||||
runnable = mService.new PostNotificationRunnable(r.getKey(), r.getSbn().getPackageName(),
|
||||
r.getUid(), SystemClock.elapsedRealtime());
|
||||
runnable.run();
|
||||
waitForIdle();
|
||||
|
||||
verify(mUsageStats).registerBlocked(any());
|
||||
verify(mUsageStats, never()).registerPostedByApp(any());
|
||||
|
||||
// style + media session - bypasses block
|
||||
mService.clearNotifications();
|
||||
reset(mUsageStats);
|
||||
nb.setStyle(new Notification.MediaStyle().setMediaSession(mock(MediaSession.Token.class)));
|
||||
sbn = new StatusBarNotification(PKG, PKG, 8, "tag", mUid, 0,
|
||||
nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
|
||||
r = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
|
||||
|
||||
mService.addEnqueuedNotification(r);
|
||||
runnable = mService.new PostNotificationRunnable(r.getKey(), r.getSbn().getPackageName(),
|
||||
r.getUid(), SystemClock.elapsedRealtime());
|
||||
runnable.run();
|
||||
waitForIdle();
|
||||
|
||||
verify(mUsageStats, never()).registerBlocked(any());
|
||||
verify(mUsageStats).registerPostedByApp(any());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCallNotificationsBypassBlock() throws Exception {
|
||||
when(mAmi.getPendingIntentFlags(any(IIntentSender.class)))
|
||||
@@ -9166,8 +9290,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
|
||||
nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
|
||||
NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
|
||||
|
||||
mBinderService.setNotificationsEnabledForPackage(
|
||||
r.getSbn().getPackageName(), r.getUid(), false);
|
||||
when(mPermissionHelper.hasPermission(mUid)).thenReturn(false);
|
||||
|
||||
// normal blocked notifications - blocked
|
||||
assertThat(mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(),
|
||||
@@ -9312,9 +9435,37 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetAllUsersNotificationPermissions_migrationNotEnabled() {
|
||||
// make sure we don't bother if the migration is not enabled
|
||||
assertThat(mService.getAllUsersNotificationPermissions()).isNull();
|
||||
public void testGetAllUsersNotificationPermissions() {
|
||||
// In this case, there are multiple users each with notification permissions (and also,
|
||||
// for good measure, some without).
|
||||
// make sure the collection returned contains info for all of them
|
||||
final List<UserInfo> userInfos = new ArrayList<>();
|
||||
userInfos.add(new UserInfo(0, "user0", 0));
|
||||
userInfos.add(new UserInfo(1, "user1", 0));
|
||||
userInfos.add(new UserInfo(2, "user2", 0));
|
||||
when(mUm.getUsers()).thenReturn(userInfos);
|
||||
|
||||
// construct the permissions for each of them
|
||||
ArrayMap<Pair<Integer, String>, Pair<Boolean, Boolean>> permissions0 = new ArrayMap<>(),
|
||||
permissions1 = new ArrayMap<>();
|
||||
permissions0.put(new Pair<>(10, "package1"), new Pair<>(true, false));
|
||||
permissions0.put(new Pair<>(20, "package2"), new Pair<>(false, true));
|
||||
permissions1.put(new Pair<>(11, "package1"), new Pair<>(false, false));
|
||||
permissions1.put(new Pair<>(21, "package2"), new Pair<>(true, true));
|
||||
when(mPermissionHelper.getNotificationPermissionValues(0)).thenReturn(permissions0);
|
||||
when(mPermissionHelper.getNotificationPermissionValues(1)).thenReturn(permissions1);
|
||||
when(mPermissionHelper.getNotificationPermissionValues(2)).thenReturn(new ArrayMap<>());
|
||||
|
||||
ArrayMap<Pair<Integer, String>, Pair<Boolean, Boolean>> combinedPermissions =
|
||||
mService.getAllUsersNotificationPermissions();
|
||||
assertTrue(combinedPermissions.get(new Pair<>(10, "package1")).first);
|
||||
assertFalse(combinedPermissions.get(new Pair<>(10, "package1")).second);
|
||||
assertFalse(combinedPermissions.get(new Pair<>(20, "package2")).first);
|
||||
assertTrue(combinedPermissions.get(new Pair<>(20, "package2")).second);
|
||||
assertFalse(combinedPermissions.get(new Pair<>(11, "package1")).first);
|
||||
assertFalse(combinedPermissions.get(new Pair<>(11, "package1")).second);
|
||||
assertTrue(combinedPermissions.get(new Pair<>(21, "package2")).first);
|
||||
assertTrue(combinedPermissions.get(new Pair<>(21, "package2")).second);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -1,877 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2021 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.server.notification;
|
||||
|
||||
import static android.app.AppOpsManager.MODE_ALLOWED;
|
||||
import static android.app.AppOpsManager.MODE_IGNORED;
|
||||
import static android.app.NotificationManager.EXTRA_BLOCKED_STATE;
|
||||
import static android.app.NotificationManager.IMPORTANCE_DEFAULT;
|
||||
import static android.app.NotificationManager.IMPORTANCE_NONE;
|
||||
import static android.app.PendingIntent.FLAG_MUTABLE;
|
||||
import static android.app.PendingIntent.FLAG_ONE_SHOT;
|
||||
import static android.content.pm.PackageManager.FEATURE_WATCH;
|
||||
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
|
||||
import static android.os.UserHandle.USER_SYSTEM;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static junit.framework.Assert.assertEquals;
|
||||
import static junit.framework.Assert.assertFalse;
|
||||
import static junit.framework.Assert.assertNotNull;
|
||||
import static junit.framework.Assert.assertTrue;
|
||||
import static junit.framework.Assert.fail;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.anyBoolean;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Matchers.anyString;
|
||||
import static org.mockito.Mockito.any;
|
||||
import static org.mockito.Mockito.anyInt;
|
||||
import static org.mockito.Mockito.anyLong;
|
||||
import static org.mockito.Mockito.atLeastOnce;
|
||||
import static org.mockito.Mockito.clearInvocations;
|
||||
import static org.mockito.Mockito.doNothing;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.reset;
|
||||
import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.app.ActivityManager;
|
||||
import android.app.ActivityManagerInternal;
|
||||
import android.app.AlarmManager;
|
||||
import android.app.AppOpsManager;
|
||||
import android.app.IActivityManager;
|
||||
import android.app.INotificationManager;
|
||||
import android.app.IUriGrantsManager;
|
||||
import android.app.Notification;
|
||||
import android.app.NotificationChannel;
|
||||
import android.app.NotificationManager;
|
||||
import android.app.StatsManager;
|
||||
import android.app.admin.DevicePolicyManagerInternal;
|
||||
import android.app.usage.UsageStatsManagerInternal;
|
||||
import android.companion.ICompanionDeviceManager;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.IIntentSender;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
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;
|
||||
import android.content.pm.UserInfo;
|
||||
import android.content.res.Resources;
|
||||
import android.media.AudioManager;
|
||||
import android.media.session.MediaSession;
|
||||
import android.os.Binder;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.IBinder;
|
||||
import android.os.Looper;
|
||||
import android.os.Process;
|
||||
import android.os.RemoteException;
|
||||
import android.os.SystemClock;
|
||||
import android.os.UserHandle;
|
||||
import android.os.UserManager;
|
||||
import android.provider.Settings;
|
||||
import android.service.notification.NotificationListenerFilter;
|
||||
import android.service.notification.StatusBarNotification;
|
||||
import android.telecom.TelecomManager;
|
||||
import android.telephony.TelephonyManager;
|
||||
import android.test.suitebuilder.annotation.SmallTest;
|
||||
import android.testing.AndroidTestingRunner;
|
||||
import android.testing.TestableContext;
|
||||
import android.testing.TestableLooper;
|
||||
import android.testing.TestableLooper.RunWithLooper;
|
||||
import android.testing.TestablePermissions;
|
||||
import android.util.ArrayMap;
|
||||
import android.util.ArraySet;
|
||||
import android.util.AtomicFile;
|
||||
import android.util.Pair;
|
||||
|
||||
import androidx.test.InstrumentationRegistry;
|
||||
|
||||
import com.android.internal.app.IAppOpsService;
|
||||
import com.android.internal.logging.InstanceIdSequence;
|
||||
import com.android.internal.logging.InstanceIdSequenceFake;
|
||||
import com.android.server.DeviceIdleInternal;
|
||||
import com.android.server.LocalServices;
|
||||
import com.android.server.SystemService;
|
||||
import com.android.server.UiServiceTestCase;
|
||||
import com.android.server.lights.LightsManager;
|
||||
import com.android.server.lights.LogicalLight;
|
||||
import com.android.server.notification.NotificationManagerService.NotificationAssistants;
|
||||
import com.android.server.notification.NotificationManagerService.NotificationListeners;
|
||||
import com.android.server.statusbar.StatusBarManagerInternal;
|
||||
import com.android.server.uri.UriGrantsManagerInternal;
|
||||
import com.android.server.utils.quota.MultiRateLimiter;
|
||||
import com.android.server.wm.ActivityTaskManagerInternal;
|
||||
import com.android.server.wm.WindowManagerInternal;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
import org.mockito.stubbing.Answer;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
|
||||
@SmallTest
|
||||
@RunWith(AndroidTestingRunner.class)
|
||||
@RunWithLooper
|
||||
/**
|
||||
* Tests that NMS reads/writes the app notification state from Package/PermissionManager when
|
||||
* migration is enabled. Because the migration field is read onStart
|
||||
* TODO (b/194833441): migrate these tests to NotificationManagerServiceTest when the migration is
|
||||
* permanently enabled.
|
||||
*/
|
||||
public class NotificationPermissionMigrationTest extends UiServiceTestCase {
|
||||
private static final String TEST_CHANNEL_ID = "NotificationManagerServiceTestChannelId";
|
||||
private static final int UID_HEADLESS = 1000000;
|
||||
|
||||
private final int mUid = Binder.getCallingUid();
|
||||
private TestableNotificationManagerService mService;
|
||||
private INotificationManager mBinderService;
|
||||
private NotificationManagerInternal mInternalService;
|
||||
private ShortcutHelper mShortcutHelper;
|
||||
@Mock
|
||||
private IPackageManager mPackageManager;
|
||||
@Mock
|
||||
private PackageManager mPackageManagerClient;
|
||||
@Mock
|
||||
private PackageManagerInternal mPackageManagerInternal;
|
||||
@Mock
|
||||
private WindowManagerInternal mWindowManagerInternal;
|
||||
@Mock
|
||||
private PermissionHelper mPermissionHelper;
|
||||
private TestableContext mContext = spy(getContext());
|
||||
private final String PKG = mContext.getPackageName();
|
||||
private TestableLooper mTestableLooper;
|
||||
@Mock
|
||||
private RankingHelper mRankingHelper;
|
||||
@Mock private PreferencesHelper mPreferencesHelper;
|
||||
AtomicFile mPolicyFile;
|
||||
File mFile;
|
||||
@Mock
|
||||
private NotificationUsageStats mUsageStats;
|
||||
@Mock
|
||||
private UsageStatsManagerInternal mAppUsageStats;
|
||||
@Mock
|
||||
private AudioManager mAudioManager;
|
||||
@Mock
|
||||
private LauncherApps mLauncherApps;
|
||||
@Mock
|
||||
private ShortcutServiceInternal mShortcutServiceInternal;
|
||||
@Mock
|
||||
private UserManager mUserManager;
|
||||
@Mock
|
||||
ActivityManager mActivityManager;
|
||||
@Mock
|
||||
Resources mResources;
|
||||
@Mock
|
||||
RankingHandler mRankingHandler;
|
||||
@Mock
|
||||
ActivityManagerInternal mAmi;
|
||||
@Mock
|
||||
private Looper mMainLooper;
|
||||
|
||||
@Mock
|
||||
IIntentSender pi1;
|
||||
|
||||
private static final int MAX_POST_DELAY = 1000;
|
||||
|
||||
private NotificationChannel mTestNotificationChannel = new NotificationChannel(
|
||||
TEST_CHANNEL_ID, TEST_CHANNEL_ID, IMPORTANCE_DEFAULT);
|
||||
|
||||
private static final String VALID_CONVO_SHORTCUT_ID = "shortcut";
|
||||
|
||||
@Mock
|
||||
private NotificationListeners mListeners;
|
||||
@Mock
|
||||
private NotificationListenerFilter mNlf;
|
||||
@Mock private NotificationAssistants mAssistants;
|
||||
@Mock private ConditionProviders mConditionProviders;
|
||||
private ManagedServices.ManagedServiceInfo mListener;
|
||||
@Mock private ICompanionDeviceManager mCompanionMgr;
|
||||
@Mock SnoozeHelper mSnoozeHelper;
|
||||
@Mock GroupHelper mGroupHelper;
|
||||
@Mock
|
||||
IBinder mPermOwner;
|
||||
@Mock
|
||||
IActivityManager mAm;
|
||||
@Mock
|
||||
ActivityTaskManagerInternal mAtm;
|
||||
@Mock
|
||||
IUriGrantsManager mUgm;
|
||||
@Mock
|
||||
UriGrantsManagerInternal mUgmInternal;
|
||||
@Mock
|
||||
AppOpsManager mAppOpsManager;
|
||||
@Mock
|
||||
private TestableNotificationManagerService.NotificationAssistantAccessGrantedCallback
|
||||
mNotificationAssistantAccessGrantedCallback;
|
||||
@Mock
|
||||
UserManager mUm;
|
||||
@Mock
|
||||
NotificationHistoryManager mHistoryManager;
|
||||
@Mock
|
||||
StatsManager mStatsManager;
|
||||
@Mock
|
||||
AlarmManager mAlarmManager;
|
||||
@Mock
|
||||
MultiRateLimiter mToastRateLimiter;
|
||||
BroadcastReceiver mPackageIntentReceiver;
|
||||
NotificationRecordLoggerFake mNotificationRecordLogger = new NotificationRecordLoggerFake();
|
||||
private InstanceIdSequence mNotificationInstanceIdSequence = new InstanceIdSequenceFake(
|
||||
1 << 30);
|
||||
@Mock
|
||||
StatusBarManagerInternal mStatusBar;
|
||||
|
||||
private NotificationManagerService.WorkerHandler mWorkerHandler;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
// These should be the only difference in setup from NMSTest
|
||||
Settings.Secure.putIntForUser(
|
||||
getContext().getContentResolver(),
|
||||
Settings.Secure.NOTIFICATION_PERMISSION_ENABLED, 1, USER_SYSTEM);
|
||||
Settings.Global.putInt(getContext().getContentResolver(),
|
||||
Settings.Global.SHOW_NOTIFICATION_CHANNEL_WARNINGS, 1);
|
||||
|
||||
// Shell permissions will override permissions of our app, so add all necessary permissions
|
||||
// for this test here:
|
||||
InstrumentationRegistry.getInstrumentation().getUiAutomation().adoptShellPermissionIdentity(
|
||||
"android.permission.WRITE_DEVICE_CONFIG",
|
||||
"android.permission.READ_DEVICE_CONFIG",
|
||||
"android.permission.READ_CONTACTS");
|
||||
|
||||
MockitoAnnotations.initMocks(this);
|
||||
|
||||
when(mPermissionHelper.isMigrationEnabled()).thenReturn(true);
|
||||
|
||||
DeviceIdleInternal deviceIdleInternal = mock(DeviceIdleInternal.class);
|
||||
when(deviceIdleInternal.getNotificationAllowlistDuration()).thenReturn(3000L);
|
||||
|
||||
LocalServices.removeServiceForTest(UriGrantsManagerInternal.class);
|
||||
LocalServices.addService(UriGrantsManagerInternal.class, mUgmInternal);
|
||||
LocalServices.removeServiceForTest(WindowManagerInternal.class);
|
||||
LocalServices.addService(WindowManagerInternal.class, mWindowManagerInternal);
|
||||
LocalServices.removeServiceForTest(StatusBarManagerInternal.class);
|
||||
LocalServices.addService(StatusBarManagerInternal.class, mStatusBar);
|
||||
LocalServices.removeServiceForTest(DeviceIdleInternal.class);
|
||||
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);
|
||||
when(mUm.getProfileIds(0, false)).thenReturn(new int[]{0});
|
||||
|
||||
doNothing().when(mContext).sendBroadcastAsUser(any(), any(), any());
|
||||
|
||||
mService = new TestableNotificationManagerService(mContext, mNotificationRecordLogger,
|
||||
mNotificationInstanceIdSequence);
|
||||
|
||||
// Use this testable looper.
|
||||
mTestableLooper = TestableLooper.get(this);
|
||||
// MockPackageManager - default returns ApplicationInfo with matching calling UID
|
||||
mContext.setMockPackageManager(mPackageManagerClient);
|
||||
|
||||
when(mPackageManager.getApplicationInfo(anyString(), anyLong(), anyInt()))
|
||||
.thenAnswer((Answer<ApplicationInfo>) invocation -> {
|
||||
Object[] args = invocation.getArguments();
|
||||
return getApplicationInfo((String) args[0], mUid);
|
||||
});
|
||||
when(mPackageManagerClient.getApplicationInfoAsUser(anyString(), anyInt(), anyInt()))
|
||||
.thenAnswer((Answer<ApplicationInfo>) invocation -> {
|
||||
Object[] args = invocation.getArguments();
|
||||
return getApplicationInfo((String) args[0], mUid);
|
||||
});
|
||||
when(mPackageManagerClient.getPackageUidAsUser(any(), anyInt())).thenReturn(mUid);
|
||||
when(mPackageManagerInternal.isSameApp(anyString(), anyInt(), anyInt())).thenAnswer(
|
||||
(Answer<Boolean>) invocation -> {
|
||||
Object[] args = invocation.getArguments();
|
||||
return (int) args[1] == mUid;
|
||||
});
|
||||
final LightsManager mockLightsManager = mock(LightsManager.class);
|
||||
when(mockLightsManager.getLight(anyInt())).thenReturn(mock(LogicalLight.class));
|
||||
when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_NORMAL);
|
||||
when(mPackageManagerClient.hasSystemFeature(FEATURE_WATCH)).thenReturn(false);
|
||||
when(mUgmInternal.newUriPermissionOwner(anyString())).thenReturn(mPermOwner);
|
||||
when(mPackageManager.getPackagesForUid(mUid)).thenReturn(new String[]{PKG});
|
||||
when(mPackageManagerClient.getPackagesForUid(anyInt())).thenReturn(new String[]{PKG});
|
||||
mContext.addMockSystemService(AppOpsManager.class, mock(AppOpsManager.class));
|
||||
|
||||
// write to a test file; the system file isn't readable from tests
|
||||
mFile = new File(mContext.getCacheDir(), "test.xml");
|
||||
mFile.createNewFile();
|
||||
final String preupgradeXml = "<notification-policy></notification-policy>";
|
||||
mPolicyFile = new AtomicFile(mFile);
|
||||
FileOutputStream fos = mPolicyFile.startWrite();
|
||||
fos.write(preupgradeXml.getBytes());
|
||||
mPolicyFile.finishWrite(fos);
|
||||
|
||||
// Setup managed services
|
||||
when(mNlf.isTypeAllowed(anyInt())).thenReturn(true);
|
||||
when(mNlf.isPackageAllowed(any())).thenReturn(true);
|
||||
when(mNlf.isPackageAllowed(null)).thenReturn(true);
|
||||
when(mListeners.getNotificationListenerFilter(any())).thenReturn(mNlf);
|
||||
mListener = mListeners.new ManagedServiceInfo(
|
||||
null, new ComponentName(PKG, "test_class"),
|
||||
UserHandle.getUserId(mUid), true, null, 0, 123);
|
||||
ComponentName defaultComponent = ComponentName.unflattenFromString("config/device");
|
||||
ArraySet<ComponentName> components = new ArraySet<>();
|
||||
components.add(defaultComponent);
|
||||
when(mListeners.getDefaultComponents()).thenReturn(components);
|
||||
when(mConditionProviders.getDefaultPackages())
|
||||
.thenReturn(new ArraySet<>(Arrays.asList("config")));
|
||||
when(mAssistants.getDefaultComponents()).thenReturn(components);
|
||||
when(mAssistants.queryPackageForServices(
|
||||
anyString(), anyInt(), anyInt())).thenReturn(components);
|
||||
when(mListeners.checkServiceTokenLocked(null)).thenReturn(mListener);
|
||||
ManagedServices.Config listenerConfig = new ManagedServices.Config();
|
||||
listenerConfig.xmlTag = NotificationListeners.TAG_ENABLED_NOTIFICATION_LISTENERS;
|
||||
when(mListeners.getConfig()).thenReturn(listenerConfig);
|
||||
ManagedServices.Config assistantConfig = new ManagedServices.Config();
|
||||
assistantConfig.xmlTag = NotificationAssistants.TAG_ENABLED_NOTIFICATION_ASSISTANTS;
|
||||
when(mAssistants.getConfig()).thenReturn(assistantConfig);
|
||||
ManagedServices.Config dndConfig = new ManagedServices.Config();
|
||||
dndConfig.xmlTag = ConditionProviders.TAG_ENABLED_DND_APPS;
|
||||
when(mConditionProviders.getConfig()).thenReturn(dndConfig);
|
||||
|
||||
when(mAssistants.isAdjustmentAllowed(anyString())).thenReturn(true);
|
||||
|
||||
// apps allowed as convos
|
||||
mService.setStringArrayResourceValue(PKG_O);
|
||||
|
||||
mWorkerHandler = spy(mService.new WorkerHandler(mTestableLooper.getLooper()));
|
||||
mService.init(mWorkerHandler, mRankingHandler, mPackageManager, mPackageManagerClient,
|
||||
mockLightsManager, mListeners, mAssistants, mConditionProviders, mCompanionMgr,
|
||||
mSnoozeHelper, mUsageStats, mPolicyFile, mActivityManager, mGroupHelper, mAm, mAtm,
|
||||
mAppUsageStats, mock(DevicePolicyManagerInternal.class), mUgm, mUgmInternal,
|
||||
mAppOpsManager, mock(IAppOpsService.class), mUm, mHistoryManager, mStatsManager,
|
||||
mock(TelephonyManager.class), mAmi, mToastRateLimiter, mPermissionHelper,
|
||||
mock(UsageStatsManagerInternal.class), mock(TelecomManager.class));
|
||||
// Return first true for RoleObserver main-thread check
|
||||
when(mMainLooper.isCurrentThread()).thenReturn(true).thenReturn(false);
|
||||
mService.onBootPhase(SystemService.PHASE_SYSTEM_SERVICES_READY, mMainLooper);
|
||||
|
||||
mService.setAudioManager(mAudioManager);
|
||||
|
||||
mShortcutHelper = mService.getShortcutHelper();
|
||||
mShortcutHelper.setLauncherApps(mLauncherApps);
|
||||
mShortcutHelper.setShortcutServiceInternal(mShortcutServiceInternal);
|
||||
mShortcutHelper.setUserManager(mUserManager);
|
||||
|
||||
// Capture PackageIntentReceiver
|
||||
ArgumentCaptor<BroadcastReceiver> broadcastReceiverCaptor =
|
||||
ArgumentCaptor.forClass(BroadcastReceiver.class);
|
||||
ArgumentCaptor<IntentFilter> intentFilterCaptor =
|
||||
ArgumentCaptor.forClass(IntentFilter.class);
|
||||
|
||||
verify(mContext, atLeastOnce()).registerReceiverAsUser(broadcastReceiverCaptor.capture(),
|
||||
any(), intentFilterCaptor.capture(), any(), any());
|
||||
verify(mContext, atLeastOnce()).registerReceiver(broadcastReceiverCaptor.capture(),
|
||||
intentFilterCaptor.capture());
|
||||
List<BroadcastReceiver> broadcastReceivers = broadcastReceiverCaptor.getAllValues();
|
||||
List<IntentFilter> intentFilters = intentFilterCaptor.getAllValues();
|
||||
|
||||
for (int i = 0; i < intentFilters.size(); i++) {
|
||||
final IntentFilter filter = intentFilters.get(i);
|
||||
if (filter.hasAction(Intent.ACTION_DISTRACTING_PACKAGES_CHANGED)
|
||||
&& filter.hasAction(Intent.ACTION_PACKAGES_UNSUSPENDED)
|
||||
&& filter.hasAction(Intent.ACTION_PACKAGES_SUSPENDED)) {
|
||||
mPackageIntentReceiver = broadcastReceivers.get(i);
|
||||
}
|
||||
}
|
||||
assertNotNull("package intent receiver should exist", mPackageIntentReceiver);
|
||||
|
||||
// Pretend the shortcut exists
|
||||
List<ShortcutInfo> shortcutInfos = new ArrayList<>();
|
||||
ShortcutInfo info = mock(ShortcutInfo.class);
|
||||
when(info.getPackage()).thenReturn(PKG);
|
||||
when(info.getId()).thenReturn(VALID_CONVO_SHORTCUT_ID);
|
||||
when(info.getUserId()).thenReturn(USER_SYSTEM);
|
||||
when(info.isLongLived()).thenReturn(true);
|
||||
when(info.isEnabled()).thenReturn(true);
|
||||
shortcutInfos.add(info);
|
||||
when(mLauncherApps.getShortcuts(any(), any())).thenReturn(shortcutInfos);
|
||||
when(mShortcutServiceInternal.isSharingShortcut(anyInt(), anyString(), anyString(),
|
||||
anyString(), anyInt(), any())).thenReturn(true);
|
||||
when(mUserManager.isUserUnlocked(any(UserHandle.class))).thenReturn(true);
|
||||
|
||||
// Set the testable bubble extractor
|
||||
RankingHelper rankingHelper = mService.getRankingHelper();
|
||||
BubbleExtractor extractor = rankingHelper.findExtractor(BubbleExtractor.class);
|
||||
extractor.setActivityManager(mActivityManager);
|
||||
|
||||
// Tests call directly into the Binder.
|
||||
mBinderService = mService.getBinderService();
|
||||
mInternalService = mService.getInternalService();
|
||||
|
||||
mBinderService.createNotificationChannels(
|
||||
PKG, new ParceledListSlice(Arrays.asList(mTestNotificationChannel)));
|
||||
mBinderService.createNotificationChannels(
|
||||
PKG_P, new ParceledListSlice(Arrays.asList(mTestNotificationChannel)));
|
||||
mBinderService.createNotificationChannels(
|
||||
PKG_O, new ParceledListSlice(Arrays.asList(mTestNotificationChannel)));
|
||||
assertNotNull(mBinderService.getNotificationChannel(
|
||||
PKG, mContext.getUserId(), PKG, TEST_CHANNEL_ID));
|
||||
clearInvocations(mRankingHandler);
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() throws Exception {
|
||||
if (mFile != null) mFile.delete();
|
||||
|
||||
try {
|
||||
mService.onDestroy();
|
||||
} catch (IllegalStateException | IllegalArgumentException e) {
|
||||
// can throw if a broadcast receiver was never registered
|
||||
}
|
||||
|
||||
InstrumentationRegistry.getInstrumentation()
|
||||
.getUiAutomation().dropShellPermissionIdentity();
|
||||
// Remove scheduled messages that would be processed when the test is already done, and
|
||||
// could cause issues, for example, messages that remove/cancel shown toasts (this causes
|
||||
// problematic interactions with mocks when they're no longer working as expected).
|
||||
mWorkerHandler.removeCallbacksAndMessages(null);
|
||||
}
|
||||
|
||||
private ApplicationInfo getApplicationInfo(String pkg, int uid) {
|
||||
final ApplicationInfo applicationInfo = new ApplicationInfo();
|
||||
applicationInfo.uid = uid;
|
||||
switch (pkg) {
|
||||
case PKG_N_MR1:
|
||||
applicationInfo.targetSdkVersion = Build.VERSION_CODES.N_MR1;
|
||||
break;
|
||||
case PKG_O:
|
||||
applicationInfo.targetSdkVersion = Build.VERSION_CODES.O;
|
||||
break;
|
||||
case PKG_P:
|
||||
applicationInfo.targetSdkVersion = Build.VERSION_CODES.P;
|
||||
break;
|
||||
default:
|
||||
applicationInfo.targetSdkVersion = Build.VERSION_CODES.CUR_DEVELOPMENT;
|
||||
break;
|
||||
}
|
||||
return applicationInfo;
|
||||
}
|
||||
|
||||
public void waitForIdle() {
|
||||
mTestableLooper.processAllMessages();
|
||||
}
|
||||
|
||||
private NotificationRecord generateNotificationRecord(NotificationChannel channel) {
|
||||
return generateNotificationRecord(channel, null);
|
||||
}
|
||||
|
||||
private NotificationRecord generateNotificationRecord(NotificationChannel channel,
|
||||
Notification.TvExtender extender) {
|
||||
if (channel == null) {
|
||||
channel = mTestNotificationChannel;
|
||||
}
|
||||
Notification.Builder nb = new Notification.Builder(mContext, channel.getId())
|
||||
.setContentTitle("foo")
|
||||
.setSmallIcon(android.R.drawable.sym_def_app_icon)
|
||||
.addAction(new Notification.Action.Builder(null, "test", null).build());
|
||||
if (extender != null) {
|
||||
nb.extend(extender);
|
||||
}
|
||||
StatusBarNotification sbn = new StatusBarNotification(PKG, PKG, 8, "tag", mUid, 0,
|
||||
nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
|
||||
return new NotificationRecord(mContext, sbn, channel);
|
||||
}
|
||||
|
||||
private void enableInteractAcrossUsers() {
|
||||
TestablePermissions perms = mContext.getTestablePermissions();
|
||||
perms.setPermission(android.Manifest.permission.INTERACT_ACROSS_USERS, PERMISSION_GRANTED);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAreNotificationsEnabledForPackage() throws Exception {
|
||||
mBinderService.areNotificationsEnabledForPackage(mContext.getPackageName(),
|
||||
mUid);
|
||||
|
||||
verify(mPermissionHelper).hasPermission(mUid);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAreNotificationsEnabledForPackage_crossUser() throws Exception {
|
||||
try {
|
||||
mBinderService.areNotificationsEnabledForPackage(mContext.getPackageName(),
|
||||
mUid + UserHandle.PER_USER_RANGE);
|
||||
fail("Cannot call cross user without permission");
|
||||
} catch (SecurityException e) {
|
||||
// pass
|
||||
}
|
||||
verify(mPermissionHelper, never()).hasPermission(anyInt());
|
||||
|
||||
// cross user, with permission, no problem
|
||||
enableInteractAcrossUsers();
|
||||
mBinderService.areNotificationsEnabledForPackage(mContext.getPackageName(),
|
||||
mUid + UserHandle.PER_USER_RANGE);
|
||||
|
||||
verify(mPermissionHelper).hasPermission(mUid + UserHandle.PER_USER_RANGE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAreNotificationsEnabledForPackage_viaInternalService() {
|
||||
mInternalService.areNotificationsEnabledForPackage(mContext.getPackageName(), mUid);
|
||||
verify(mPermissionHelper).hasPermission(mUid);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetPackageImportance() throws Exception {
|
||||
when(mPermissionHelper.hasPermission(mUid)).thenReturn(true);
|
||||
assertThat(mBinderService.getPackageImportance(mContext.getPackageName()))
|
||||
.isEqualTo(IMPORTANCE_DEFAULT);
|
||||
|
||||
when(mPermissionHelper.hasPermission(mUid)).thenReturn(false);
|
||||
assertThat(mBinderService.getPackageImportance(mContext.getPackageName()))
|
||||
.isEqualTo(IMPORTANCE_NONE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEnqueueNotificationInternal_noChannel() throws Exception {
|
||||
when(mPermissionHelper.hasPermission(mUid)).thenReturn(false);
|
||||
NotificationRecord nr = generateNotificationRecord(
|
||||
new NotificationChannel("did not create", "", IMPORTANCE_DEFAULT));
|
||||
|
||||
mBinderService.enqueueNotificationWithTag(PKG, PKG, nr.getSbn().getTag(),
|
||||
nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
|
||||
waitForIdle();
|
||||
|
||||
verify(mPermissionHelper).hasPermission(mUid);
|
||||
verify(mPermissionHelper, never()).hasPermission(Process.SYSTEM_UID);
|
||||
|
||||
reset(mPermissionHelper);
|
||||
when(mPermissionHelper.hasPermission(mUid)).thenReturn(true);
|
||||
|
||||
mBinderService.enqueueNotificationWithTag(PKG, PKG, nr.getSbn().getTag(),
|
||||
nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
|
||||
waitForIdle();
|
||||
|
||||
verify(mPermissionHelper).hasPermission(mUid);
|
||||
assertThat(mService.mChannelToastsSent).contains(mUid);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetNotificationsEnabledForPackage_noChange() throws Exception {
|
||||
when(mPermissionHelper.hasPermission(mUid)).thenReturn(true);
|
||||
mBinderService.setNotificationsEnabledForPackage(mContext.getPackageName(), mUid, true);
|
||||
|
||||
verify(mPermissionHelper, never()).setNotificationPermission(
|
||||
anyString(), anyInt(), anyBoolean(), anyBoolean());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetNotificationsEnabledForPackage() throws Exception {
|
||||
when(mPermissionHelper.hasPermission(mUid)).thenReturn(true);
|
||||
mBinderService.setNotificationsEnabledForPackage(mContext.getPackageName(), mUid, false);
|
||||
|
||||
verify(mPermissionHelper).setNotificationPermission(
|
||||
mContext.getPackageName(), UserHandle.getUserId(mUid), false, true);
|
||||
|
||||
verify(mAppOpsManager, never()).setMode(anyInt(), anyInt(), anyString(), anyInt());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateAppNotifyCreatorBlock() throws Exception {
|
||||
when(mPermissionHelper.hasPermission(mUid)).thenReturn(true);
|
||||
|
||||
mBinderService.setNotificationsEnabledForPackage(PKG, mUid, false);
|
||||
Thread.sleep(500);
|
||||
waitForIdle();
|
||||
|
||||
ArgumentCaptor<Intent> captor = ArgumentCaptor.forClass(Intent.class);
|
||||
verify(mContext, times(1)).sendBroadcastAsUser(captor.capture(), any(), eq(null));
|
||||
|
||||
assertEquals(NotificationManager.ACTION_APP_BLOCK_STATE_CHANGED,
|
||||
captor.getValue().getAction());
|
||||
assertEquals(PKG, captor.getValue().getPackage());
|
||||
assertTrue(captor.getValue().getBooleanExtra(EXTRA_BLOCKED_STATE, true));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateAppNotifyCreatorUnblock() throws Exception {
|
||||
when(mPermissionHelper.hasPermission(mUid)).thenReturn(false);
|
||||
|
||||
mBinderService.setNotificationsEnabledForPackage(PKG, mUid, true);
|
||||
Thread.sleep(500);
|
||||
waitForIdle();
|
||||
|
||||
ArgumentCaptor<Intent> captor = ArgumentCaptor.forClass(Intent.class);
|
||||
verify(mContext, times(1)).sendBroadcastAsUser(captor.capture(), any(), eq(null));
|
||||
|
||||
assertEquals(NotificationManager.ACTION_APP_BLOCK_STATE_CHANGED,
|
||||
captor.getValue().getAction());
|
||||
assertEquals(PKG, captor.getValue().getPackage());
|
||||
assertFalse(captor.getValue().getBooleanExtra(EXTRA_BLOCKED_STATE, true));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetNotificationChannelsBypassingDnd_blocked() throws RemoteException {
|
||||
mService.setPreferencesHelper(mPreferencesHelper);
|
||||
|
||||
when(mPermissionHelper.hasPermission(mUid)).thenReturn(false);
|
||||
|
||||
assertThat(mBinderService.getNotificationChannelsBypassingDnd(PKG, mUid).getList())
|
||||
.isEmpty();
|
||||
verify(mPreferencesHelper, never()).getImportance(anyString(), anyInt());
|
||||
verify(mPreferencesHelper, never()).getNotificationChannelsBypassingDnd(PKG, mUid);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBlockedNotifications_blockedByUser() throws Exception {
|
||||
when(mPackageManager.isPackageSuspendedForUser(anyString(), anyInt())).thenReturn(false);
|
||||
when(mAssistants.isSameUser(any(), anyInt())).thenReturn(true);
|
||||
|
||||
NotificationChannel channel = new NotificationChannel("id", "name",
|
||||
NotificationManager.IMPORTANCE_HIGH);
|
||||
NotificationRecord r = generateNotificationRecord(channel);
|
||||
mService.addEnqueuedNotification(r);
|
||||
|
||||
when(mPermissionHelper.hasPermission(anyInt())).thenReturn(false);
|
||||
|
||||
NotificationManagerService.PostNotificationRunnable runnable =
|
||||
mService.new PostNotificationRunnable(r.getKey(), r.getSbn().getPackageName(),
|
||||
r.getUid(), SystemClock.elapsedRealtime());
|
||||
runnable.run();
|
||||
waitForIdle();
|
||||
|
||||
verify(mUsageStats).registerBlocked(any());
|
||||
verify(mUsageStats, never()).registerPostedByApp(any());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEnqueueNotification_appBlocked() throws Exception {
|
||||
when(mPermissionHelper.hasPermission(mUid)).thenReturn(false);
|
||||
|
||||
mBinderService.enqueueNotificationWithTag(PKG, PKG,
|
||||
"testEnqueueNotification_appBlocked", 0,
|
||||
generateNotificationRecord(null).getNotification(), 0);
|
||||
waitForIdle();
|
||||
verify(mWorkerHandler, never()).post(
|
||||
any(NotificationManagerService.EnqueueNotificationRunnable.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDefaultChannelDoesNotUpdateApp_postMigrationToPermissions() throws Exception {
|
||||
final NotificationChannel defaultChannel = mBinderService.getNotificationChannel(
|
||||
PKG_N_MR1, ActivityManager.getCurrentUser(), PKG_N_MR1,
|
||||
NotificationChannel.DEFAULT_CHANNEL_ID);
|
||||
defaultChannel.setImportance(IMPORTANCE_NONE);
|
||||
|
||||
mBinderService.updateNotificationChannelForPackage(PKG_N_MR1, mUid, defaultChannel);
|
||||
|
||||
verify(mPermissionHelper).setNotificationPermission(
|
||||
PKG_N_MR1, ActivityManager.getCurrentUser(), false, true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPostNotification_appPermissionFixed() throws Exception {
|
||||
when(mPermissionHelper.hasPermission(mUid)).thenReturn(true);
|
||||
when(mPermissionHelper.isPermissionFixed(PKG, 0)).thenReturn(true);
|
||||
|
||||
NotificationRecord temp = generateNotificationRecord(mTestNotificationChannel);
|
||||
mBinderService.enqueueNotificationWithTag(PKG, PKG,
|
||||
"testPostNotification_appPermissionFixed", 0,
|
||||
temp.getNotification(), 0);
|
||||
waitForIdle();
|
||||
assertThat(mService.getNotificationRecordCount()).isEqualTo(1);
|
||||
StatusBarNotification[] notifs =
|
||||
mBinderService.getActiveNotifications(PKG);
|
||||
assertThat(mService.getNotificationRecord(notifs[0].getKey()).isImportanceFixed()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSummaryNotification_appPermissionFixed() {
|
||||
NotificationRecord temp = generateNotificationRecord(mTestNotificationChannel);
|
||||
mService.addNotification(temp);
|
||||
|
||||
when(mPermissionHelper.hasPermission(mUid)).thenReturn(true);
|
||||
when(mPermissionHelper.isPermissionFixed(PKG, temp.getUserId())).thenReturn(true);
|
||||
|
||||
NotificationRecord r = mService.createAutoGroupSummary(
|
||||
temp.getUserId(), temp.getSbn().getPackageName(), temp.getKey(), false);
|
||||
|
||||
assertThat(r.isImportanceFixed()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMediaNotificationsBypassBlock() throws Exception {
|
||||
when(mAmi.getPendingIntentFlags(any(IIntentSender.class)))
|
||||
.thenReturn(FLAG_MUTABLE | FLAG_ONE_SHOT);
|
||||
when(mAssistants.isSameUser(any(), anyInt())).thenReturn(true);
|
||||
|
||||
Notification.Builder nb = new Notification.Builder(
|
||||
mContext, mTestNotificationChannel.getId())
|
||||
.setContentTitle("foo")
|
||||
.setSmallIcon(android.R.drawable.sym_def_app_icon)
|
||||
.addAction(new Notification.Action.Builder(null, "test", null).build());
|
||||
StatusBarNotification sbn = new StatusBarNotification(PKG, PKG, 8, "tag", mUid, 0,
|
||||
nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
|
||||
NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
|
||||
|
||||
when(mPermissionHelper.hasPermission(mUid)).thenReturn(false);
|
||||
|
||||
// normal blocked notifications - blocked
|
||||
assertThat(mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(),
|
||||
r.getSbn().getId(), r.getSbn().getTag(), r, false)).isFalse();
|
||||
|
||||
// just using the style - blocked
|
||||
nb.setStyle(new Notification.MediaStyle());
|
||||
sbn = new StatusBarNotification(PKG, PKG, 8, "tag", mUid, 0,
|
||||
nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
|
||||
r = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
|
||||
|
||||
assertThat(mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(),
|
||||
r.getSbn().getId(), r.getSbn().getTag(), r, false)).isFalse();
|
||||
|
||||
// using the style, but incorrect type in session - blocked
|
||||
nb.setStyle(new Notification.MediaStyle());
|
||||
Bundle extras = new Bundle();
|
||||
extras.putParcelable(Notification.EXTRA_MEDIA_SESSION, new Intent());
|
||||
nb.addExtras(extras);
|
||||
sbn = new StatusBarNotification(PKG, PKG, 8, "tag", mUid, 0,
|
||||
nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
|
||||
r = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
|
||||
|
||||
assertThat(mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(),
|
||||
r.getSbn().getId(), r.getSbn().getTag(), r, false)).isFalse();
|
||||
|
||||
// style + media session - bypasses block
|
||||
nb.setStyle(new Notification.MediaStyle().setMediaSession(mock(MediaSession.Token.class)));
|
||||
sbn = new StatusBarNotification(PKG, PKG, 8, "tag", mUid, 0,
|
||||
nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
|
||||
r = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
|
||||
|
||||
assertThat(mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(),
|
||||
r.getSbn().getId(), r.getSbn().getTag(), r, false)).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMediaNotificationsBypassBlock_atPost() throws Exception {
|
||||
when(mPackageManager.isPackageSuspendedForUser(anyString(), anyInt())).thenReturn(false);
|
||||
when(mAssistants.isSameUser(any(), anyInt())).thenReturn(true);
|
||||
|
||||
Notification.Builder nb = new Notification.Builder(
|
||||
mContext, mTestNotificationChannel.getId())
|
||||
.setContentTitle("foo")
|
||||
.setSmallIcon(android.R.drawable.sym_def_app_icon)
|
||||
.addAction(new Notification.Action.Builder(null, "test", null).build());
|
||||
StatusBarNotification sbn = new StatusBarNotification(PKG, PKG, 8, "tag", mUid, 0,
|
||||
nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
|
||||
NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
|
||||
|
||||
when(mPermissionHelper.hasPermission(anyInt())).thenReturn(false);
|
||||
|
||||
mService.addEnqueuedNotification(r);
|
||||
NotificationManagerService.PostNotificationRunnable runnable =
|
||||
mService.new PostNotificationRunnable(r.getKey(), r.getSbn().getPackageName(),
|
||||
r.getUid(), SystemClock.elapsedRealtime());
|
||||
runnable.run();
|
||||
waitForIdle();
|
||||
|
||||
verify(mUsageStats).registerBlocked(any());
|
||||
verify(mUsageStats, never()).registerPostedByApp(any());
|
||||
|
||||
// just using the style - blocked
|
||||
mService.clearNotifications();
|
||||
reset(mUsageStats);
|
||||
nb.setStyle(new Notification.MediaStyle());
|
||||
sbn = new StatusBarNotification(PKG, PKG, 8, "tag", mUid, 0,
|
||||
nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
|
||||
r = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
|
||||
|
||||
mService.addEnqueuedNotification(r);
|
||||
runnable = mService.new PostNotificationRunnable(r.getKey(), r.getSbn().getPackageName(),
|
||||
r.getUid(), SystemClock.elapsedRealtime());
|
||||
runnable.run();
|
||||
waitForIdle();
|
||||
|
||||
verify(mUsageStats).registerBlocked(any());
|
||||
verify(mUsageStats, never()).registerPostedByApp(any());
|
||||
|
||||
// style + media session - bypasses block
|
||||
mService.clearNotifications();
|
||||
reset(mUsageStats);
|
||||
nb.setStyle(new Notification.MediaStyle().setMediaSession(mock(MediaSession.Token.class)));
|
||||
sbn = new StatusBarNotification(PKG, PKG, 8, "tag", mUid, 0,
|
||||
nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
|
||||
r = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
|
||||
|
||||
mService.addEnqueuedNotification(r);
|
||||
runnable = mService.new PostNotificationRunnable(r.getKey(), r.getSbn().getPackageName(),
|
||||
r.getUid(), SystemClock.elapsedRealtime());
|
||||
runnable.run();
|
||||
waitForIdle();
|
||||
|
||||
verify(mUsageStats, never()).registerBlocked(any());
|
||||
verify(mUsageStats).registerPostedByApp(any());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetAllUsersNotificationPermissions() {
|
||||
// In this case, there are multiple users each with notification permissions (and also,
|
||||
// for good measure, some without).
|
||||
// make sure the collection returned contains info for all of them
|
||||
final List<UserInfo> userInfos = new ArrayList<>();
|
||||
userInfos.add(new UserInfo(0, "user0", 0));
|
||||
userInfos.add(new UserInfo(1, "user1", 0));
|
||||
userInfos.add(new UserInfo(2, "user2", 0));
|
||||
when(mUm.getUsers()).thenReturn(userInfos);
|
||||
|
||||
// construct the permissions for each of them
|
||||
ArrayMap<Pair<Integer, String>, Pair<Boolean, Boolean>> permissions0 = new ArrayMap<>(),
|
||||
permissions1 = new ArrayMap<>();
|
||||
permissions0.put(new Pair<>(10, "package1"), new Pair<>(true, false));
|
||||
permissions0.put(new Pair<>(20, "package2"), new Pair<>(false, true));
|
||||
permissions1.put(new Pair<>(11, "package1"), new Pair<>(false, false));
|
||||
permissions1.put(new Pair<>(21, "package2"), new Pair<>(true, true));
|
||||
when(mPermissionHelper.getNotificationPermissionValues(0)).thenReturn(permissions0);
|
||||
when(mPermissionHelper.getNotificationPermissionValues(1)).thenReturn(permissions1);
|
||||
when(mPermissionHelper.getNotificationPermissionValues(2)).thenReturn(new ArrayMap<>());
|
||||
|
||||
ArrayMap<Pair<Integer, String>, Pair<Boolean, Boolean>> combinedPermissions =
|
||||
mService.getAllUsersNotificationPermissions();
|
||||
assertTrue(combinedPermissions.get(new Pair<>(10, "package1")).first);
|
||||
assertFalse(combinedPermissions.get(new Pair<>(10, "package1")).second);
|
||||
assertFalse(combinedPermissions.get(new Pair<>(20, "package2")).first);
|
||||
assertTrue(combinedPermissions.get(new Pair<>(20, "package2")).second);
|
||||
assertFalse(combinedPermissions.get(new Pair<>(11, "package1")).first);
|
||||
assertFalse(combinedPermissions.get(new Pair<>(11, "package1")).second);
|
||||
assertTrue(combinedPermissions.get(new Pair<>(21, "package2")).first);
|
||||
assertTrue(combinedPermissions.get(new Pair<>(21, "package2")).second);
|
||||
}
|
||||
}
|
||||
@@ -1065,9 +1065,8 @@ public class NotificationRecordTest extends UiServiceTestCase {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testApplyImportanceAdjustmentsForNonOemDefaultAppLockedChannels() {
|
||||
public void testApplyImportanceAdjustments() {
|
||||
NotificationChannel channel = new NotificationChannel("a", "a", IMPORTANCE_DEFAULT);
|
||||
channel.setImportanceLockedByOEM(false);
|
||||
|
||||
StatusBarNotification sbn = getNotification(PKG_O, true /* noisy */,
|
||||
true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */,
|
||||
|
||||
@@ -88,51 +88,13 @@ public class PermissionHelperTest extends UiServiceTestCase {
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
mPermissionHelper = new PermissionHelper(mPmi, mPackageManager, mPermManager, true, false);
|
||||
mPermissionHelper = new PermissionHelper(mPmi, mPackageManager, mPermManager, false);
|
||||
PackageInfo testPkgInfo = new PackageInfo();
|
||||
testPkgInfo.requestedPermissions = new String[]{ Manifest.permission.POST_NOTIFICATIONS };
|
||||
when(mPackageManager.getPackageInfo(anyString(), anyLong(), anyInt()))
|
||||
.thenReturn(testPkgInfo);
|
||||
}
|
||||
|
||||
// TODO (b/194833441): Remove when the migration is enabled
|
||||
@Test
|
||||
public void testMethodsThrowIfMigrationDisabled() throws IllegalAccessException,
|
||||
InvocationTargetException {
|
||||
PermissionHelper permHelper =
|
||||
new PermissionHelper(mPmi, mPackageManager, mPermManager, false, false);
|
||||
|
||||
Method[] allMethods = PermissionHelper.class.getDeclaredMethods();
|
||||
for (Method method : allMethods) {
|
||||
if (Modifier.isPublic(method.getModifiers()) &&
|
||||
!Objects.equals("isMigrationEnabled", method.getName())) {
|
||||
Parameter[] params = method.getParameters();
|
||||
List<Object> args = Lists.newArrayListWithCapacity(params.length);
|
||||
for (int i = 0; i < params.length; i++) {
|
||||
Type type = params[i].getParameterizedType();
|
||||
if (type.getTypeName().equals("java.lang.String")) {
|
||||
args.add("");
|
||||
} else if (type.getTypeName().equals("boolean")){
|
||||
args.add(false);
|
||||
} else if (type.getTypeName().equals("int")) {
|
||||
args.add(1);
|
||||
} else if (type.getTypeName().equals(
|
||||
"com.android.server.notification.PermissionHelper$PackagePermission")) {
|
||||
args.add(null);
|
||||
}
|
||||
}
|
||||
try {
|
||||
method.invoke(permHelper, args.toArray());
|
||||
fail("Method should have thrown because migration flag is disabled");
|
||||
} catch (InvocationTargetException e) {
|
||||
if (!(e.getTargetException() instanceof IllegalStateException)) {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHasPermission() throws Exception {
|
||||
when(mPmi.checkPostNotificationsPermissionGrantedOrLegacyAccess(anyInt()))
|
||||
@@ -304,7 +266,7 @@ public class PermissionHelperTest extends UiServiceTestCase {
|
||||
@Test
|
||||
public void testSetNotificationPermission_pkgPerm_grantedByDefaultPermSet_allUserSet()
|
||||
throws Exception {
|
||||
mPermissionHelper = new PermissionHelper(mPmi, mPackageManager, mPermManager, true, true);
|
||||
mPermissionHelper = new PermissionHelper(mPmi, mPackageManager, mPermManager, true);
|
||||
when(mPmi.checkPermission(anyString(), anyString(), anyInt()))
|
||||
.thenReturn(PERMISSION_DENIED);
|
||||
when(mPermManager.getPermissionFlags(anyString(),
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -168,7 +168,8 @@ public class RoleObserverTest extends UiServiceTestCase {
|
||||
mock(StatsManager.class), mock(TelephonyManager.class),
|
||||
mock(ActivityManagerInternal.class),
|
||||
mock(MultiRateLimiter.class), mock(PermissionHelper.class),
|
||||
mock(UsageStatsManagerInternal.class), mock (TelecomManager.class));
|
||||
mock(UsageStatsManagerInternal.class), mock (TelecomManager.class),
|
||||
mock(NotificationChannelLogger.class));
|
||||
} catch (SecurityException e) {
|
||||
if (!e.getMessage().contains("Permission Denial: not allowed to send broadcast")) {
|
||||
throw e;
|
||||
|
||||
Reference in New Issue
Block a user