Merge "Allow apps to proxy notifications for other apps"
This commit is contained in:
committed by
Android (Google) Code Review
commit
f0bb83bab6
@@ -5680,6 +5680,7 @@ package android.app {
|
||||
public class NotificationManager {
|
||||
method public java.lang.String addAutomaticZenRule(android.app.AutomaticZenRule);
|
||||
method public boolean areNotificationsEnabled();
|
||||
method public boolean canNotifyAsPackage(java.lang.String);
|
||||
method public void cancel(int);
|
||||
method public void cancel(java.lang.String, int);
|
||||
method public void cancelAll();
|
||||
@@ -5698,13 +5699,17 @@ package android.app {
|
||||
method public android.app.NotificationChannelGroup getNotificationChannelGroup(java.lang.String);
|
||||
method public java.util.List<android.app.NotificationChannelGroup> getNotificationChannelGroups();
|
||||
method public java.util.List<android.app.NotificationChannel> getNotificationChannels();
|
||||
method public java.lang.String getNotificationDelegate();
|
||||
method public android.app.NotificationManager.Policy getNotificationPolicy();
|
||||
method public boolean isNotificationListenerAccessGranted(android.content.ComponentName);
|
||||
method public boolean isNotificationPolicyAccessGranted();
|
||||
method public void notify(int, android.app.Notification);
|
||||
method public void notify(java.lang.String, int, android.app.Notification);
|
||||
method public void notifyAsPackage(java.lang.String, java.lang.String, int, android.app.Notification);
|
||||
method public boolean removeAutomaticZenRule(java.lang.String);
|
||||
method public void revokeNotificationDelegate();
|
||||
method public final void setInterruptionFilter(int);
|
||||
method public void setNotificationDelegate(java.lang.String);
|
||||
method public void setNotificationPolicy(android.app.NotificationManager.Policy);
|
||||
method public boolean updateAutomaticZenRule(java.lang.String, android.app.AutomaticZenRule);
|
||||
field public static final java.lang.String ACTION_APP_BLOCK_STATE_CHANGED = "android.app.action.APP_BLOCK_STATE_CHANGED";
|
||||
@@ -39652,10 +39657,12 @@ package android.service.notification {
|
||||
method public int getId();
|
||||
method public java.lang.String getKey();
|
||||
method public android.app.Notification getNotification();
|
||||
method public java.lang.String getOpPkg();
|
||||
method public java.lang.String getOverrideGroupKey();
|
||||
method public java.lang.String getPackageName();
|
||||
method public long getPostTime();
|
||||
method public java.lang.String getTag();
|
||||
method public int getUid();
|
||||
method public android.os.UserHandle getUser();
|
||||
method public deprecated int getUserId();
|
||||
method public boolean isClearable();
|
||||
|
||||
@@ -165,4 +165,9 @@ interface INotificationManager
|
||||
void applyRestore(in byte[] payload, int user);
|
||||
|
||||
ParceledListSlice getAppActiveNotifications(String callingPkg, int userId);
|
||||
|
||||
void setNotificationDelegate(String callingPkg, String delegate);
|
||||
void revokeNotificationDelegate(String callingPkg);
|
||||
String getNotificationDelegate(String callingPkg);
|
||||
boolean canNotifyAsPackage(String callingPkg, String targetPkg);
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ package android.app;
|
||||
|
||||
import android.annotation.IntDef;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.annotation.SdkConstant;
|
||||
import android.annotation.SystemService;
|
||||
import android.annotation.TestApi;
|
||||
@@ -352,7 +353,7 @@ public class NotificationManager {
|
||||
}
|
||||
|
||||
/**
|
||||
* Post a notification to be shown in the status bar. If a notification with
|
||||
* Posts a notification to be shown in the status bar. If a notification with
|
||||
* the same tag and id has already been posted by your application and has not yet been
|
||||
* canceled, it will be replaced by the updated information.
|
||||
*
|
||||
@@ -375,6 +376,42 @@ public class NotificationManager {
|
||||
notifyAsUser(tag, id, notification, mContext.getUser());
|
||||
}
|
||||
|
||||
/**
|
||||
* Posts a notification as a specified package to be shown in the status bar. If a notification
|
||||
* with the same tag and id has already been posted for that package and has not yet been
|
||||
* canceled, it will be replaced by the updated information.
|
||||
*
|
||||
* All {@link android.service.notification.NotificationListenerService listener services} will
|
||||
* be granted {@link Intent#FLAG_GRANT_READ_URI_PERMISSION} access to any {@link Uri uris}
|
||||
* provided on this notification or the
|
||||
* {@link NotificationChannel} this notification is posted to using
|
||||
* {@link Context#grantUriPermission(String, Uri, int)}. Permission will be revoked when the
|
||||
* notification is canceled, or you can revoke permissions with
|
||||
* {@link Context#revokeUriPermission(Uri, int)}.
|
||||
*
|
||||
* @param targetPackage The package to post the notification as. The package must have granted
|
||||
* you access to post notifications on their behalf with
|
||||
* {@link #setNotificationDelegate(String)}.
|
||||
* @param tag A string identifier for this notification. May be {@code null}.
|
||||
* @param id An identifier for this notification. The pair (tag, id) must be unique
|
||||
* within your application.
|
||||
* @param notification A {@link Notification} object describing what to
|
||||
* show the user. Must not be null.
|
||||
*/
|
||||
public void notifyAsPackage(@NonNull String targetPackage, @NonNull String tag, int id,
|
||||
Notification notification) {
|
||||
INotificationManager service = getService();
|
||||
String sender = mContext.getPackageName();
|
||||
|
||||
try {
|
||||
if (localLOGV) Log.v(TAG, sender + ": notify(" + id + ", " + notification + ")");
|
||||
service.enqueueNotificationWithTag(targetPackage, sender, tag, id,
|
||||
fixNotification(notification), mContext.getUser().getIdentifier());
|
||||
} catch (RemoteException e) {
|
||||
throw e.rethrowFromSystemServer();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
@@ -383,6 +420,18 @@ public class NotificationManager {
|
||||
{
|
||||
INotificationManager service = getService();
|
||||
String pkg = mContext.getPackageName();
|
||||
|
||||
try {
|
||||
if (localLOGV) Log.v(TAG, pkg + ": notify(" + id + ", " + notification + ")");
|
||||
service.enqueueNotificationWithTag(pkg, mContext.getOpPackageName(), tag, id,
|
||||
fixNotification(notification), user.getIdentifier());
|
||||
} catch (RemoteException e) {
|
||||
throw e.rethrowFromSystemServer();
|
||||
}
|
||||
}
|
||||
|
||||
private Notification fixNotification(Notification notification) {
|
||||
String pkg = mContext.getPackageName();
|
||||
// Fix the notification as best we can.
|
||||
Notification.addFieldsFromContext(mContext, notification);
|
||||
|
||||
@@ -400,19 +449,12 @@ public class NotificationManager {
|
||||
+ notification);
|
||||
}
|
||||
}
|
||||
if (localLOGV) Log.v(TAG, pkg + ": notify(" + id + ", " + notification + ")");
|
||||
|
||||
notification.reduceImageSizes(mContext);
|
||||
|
||||
ActivityManager am = (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE);
|
||||
boolean isLowRam = am.isLowRamDevice();
|
||||
final Notification copy = Builder.maybeCloneStrippedForDelivery(notification, isLowRam,
|
||||
mContext);
|
||||
try {
|
||||
service.enqueueNotificationWithTag(pkg, mContext.getOpPackageName(), tag, id,
|
||||
copy, user.getIdentifier());
|
||||
} catch (RemoteException e) {
|
||||
throw e.rethrowFromSystemServer();
|
||||
}
|
||||
return Builder.maybeCloneStrippedForDelivery(notification, isLowRam, mContext);
|
||||
}
|
||||
|
||||
private void fixLegacySmallIcon(Notification n, String pkg) {
|
||||
@@ -473,6 +515,72 @@ public class NotificationManager {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows a package to post notifications on your behalf using
|
||||
* {@link #notifyAsPackage(String, String, int, Notification)}.
|
||||
*
|
||||
* This can be used to allow persistent processes to post notifications based on messages
|
||||
* received on your behalf from the cloud, without your process having to wake up.
|
||||
*
|
||||
* You can check if you have an allowed delegate with {@link #getNotificationDelegate()} and
|
||||
* revoke your delegate with {@link #revokeNotificationDelegate()}.
|
||||
*
|
||||
* @param delegate Package name of the app which can send notifications on your behalf.
|
||||
*/
|
||||
public void setNotificationDelegate(@NonNull String delegate) {
|
||||
INotificationManager service = getService();
|
||||
String pkg = mContext.getPackageName();
|
||||
if (localLOGV) Log.v(TAG, pkg + ": cancelAll()");
|
||||
try {
|
||||
service.setNotificationDelegate(pkg, delegate);
|
||||
} catch (RemoteException e) {
|
||||
throw e.rethrowFromSystemServer();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Revokes permission for your {@link #setNotificationDelegate(String) notification delegate}
|
||||
* to post notifications on your behalf.
|
||||
*/
|
||||
public void revokeNotificationDelegate() {
|
||||
INotificationManager service = getService();
|
||||
String pkg = mContext.getPackageName();
|
||||
try {
|
||||
service.revokeNotificationDelegate(pkg);
|
||||
} catch (RemoteException e) {
|
||||
throw e.rethrowFromSystemServer();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link #setNotificationDelegate(String) delegate} that can post notifications on
|
||||
* your behalf, if there currently is one.
|
||||
*/
|
||||
public @Nullable String getNotificationDelegate() {
|
||||
INotificationManager service = getService();
|
||||
String pkg = mContext.getPackageName();
|
||||
try {
|
||||
return service.getNotificationDelegate(pkg);
|
||||
} catch (RemoteException e) {
|
||||
throw e.rethrowFromSystemServer();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether you are allowed to post notifications on behalf of a given package, with
|
||||
* {@link #notifyAsPackage(String, String, int, Notification)}.
|
||||
*
|
||||
* See {@link #setNotificationDelegate(String)}.
|
||||
*/
|
||||
public boolean canNotifyAsPackage(String pkg) {
|
||||
INotificationManager service = getService();
|
||||
try {
|
||||
return service.canNotifyAsPackage(mContext.getPackageName(), pkg);
|
||||
} catch (RemoteException e) {
|
||||
throw e.rethrowFromSystemServer();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a group container for {@link NotificationChannel} objects.
|
||||
*
|
||||
|
||||
@@ -18,7 +18,7 @@ package android.service.notification;
|
||||
|
||||
import android.annotation.UnsupportedAppUsage;
|
||||
import android.app.Notification;
|
||||
import android.app.NotificationChannel;
|
||||
import android.app.NotificationManager;
|
||||
import android.content.Context;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
@@ -261,7 +261,7 @@ public class StatusBarNotification implements Parcelable {
|
||||
return this.user.getIdentifier();
|
||||
}
|
||||
|
||||
/** The package of the app that posted the notification. */
|
||||
/** The package that the notification belongs to. */
|
||||
public String getPackageName() {
|
||||
return pkg;
|
||||
}
|
||||
@@ -277,14 +277,18 @@ public class StatusBarNotification implements Parcelable {
|
||||
return tag;
|
||||
}
|
||||
|
||||
/** The notifying app's calling uid. @hide */
|
||||
@UnsupportedAppUsage
|
||||
/**
|
||||
* The notifying app's ({@link #getPackageName()}'s) uid.
|
||||
*/
|
||||
public int getUid() {
|
||||
return uid;
|
||||
}
|
||||
|
||||
/** The package used for AppOps tracking. @hide */
|
||||
@UnsupportedAppUsage
|
||||
/** The package that posted the notification.
|
||||
*<p>
|
||||
* Might be different from {@link #getPackageName()} if the app owning the notification has
|
||||
* a {@link NotificationManager#setNotificationDelegate(String) notification delegate}.
|
||||
*/
|
||||
public String getOpPkg() {
|
||||
return opPkg;
|
||||
}
|
||||
|
||||
@@ -5296,7 +5296,9 @@ public class AccountManagerService
|
||||
try {
|
||||
INotificationManager notificationManager = mInjector.getNotificationManager();
|
||||
try {
|
||||
notificationManager.enqueueNotificationWithTag(packageName, packageName,
|
||||
// The calling uid must match either the package or op package, so use an op
|
||||
// package that matches the cleared calling identity.
|
||||
notificationManager.enqueueNotificationWithTag(packageName, "android",
|
||||
id.mTag, id.mId, notification, userId);
|
||||
} catch (RemoteException e) {
|
||||
/* ignore - local call */
|
||||
|
||||
@@ -35,6 +35,8 @@ import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_SCREEN_ON
|
||||
import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_STATUS_BAR;
|
||||
import static android.content.pm.PackageManager.FEATURE_LEANBACK;
|
||||
import static android.content.pm.PackageManager.FEATURE_TELEVISION;
|
||||
import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_AWARE;
|
||||
import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_UNAWARE;
|
||||
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
|
||||
import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_CRITICAL;
|
||||
import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_NORMAL;
|
||||
@@ -203,6 +205,7 @@ import com.android.server.lights.Light;
|
||||
import com.android.server.lights.LightsManager;
|
||||
import com.android.server.notification.ManagedServices.ManagedServiceInfo;
|
||||
import com.android.server.notification.ManagedServices.UserProfiles;
|
||||
import com.android.server.pm.PackageManagerService;
|
||||
import com.android.server.policy.PhoneWindowManager;
|
||||
import com.android.server.statusbar.StatusBarManagerInternal;
|
||||
import com.android.server.uri.UriGrantsManagerInternal;
|
||||
@@ -470,8 +473,8 @@ public class NotificationManagerService extends SystemService {
|
||||
// Gather all notification listener components for candidate pkgs.
|
||||
Set<ComponentName> approvedListeners =
|
||||
mListeners.queryPackageForServices(whitelisted,
|
||||
PackageManager.MATCH_DIRECT_BOOT_AWARE
|
||||
| PackageManager.MATCH_DIRECT_BOOT_UNAWARE, userId);
|
||||
MATCH_DIRECT_BOOT_AWARE
|
||||
| MATCH_DIRECT_BOOT_UNAWARE, userId);
|
||||
for (ComponentName cn : approvedListeners) {
|
||||
try {
|
||||
getBinderService().setNotificationListenerAccessGrantedForUser(cn,
|
||||
@@ -507,8 +510,8 @@ public class NotificationManagerService extends SystemService {
|
||||
// only be one
|
||||
Set<ComponentName> approvedAssistants =
|
||||
mAssistants.queryPackageForServices(defaultAssistantAccess,
|
||||
PackageManager.MATCH_DIRECT_BOOT_AWARE
|
||||
| PackageManager.MATCH_DIRECT_BOOT_UNAWARE, userId);
|
||||
MATCH_DIRECT_BOOT_AWARE
|
||||
| MATCH_DIRECT_BOOT_UNAWARE, userId);
|
||||
for (ComponentName cn : approvedAssistants) {
|
||||
try {
|
||||
getBinderService().setNotificationAssistantAccessGrantedForUser(
|
||||
@@ -1377,7 +1380,7 @@ public class NotificationManagerService extends SystemService {
|
||||
NotificationUsageStats usageStats, AtomicFile policyFile,
|
||||
ActivityManager activityManager, GroupHelper groupHelper, IActivityManager am,
|
||||
UsageStatsManagerInternal appUsageStats, DevicePolicyManagerInternal dpm,
|
||||
IUriGrantsManager ugm, UriGrantsManagerInternal ugmInternal) {
|
||||
IUriGrantsManager ugm, UriGrantsManagerInternal ugmInternal, AppOpsManager appOps) {
|
||||
Resources resources = getContext().getResources();
|
||||
mMaxPackageEnqueueRate = Settings.Global.getFloat(getContext().getContentResolver(),
|
||||
Settings.Global.MAX_NOTIFICATION_ENQUEUE_RATE,
|
||||
@@ -1390,7 +1393,7 @@ public class NotificationManagerService extends SystemService {
|
||||
mUgmInternal = ugmInternal;
|
||||
mPackageManager = packageManager;
|
||||
mPackageManagerClient = packageManagerClient;
|
||||
mAppOps = (AppOpsManager) getContext().getSystemService(Context.APP_OPS_SERVICE);
|
||||
mAppOps = appOps;
|
||||
mVibrator = (Vibrator) getContext().getSystemService(Context.VIBRATOR_SERVICE);
|
||||
mAppUsageStats = appUsageStats;
|
||||
mAlarmManager = (AlarmManager) getContext().getSystemService(Context.ALARM_SERVICE);
|
||||
@@ -1544,7 +1547,8 @@ public class NotificationManagerService extends SystemService {
|
||||
LocalServices.getService(UsageStatsManagerInternal.class),
|
||||
LocalServices.getService(DevicePolicyManagerInternal.class),
|
||||
UriGrantsManager.getService(),
|
||||
LocalServices.getService(UriGrantsManagerInternal.class));
|
||||
LocalServices.getService(UriGrantsManagerInternal.class),
|
||||
(AppOpsManager) getContext().getSystemService(Context.APP_OPS_SERVICE));
|
||||
|
||||
// register for various Intents
|
||||
IntentFilter filter = new IntentFilter();
|
||||
@@ -2233,6 +2237,60 @@ public class NotificationManagerService extends SystemService {
|
||||
savePolicyFile();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setNotificationDelegate(String callingPkg, String delegate) {
|
||||
checkCallerIsSameApp(callingPkg);
|
||||
final int callingUid = Binder.getCallingUid();
|
||||
UserHandle user = UserHandle.getUserHandleForUid(callingUid);
|
||||
try {
|
||||
ApplicationInfo info =
|
||||
mPackageManager.getApplicationInfo(delegate,
|
||||
MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE,
|
||||
user.getIdentifier());
|
||||
if (info != null) {
|
||||
mPreferencesHelper.setNotificationDelegate(
|
||||
callingPkg, callingUid, delegate, info.uid);
|
||||
savePolicyFile();
|
||||
}
|
||||
} catch (RemoteException e) {
|
||||
// :(
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void revokeNotificationDelegate(String callingPkg) {
|
||||
checkCallerIsSameApp(callingPkg);
|
||||
mPreferencesHelper.revokeNotificationDelegate(callingPkg, Binder.getCallingUid());
|
||||
savePolicyFile();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getNotificationDelegate(String callingPkg) {
|
||||
// callable by Settings also
|
||||
checkCallerIsSystemOrSameApp(callingPkg);
|
||||
return mPreferencesHelper.getNotificationDelegate(callingPkg, Binder.getCallingUid());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canNotifyAsPackage(String callingPkg, String targetPkg) {
|
||||
checkCallerIsSameApp(callingPkg);
|
||||
final int callingUid = Binder.getCallingUid();
|
||||
UserHandle user = UserHandle.getUserHandleForUid(callingUid);
|
||||
try {
|
||||
ApplicationInfo info =
|
||||
mPackageManager.getApplicationInfo(targetPkg,
|
||||
MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE,
|
||||
user.getIdentifier());
|
||||
if (info != null) {
|
||||
return mPreferencesHelper.isDelegateAllowed(
|
||||
targetPkg, info.uid, callingPkg, callingUid);
|
||||
}
|
||||
} catch (RemoteException e) {
|
||||
// :(
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateNotificationChannelGroupForPackage(String pkg, int uid,
|
||||
NotificationChannelGroup group) throws RemoteException {
|
||||
@@ -4053,20 +4111,21 @@ public class NotificationManagerService extends SystemService {
|
||||
Slog.v(TAG, "enqueueNotificationInternal: pkg=" + pkg + " id=" + id
|
||||
+ " notification=" + notification);
|
||||
}
|
||||
checkCallerIsSystemOrSameApp(pkg);
|
||||
checkRestrictedCategories(notification);
|
||||
|
||||
final int userId = ActivityManager.handleIncomingUser(callingPid,
|
||||
callingUid, incomingUserId, true, false, "enqueueNotification", pkg);
|
||||
final UserHandle user = new UserHandle(userId);
|
||||
|
||||
if (pkg == null || notification == null) {
|
||||
throw new IllegalArgumentException("null not allowed: pkg=" + pkg
|
||||
+ " id=" + id + " notification=" + notification);
|
||||
}
|
||||
|
||||
// The system can post notifications for any package, let us resolve that.
|
||||
final int notificationUid = resolveNotificationUid(opPkg, callingUid, userId);
|
||||
final int userId = ActivityManager.handleIncomingUser(callingPid,
|
||||
callingUid, incomingUserId, true, false, "enqueueNotification", pkg);
|
||||
final UserHandle user = UserHandle.of(userId);
|
||||
|
||||
// Can throw a SecurityException if the calling uid doesn't have permission to post
|
||||
// as "pkg"
|
||||
final int notificationUid = resolveNotificationUid(opPkg, pkg, callingUid, userId);
|
||||
|
||||
checkRestrictedCategories(notification);
|
||||
|
||||
// Fix the notification as best we can.
|
||||
try {
|
||||
@@ -4193,17 +4252,28 @@ public class NotificationManagerService extends SystemService {
|
||||
}
|
||||
}
|
||||
|
||||
private int resolveNotificationUid(String opPackageName, int callingUid, int userId) {
|
||||
// The system can post notifications on behalf of any package it wants
|
||||
if (isCallerSystemOrPhone() && opPackageName != null && !"android".equals(opPackageName)) {
|
||||
try {
|
||||
return getContext().getPackageManager()
|
||||
.getPackageUidAsUser(opPackageName, userId);
|
||||
} catch (NameNotFoundException e) {
|
||||
/* ignore */
|
||||
}
|
||||
@VisibleForTesting
|
||||
int resolveNotificationUid(String callingPkg, String targetPkg,
|
||||
int callingUid, int userId) {
|
||||
// posted from app A on behalf of app A
|
||||
if (isCallerSameApp(targetPkg, callingUid) && TextUtils.equals(callingPkg, targetPkg)) {
|
||||
return callingUid;
|
||||
}
|
||||
return callingUid;
|
||||
|
||||
int targetUid = -1;
|
||||
try {
|
||||
targetUid = mPackageManagerClient.getPackageUidAsUser(targetPkg, userId);
|
||||
} catch (NameNotFoundException e) {
|
||||
/* ignore */
|
||||
}
|
||||
// posted from app A on behalf of app B
|
||||
if (targetUid != -1 && (isCallerAndroid(callingPkg, callingUid)
|
||||
|| mPreferencesHelper.isDelegateAllowed(
|
||||
targetPkg, targetUid, callingPkg, callingUid))) {
|
||||
return targetUid;
|
||||
}
|
||||
|
||||
throw new SecurityException("Caller " + callingUid + " cannot post for pkg " + targetPkg);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -4222,7 +4292,8 @@ public class NotificationManagerService extends SystemService {
|
||||
// package or a registered listener can enqueue. Prevents DOS attacks and deals with leaks.
|
||||
if (!isSystemNotification && !isNotificationFromListener) {
|
||||
synchronized (mNotificationLock) {
|
||||
if (mNotificationsByKey.get(r.sbn.getKey()) == null && isCallerInstantApp(pkg)) {
|
||||
if (mNotificationsByKey.get(r.sbn.getKey()) == null
|
||||
&& isCallerInstantApp(pkg, callingUid)) {
|
||||
// Ephemeral apps have some special constraints for notifications.
|
||||
// They are not allowed to create new notifications however they are allowed to
|
||||
// update notifications created by the system (e.g. a foreground service
|
||||
@@ -5149,11 +5220,11 @@ public class NotificationManagerService extends SystemService {
|
||||
try {
|
||||
Thread.sleep(waitMs);
|
||||
} catch (InterruptedException e) { }
|
||||
mVibrator.vibrate(record.sbn.getUid(), record.sbn.getOpPkg(),
|
||||
mVibrator.vibrate(record.sbn.getUid(), record.sbn.getPackageName(),
|
||||
effect, "Notification (delayed)", record.getAudioAttributes());
|
||||
}).start();
|
||||
} else {
|
||||
mVibrator.vibrate(record.sbn.getUid(), record.sbn.getOpPkg(),
|
||||
mVibrator.vibrate(record.sbn.getUid(), record.sbn.getPackageName(),
|
||||
effect, "Notification", record.getAudioAttributes());
|
||||
}
|
||||
return true;
|
||||
@@ -6282,6 +6353,11 @@ public class NotificationManagerService extends SystemService {
|
||||
checkCallerIsSameApp(pkg);
|
||||
}
|
||||
|
||||
private boolean isCallerAndroid(String callingPkg, int uid) {
|
||||
return isUidSystemOrPhone(uid) && callingPkg != null
|
||||
&& PackageManagerService.PLATFORM_PACKAGE_NAME.equals(callingPkg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the notification is of a category type that is restricted to system use only,
|
||||
* if so throw SecurityException
|
||||
@@ -6302,13 +6378,13 @@ public class NotificationManagerService extends SystemService {
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isCallerInstantApp(String pkg) {
|
||||
private boolean isCallerInstantApp(String pkg, int callingUid) {
|
||||
// System is always allowed to act for ephemeral apps.
|
||||
if (isCallerSystemOrPhone()) {
|
||||
if (isUidSystemOrPhone(callingUid)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
mAppOps.checkPackage(Binder.getCallingUid(), pkg);
|
||||
mAppOps.checkPackage(callingUid, pkg);
|
||||
|
||||
try {
|
||||
ApplicationInfo ai = mPackageManager.getApplicationInfo(pkg, 0,
|
||||
@@ -6324,7 +6400,10 @@ public class NotificationManagerService extends SystemService {
|
||||
}
|
||||
|
||||
private void checkCallerIsSameApp(String pkg) {
|
||||
final int uid = Binder.getCallingUid();
|
||||
checkCallerIsSameApp(pkg, Binder.getCallingUid());
|
||||
}
|
||||
|
||||
private void checkCallerIsSameApp(String pkg, int uid) {
|
||||
try {
|
||||
ApplicationInfo ai = mPackageManager.getApplicationInfo(
|
||||
pkg, 0, UserHandle.getCallingUserId());
|
||||
@@ -6340,6 +6419,24 @@ public class NotificationManagerService extends SystemService {
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isCallerSameApp(String pkg) {
|
||||
try {
|
||||
checkCallerIsSameApp(pkg);
|
||||
return true;
|
||||
} catch (SecurityException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isCallerSameApp(String pkg, int uid) {
|
||||
try {
|
||||
checkCallerIsSameApp(pkg, uid);
|
||||
return true;
|
||||
} catch (SecurityException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static String callStateToString(int state) {
|
||||
switch (state) {
|
||||
case TelephonyManager.CALL_STATE_IDLE: return "CALL_STATE_IDLE";
|
||||
|
||||
@@ -20,6 +20,7 @@ import static android.app.NotificationManager.IMPORTANCE_NONE;
|
||||
|
||||
import android.annotation.IntDef;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.app.Notification;
|
||||
import android.app.NotificationChannel;
|
||||
import android.app.NotificationChannelGroup;
|
||||
@@ -66,12 +67,14 @@ import java.util.concurrent.ConcurrentHashMap;
|
||||
public class PreferencesHelper implements RankingConfig {
|
||||
private static final String TAG = "NotificationPrefHelper";
|
||||
private static final int XML_VERSION = 1;
|
||||
private static final int UNKNOWN_UID = UserHandle.USER_NULL;
|
||||
|
||||
@VisibleForTesting
|
||||
static final String TAG_RANKING = "ranking";
|
||||
private static final String TAG_PACKAGE = "package";
|
||||
private static final String TAG_CHANNEL = "channel";
|
||||
private static final String TAG_GROUP = "channelGroup";
|
||||
private static final String TAG_DELEGATE = "delegate";
|
||||
|
||||
private static final String ATT_VERSION = "version";
|
||||
private static final String ATT_NAME = "name";
|
||||
@@ -82,6 +85,8 @@ public class PreferencesHelper implements RankingConfig {
|
||||
private static final String ATT_IMPORTANCE = "importance";
|
||||
private static final String ATT_SHOW_BADGE = "show_badge";
|
||||
private static final String ATT_APP_USER_LOCKED_FIELDS = "app_user_locked_fields";
|
||||
private static final String ATT_ENABLED = "enabled";
|
||||
private static final String ATT_USER_ALLOWED = "allowed";
|
||||
|
||||
private static final int DEFAULT_PRIORITY = Notification.PRIORITY_DEFAULT;
|
||||
private static final int DEFAULT_VISIBILITY = NotificationManager.VISIBILITY_NO_OVERRIDE;
|
||||
@@ -147,8 +152,7 @@ public class PreferencesHelper implements RankingConfig {
|
||||
}
|
||||
if (type == XmlPullParser.START_TAG) {
|
||||
if (TAG_PACKAGE.equals(tag)) {
|
||||
int uid = XmlUtils.readIntAttribute(parser, ATT_UID,
|
||||
PackagePreferences.UNKNOWN_UID);
|
||||
int uid = XmlUtils.readIntAttribute(parser, ATT_UID, UNKNOWN_UID);
|
||||
String name = parser.getAttributeValue(null, ATT_NAME);
|
||||
if (!TextUtils.isEmpty(name)) {
|
||||
if (forRestore) {
|
||||
@@ -217,6 +221,24 @@ public class PreferencesHelper implements RankingConfig {
|
||||
r.channels.put(id, channel);
|
||||
}
|
||||
}
|
||||
// Delegate
|
||||
if (TAG_DELEGATE.equals(tagName)) {
|
||||
int delegateId =
|
||||
XmlUtils.readIntAttribute(parser, ATT_UID, UNKNOWN_UID);
|
||||
String delegateName =
|
||||
XmlUtils.readStringAttribute(parser, ATT_NAME);
|
||||
boolean delegateEnabled = XmlUtils.readBooleanAttribute(
|
||||
parser, ATT_ENABLED, Delegate.DEFAULT_ENABLED);
|
||||
boolean userAllowed = XmlUtils.readBooleanAttribute(
|
||||
parser, ATT_USER_ALLOWED, Delegate.DEFAULT_USER_ALLOWED);
|
||||
Delegate d = null;
|
||||
if (delegateId != UNKNOWN_UID && !TextUtils.isEmpty(delegateName)) {
|
||||
d = new Delegate(
|
||||
delegateName, delegateId, delegateEnabled, userAllowed);
|
||||
}
|
||||
r.delegate = d;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
try {
|
||||
@@ -248,7 +270,7 @@ public class PreferencesHelper implements RankingConfig {
|
||||
final String key = packagePreferencesKey(pkg, uid);
|
||||
synchronized (mPackagePreferencess) {
|
||||
PackagePreferences
|
||||
r = (uid == PackagePreferences.UNKNOWN_UID) ? mRestoredWithoutUids.get(pkg)
|
||||
r = (uid == UNKNOWN_UID) ? mRestoredWithoutUids.get(pkg)
|
||||
: mPackagePreferencess.get(key);
|
||||
if (r == null) {
|
||||
r = new PackagePreferences();
|
||||
@@ -265,7 +287,7 @@ public class PreferencesHelper implements RankingConfig {
|
||||
Slog.e(TAG, "createDefaultChannelIfNeeded - Exception: " + e);
|
||||
}
|
||||
|
||||
if (r.uid == PackagePreferences.UNKNOWN_UID) {
|
||||
if (r.uid == UNKNOWN_UID) {
|
||||
mRestoredWithoutUids.put(pkg, r);
|
||||
} else {
|
||||
mPackagePreferencess.put(key, r);
|
||||
@@ -357,7 +379,8 @@ public class PreferencesHelper implements RankingConfig {
|
||||
|| r.showBadge != DEFAULT_SHOW_BADGE
|
||||
|| r.lockedAppFields != DEFAULT_LOCKED_APP_FIELDS
|
||||
|| r.channels.size() > 0
|
||||
|| r.groups.size() > 0;
|
||||
|| r.groups.size() > 0
|
||||
|| r.delegate != null;
|
||||
if (hasNonDefaultSettings) {
|
||||
out.startTag(null, TAG_PACKAGE);
|
||||
out.attribute(null, ATT_NAME, r.pkg);
|
||||
@@ -378,6 +401,21 @@ public class PreferencesHelper implements RankingConfig {
|
||||
out.attribute(null, ATT_UID, Integer.toString(r.uid));
|
||||
}
|
||||
|
||||
if (r.delegate != null) {
|
||||
out.startTag(null, TAG_DELEGATE);
|
||||
|
||||
out.attribute(null, ATT_NAME, r.delegate.mPkg);
|
||||
out.attribute(null, ATT_UID, Integer.toString(r.delegate.mUid));
|
||||
if (r.delegate.mEnabled != Delegate.DEFAULT_ENABLED) {
|
||||
out.attribute(null, ATT_ENABLED, Boolean.toString(r.delegate.mEnabled));
|
||||
}
|
||||
if (r.delegate.mUserAllowed != Delegate.DEFAULT_USER_ALLOWED) {
|
||||
out.attribute(null, ATT_USER_ALLOWED,
|
||||
Boolean.toString(r.delegate.mUserAllowed));
|
||||
}
|
||||
out.endTag(null, TAG_DELEGATE);
|
||||
}
|
||||
|
||||
for (NotificationChannelGroup group : r.groups.values()) {
|
||||
group.writeXml(out);
|
||||
}
|
||||
@@ -923,16 +961,76 @@ public class PreferencesHelper implements RankingConfig {
|
||||
* considered for sentiment adjustments (and thus never show a blocking helper).
|
||||
*/
|
||||
public void setAppImportanceLocked(String packageName, int uid) {
|
||||
PackagePreferences PackagePreferences = getOrCreatePackagePreferences(packageName, uid);
|
||||
if ((PackagePreferences.lockedAppFields & LockableAppFields.USER_LOCKED_IMPORTANCE) != 0) {
|
||||
PackagePreferences prefs = getOrCreatePackagePreferences(packageName, uid);
|
||||
if ((prefs.lockedAppFields & LockableAppFields.USER_LOCKED_IMPORTANCE) != 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
PackagePreferences.lockedAppFields =
|
||||
PackagePreferences.lockedAppFields | LockableAppFields.USER_LOCKED_IMPORTANCE;
|
||||
prefs.lockedAppFields = prefs.lockedAppFields | LockableAppFields.USER_LOCKED_IMPORTANCE;
|
||||
updateConfig();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the delegate for a given package, if it's allowed by the package and the user.
|
||||
*/
|
||||
public @Nullable String getNotificationDelegate(String sourcePkg, int sourceUid) {
|
||||
PackagePreferences prefs = getPackagePreferences(sourcePkg, sourceUid);
|
||||
|
||||
if (prefs == null || prefs.delegate == null) {
|
||||
return null;
|
||||
}
|
||||
if (!prefs.delegate.mUserAllowed || !prefs.delegate.mEnabled) {
|
||||
return null;
|
||||
}
|
||||
return prefs.delegate.mPkg;
|
||||
}
|
||||
|
||||
/**
|
||||
* Used by an app to delegate notification posting privileges to another apps.
|
||||
*/
|
||||
public void setNotificationDelegate(String sourcePkg, int sourceUid,
|
||||
String delegatePkg, int delegateUid) {
|
||||
PackagePreferences prefs = getOrCreatePackagePreferences(sourcePkg, sourceUid);
|
||||
|
||||
boolean userAllowed = prefs.delegate == null || prefs.delegate.mUserAllowed;
|
||||
Delegate delegate = new Delegate(delegatePkg, delegateUid, true, userAllowed);
|
||||
prefs.delegate = delegate;
|
||||
updateConfig();
|
||||
}
|
||||
|
||||
/**
|
||||
* Used by an app to turn off its notification delegate.
|
||||
*/
|
||||
public void revokeNotificationDelegate(String sourcePkg, int sourceUid) {
|
||||
PackagePreferences prefs = getPackagePreferences(sourcePkg, sourceUid);
|
||||
if (prefs != null && prefs.delegate != null) {
|
||||
prefs.delegate.mEnabled = false;
|
||||
updateConfig();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggles whether an app can have a notification delegate on behalf of a user.
|
||||
*/
|
||||
public void toggleNotificationDelegate(String sourcePkg, int sourceUid, boolean userAllowed) {
|
||||
PackagePreferences prefs = getPackagePreferences(sourcePkg, sourceUid);
|
||||
if (prefs != null && prefs.delegate != null) {
|
||||
prefs.delegate.mUserAllowed = userAllowed;
|
||||
updateConfig();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the given app is allowed on post notifications on behalf of the other given
|
||||
* app.
|
||||
*/
|
||||
public boolean isDelegateAllowed(String sourcePkg, int sourceUid,
|
||||
String potentialDelegatePkg, int potentialDelegateUid) {
|
||||
PackagePreferences prefs = getPackagePreferences(sourcePkg, sourceUid);
|
||||
|
||||
return prefs != null && prefs.isValidDelegate(potentialDelegatePkg, potentialDelegateUid);
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
void lockFieldsForUpdate(NotificationChannel original, NotificationChannel update) {
|
||||
if (original.canBypassDnd() != update.canBypassDnd()) {
|
||||
@@ -994,8 +1092,7 @@ public class PreferencesHelper implements RankingConfig {
|
||||
pw.print(" AppSettings: ");
|
||||
pw.print(r.pkg);
|
||||
pw.print(" (");
|
||||
pw.print(r.uid == PackagePreferences.UNKNOWN_UID ? "UNKNOWN_UID"
|
||||
: Integer.toString(r.uid));
|
||||
pw.print(r.uid == UNKNOWN_UID ? "UNKNOWN_UID" : Integer.toString(r.uid));
|
||||
pw.print(')');
|
||||
if (r.importance != DEFAULT_IMPORTANCE) {
|
||||
pw.print(" importance=");
|
||||
@@ -1356,8 +1453,6 @@ public class PreferencesHelper implements RankingConfig {
|
||||
}
|
||||
|
||||
private static class PackagePreferences {
|
||||
static int UNKNOWN_UID = UserHandle.USER_NULL;
|
||||
|
||||
String pkg;
|
||||
int uid = UNKNOWN_UID;
|
||||
int importance = DEFAULT_IMPORTANCE;
|
||||
@@ -1366,7 +1461,37 @@ public class PreferencesHelper implements RankingConfig {
|
||||
boolean showBadge = DEFAULT_SHOW_BADGE;
|
||||
int lockedAppFields = DEFAULT_LOCKED_APP_FIELDS;
|
||||
|
||||
Delegate delegate = null;
|
||||
ArrayMap<String, NotificationChannel> channels = new ArrayMap<>();
|
||||
Map<String, NotificationChannelGroup> groups = new ConcurrentHashMap<>();
|
||||
|
||||
public boolean isValidDelegate(String pkg, int uid) {
|
||||
return delegate != null && delegate.isAllowed(pkg, uid);
|
||||
}
|
||||
}
|
||||
|
||||
private static class Delegate {
|
||||
static final boolean DEFAULT_ENABLED = true;
|
||||
static final boolean DEFAULT_USER_ALLOWED = true;
|
||||
String mPkg;
|
||||
int mUid = UNKNOWN_UID;
|
||||
boolean mEnabled = DEFAULT_ENABLED;
|
||||
boolean mUserAllowed = DEFAULT_USER_ALLOWED;
|
||||
|
||||
Delegate(String pkg, int uid, boolean enabled, boolean userAllowed) {
|
||||
mPkg = pkg;
|
||||
mUid = uid;
|
||||
mEnabled = enabled;
|
||||
mUserAllowed = userAllowed;
|
||||
}
|
||||
|
||||
public boolean isAllowed(String pkg, int uid) {
|
||||
if (pkg == null || uid == UNKNOWN_UID) {
|
||||
return false;
|
||||
}
|
||||
return pkg.equals(mPkg)
|
||||
&& uid == mUid
|
||||
&& (mUserAllowed && mEnabled);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -65,6 +65,8 @@ import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.app.ActivityManager;
|
||||
import android.app.AppOpsManager;
|
||||
import android.app.Application;
|
||||
import android.app.IActivityManager;
|
||||
import android.app.INotificationManager;
|
||||
import android.app.Notification;
|
||||
@@ -195,6 +197,8 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
|
||||
IUriGrantsManager mUgm;
|
||||
@Mock
|
||||
UriGrantsManagerInternal mUgmInternal;
|
||||
@Mock
|
||||
AppOpsManager mAppOpsManager;
|
||||
|
||||
// Use a Testable subclass so we can simulate calls from the system without failing.
|
||||
private static class TestableNotificationManagerService extends NotificationManagerService {
|
||||
@@ -295,7 +299,8 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
|
||||
mListeners, mAssistants, mConditionProviders,
|
||||
mCompanionMgr, mSnoozeHelper, mUsageStats, mPolicyFile, mActivityManager,
|
||||
mGroupHelper, mAm, mAppUsageStats,
|
||||
mock(DevicePolicyManagerInternal.class), mUgm, mUgmInternal);
|
||||
mock(DevicePolicyManagerInternal.class), mUgm, mUgmInternal,
|
||||
mAppOpsManager);
|
||||
} catch (SecurityException e) {
|
||||
if (!e.getMessage().contains("Permission Denial: not allowed to send broadcast")) {
|
||||
throw e;
|
||||
@@ -531,7 +536,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
|
||||
mBinderService.createNotificationChannels(
|
||||
PKG, new ParceledListSlice(Arrays.asList(channel)));
|
||||
final StatusBarNotification sbn = generateNotificationRecord(channel).sbn;
|
||||
mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag",
|
||||
mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag",
|
||||
sbn.getId(), sbn.getNotification(), sbn.getUserId());
|
||||
waitForIdle();
|
||||
assertEquals(0, mBinderService.getActiveNotifications(sbn.getPackageName()).length);
|
||||
@@ -549,7 +554,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
|
||||
|
||||
final StatusBarNotification sbn = generateNotificationRecord(channel).sbn;
|
||||
sbn.getNotification().flags |= FLAG_FOREGROUND_SERVICE;
|
||||
mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag",
|
||||
mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag",
|
||||
sbn.getId(), sbn.getNotification(), sbn.getUserId());
|
||||
waitForIdle();
|
||||
assertEquals(1, mBinderService.getActiveNotifications(sbn.getPackageName()).length);
|
||||
@@ -578,7 +583,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
|
||||
|
||||
StatusBarNotification sbn = generateNotificationRecord(channel).sbn;
|
||||
sbn.getNotification().flags |= FLAG_FOREGROUND_SERVICE;
|
||||
mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag",
|
||||
mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag",
|
||||
sbn.getId(), sbn.getNotification(), sbn.getUserId());
|
||||
waitForIdle();
|
||||
// The first time a foreground service notification is shown, we allow the channel
|
||||
@@ -600,7 +605,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
|
||||
|
||||
sbn = generateNotificationRecord(channel).sbn;
|
||||
sbn.getNotification().flags |= FLAG_FOREGROUND_SERVICE;
|
||||
mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag",
|
||||
mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag",
|
||||
sbn.getId(), sbn.getNotification(), sbn.getUserId());
|
||||
waitForIdle();
|
||||
// The second time it is shown, we keep the user's preference.
|
||||
@@ -631,7 +636,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
|
||||
mBinderService.setNotificationsEnabledForPackage(PKG, mUid, false);
|
||||
|
||||
final StatusBarNotification sbn = generateNotificationRecord(null).sbn;
|
||||
mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag",
|
||||
mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag",
|
||||
sbn.getId(), sbn.getNotification(), sbn.getUserId());
|
||||
waitForIdle();
|
||||
assertEquals(0, mBinderService.getActiveNotifications(sbn.getPackageName()).length);
|
||||
@@ -645,7 +650,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
|
||||
|
||||
final StatusBarNotification sbn = generateNotificationRecord(null).sbn;
|
||||
sbn.getNotification().flags |= FLAG_FOREGROUND_SERVICE;
|
||||
mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag",
|
||||
mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag",
|
||||
sbn.getId(), sbn.getNotification(), sbn.getUserId());
|
||||
waitForIdle();
|
||||
assertEquals(0, mBinderService.getActiveNotifications(sbn.getPackageName()).length);
|
||||
@@ -667,7 +672,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
|
||||
final StatusBarNotification sbn =
|
||||
generateNotificationRecord(mTestNotificationChannel, ++id, "", false).sbn;
|
||||
sbn.getNotification().category = category;
|
||||
mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag",
|
||||
mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag",
|
||||
sbn.getId(), sbn.getNotification(), sbn.getUserId());
|
||||
}
|
||||
waitForIdle();
|
||||
@@ -691,7 +696,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
|
||||
final StatusBarNotification sbn =
|
||||
generateNotificationRecord(mTestNotificationChannel, ++id, "", false).sbn;
|
||||
sbn.getNotification().category = category;
|
||||
mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag",
|
||||
mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag",
|
||||
sbn.getId(), sbn.getNotification(), sbn.getUserId());
|
||||
}
|
||||
waitForIdle();
|
||||
@@ -714,7 +719,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
|
||||
final StatusBarNotification sbn = generateNotificationRecord(null).sbn;
|
||||
sbn.getNotification().category = category;
|
||||
try {
|
||||
mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag",
|
||||
mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag",
|
||||
sbn.getId(), sbn.getNotification(), sbn.getUserId());
|
||||
fail("Calls from non system apps should not allow use of restricted categories");
|
||||
} catch (SecurityException e) {
|
||||
@@ -746,7 +751,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
|
||||
|
||||
@Test
|
||||
public void testEnqueueNotificationWithTag_PopulatesGetActiveNotifications() throws Exception {
|
||||
mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag", 0,
|
||||
mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag", 0,
|
||||
generateNotificationRecord(null).getNotification(), 0);
|
||||
waitForIdle();
|
||||
StatusBarNotification[] notifs = mBinderService.getActiveNotifications(PKG);
|
||||
@@ -756,7 +761,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
|
||||
|
||||
@Test
|
||||
public void testCancelNotificationImmediatelyAfterEnqueue() throws Exception {
|
||||
mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag", 0,
|
||||
mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag", 0,
|
||||
generateNotificationRecord(null).getNotification(), 0);
|
||||
mBinderService.cancelNotificationWithTag(PKG, "tag", 0, 0);
|
||||
waitForIdle();
|
||||
@@ -768,10 +773,10 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
|
||||
|
||||
@Test
|
||||
public void testCancelNotificationWhilePostedAndEnqueued() throws Exception {
|
||||
mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag", 0,
|
||||
mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag", 0,
|
||||
generateNotificationRecord(null).getNotification(), 0);
|
||||
waitForIdle();
|
||||
mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag", 0,
|
||||
mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag", 0,
|
||||
generateNotificationRecord(null).getNotification(), 0);
|
||||
mBinderService.cancelNotificationWithTag(PKG, "tag", 0, 0);
|
||||
waitForIdle();
|
||||
@@ -788,7 +793,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
|
||||
public void testCancelNotificationsFromListenerImmediatelyAfterEnqueue() throws Exception {
|
||||
NotificationRecord r = generateNotificationRecord(null);
|
||||
final StatusBarNotification sbn = r.sbn;
|
||||
mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag",
|
||||
mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag",
|
||||
sbn.getId(), sbn.getNotification(), sbn.getUserId());
|
||||
mBinderService.cancelNotificationsFromListener(null, null);
|
||||
waitForIdle();
|
||||
@@ -801,7 +806,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
|
||||
@Test
|
||||
public void testCancelAllNotificationsImmediatelyAfterEnqueue() throws Exception {
|
||||
final StatusBarNotification sbn = generateNotificationRecord(null).sbn;
|
||||
mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag",
|
||||
mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag",
|
||||
sbn.getId(), sbn.getNotification(), sbn.getUserId());
|
||||
mBinderService.cancelAllNotifications(PKG, sbn.getUserId());
|
||||
waitForIdle();
|
||||
@@ -816,7 +821,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
|
||||
final NotificationRecord n = generateNotificationRecord(
|
||||
mTestNotificationChannel, 1, "group", true);
|
||||
|
||||
mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag",
|
||||
mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag",
|
||||
n.sbn.getId(), n.sbn.getNotification(), n.sbn.getUserId());
|
||||
waitForIdle();
|
||||
|
||||
@@ -839,9 +844,9 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
|
||||
final NotificationRecord child = generateNotificationRecord(
|
||||
mTestNotificationChannel, 2, "group1", false);
|
||||
|
||||
mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag",
|
||||
mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag",
|
||||
parent.sbn.getId(), parent.sbn.getNotification(), parent.sbn.getUserId());
|
||||
mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag",
|
||||
mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag",
|
||||
child.sbn.getId(), child.sbn.getNotification(), child.sbn.getUserId());
|
||||
waitForIdle();
|
||||
|
||||
@@ -854,7 +859,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
|
||||
public void testCancelAllNotificationsMultipleEnqueuedDoesNotCrash() throws Exception {
|
||||
final StatusBarNotification sbn = generateNotificationRecord(null).sbn;
|
||||
for (int i = 0; i < 10; i++) {
|
||||
mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag",
|
||||
mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag",
|
||||
sbn.getId(), sbn.getNotification(), sbn.getUserId());
|
||||
}
|
||||
mBinderService.cancelAllNotifications(PKG, sbn.getUserId());
|
||||
@@ -873,17 +878,17 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
|
||||
mTestNotificationChannel, 2, "group1", false);
|
||||
|
||||
// fully post parent notification
|
||||
mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag",
|
||||
mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag",
|
||||
parent.sbn.getId(), parent.sbn.getNotification(), parent.sbn.getUserId());
|
||||
waitForIdle();
|
||||
|
||||
// enqueue the child several times
|
||||
for (int i = 0; i < 10; i++) {
|
||||
mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag",
|
||||
mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag",
|
||||
child.sbn.getId(), child.sbn.getNotification(), child.sbn.getUserId());
|
||||
}
|
||||
// make the parent a child, which will cancel the child notification
|
||||
mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag",
|
||||
mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag",
|
||||
parentAsChild.sbn.getId(), parentAsChild.sbn.getNotification(),
|
||||
parentAsChild.sbn.getUserId());
|
||||
waitForIdle();
|
||||
@@ -895,7 +900,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
|
||||
public void testCancelAllNotifications_IgnoreForegroundService() throws Exception {
|
||||
final StatusBarNotification sbn = generateNotificationRecord(null).sbn;
|
||||
sbn.getNotification().flags |= FLAG_FOREGROUND_SERVICE;
|
||||
mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag",
|
||||
mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag",
|
||||
sbn.getId(), sbn.getNotification(), sbn.getUserId());
|
||||
mBinderService.cancelAllNotifications(PKG, sbn.getUserId());
|
||||
waitForIdle();
|
||||
@@ -909,7 +914,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
|
||||
public void testCancelAllNotifications_IgnoreOtherPackages() throws Exception {
|
||||
final StatusBarNotification sbn = generateNotificationRecord(null).sbn;
|
||||
sbn.getNotification().flags |= FLAG_FOREGROUND_SERVICE;
|
||||
mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag",
|
||||
mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag",
|
||||
sbn.getId(), sbn.getNotification(), sbn.getUserId());
|
||||
mBinderService.cancelAllNotifications("other_pkg_name", sbn.getUserId());
|
||||
waitForIdle();
|
||||
@@ -922,7 +927,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
|
||||
@Test
|
||||
public void testCancelAllNotifications_NullPkgRemovesAll() throws Exception {
|
||||
final StatusBarNotification sbn = generateNotificationRecord(null).sbn;
|
||||
mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag",
|
||||
mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag",
|
||||
sbn.getId(), sbn.getNotification(), sbn.getUserId());
|
||||
mBinderService.cancelAllNotifications(null, sbn.getUserId());
|
||||
waitForIdle();
|
||||
@@ -935,7 +940,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
|
||||
@Test
|
||||
public void testCancelAllNotifications_NullPkgIgnoresUserAllNotifications() throws Exception {
|
||||
final StatusBarNotification sbn = generateNotificationRecord(null).sbn;
|
||||
mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag",
|
||||
mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag",
|
||||
sbn.getId(), sbn.getNotification(), UserHandle.USER_ALL);
|
||||
// Null pkg is how we signal a user switch.
|
||||
mBinderService.cancelAllNotifications(null, sbn.getUserId());
|
||||
@@ -950,7 +955,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
|
||||
public void testAppInitiatedCancelAllNotifications_CancelsNoClearFlag() throws Exception {
|
||||
final StatusBarNotification sbn = generateNotificationRecord(null).sbn;
|
||||
sbn.getNotification().flags |= Notification.FLAG_NO_CLEAR;
|
||||
mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag",
|
||||
mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag",
|
||||
sbn.getId(), sbn.getNotification(), sbn.getUserId());
|
||||
mBinderService.cancelAllNotifications(PKG, sbn.getUserId());
|
||||
waitForIdle();
|
||||
@@ -1037,7 +1042,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
|
||||
public void testRemoveForegroundServiceFlag_ImmediatelyAfterEnqueue() throws Exception {
|
||||
final StatusBarNotification sbn = generateNotificationRecord(null).sbn;
|
||||
sbn.getNotification().flags |= FLAG_FOREGROUND_SERVICE;
|
||||
mBinderService.enqueueNotificationWithTag(PKG, "opPkg", null,
|
||||
mBinderService.enqueueNotificationWithTag(PKG, PKG, null,
|
||||
sbn.getId(), sbn.getNotification(), sbn.getUserId());
|
||||
mInternalService.removeForegroundServiceFlagFromNotification(PKG, sbn.getId(),
|
||||
sbn.getUserId());
|
||||
@@ -1052,10 +1057,10 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
|
||||
final StatusBarNotification sbn = generateNotificationRecord(null).sbn;
|
||||
sbn.getNotification().flags =
|
||||
Notification.FLAG_ONGOING_EVENT | FLAG_FOREGROUND_SERVICE;
|
||||
mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag",
|
||||
mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag",
|
||||
sbn.getId(), sbn.getNotification(), sbn.getUserId());
|
||||
sbn.getNotification().flags = Notification.FLAG_ONGOING_EVENT;
|
||||
mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag",
|
||||
mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag",
|
||||
sbn.getId(), sbn.getNotification(), sbn.getUserId());
|
||||
mBinderService.cancelNotificationWithTag(PKG, "tag", sbn.getId(), sbn.getUserId());
|
||||
waitForIdle();
|
||||
@@ -1145,21 +1150,21 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
|
||||
// should not be returned
|
||||
final NotificationRecord group2 = generateNotificationRecord(
|
||||
mTestNotificationChannel, 2, "group2", true);
|
||||
mBinderService.enqueueNotificationWithTag(PKG, "opPkg", null,
|
||||
mBinderService.enqueueNotificationWithTag(PKG, PKG, null,
|
||||
group2.sbn.getId(), group2.sbn.getNotification(), group2.sbn.getUserId());
|
||||
waitForIdle();
|
||||
|
||||
// should not be returned
|
||||
final NotificationRecord nonGroup = generateNotificationRecord(
|
||||
mTestNotificationChannel, 3, null, false);
|
||||
mBinderService.enqueueNotificationWithTag(PKG, "opPkg", null,
|
||||
mBinderService.enqueueNotificationWithTag(PKG, PKG, null,
|
||||
nonGroup.sbn.getId(), nonGroup.sbn.getNotification(), nonGroup.sbn.getUserId());
|
||||
waitForIdle();
|
||||
|
||||
// same group, child, should be returned
|
||||
final NotificationRecord group1Child = generateNotificationRecord(
|
||||
mTestNotificationChannel, 4, "group1", false);
|
||||
mBinderService.enqueueNotificationWithTag(PKG, "opPkg", null, group1Child.sbn.getId(),
|
||||
mBinderService.enqueueNotificationWithTag(PKG, PKG, null, group1Child.sbn.getId(),
|
||||
group1Child.sbn.getNotification(), group1Child.sbn.getUserId());
|
||||
waitForIdle();
|
||||
|
||||
@@ -1216,7 +1221,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
|
||||
public void testAppInitiatedCancelAllNotifications_CancelsOnGoingFlag() throws Exception {
|
||||
final StatusBarNotification sbn = generateNotificationRecord(null).sbn;
|
||||
sbn.getNotification().flags |= Notification.FLAG_ONGOING_EVENT;
|
||||
mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag",
|
||||
mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag",
|
||||
sbn.getId(), sbn.getNotification(), sbn.getUserId());
|
||||
mBinderService.cancelAllNotifications(PKG, sbn.getUserId());
|
||||
waitForIdle();
|
||||
@@ -1333,7 +1338,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
|
||||
new NotificationChannel("foo", "foo", IMPORTANCE_HIGH));
|
||||
|
||||
Notification.TvExtender tv = new Notification.TvExtender().setChannelId("foo");
|
||||
mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag", 0,
|
||||
mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag", 0,
|
||||
generateNotificationRecord(null, tv).getNotification(), 0);
|
||||
verify(mPreferencesHelper, times(1)).getNotificationChannel(
|
||||
anyString(), anyInt(), eq("foo"), anyBoolean());
|
||||
@@ -1348,7 +1353,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
|
||||
mTestNotificationChannel);
|
||||
|
||||
Notification.TvExtender tv = new Notification.TvExtender().setChannelId("foo");
|
||||
mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag", 0,
|
||||
mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag", 0,
|
||||
generateNotificationRecord(null, tv).getNotification(), 0);
|
||||
verify(mPreferencesHelper, times(1)).getNotificationChannel(
|
||||
anyString(), anyInt(), eq(mTestNotificationChannel.getId()), anyBoolean());
|
||||
@@ -1879,7 +1884,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
|
||||
final NotificationRecord child = generateNotificationRecord(
|
||||
mTestNotificationChannel, 2, "group", false);
|
||||
|
||||
mBinderService.enqueueNotificationWithTag(PKG, "opPkg", null,
|
||||
mBinderService.enqueueNotificationWithTag(PKG, PKG, null,
|
||||
child.sbn.getId(), child.sbn.getNotification(), child.sbn.getUserId());
|
||||
waitForIdle();
|
||||
|
||||
@@ -1892,7 +1897,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
|
||||
final NotificationRecord record = generateNotificationRecord(
|
||||
mTestNotificationChannel, 2, null, false);
|
||||
|
||||
mBinderService.enqueueNotificationWithTag(PKG, "opPkg", null,
|
||||
mBinderService.enqueueNotificationWithTag(PKG, PKG, null,
|
||||
record.sbn.getId(), record.sbn.getNotification(), record.sbn.getUserId());
|
||||
waitForIdle();
|
||||
|
||||
@@ -1904,7 +1909,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
|
||||
final NotificationRecord parent = generateNotificationRecord(
|
||||
mTestNotificationChannel, 2, "group", true);
|
||||
|
||||
mBinderService.enqueueNotificationWithTag(PKG, "opPkg", null,
|
||||
mBinderService.enqueueNotificationWithTag(PKG, PKG, null,
|
||||
parent.sbn.getId(), parent.sbn.getNotification(), parent.sbn.getUserId());
|
||||
waitForIdle();
|
||||
|
||||
@@ -2378,12 +2383,12 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
|
||||
@Test
|
||||
public void testBumpFGImportance_noChannelChangePreOApp() throws Exception {
|
||||
String preOPkg = PKG_N_MR1;
|
||||
int preOUid = 145;
|
||||
final ApplicationInfo legacy = new ApplicationInfo();
|
||||
legacy.targetSdkVersion = Build.VERSION_CODES.N_MR1;
|
||||
when(mPackageManagerClient.getApplicationInfoAsUser(eq(preOPkg), anyInt(), anyInt()))
|
||||
.thenReturn(legacy);
|
||||
when(mPackageManagerClient.getPackageUidAsUser(eq(preOPkg), anyInt())).thenReturn(preOUid);
|
||||
when(mPackageManagerClient.getPackageUidAsUser(eq(preOPkg), anyInt()))
|
||||
.thenReturn(Binder.getCallingUid());
|
||||
getContext().setMockPackageManager(mPackageManagerClient);
|
||||
|
||||
Notification.Builder nb = new Notification.Builder(mContext,
|
||||
@@ -2393,12 +2398,13 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
|
||||
.setFlag(FLAG_FOREGROUND_SERVICE, true)
|
||||
.setPriority(Notification.PRIORITY_MIN);
|
||||
|
||||
StatusBarNotification sbn = new StatusBarNotification(preOPkg, preOPkg, 9, "tag", preOUid,
|
||||
0, nb.build(), new UserHandle(preOUid), null, 0);
|
||||
StatusBarNotification sbn = new StatusBarNotification(preOPkg, preOPkg, 9, "tag",
|
||||
Binder.getCallingUid(), 0, nb.build(), new UserHandle(Binder.getCallingUid()), null, 0);
|
||||
|
||||
mBinderService.enqueueNotificationWithTag(preOPkg, preOPkg, "tag",
|
||||
sbn.getId(), sbn.getNotification(), sbn.getUserId());
|
||||
mBinderService.enqueueNotificationWithTag(sbn.getPackageName(), sbn.getOpPkg(),
|
||||
sbn.getTag(), sbn.getId(), sbn.getNotification(), sbn.getUserId());
|
||||
waitForIdle();
|
||||
|
||||
assertEquals(IMPORTANCE_LOW,
|
||||
mService.getNotificationRecord(sbn.getKey()).getImportance());
|
||||
|
||||
@@ -2408,8 +2414,8 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
|
||||
.setFlag(FLAG_FOREGROUND_SERVICE, true)
|
||||
.setPriority(Notification.PRIORITY_MIN);
|
||||
|
||||
sbn = new StatusBarNotification(preOPkg, preOPkg, 9, "tag", preOUid,
|
||||
0, nb.build(), new UserHandle(preOUid), null, 0);
|
||||
sbn = new StatusBarNotification(preOPkg, preOPkg, 9, "tag", Binder.getCallingUid(),
|
||||
0, nb.build(), new UserHandle(Binder.getCallingUid()), null, 0);
|
||||
|
||||
mBinderService.enqueueNotificationWithTag(preOPkg, preOPkg, "tag",
|
||||
sbn.getId(), sbn.getNotification(), sbn.getUserId());
|
||||
@@ -3360,7 +3366,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMybeRecordInterruptionLocked_doesNotRecordTwice()
|
||||
public void testMaybeRecordInterruptionLocked_doesNotRecordTwice()
|
||||
throws RemoteException {
|
||||
final NotificationRecord r = generateNotificationRecord(
|
||||
mTestNotificationChannel, 1, null, true);
|
||||
@@ -3373,4 +3379,78 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
|
||||
verify(mAppUsageStats, times(1)).reportInterruptiveNotification(
|
||||
anyString(), anyString(), anyInt());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testResolveNotificationUid_sameApp() throws Exception {
|
||||
ApplicationInfo info = new ApplicationInfo();
|
||||
info.uid = Binder.getCallingUid();
|
||||
when(mPackageManager.getApplicationInfo(anyString(), anyInt(), anyInt())).thenReturn(info);
|
||||
|
||||
int actualUid = mService.resolveNotificationUid("caller", "caller", info.uid, 0);
|
||||
|
||||
assertEquals(info.uid, actualUid);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testResolveNotificationUid_sameAppWrongPkg() throws Exception {
|
||||
ApplicationInfo info = new ApplicationInfo();
|
||||
info.uid = Binder.getCallingUid();
|
||||
when(mPackageManager.getApplicationInfo(anyString(), anyInt(), anyInt())).thenReturn(info);
|
||||
|
||||
try {
|
||||
mService.resolveNotificationUid("caller", "other", info.uid, 0);
|
||||
fail("Incorrect pkg didn't throw security exception");
|
||||
} catch (SecurityException e) {
|
||||
// yay
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testResolveNotificationUid_sameAppWrongUid() throws Exception {
|
||||
ApplicationInfo info = new ApplicationInfo();
|
||||
info.uid = 1356347;
|
||||
when(mPackageManager.getApplicationInfo(anyString(), anyInt(), anyInt())).thenReturn(info);
|
||||
|
||||
try {
|
||||
mService.resolveNotificationUid("caller", "caller", 9, 0);
|
||||
fail("Incorrect uid didn't throw security exception");
|
||||
} catch (SecurityException e) {
|
||||
// yay
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testResolveNotificationUid_delegateAllowed() throws Exception {
|
||||
int expectedUid = 123;
|
||||
|
||||
when(mPackageManagerClient.getPackageUidAsUser("target", 0)).thenReturn(expectedUid);
|
||||
mService.setPreferencesHelper(mPreferencesHelper);
|
||||
when(mPreferencesHelper.isDelegateAllowed(anyString(), anyInt(), anyString(), anyInt()))
|
||||
.thenReturn(true);
|
||||
|
||||
assertEquals(expectedUid, mService.resolveNotificationUid("caller", "target", 9, 0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testResolveNotificationUid_androidAllowed() throws Exception {
|
||||
int expectedUid = 123;
|
||||
|
||||
when(mPackageManagerClient.getPackageUidAsUser("target", 0)).thenReturn(expectedUid);
|
||||
// no delegate
|
||||
|
||||
assertEquals(expectedUid, mService.resolveNotificationUid("android", "target", 0, 0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testResolveNotificationUid_delegateNotAllowed() throws Exception {
|
||||
when(mPackageManagerClient.getPackageUidAsUser("target", 0)).thenReturn(123);
|
||||
// no delegate
|
||||
|
||||
try {
|
||||
mService.resolveNotificationUid("caller", "target", 9, 0);
|
||||
fail("Incorrect uid didn't throw security exception");
|
||||
} catch (SecurityException e) {
|
||||
// yay
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -123,7 +123,6 @@ public class PreferencesHelperTest extends UiServiceTestCase {
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
UserHandle user = UserHandle.ALL;
|
||||
|
||||
final ApplicationInfo legacy = new ApplicationInfo();
|
||||
legacy.targetSdkVersion = Build.VERSION_CODES.N_MR1;
|
||||
@@ -176,11 +175,6 @@ public class PreferencesHelperTest extends UiServiceTestCase {
|
||||
.build();
|
||||
}
|
||||
|
||||
private NotificationChannel getDefaultChannel() {
|
||||
return new NotificationChannel(NotificationChannel.DEFAULT_CHANNEL_ID, "name",
|
||||
IMPORTANCE_LOW);
|
||||
}
|
||||
|
||||
private ByteArrayOutputStream writeXmlAndPurge(String pkg, int uid, boolean forBackup,
|
||||
String... channelIds)
|
||||
throws Exception {
|
||||
@@ -1787,4 +1781,159 @@ public class PreferencesHelperTest extends UiServiceTestCase {
|
||||
mHelper.setEnabled(PKG_N_MR1, 1000, true);
|
||||
assertEquals(3, mHelper.getBlockedAppCount(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetNotificationDelegate() {
|
||||
mHelper.setNotificationDelegate(PKG_O, UID_O, "other", 53);
|
||||
assertEquals("other", mHelper.getNotificationDelegate(PKG_O, UID_O));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRevokeNotificationDelegate() {
|
||||
mHelper.setNotificationDelegate(PKG_O, UID_O, "other", 53);
|
||||
mHelper.revokeNotificationDelegate(PKG_O, UID_O);
|
||||
|
||||
assertNull(mHelper.getNotificationDelegate(PKG_O, UID_O));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRevokeNotificationDelegate_noDelegateExistsNoCrash() {
|
||||
mHelper.revokeNotificationDelegate(PKG_O, UID_O);
|
||||
|
||||
assertNull(mHelper.getNotificationDelegate(PKG_O, UID_O));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testToggleNotificationDelegate() {
|
||||
mHelper.setNotificationDelegate(PKG_O, UID_O, "other", 53);
|
||||
mHelper.toggleNotificationDelegate(PKG_O, UID_O, false);
|
||||
|
||||
assertNull(mHelper.getNotificationDelegate(PKG_O, UID_O));
|
||||
|
||||
mHelper.toggleNotificationDelegate(PKG_O, UID_O, true);
|
||||
assertEquals("other", mHelper.getNotificationDelegate(PKG_O, UID_O));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testToggleNotificationDelegate_noDelegateExistsNoCrash() {
|
||||
mHelper.toggleNotificationDelegate(PKG_O, UID_O, false);
|
||||
assertNull(mHelper.getNotificationDelegate(PKG_O, UID_O));
|
||||
|
||||
mHelper.toggleNotificationDelegate(PKG_O, UID_O, true);
|
||||
assertNull(mHelper.getNotificationDelegate(PKG_O, UID_O));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsDelegateAllowed_noSource() {
|
||||
assertFalse(mHelper.isDelegateAllowed("does not exist", -1, "whatever", 0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsDelegateAllowed_noDelegate() {
|
||||
mHelper.setImportance(PKG_O, UID_O, IMPORTANCE_UNSPECIFIED);
|
||||
|
||||
assertFalse(mHelper.isDelegateAllowed(PKG_O, UID_O, "whatever", 0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsDelegateAllowed_delegateDisabledByApp() {
|
||||
mHelper.setNotificationDelegate(PKG_O, UID_O, "other", 53);
|
||||
mHelper.revokeNotificationDelegate(PKG_O, UID_O);
|
||||
|
||||
assertFalse(mHelper.isDelegateAllowed(PKG_O, UID_O, "other", 53));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsDelegateAllowed_wrongDelegate() {
|
||||
mHelper.setNotificationDelegate(PKG_O, UID_O, "other", 53);
|
||||
mHelper.revokeNotificationDelegate(PKG_O, UID_O);
|
||||
|
||||
assertFalse(mHelper.isDelegateAllowed(PKG_O, UID_O, "banana", 27));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsDelegateAllowed_delegateDisabledByUser() {
|
||||
mHelper.setNotificationDelegate(PKG_O, UID_O, "other", 53);
|
||||
mHelper.toggleNotificationDelegate(PKG_O, UID_O, false);
|
||||
|
||||
assertFalse(mHelper.isDelegateAllowed(PKG_O, UID_O, "other", 53));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsDelegateAllowed() {
|
||||
mHelper.setNotificationDelegate(PKG_O, UID_O, "other", 53);
|
||||
|
||||
assertTrue(mHelper.isDelegateAllowed(PKG_O, UID_O, "other", 53));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDelegateXml_noDelegate() throws Exception {
|
||||
mHelper.setImportance(PKG_O, UID_O, IMPORTANCE_UNSPECIFIED);
|
||||
|
||||
ByteArrayOutputStream baos = writeXmlAndPurge(PKG_O, UID_O, false);
|
||||
mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper);
|
||||
loadStreamXml(baos, false);
|
||||
|
||||
assertNull(mHelper.getNotificationDelegate(PKG_O, UID_O));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDelegateXml_delegate() throws Exception {
|
||||
mHelper.setNotificationDelegate(PKG_O, UID_O, "other", 53);
|
||||
|
||||
ByteArrayOutputStream baos = writeXmlAndPurge(PKG_O, UID_O, false);
|
||||
mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper);
|
||||
loadStreamXml(baos, false);
|
||||
|
||||
assertEquals("other", mHelper.getNotificationDelegate(PKG_O, UID_O));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDelegateXml_disabledDelegate() throws Exception {
|
||||
mHelper.setNotificationDelegate(PKG_O, UID_O, "other", 53);
|
||||
mHelper.revokeNotificationDelegate(PKG_O, UID_O);
|
||||
|
||||
ByteArrayOutputStream baos = writeXmlAndPurge(PKG_O, UID_O, false);
|
||||
mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper);
|
||||
loadStreamXml(baos, false);
|
||||
|
||||
assertNull(mHelper.getNotificationDelegate(PKG_O, UID_O));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDelegateXml_userDisabledDelegate() throws Exception {
|
||||
mHelper.setNotificationDelegate(PKG_O, UID_O, "other", 53);
|
||||
mHelper.toggleNotificationDelegate(PKG_O, UID_O, false);
|
||||
|
||||
ByteArrayOutputStream baos = writeXmlAndPurge(PKG_O, UID_O, false);
|
||||
mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper);
|
||||
loadStreamXml(baos, false);
|
||||
|
||||
// appears disabled
|
||||
assertNull(mHelper.getNotificationDelegate(PKG_O, UID_O));
|
||||
|
||||
// but was loaded and can be toggled back on
|
||||
mHelper.toggleNotificationDelegate(PKG_O, UID_O, true);
|
||||
assertEquals("other", mHelper.getNotificationDelegate(PKG_O, UID_O));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDelegateXml_entirelyDisabledDelegate() throws Exception {
|
||||
mHelper.setNotificationDelegate(PKG_O, UID_O, "other", 53);
|
||||
mHelper.toggleNotificationDelegate(PKG_O, UID_O, false);
|
||||
mHelper.revokeNotificationDelegate(PKG_O, UID_O);
|
||||
|
||||
ByteArrayOutputStream baos = writeXmlAndPurge(PKG_O, UID_O, false);
|
||||
mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper);
|
||||
loadStreamXml(baos, false);
|
||||
|
||||
// appears disabled
|
||||
assertNull(mHelper.getNotificationDelegate(PKG_O, UID_O));
|
||||
|
||||
mHelper.setNotificationDelegate(PKG_O, UID_O, "other", 53);
|
||||
assertNull(mHelper.getNotificationDelegate(PKG_O, UID_O));
|
||||
|
||||
mHelper.toggleNotificationDelegate(PKG_O, UID_O, true);
|
||||
assertEquals("other", mHelper.getNotificationDelegate(PKG_O, UID_O));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user