Merge "Remove FLAG_FOREGROUND_SERVICE on Service.stopForeground()" into lmp-dev
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index d38074f..3f83a02 100755
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -24,6 +24,7 @@
 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 @@
                         r.cancelNotification();
                         r.foregroundId = 0;
                         r.foregroundNoti = null;
+                    } else if (r.appInfo.targetSdkVersion >= Build.VERSION_CODES.L) {
+                        r.stripForegroundServiceFlagFromNotification();
                     }
                 }
             }
diff --git a/services/core/java/com/android/server/am/ServiceRecord.java b/services/core/java/com/android/server/am/ServiceRecord.java
index 0a66a5c..d4a378b 100644
--- a/services/core/java/com/android/server/am/ServiceRecord.java
+++ b/services/core/java/com/android/server/am/ServiceRecord.java
@@ -517,6 +517,31 @@
             });
         }
     }
+
+    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--) {
diff --git a/services/core/java/com/android/server/notification/NotificationManagerInternal.java b/services/core/java/com/android/server/notification/NotificationManagerInternal.java
index b695b68..c6b0d36 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerInternal.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerInternal.java
@@ -21,4 +21,6 @@
 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);
 }
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 14587e6..2829e2b 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -1610,6 +1610,30 @@
             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,
diff --git a/services/core/java/com/android/server/notification/NotificationRecord.java b/services/core/java/com/android/server/notification/NotificationRecord.java
index fd34aa5..ea6f2db 100644
--- a/services/core/java/com/android/server/notification/NotificationRecord.java
+++ b/services/core/java/com/android/server/notification/NotificationRecord.java
@@ -45,6 +45,8 @@
  */
 public final class NotificationRecord {
     final StatusBarNotification sbn;
+    final int mOriginalFlags;
+
     NotificationUsageStats.SingleNotificationStats stats;
     boolean isCanceled;
     int score;
@@ -73,6 +75,7 @@
     {
         this.sbn = sbn;
         this.score = score;
+        mOriginalFlags = sbn.getNotification().flags;
         mRankingTimeMs = calculateRankingTimeMs(0L);
     }