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

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

Merge "Allow apps to proxy notifications for other apps"

parents 81d9fc06 a7ba45ac
Loading
Loading
Loading
Loading
+7 −0
Original line number Diff line number Diff line
@@ -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();
+5 −0
Original line number Diff line number Diff line
@@ -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);
}
+118 −10
Original line number Diff line number Diff line
@@ -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.
     *
+10 −6
Original line number Diff line number Diff line
@@ -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;
    }
+3 −1
Original line number Diff line number Diff line
@@ -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 */
Loading