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

Commit ecf40203 authored by Kweku Adams's avatar Kweku Adams
Browse files

Remove job notifications on user stop.

Remove any notifications posted by an app via
JobService#setNotification() if the user stops the app for any reason.

Bug: 260848384
Bug: 261999509
Test: atest CtsJobSchedulerTestCases:NotificationTest
Test: atest FrameworksMockingServicesTests:JobNotificationCoordinatorTest
Change-Id: Icf034201dcefe8b5934e0b1b6041515f3c22bc3b
parent 0b0ce87c
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@ package android.app.job;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.TestApi;
import android.app.ActivityManager;
import android.app.usage.UsageStatsManager;
import android.compat.annotation.UnsupportedAppUsage;
@@ -102,6 +103,7 @@ public class JobParameters implements Parcelable {
     * The user stopped the job via some UI (eg. Task Manager).
     * @hide
     */
    @TestApi
    public static final int INTERNAL_STOP_REASON_USER_UI_STOP =
            JobProtoEnums.INTERNAL_STOP_REASON_USER_UI_STOP; // 11.
    /**
+8 −3
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@ import static android.app.job.JobService.JOB_END_NOTIFICATION_POLICY_REMOVE;

import android.annotation.NonNull;
import android.app.Notification;
import android.app.job.JobParameters;
import android.app.job.JobService;
import android.content.pm.UserPackage;
import android.os.UserHandle;
@@ -80,7 +81,7 @@ class JobNotificationCoordinator {
        final NotificationDetails oldDetails = mNotificationDetails.get(hostingContext);
        if (oldDetails != null && oldDetails.notificationId != notificationId) {
            // App is switching notification IDs. Remove association with the old one.
            removeNotificationAssociation(hostingContext);
            removeNotificationAssociation(hostingContext, JobParameters.STOP_REASON_UNDEFINED);
        }
        final int userId = UserHandle.getUserId(callingUid);
        // TODO(260848384): ensure apps can't cancel the notification for user-initiated job
@@ -100,7 +101,8 @@ class JobNotificationCoordinator {
        mNotificationDetails.put(hostingContext, details);
    }

    void removeNotificationAssociation(@NonNull JobServiceContext hostingContext) {
    void removeNotificationAssociation(@NonNull JobServiceContext hostingContext,
            @JobParameters.StopReason int stopReason) {
        final NotificationDetails details = mNotificationDetails.remove(hostingContext);
        if (details == null) {
            return;
@@ -114,7 +116,10 @@ class JobNotificationCoordinator {
        ArraySet<JobServiceContext> associatedContexts = associations.get(details.notificationId);
        if (associatedContexts == null || associatedContexts.isEmpty()) {
            // No more jobs using this notification. Apply the final job stop policy.
            if (details.jobEndNotificationPolicy == JOB_END_NOTIFICATION_POLICY_REMOVE) {
            // If the user attempted to stop the job/app, then always remove the notification
            // so the user doesn't get confused about the app state.
            if (details.jobEndNotificationPolicy == JOB_END_NOTIFICATION_POLICY_REMOVE
                    || stopReason == JobParameters.STOP_REASON_USER) {
                final String packageName = details.userPackage.packageName;
                mNotificationManagerInternal.cancelNotification(
                        packageName, packageName, details.appUid, details.appPid, /* tag */ null,
+1 −0
Original line number Diff line number Diff line
@@ -670,6 +670,7 @@ public final class JobSchedulerShellCommand extends BasicShellCommandHandler {
                + " [PACKAGE] [JOB_ID]");
        pw.println("    Trigger immediate timeout of currently executing jobs, as if their");
        pw.println("    execution timeout had expired.");
        pw.println("    This is the equivalent of calling `stop -s 3 -i 3`.");
        pw.println("    Options:");
        pw.println("      -u or --user: specify which user's job is to be run; the default is");
        pw.println("         all users");
+1 −1
Original line number Diff line number Diff line
@@ -1373,7 +1373,7 @@ public final class JobServiceContext implements ServiceConnection {
                    JobSchedulerEconomicPolicy.ACTION_JOB_TIMEOUT,
                    String.valueOf(mRunningJob.getJobId()));
        }
        mNotificationCoordinator.removeNotificationAssociation(this);
        mNotificationCoordinator.removeNotificationAssociation(this, reschedulingStopReason);
        if (mWakeLock != null) {
            mWakeLock.release();
        }
+8 −0
Original line number Diff line number Diff line
@@ -725,6 +725,14 @@ package android.app.contentsuggestions {

}

package android.app.job {

  public class JobParameters implements android.os.Parcelable {
    field public static final int INTERNAL_STOP_REASON_USER_UI_STOP = 11; // 0xb
  }

}

package android.app.prediction {

  public final class AppPredictor {
Loading