Merge "Ensuring that user-specific Recent tasks are removed. (Bug 18036610)" into lmp-mr1-dev
This commit is contained in:
@@ -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) {
|
||||||
|
|||||||
@@ -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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user