am 623484d2: Merge "Ensuring that user-specific Recent tasks are removed. (Bug 18036610)" into lmp-mr1-dev

* commit '623484d231436ee209089adaa6b88b68f0ebf534':
  Ensuring that user-specific Recent tasks are removed. (Bug 18036610)
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/KeyStoreLruCache.java b/packages/SystemUI/src/com/android/systemui/recents/model/KeyStoreLruCache.java
index 7ccefc6..97e0916 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/KeyStoreLruCache.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/KeyStoreLruCache.java
@@ -21,15 +21,16 @@
 import java.util.HashMap;
 
 /**
- * An LRU cache that support querying the keys as well as values. By using the Task's key, we can
- * prevent holding onto a reference to the Task resource data, while keeping the cache data in
- * memory where necessary.
+ * An LRU cache that internally support querying the keys as well as values.  We use this to keep
+ * track of the task metadata to determine when to invalidate the cache when tasks have been
+ * updated. Generally, this cache will return the last known cache value for the requested task
+ * key.
  */
 public class KeyStoreLruCache<V> {
     // We keep a set of keys that are associated with the LRU cache, so that we can find out
     // information about the Task that was previously in the cache.
     HashMap<Integer, Task.TaskKey> mTaskKeys = new HashMap<Integer, Task.TaskKey>();
-    // The cache implementation
+    // The cache implementation, mapping task id -> value
     LruCache<Integer, V> mCache;
 
     public KeyStoreLruCache(int cacheSize) {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsPackageMonitor.java b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsPackageMonitor.java
index 60e89bf..e48e5f0 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsPackageMonitor.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsPackageMonitor.java
@@ -19,6 +19,7 @@
 import android.content.ComponentName;
 import android.content.Context;
 import android.os.Looper;
+import android.os.UserHandle;
 import com.android.internal.content.PackageMonitor;
 import com.android.systemui.recents.misc.SystemServicesProxy;
 
@@ -26,16 +27,16 @@
 import java.util.List;
 
 /**
- * The package monitor listens for changes from PackageManager to update the contents of the Recents
- * list.
+ * The package monitor listens for changes from PackageManager to update the contents of the
+ * Recents list.
  */
 public class RecentsPackageMonitor extends PackageMonitor {
     public interface PackageCallbacks {
-        public void onComponentRemoved(HashSet<ComponentName> cns);
+        public void onPackagesChanged(RecentsPackageMonitor monitor, String packageName,
+                                      int userId);
     }
 
     PackageCallbacks mCb;
-    List<Task.TaskKey> mTasks;
     SystemServicesProxy mSystemServicesProxy;
 
     /** Registers the broadcast receivers with the specified callbacks. */
@@ -43,7 +44,9 @@
         mSystemServicesProxy = new SystemServicesProxy(context);
         mCb = cb;
         try {
-            register(context, Looper.getMainLooper(), true);
+            // We register for events from all users, but will cross-reference them with
+            // packages for the current user and any profiles they have
+            register(context, Looper.getMainLooper(), UserHandle.ALL, true);
         } catch (IllegalStateException e) {
             e.printStackTrace();
         }
@@ -59,29 +62,15 @@
         }
         mSystemServicesProxy = null;
         mCb = null;
-        mTasks.clear();
-    }
-
-    /** Sets the list of tasks to match against package broadcast changes. */
-    void setTasks(List<Task.TaskKey> tasks) {
-        mTasks = tasks;
     }
 
     @Override
     public void onPackageRemoved(String packageName, int uid) {
         if (mCb == null) return;
 
-        // Identify all the tasks that should be removed as a result of the package being removed.
-        // Using a set to ensure that we callback once per unique component.
-        HashSet<ComponentName> componentsToRemove = new HashSet<ComponentName>();
-        for (Task.TaskKey t : mTasks) {
-            ComponentName cn = t.baseIntent.getComponent();
-            if (cn.getPackageName().equals(packageName)) {
-                componentsToRemove.add(cn);
-            }
-        }
-        // Notify our callbacks that the components no longer exist
-        mCb.onComponentRemoved(componentsToRemove);
+        // Notify callbacks that a package has changed
+        final int eventUserId = getChangingUserId();
+        mCb.onPackagesChanged(this, packageName, eventUserId);
     }
 
     @Override
@@ -94,25 +83,38 @@
     public void onPackageModified(String packageName) {
         if (mCb == null) return;
 
+        // Notify callbacks that a package has changed
+        final int eventUserId = getChangingUserId();
+        mCb.onPackagesChanged(this, packageName, eventUserId);
+    }
+
+    /**
+     * Computes the components that have been removed as a result of a change in the specified
+     * package.
+     */
+    public HashSet<ComponentName> computeComponentsRemoved(List<Task.TaskKey> taskKeys,
+            String packageName, int userId) {
         // Identify all the tasks that should be removed as a result of the package being removed.
         // Using a set to ensure that we callback once per unique component.
-        HashSet<ComponentName> componentsKnownToExist = new HashSet<ComponentName>();
-        HashSet<ComponentName> componentsToRemove = new HashSet<ComponentName>();
-        for (Task.TaskKey t : mTasks) {
+        HashSet<ComponentName> existingComponents = new HashSet<ComponentName>();
+        HashSet<ComponentName> removedComponents = new HashSet<ComponentName>();
+        for (Task.TaskKey t : taskKeys) {
+            // Skip if this doesn't apply to the current user
+            if (t.userId != userId) continue;
+
             ComponentName cn = t.baseIntent.getComponent();
             if (cn.getPackageName().equals(packageName)) {
-                if (componentsKnownToExist.contains(cn)) {
+                if (existingComponents.contains(cn)) {
                     // If we know that the component still exists in the package, then skip
                     continue;
                 }
-                if (mSystemServicesProxy.getActivityInfo(cn) != null) {
-                    componentsKnownToExist.add(cn);
+                if (mSystemServicesProxy.getActivityInfo(cn, userId) != null) {
+                    existingComponents.add(cn);
                 } else {
-                    componentsToRemove.add(cn);
+                    removedComponents.add(cn);
                 }
             }
         }
-        // Notify our callbacks that the components no longer exist
-        mCb.onComponentRemoved(componentsToRemove);
+        return removedComponents;
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java
index d40e847..114e93f 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java
@@ -420,10 +420,6 @@
         // Start the task loader and add all the tasks we need to load
         mLoader.start(context);
         mLoadQueue.addTasks(tasksToLoad);
-
-        // Update the package monitor with the list of packages to listen for
-        mPackageMonitor.setTasks(taskKeys);
-
         return root;
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/Task.java b/packages/SystemUI/src/com/android/systemui/recents/model/Task.java
index a7e2b0b..55dfe45 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/Task.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/Task.java
@@ -129,7 +129,7 @@
     TaskCallbacks mCb;
 
     public Task() {
-        // Only used by RecentsService for task rect calculations.
+        // Do nothing
     }
 
     public Task(TaskKey key, boolean isActive, int taskAffiliation, int taskAffiliationColor,
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java b/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java
index 1e47b50..a37b9e6 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java
@@ -255,6 +255,17 @@
         return mTaskList.getTasks().get(mTaskList.size() - 1);
     }
 
+    /** Gets the task keys */
+    public ArrayList<Task.TaskKey> getTaskKeys() {
+        ArrayList<Task.TaskKey> taskKeys = new ArrayList<Task.TaskKey>();
+        ArrayList<Task> tasks = mTaskList.getTasks();
+        int taskCount = tasks.size();
+        for (int i = 0; i < taskCount; i++) {
+            taskKeys.add(tasks.get(i).key);
+        }
+        return taskKeys;
+    }
+
     /** Gets the tasks */
     public ArrayList<Task> getTasks() {
         return mTaskList.getTasks();
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
index 9dfebfe..6b0d306 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
@@ -18,7 +18,6 @@
 
 import android.app.ActivityOptions;
 import android.app.TaskStackBuilder;
-import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
 import android.graphics.Bitmap;
@@ -42,7 +41,6 @@
 import com.android.systemui.recents.model.TaskStack;
 
 import java.util.ArrayList;
-import java.util.HashSet;
 
 /**
  * This view is the the top level layout that contains TaskStacks (which are laid out according
@@ -564,14 +562,14 @@
     /**** RecentsPackageMonitor.PackageCallbacks Implementation ****/
 
     @Override
-    public void onComponentRemoved(HashSet<ComponentName> cns) {
+    public void onPackagesChanged(RecentsPackageMonitor monitor, String packageName, int userId) {
         // Propagate this event down to each task stack view
         int childCount = getChildCount();
         for (int i = 0; i < childCount; i++) {
             View child = getChildAt(i);
             if (child != mSearchBar) {
                 TaskStackView stackView = (TaskStackView) child;
-                stackView.onComponentRemoved(cns);
+                stackView.onPackagesChanged(monitor, packageName, userId);
             }
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
index e479952..dee26e6 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
@@ -1081,12 +1081,16 @@
     /**** RecentsPackageMonitor.PackageCallbacks Implementation ****/
 
     @Override
-    public void onComponentRemoved(HashSet<ComponentName> cns) {
+    public void onPackagesChanged(RecentsPackageMonitor monitor, String packageName, int userId) {
+        // Compute which components need to be removed
+        HashSet<ComponentName> removedComponents = monitor.computeComponentsRemoved(
+                mStack.getTaskKeys(), packageName, userId);
+
         // For other tasks, just remove them directly if they no longer exist
         ArrayList<Task> tasks = mStack.getTasks();
         for (int i = tasks.size() - 1; i >= 0; i--) {
             final Task t = tasks.get(i);
-            if (cns.contains(t.key.baseIntent.getComponent())) {
+            if (removedComponents.contains(t.key.baseIntent.getComponent())) {
                 TaskView tv = getChildViewForTask(t);
                 if (tv != null) {
                     // For visible children, defer removing the task until after the animation