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

Commit 365e4c38 authored by Christoph Studer's avatar Christoph Studer
Browse files

Remove FLAG_FOREGROUND_SERVICE on Service.stopForeground()

When services call Service.stopForeground(), remove
FLAG_FOREGROUND_SERVICE from the notification that was supplied
to Service.startForeground().

This enables services to post notifications that become user
dismissable when they switch to being a background service.

Restrict this to targetSdk=L apps to reduce the risk of breaking
existing apps.

Bug: 17551106
Change-Id: Iff8541e5bb2a23ad1fbc9ad80df5fd6eb683148b
parent da6ffa06
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -24,6 +24,7 @@ import java.util.HashSet;
import java.util.Iterator;
import java.util.List;

import android.os.Build;
import android.os.DeadObjectException;
import android.os.Handler;
import android.os.Looper;
@@ -590,6 +591,8 @@ public final class ActiveServices {
                        r.cancelNotification();
                        r.foregroundId = 0;
                        r.foregroundNoti = null;
                    } else if (r.appInfo.targetSdkVersion >= Build.VERSION_CODES.L) {
                        r.stripForegroundServiceFlagFromNotification();
                    }
                }
            }
+25 −0
Original line number Diff line number Diff line
@@ -518,6 +518,31 @@ final class ServiceRecord extends Binder {
        }
    }

    public void stripForegroundServiceFlagFromNotification() {
        if (foregroundId == 0) {
            return;
        }

        final int localForegroundId = foregroundId;
        final int localUserId = userId;
        final String localPackageName = packageName;

        // Do asynchronous communication with notification manager to
        // avoid deadlocks.
        ams.mHandler.post(new Runnable() {
            @Override
            public void run() {
                NotificationManagerInternal nmi = LocalServices.getService(
                        NotificationManagerInternal.class);
                if (nmi == null) {
                    return;
                }
                nmi.removeForegroundServiceFlagFromNotification(localPackageName, localForegroundId,
                        localUserId);
            }
        });
    }
    
    public void clearDeliveredStartsLocked() {
        for (int i=deliveredStarts.size()-1; i>=0; i--) {
            deliveredStarts.get(i).removeUriPermissionsLocked();
+2 −0
Original line number Diff line number Diff line
@@ -21,4 +21,6 @@ import android.app.Notification;
public interface NotificationManagerInternal {
    void enqueueNotification(String pkg, String basePkg, int callingUid, int callingPid,
            String tag, int id, Notification notification, int[] idReceived, int userId);

    void removeForegroundServiceFlagFromNotification(String pkg, int notificationId, int userId);
}
+24 −0
Original line number Diff line number Diff line
@@ -1610,6 +1610,30 @@ public class NotificationManagerService extends SystemService {
            enqueueNotificationInternal(pkg, opPkg, callingUid, callingPid, tag, id, notification,
                    idReceived, userId);
        }

        @Override
        public void removeForegroundServiceFlagFromNotification(String pkg, int notificationId,
                int userId) {
            checkCallerIsSystem();
            synchronized (mNotificationList) {
                int i = indexOfNotificationLocked(pkg, null, notificationId, userId);
                if (i < 0) {
                    Log.d(TAG, "stripForegroundServiceFlag: Could not find notification with "
                            + "pkg=" + pkg + " / id=" + notificationId + " / userId=" + userId);
                    return;
                }
                NotificationRecord r = mNotificationList.get(i);
                StatusBarNotification sbn = r.sbn;
                // NoMan adds flags FLAG_NO_CLEAR and FLAG_ONGOING_EVENT when it sees
                // FLAG_FOREGROUND_SERVICE. Hence it's not enough to remove FLAG_FOREGROUND_SERVICE,
                // we have to revert to the flags we received initially *and* force remove
                // FLAG_FOREGROUND_SERVICE.
                sbn.getNotification().flags =
                        (r.mOriginalFlags & ~Notification.FLAG_FOREGROUND_SERVICE);
                mRankingHelper.sort(mNotificationList);
                mListeners.notifyPostedLocked(sbn, sbn /* oldSbn */);
            }
        }
    };

    void enqueueNotificationInternal(final String pkg, final String opPkg, final int callingUid,
+3 −0
Original line number Diff line number Diff line
@@ -45,6 +45,8 @@ import java.util.Objects;
 */
public final class NotificationRecord {
    final StatusBarNotification sbn;
    final int mOriginalFlags;

    NotificationUsageStats.SingleNotificationStats stats;
    boolean isCanceled;
    int score;
@@ -73,6 +75,7 @@ public final class NotificationRecord {
    {
        this.sbn = sbn;
        this.score = score;
        mOriginalFlags = sbn.getNotification().flags;
        mRankingTimeMs = calculateRankingTimeMs(0L);
    }