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

This commit is contained in:
Winson Chung
2014-10-24 18:25:07 +00:00
committed by Android (Google) Code Review
7 changed files with 58 additions and 46 deletions

View File

@@ -21,15 +21,16 @@ import android.util.LruCache;
import java.util.HashMap; import java.util.HashMap;
/** /**
* An LRU cache that support querying the keys as well as values. By using the Task's key, we can * An LRU cache that internally support querying the keys as well as values. We use this to keep
* prevent holding onto a reference to the Task resource data, while keeping the cache data in * track of the task metadata to determine when to invalidate the cache when tasks have been
* memory where necessary. * updated. Generally, this cache will return the last known cache value for the requested task
* key.
*/ */
public class KeyStoreLruCache<V> { public class KeyStoreLruCache<V> {
// We keep a set of keys that are associated with the LRU cache, so that we can find out // 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. // information about the Task that was previously in the cache.
HashMap<Integer, Task.TaskKey> mTaskKeys = new HashMap<Integer, Task.TaskKey>(); HashMap<Integer, Task.TaskKey> mTaskKeys = new HashMap<Integer, Task.TaskKey>();
// The cache implementation // The cache implementation, mapping task id -> value
LruCache<Integer, V> mCache; LruCache<Integer, V> mCache;
public KeyStoreLruCache(int cacheSize) { public KeyStoreLruCache(int cacheSize) {

View File

@@ -19,6 +19,7 @@ package com.android.systemui.recents.model;
import android.content.ComponentName; import android.content.ComponentName;
import android.content.Context; import android.content.Context;
import android.os.Looper; import android.os.Looper;
import android.os.UserHandle;
import com.android.internal.content.PackageMonitor; import com.android.internal.content.PackageMonitor;
import com.android.systemui.recents.misc.SystemServicesProxy; import com.android.systemui.recents.misc.SystemServicesProxy;
@@ -26,16 +27,16 @@ import java.util.HashSet;
import java.util.List; import java.util.List;
/** /**
* The package monitor listens for changes from PackageManager to update the contents of the Recents * The package monitor listens for changes from PackageManager to update the contents of the
* list. * Recents list.
*/ */
public class RecentsPackageMonitor extends PackageMonitor { public class RecentsPackageMonitor extends PackageMonitor {
public interface PackageCallbacks { public interface PackageCallbacks {
public void onComponentRemoved(HashSet<ComponentName> cns); public void onPackagesChanged(RecentsPackageMonitor monitor, String packageName,
int userId);
} }
PackageCallbacks mCb; PackageCallbacks mCb;
List<Task.TaskKey> mTasks;
SystemServicesProxy mSystemServicesProxy; SystemServicesProxy mSystemServicesProxy;
/** Registers the broadcast receivers with the specified callbacks. */ /** Registers the broadcast receivers with the specified callbacks. */
@@ -43,7 +44,9 @@ public class RecentsPackageMonitor extends PackageMonitor {
mSystemServicesProxy = new SystemServicesProxy(context); mSystemServicesProxy = new SystemServicesProxy(context);
mCb = cb; mCb = cb;
try { 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) { } catch (IllegalStateException e) {
e.printStackTrace(); e.printStackTrace();
} }
@@ -59,29 +62,15 @@ public class RecentsPackageMonitor extends PackageMonitor {
} }
mSystemServicesProxy = null; mSystemServicesProxy = null;
mCb = 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 @Override
public void onPackageRemoved(String packageName, int uid) { public void onPackageRemoved(String packageName, int uid) {
if (mCb == null) return; if (mCb == null) return;
// Identify all the tasks that should be removed as a result of the package being removed. // Notify callbacks that a package has changed
// Using a set to ensure that we callback once per unique component. final int eventUserId = getChangingUserId();
HashSet<ComponentName> componentsToRemove = new HashSet<ComponentName>(); mCb.onPackagesChanged(this, packageName, eventUserId);
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);
} }
@Override @Override
@@ -94,25 +83,38 @@ public class RecentsPackageMonitor extends PackageMonitor {
public void onPackageModified(String packageName) { public void onPackageModified(String packageName) {
if (mCb == null) return; 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. // 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. // Using a set to ensure that we callback once per unique component.
HashSet<ComponentName> componentsKnownToExist = new HashSet<ComponentName>(); HashSet<ComponentName> existingComponents = new HashSet<ComponentName>();
HashSet<ComponentName> componentsToRemove = new HashSet<ComponentName>(); HashSet<ComponentName> removedComponents = new HashSet<ComponentName>();
for (Task.TaskKey t : mTasks) { 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(); ComponentName cn = t.baseIntent.getComponent();
if (cn.getPackageName().equals(packageName)) { 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 // If we know that the component still exists in the package, then skip
continue; continue;
} }
if (mSystemServicesProxy.getActivityInfo(cn) != null) { if (mSystemServicesProxy.getActivityInfo(cn, userId) != null) {
componentsKnownToExist.add(cn); existingComponents.add(cn);
} else { } else {
componentsToRemove.add(cn); removedComponents.add(cn);
} }
} }
} }
// Notify our callbacks that the components no longer exist return removedComponents;
mCb.onComponentRemoved(componentsToRemove);
} }
} }

View File

@@ -420,10 +420,6 @@ public class RecentsTaskLoader {
// Start the task loader and add all the tasks we need to load // Start the task loader and add all the tasks we need to load
mLoader.start(context); mLoader.start(context);
mLoadQueue.addTasks(tasksToLoad); mLoadQueue.addTasks(tasksToLoad);
// Update the package monitor with the list of packages to listen for
mPackageMonitor.setTasks(taskKeys);
return root; return root;
} }

View File

@@ -129,7 +129,7 @@ public class Task {
TaskCallbacks mCb; TaskCallbacks mCb;
public Task() { public Task() {
// Only used by RecentsService for task rect calculations. // Do nothing
} }
public Task(TaskKey key, boolean isActive, int taskAffiliation, int taskAffiliationColor, public Task(TaskKey key, boolean isActive, int taskAffiliation, int taskAffiliationColor,

View File

@@ -255,6 +255,17 @@ public class TaskStack {
return mTaskList.getTasks().get(mTaskList.size() - 1); 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 */ /** Gets the tasks */
public ArrayList<Task> getTasks() { public ArrayList<Task> getTasks() {
return mTaskList.getTasks(); return mTaskList.getTasks();

View File

@@ -18,7 +18,6 @@ package com.android.systemui.recents.views;
import android.app.ActivityOptions; import android.app.ActivityOptions;
import android.app.TaskStackBuilder; import android.app.TaskStackBuilder;
import android.content.ComponentName;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.graphics.Bitmap; import android.graphics.Bitmap;
@@ -42,7 +41,6 @@ import com.android.systemui.recents.model.Task;
import com.android.systemui.recents.model.TaskStack; import com.android.systemui.recents.model.TaskStack;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashSet;
/** /**
* This view is the the top level layout that contains TaskStacks (which are laid out according * This view is the the top level layout that contains TaskStacks (which are laid out according
@@ -564,14 +562,14 @@ public class RecentsView extends FrameLayout implements TaskStackView.TaskStackV
/**** RecentsPackageMonitor.PackageCallbacks Implementation ****/ /**** RecentsPackageMonitor.PackageCallbacks Implementation ****/
@Override @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 // Propagate this event down to each task stack view
int childCount = getChildCount(); int childCount = getChildCount();
for (int i = 0; i < childCount; i++) { for (int i = 0; i < childCount; i++) {
View child = getChildAt(i); View child = getChildAt(i);
if (child != mSearchBar) { if (child != mSearchBar) {
TaskStackView stackView = (TaskStackView) child; TaskStackView stackView = (TaskStackView) child;
stackView.onComponentRemoved(cns); stackView.onPackagesChanged(monitor, packageName, userId);
} }
} }
} }

View File

@@ -1081,12 +1081,16 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
/**** RecentsPackageMonitor.PackageCallbacks Implementation ****/ /**** RecentsPackageMonitor.PackageCallbacks Implementation ****/
@Override @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 // For other tasks, just remove them directly if they no longer exist
ArrayList<Task> tasks = mStack.getTasks(); ArrayList<Task> tasks = mStack.getTasks();
for (int i = tasks.size() - 1; i >= 0; i--) { for (int i = tasks.size() - 1; i >= 0; i--) {
final Task t = tasks.get(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); TaskView tv = getChildViewForTask(t);
if (tv != null) { if (tv != null) {
// For visible children, defer removing the task until after the animation // For visible children, defer removing the task until after the animation