Merge "Improve caching behavior of thumbnails" into oc-dev
am: b67e105e74
Change-Id: I48914589de80ca11c97919bb5af6903ae46d2b3f
This commit is contained in:
@@ -72,6 +72,7 @@ import com.android.systemui.recents.model.Task;
|
||||
import com.android.systemui.recents.model.TaskGrouping;
|
||||
import com.android.systemui.recents.model.TaskStack;
|
||||
import com.android.systemui.recents.views.TaskStackLayoutAlgorithm;
|
||||
import com.android.systemui.recents.views.TaskStackLayoutAlgorithm.VisibilityReport;
|
||||
import com.android.systemui.recents.views.TaskStackView;
|
||||
import com.android.systemui.recents.views.TaskStackViewScroller;
|
||||
import com.android.systemui.recents.views.TaskViewHeader;
|
||||
@@ -126,11 +127,22 @@ public class RecentsImpl implements ActivityOptions.OnAnimationFinishedListener
|
||||
if (runningTaskInfo != null) {
|
||||
launchOpts.runningTaskId = runningTaskInfo.id;
|
||||
}
|
||||
launchOpts.numVisibleTasks = 2;
|
||||
launchOpts.numVisibleTaskThumbnails = 2;
|
||||
mDummyStackView.setTasks(plan.getTaskStack(), false /* allowNotify */);
|
||||
updateDummyStackViewLayout(plan.getTaskStack(),
|
||||
getWindowRect(null /* windowRectOverride */));
|
||||
|
||||
// Launched from app is always the worst case (in terms of how many thumbnails/tasks
|
||||
// visible)
|
||||
RecentsActivityLaunchState launchState = new RecentsActivityLaunchState();
|
||||
launchState.launchedFromApp = true;
|
||||
mDummyStackView.updateLayoutAlgorithm(true /* boundScroll */, launchState);
|
||||
|
||||
VisibilityReport visibilityReport = mDummyStackView.computeStackVisibilityReport();
|
||||
launchOpts.numVisibleTasks = visibilityReport.numVisibleTasks;
|
||||
launchOpts.numVisibleTaskThumbnails = visibilityReport.numVisibleThumbnails;
|
||||
launchOpts.onlyLoadForCache = true;
|
||||
launchOpts.onlyLoadPausedActivities = true;
|
||||
launchOpts.loadThumbnails = !ActivityManager.ENABLE_TASK_SNAPSHOTS;
|
||||
launchOpts.loadThumbnails = true;
|
||||
loader.loadTasks(mContext, plan, launchOpts);
|
||||
}
|
||||
}
|
||||
@@ -605,23 +617,12 @@ public class RecentsImpl implements ActivityOptions.OnAnimationFinishedListener
|
||||
mHeaderBar.setLayoutDirection(res.getConfiguration().getLayoutDirection());
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepares the header bar layout for the next transition, if the task view bounds has changed
|
||||
* since the last call, it will attempt to re-measure and layout the header bar to the new size.
|
||||
*
|
||||
* @param stack the stack to initialize the stack layout with
|
||||
* @param windowRectOverride the rectangle to use when calculating the stack state which can
|
||||
* be different from the current window rect if recents is resizing
|
||||
* while being launched
|
||||
*/
|
||||
private void updateHeaderBarLayout(TaskStack stack, Rect windowRectOverride) {
|
||||
private void updateDummyStackViewLayout(TaskStack stack, Rect windowRect) {
|
||||
SystemServicesProxy ssp = Recents.getSystemServices();
|
||||
Rect displayRect = ssp.getDisplayRect();
|
||||
Rect systemInsets = new Rect();
|
||||
ssp.getStableInsets(systemInsets);
|
||||
Rect windowRect = windowRectOverride != null
|
||||
? new Rect(windowRectOverride)
|
||||
: ssp.getWindowRect();
|
||||
|
||||
// When docked, the nav bar insets are consumed and the activity is measured without insets.
|
||||
// However, the window bounds include the insets, so we need to subtract them here to make
|
||||
// them identical.
|
||||
@@ -642,6 +643,29 @@ public class RecentsImpl implements ActivityOptions.OnAnimationFinishedListener
|
||||
stackLayout.reset();
|
||||
stackLayout.initialize(displayRect, windowRect, mTaskStackBounds,
|
||||
TaskStackLayoutAlgorithm.StackState.getStackStateForStack(stack));
|
||||
}
|
||||
}
|
||||
|
||||
private Rect getWindowRect(Rect windowRectOverride) {
|
||||
return windowRectOverride != null
|
||||
? new Rect(windowRectOverride)
|
||||
: Recents.getSystemServices().getWindowRect();
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepares the header bar layout for the next transition, if the task view bounds has changed
|
||||
* since the last call, it will attempt to re-measure and layout the header bar to the new size.
|
||||
*
|
||||
* @param stack the stack to initialize the stack layout with
|
||||
* @param windowRectOverride the rectangle to use when calculating the stack state which can
|
||||
* be different from the current window rect if recents is resizing
|
||||
* while being launched
|
||||
*/
|
||||
private void updateHeaderBarLayout(TaskStack stack, Rect windowRectOverride) {
|
||||
Rect windowRect = getWindowRect(windowRectOverride);
|
||||
updateDummyStackViewLayout(stack, windowRect);
|
||||
if (stack != null) {
|
||||
TaskStackLayoutAlgorithm stackLayout = mDummyStackView.getStackAlgorithm();
|
||||
mDummyStackView.setTasks(stack, false /* allowNotifyStackChanges */);
|
||||
// Get the width of a task view so that we know how wide to draw the header bar.
|
||||
int taskViewWidth = 0;
|
||||
|
||||
@@ -671,8 +671,7 @@ public class SystemServicesProxy {
|
||||
if (ActivityManager.ENABLE_TASK_SNAPSHOTS) {
|
||||
ActivityManager.TaskSnapshot snapshot = null;
|
||||
try {
|
||||
snapshot = ActivityManager.getService().getTaskSnapshot(taskId,
|
||||
false /* reducedResolution */);
|
||||
snapshot = ActivityManager.getService().getTaskSnapshot(taskId, reducedResolution);
|
||||
} catch (RemoteException e) {
|
||||
Log.w(TAG, "Failed to retrieve snapshot", e);
|
||||
}
|
||||
|
||||
@@ -64,7 +64,7 @@ public class RecentsTaskLoadPlan {
|
||||
public static class Options {
|
||||
public int runningTaskId = -1;
|
||||
public boolean loadIcons = true;
|
||||
public boolean loadThumbnails = true;
|
||||
public boolean loadThumbnails = false;
|
||||
public boolean onlyLoadForCache = false;
|
||||
public boolean onlyLoadPausedActivities = false;
|
||||
public int numVisibleTasks = 0;
|
||||
@@ -189,7 +189,7 @@ public class RecentsTaskLoadPlan {
|
||||
? loader.getAndUpdateActivityIcon(taskKey, t.taskDescription, res, false)
|
||||
: null;
|
||||
ThumbnailData thumbnail = loader.getAndUpdateThumbnail(taskKey,
|
||||
false /* loadIfNotCached */);
|
||||
false /* loadIfNotCached */, false /* storeInCache */);
|
||||
int activityColor = loader.getActivityPrimaryColor(t.taskDescription);
|
||||
int backgroundColor = loader.getActivityBackgroundColor(t.taskDescription);
|
||||
boolean isSystemApp = (info != null) &&
|
||||
@@ -223,9 +223,7 @@ public class RecentsTaskLoadPlan {
|
||||
/**
|
||||
* Called to apply the actual loading based on the specified conditions.
|
||||
*/
|
||||
public synchronized void executePlan(Options opts, RecentsTaskLoader loader,
|
||||
TaskResourceLoadQueue loadQueue) {
|
||||
RecentsConfiguration config = Recents.getConfiguration();
|
||||
public synchronized void executePlan(Options opts, RecentsTaskLoader loader) {
|
||||
Resources res = mContext.getResources();
|
||||
|
||||
// Iterate through each of the tasks and load them according to the load conditions.
|
||||
@@ -250,15 +248,9 @@ public class RecentsTaskLoadPlan {
|
||||
true);
|
||||
}
|
||||
}
|
||||
if (opts.loadThumbnails && (isRunningTask || isVisibleThumbnail)) {
|
||||
if (task.thumbnail == null || isRunningTask) {
|
||||
if (config.svelteLevel <= RecentsConfiguration.SVELTE_LIMIT_CACHE) {
|
||||
task.thumbnail = loader.getAndUpdateThumbnail(taskKey,
|
||||
true /* loadIfNotCached */);
|
||||
} else if (config.svelteLevel == RecentsConfiguration.SVELTE_DISABLE_CACHE) {
|
||||
loadQueue.addTask(task);
|
||||
}
|
||||
}
|
||||
if (opts.loadThumbnails && isVisibleThumbnail) {
|
||||
task.thumbnail = loader.getAndUpdateThumbnail(taskKey,
|
||||
true /* loadIfNotCached */, true /* storeInCache */);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,8 +37,6 @@ import com.android.systemui.recents.RecentsConfiguration;
|
||||
import com.android.systemui.recents.RecentsDebugFlags;
|
||||
import com.android.systemui.recents.events.activity.PackagesChangedEvent;
|
||||
import com.android.systemui.recents.misc.SystemServicesProxy;
|
||||
import com.android.systemui.recents.misc.Utilities;
|
||||
import com.android.systemui.recents.model.Task.TaskKey;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.util.Map;
|
||||
@@ -245,11 +243,11 @@ public class RecentsTaskLoader {
|
||||
private final TaskResourceLoadQueue mLoadQueue;
|
||||
private final BackgroundTaskLoader mLoader;
|
||||
private final HighResThumbnailLoader mHighResThumbnailLoader;
|
||||
|
||||
private final TaskKeyStrongCache<ThumbnailData> mThumbnailCache = new TaskKeyStrongCache<>();
|
||||
private final TaskKeyStrongCache<ThumbnailData> mTempCache = new TaskKeyStrongCache<>();
|
||||
private final int mMaxThumbnailCacheSize;
|
||||
private final int mMaxIconCacheSize;
|
||||
private int mNumVisibleTasksLoaded;
|
||||
private int mNumVisibleThumbnailsLoaded;
|
||||
|
||||
int mDefaultTaskBarBackgroundColor;
|
||||
int mDefaultTaskViewBackgroundColor;
|
||||
@@ -332,10 +330,19 @@ public class RecentsTaskLoader {
|
||||
if (opts == null) {
|
||||
throw new RuntimeException("Requires load options");
|
||||
}
|
||||
plan.executePlan(opts, this, mLoadQueue);
|
||||
if (opts.onlyLoadForCache && opts.loadThumbnails) {
|
||||
|
||||
// If we are loading for the cache, we'd like to have the real cache only include the
|
||||
// visible thumbnails. However, we also don't want to reload already cached thumbnails.
|
||||
// Thus, we copy over the current entries into a second cache, and clear the real cache,
|
||||
// such that the real cache only contains visible thumbnails.
|
||||
mTempCache.copyEntries(mThumbnailCache);
|
||||
mThumbnailCache.evictAll();
|
||||
}
|
||||
plan.executePlan(opts, this);
|
||||
mTempCache.evictAll();
|
||||
if (!opts.onlyLoadForCache) {
|
||||
mNumVisibleTasksLoaded = opts.numVisibleTasks;
|
||||
mNumVisibleThumbnailsLoaded = opts.numVisibleTaskThumbnails;
|
||||
|
||||
// Start the loader
|
||||
mLoader.start(context);
|
||||
@@ -349,7 +356,7 @@ public class RecentsTaskLoader {
|
||||
Drawable icon = mIconCache.getAndInvalidateIfModified(t.key);
|
||||
icon = icon != null ? icon : mDefaultIcon;
|
||||
mLoadQueue.addTask(t);
|
||||
t.notifyTaskDataLoaded(null, icon);
|
||||
t.notifyTaskDataLoaded(t.thumbnail, icon);
|
||||
}
|
||||
|
||||
/** Releases the task resource data back into the pool. */
|
||||
@@ -404,6 +411,7 @@ public class RecentsTaskLoader {
|
||||
// The cache is small, only clear the label cache when we are critical
|
||||
mActivityLabelCache.evictAll();
|
||||
mContentDescriptionCache.evictAll();
|
||||
mThumbnailCache.evictAll();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@@ -500,15 +508,31 @@ public class RecentsTaskLoader {
|
||||
/**
|
||||
* Returns the cached thumbnail if the task key is not expired, updating the cache if it is.
|
||||
*/
|
||||
ThumbnailData getAndUpdateThumbnail(Task.TaskKey taskKey, boolean loadIfNotCached) {
|
||||
ThumbnailData getAndUpdateThumbnail(Task.TaskKey taskKey, boolean loadIfNotCached,
|
||||
boolean storeInCache) {
|
||||
SystemServicesProxy ssp = Recents.getSystemServices();
|
||||
|
||||
ThumbnailData cached = mThumbnailCache.getAndInvalidateIfModified(taskKey);
|
||||
if (cached != null) {
|
||||
return cached;
|
||||
}
|
||||
|
||||
cached = mTempCache.getAndInvalidateIfModified(taskKey);
|
||||
if (cached != null) {
|
||||
mThumbnailCache.put(taskKey, cached);
|
||||
return cached;
|
||||
}
|
||||
|
||||
if (loadIfNotCached) {
|
||||
RecentsConfiguration config = Recents.getConfiguration();
|
||||
if (config.svelteLevel < RecentsConfiguration.SVELTE_DISABLE_LOADING) {
|
||||
// Load the thumbnail from the system
|
||||
ThumbnailData thumbnailData = ssp.getTaskThumbnail(taskKey.id, true /* reducedResolution */);
|
||||
ThumbnailData thumbnailData = ssp.getTaskThumbnail(taskKey.id,
|
||||
true /* reducedResolution */);
|
||||
if (thumbnailData.thumbnail != null) {
|
||||
if (storeInCache) {
|
||||
mThumbnailCache.put(taskKey, thumbnailData);
|
||||
}
|
||||
return thumbnailData;
|
||||
}
|
||||
}
|
||||
@@ -590,5 +614,6 @@ public class RecentsTaskLoader {
|
||||
writer.print(prefix); writer.println(TAG);
|
||||
writer.print(prefix); writer.println("Icon Cache");
|
||||
mIconCache.dump(innerPrefix, writer);
|
||||
mThumbnailCache.dump(innerPrefix, writer);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
* Copyright (C) 2017 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License
|
||||
*/
|
||||
|
||||
package com.android.systemui.recents.model;
|
||||
|
||||
import android.util.Log;
|
||||
import android.util.SparseArray;
|
||||
|
||||
import com.android.systemui.recents.model.Task.TaskKey;
|
||||
|
||||
/**
|
||||
* Base class for both strong and LRU task key cache.
|
||||
*/
|
||||
public abstract class TaskKeyCache<V> {
|
||||
|
||||
protected static final String TAG = "TaskKeyCache";
|
||||
|
||||
protected final SparseArray<TaskKey> mKeys = new SparseArray<>();
|
||||
|
||||
/**
|
||||
* Gets a specific entry in the cache with the specified key, regardless of whether the cached
|
||||
* value is valid or not.
|
||||
*/
|
||||
final V get(Task.TaskKey key) {
|
||||
return getCacheEntry(key.id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value only if the key is valid (has not been updated since the last time it was
|
||||
* in the cache)
|
||||
*/
|
||||
final V getAndInvalidateIfModified(Task.TaskKey key) {
|
||||
Task.TaskKey lastKey = mKeys.get(key.id);
|
||||
if (lastKey != null) {
|
||||
if ((lastKey.stackId != key.stackId) ||
|
||||
(lastKey.lastActiveTime != key.lastActiveTime)) {
|
||||
// The task has updated (been made active since the last time it was put into the
|
||||
// LRU cache) or the stack id for the task has changed, invalidate that cache item
|
||||
remove(key);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
// Either the task does not exist in the cache, or the last active time is the same as
|
||||
// the key specified, so return what is in the cache
|
||||
return getCacheEntry(key.id);
|
||||
}
|
||||
|
||||
/** Puts an entry in the cache for a specific key. */
|
||||
final void put(Task.TaskKey key, V value) {
|
||||
if (key == null || value == null) {
|
||||
Log.e(TAG, "Unexpected null key or value: " + key + ", " + value);
|
||||
return;
|
||||
}
|
||||
mKeys.put(key.id, key);
|
||||
putCacheEntry(key.id, value);
|
||||
}
|
||||
|
||||
|
||||
/** Removes a cache entry for a specific key. */
|
||||
final void remove(Task.TaskKey key) {
|
||||
// Remove the key after the cache value because we need it to make the callback
|
||||
removeCacheEntry(key.id);
|
||||
mKeys.remove(key.id);
|
||||
}
|
||||
|
||||
/** Removes all the entries in the cache. */
|
||||
final void evictAll() {
|
||||
evictAllCache();
|
||||
mKeys.clear();
|
||||
}
|
||||
|
||||
protected abstract V getCacheEntry(int id);
|
||||
protected abstract void putCacheEntry(int id, V value);
|
||||
protected abstract void removeCacheEntry(int id);
|
||||
protected abstract void evictAllCache();
|
||||
}
|
||||
@@ -16,12 +16,9 @@
|
||||
|
||||
package com.android.systemui.recents.model;
|
||||
|
||||
import android.util.Log;
|
||||
import android.util.LruCache;
|
||||
import android.util.SparseArray;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
* A mapping of {@link Task.TaskKey} to value, with additional LRU functionality where the least
|
||||
@@ -31,15 +28,12 @@ import java.util.ArrayList;
|
||||
* In addition, this also allows the caller to invalidate cached values for keys that have since
|
||||
* changed.
|
||||
*/
|
||||
public class TaskKeyLruCache<V> {
|
||||
public class TaskKeyLruCache<V> extends TaskKeyCache<V> {
|
||||
|
||||
public interface EvictionCallback {
|
||||
public void onEntryEvicted(Task.TaskKey key);
|
||||
}
|
||||
|
||||
private static final String TAG = "TaskKeyLruCache";
|
||||
|
||||
private final SparseArray<Task.TaskKey> mKeys = new SparseArray<>();
|
||||
private final LruCache<Integer, V> mCache;
|
||||
private final EvictionCallback mEvictionCallback;
|
||||
|
||||
@@ -61,57 +55,6 @@ public class TaskKeyLruCache<V> {
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a specific entry in the cache with the specified key, regardless of whether the cached
|
||||
* value is valid or not.
|
||||
*/
|
||||
final V get(Task.TaskKey key) {
|
||||
return mCache.get(key.id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value only if the key is valid (has not been updated since the last time it was
|
||||
* in the cache)
|
||||
*/
|
||||
final V getAndInvalidateIfModified(Task.TaskKey key) {
|
||||
Task.TaskKey lastKey = mKeys.get(key.id);
|
||||
if (lastKey != null) {
|
||||
if ((lastKey.stackId != key.stackId) ||
|
||||
(lastKey.lastActiveTime != key.lastActiveTime)) {
|
||||
// The task has updated (been made active since the last time it was put into the
|
||||
// LRU cache) or the stack id for the task has changed, invalidate that cache item
|
||||
remove(key);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
// Either the task does not exist in the cache, or the last active time is the same as
|
||||
// the key specified, so return what is in the cache
|
||||
return mCache.get(key.id);
|
||||
}
|
||||
|
||||
/** Puts an entry in the cache for a specific key. */
|
||||
final void put(Task.TaskKey key, V value) {
|
||||
if (key == null || value == null) {
|
||||
Log.e(TAG, "Unexpected null key or value: " + key + ", " + value);
|
||||
return;
|
||||
}
|
||||
mKeys.put(key.id, key);
|
||||
mCache.put(key.id, value);
|
||||
}
|
||||
|
||||
/** Removes a cache entry for a specific key. */
|
||||
final void remove(Task.TaskKey key) {
|
||||
// Remove the key after the cache value because we need it to make the callback
|
||||
mCache.remove(key.id);
|
||||
mKeys.remove(key.id);
|
||||
}
|
||||
|
||||
/** Removes all the entries in the cache. */
|
||||
final void evictAll() {
|
||||
mCache.evictAll();
|
||||
mKeys.clear();
|
||||
}
|
||||
|
||||
/** Trims the cache to a specific size */
|
||||
final void trimToSize(int cacheSize) {
|
||||
mCache.trimToSize(cacheSize);
|
||||
@@ -128,4 +71,24 @@ public class TaskKeyLruCache<V> {
|
||||
writer.print(innerPrefix); writer.println(mKeys.get(mKeys.keyAt(i)));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected V getCacheEntry(int id) {
|
||||
return mCache.get(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void putCacheEntry(int id, V value) {
|
||||
mCache.put(id, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void removeCacheEntry(int id) {
|
||||
mCache.remove(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void evictAllCache() {
|
||||
mCache.evictAll();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* Copyright (C) 2017 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License
|
||||
*/
|
||||
|
||||
package com.android.systemui.recents.model;
|
||||
|
||||
import android.util.ArrayMap;
|
||||
import android.util.Log;
|
||||
import android.util.SparseArray;
|
||||
|
||||
import com.android.systemui.recents.model.Task.TaskKey;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
|
||||
/**
|
||||
* Like {@link TaskKeyLruCache}, but without LRU functionality.
|
||||
*/
|
||||
public class TaskKeyStrongCache<V> extends TaskKeyCache<V> {
|
||||
|
||||
private static final String TAG = "TaskKeyCache";
|
||||
|
||||
private final ArrayMap<Integer, V> mCache = new ArrayMap<>();
|
||||
|
||||
final void copyEntries(TaskKeyStrongCache<V> other) {
|
||||
for (int i = other.mKeys.size() - 1; i >= 0; i--) {
|
||||
TaskKey key = other.mKeys.valueAt(i);
|
||||
put(key, other.mCache.get(key.id));
|
||||
}
|
||||
}
|
||||
|
||||
public void dump(String prefix, PrintWriter writer) {
|
||||
String innerPrefix = prefix + " ";
|
||||
writer.print(prefix); writer.print(TAG);
|
||||
writer.print(" numEntries="); writer.print(mKeys.size());
|
||||
writer.println();
|
||||
int keyCount = mKeys.size();
|
||||
for (int i = 0; i < keyCount; i++) {
|
||||
writer.print(innerPrefix); writer.println(mKeys.get(mKeys.keyAt(i)));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected V getCacheEntry(int id) {
|
||||
return mCache.get(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void putCacheEntry(int id, V value) {
|
||||
mCache.put(id, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void removeCacheEntry(int id) {
|
||||
mCache.remove(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void evictAllCache() {
|
||||
mCache.clear();
|
||||
}
|
||||
}
|
||||
@@ -220,12 +220,11 @@ public class TaskStackLayoutAlgorithm {
|
||||
}
|
||||
|
||||
// A report of the visibility state of the stack
|
||||
public class VisibilityReport {
|
||||
public static class VisibilityReport {
|
||||
public int numVisibleTasks;
|
||||
public int numVisibleThumbnails;
|
||||
|
||||
/** Package level ctor */
|
||||
VisibilityReport(int tasks, int thumbnails) {
|
||||
public VisibilityReport(int tasks, int thumbnails) {
|
||||
numVisibleTasks = tasks;
|
||||
numVisibleThumbnails = thumbnails;
|
||||
}
|
||||
@@ -505,9 +504,9 @@ public class TaskStackLayoutAlgorithm {
|
||||
* Computes the minimum and maximum scroll progress values and the progress values for each task
|
||||
* in the stack.
|
||||
*/
|
||||
void update(TaskStack stack, ArraySet<Task.TaskKey> ignoreTasksSet) {
|
||||
void update(TaskStack stack, ArraySet<Task.TaskKey> ignoreTasksSet,
|
||||
RecentsActivityLaunchState launchState) {
|
||||
SystemServicesProxy ssp = Recents.getSystemServices();
|
||||
RecentsActivityLaunchState launchState = Recents.getConfiguration().getLaunchState();
|
||||
|
||||
// Clear the progress map
|
||||
mTaskIndexMap.clear();
|
||||
@@ -788,6 +787,10 @@ public class TaskStackLayoutAlgorithm {
|
||||
* stack scroll. Requires that update() is called first.
|
||||
*/
|
||||
public VisibilityReport computeStackVisibilityReport(ArrayList<Task> tasks) {
|
||||
if (useGridLayout()) {
|
||||
return mTaskGridLayoutAlgorithm.computeStackVisibilityReport(tasks);
|
||||
}
|
||||
|
||||
// Ensure minimum visibility count
|
||||
if (tasks.size() <= 1) {
|
||||
return new VisibilityReport(1, 1);
|
||||
@@ -795,8 +798,8 @@ public class TaskStackLayoutAlgorithm {
|
||||
|
||||
// Quick return when there are no stack tasks
|
||||
if (mNumStackTasks == 0) {
|
||||
return new VisibilityReport(Math.max(mNumFreeformTasks, 1),
|
||||
Math.max(mNumFreeformTasks, 1));
|
||||
return new VisibilityReport(mNumFreeformTasks > 0 ? Math.max(mNumFreeformTasks, 1) : 0,
|
||||
mNumFreeformTasks > 0 ? Math.max(mNumFreeformTasks, 1) : 0);
|
||||
}
|
||||
|
||||
// Otherwise, walk backwards in the stack and count the number of tasks and visible
|
||||
@@ -806,8 +809,8 @@ public class TaskStackLayoutAlgorithm {
|
||||
currentRange.offset(mInitialScrollP);
|
||||
int taskBarHeight = mContext.getResources().getDimensionPixelSize(
|
||||
R.dimen.recents_task_view_header_height);
|
||||
int numVisibleTasks = Math.max(mNumFreeformTasks, 1);
|
||||
int numVisibleThumbnails = Math.max(mNumFreeformTasks, 1);
|
||||
int numVisibleTasks = mNumFreeformTasks > 0 ? Math.max(mNumFreeformTasks, 1) : 0;
|
||||
int numVisibleThumbnails = mNumFreeformTasks > 0 ? Math.max(mNumFreeformTasks, 0) : 0;
|
||||
float prevScreenY = Integer.MAX_VALUE;
|
||||
for (int i = tasks.size() - 1; i >= 0; i--) {
|
||||
Task task = tasks.get(i);
|
||||
@@ -838,15 +841,15 @@ public class TaskStackLayoutAlgorithm {
|
||||
// Once we hit the next front most task that does not have a visible thumbnail,
|
||||
// walk through remaining visible set
|
||||
for (int j = i; j >= 0; j--) {
|
||||
numVisibleTasks++;
|
||||
taskProgress = getStackScrollForTask(tasks.get(j));
|
||||
if (!currentRange.isInRange(taskProgress)) {
|
||||
continue;
|
||||
break;
|
||||
}
|
||||
numVisibleTasks++;
|
||||
}
|
||||
break;
|
||||
}
|
||||
} else if (!isFrontMostTaskInGroup) {
|
||||
} else {
|
||||
// Affiliated task, no thumbnail
|
||||
numVisibleTasks++;
|
||||
}
|
||||
|
||||
@@ -868,12 +868,17 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
|
||||
mTaskViewsClipDirty = false;
|
||||
}
|
||||
|
||||
public void updateLayoutAlgorithm(boolean boundScrollToNewMinMax) {
|
||||
updateLayoutAlgorithm(boundScrollToNewMinMax, Recents.getConfiguration().getLaunchState());
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the layout algorithm min and max virtual scroll bounds.
|
||||
*/
|
||||
public void updateLayoutAlgorithm(boolean boundScrollToNewMinMax) {
|
||||
public void updateLayoutAlgorithm(boolean boundScrollToNewMinMax,
|
||||
RecentsActivityLaunchState launchState) {
|
||||
// Compute the min and max scroll values
|
||||
mLayoutAlgorithm.update(mStack, mIgnoreTasks);
|
||||
mLayoutAlgorithm.update(mStack, mIgnoreTasks, launchState);
|
||||
|
||||
// Update the freeform workspace background
|
||||
SystemServicesProxy ssp = Recents.getSystemServices();
|
||||
@@ -1550,6 +1555,10 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
|
||||
|
||||
@Override
|
||||
public void onStackTasksUpdated(TaskStack stack) {
|
||||
if (mAwaitingFirstLayout) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Update the layout and immediately layout
|
||||
updateLayoutAlgorithm(false /* boundScroll */);
|
||||
relayoutTaskViews(AnimationProps.IMMEDIATE);
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
|
||||
package com.android.systemui.recents.views.grid;
|
||||
|
||||
import static com.android.systemui.recents.views.TaskStackLayoutAlgorithm.*;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.Point;
|
||||
@@ -26,9 +28,12 @@ import com.android.systemui.R;
|
||||
import com.android.systemui.recents.events.ui.focus.NavigateTaskViewEvent;
|
||||
import com.android.systemui.recents.events.ui.focus.NavigateTaskViewEvent.Direction;
|
||||
import com.android.systemui.recents.misc.Utilities;
|
||||
import com.android.systemui.recents.model.Task;
|
||||
import com.android.systemui.recents.views.TaskStackLayoutAlgorithm;
|
||||
import com.android.systemui.recents.views.TaskViewTransform;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class TaskGridLayoutAlgorithm {
|
||||
|
||||
private final String TAG = "TaskGridLayoutAlgorithm";
|
||||
@@ -313,4 +318,9 @@ public class TaskGridLayoutAlgorithm {
|
||||
public int getFocusFrameThickness() {
|
||||
return mFocusedFrameThickness;
|
||||
}
|
||||
|
||||
public VisibilityReport computeStackVisibilityReport(ArrayList<Task> tasks) {
|
||||
int visibleCount = Math.min(TaskGridLayoutAlgorithm.MAX_LAYOUT_TASK_COUNT, tasks.size());
|
||||
return new VisibilityReport(visibleCount, visibleCount);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,15 +32,10 @@ import java.util.Map.Entry;
|
||||
*/
|
||||
class TaskSnapshotCache {
|
||||
|
||||
// TODO: Make this more dynamic to accomodate for different clients.
|
||||
private static final int RETRIEVAL_CACHE_SIZE = 4;
|
||||
|
||||
private final WindowManagerService mService;
|
||||
private final TaskSnapshotLoader mLoader;
|
||||
private final ArrayMap<AppWindowToken, Integer> mAppTaskMap = new ArrayMap<>();
|
||||
private final ArrayMap<Integer, CacheEntry> mRunningCache = new ArrayMap<>();
|
||||
private final LruCache<Integer, TaskSnapshot> mRetrievalCache =
|
||||
new LruCache<>(RETRIEVAL_CACHE_SIZE);
|
||||
|
||||
TaskSnapshotCache(WindowManagerService service, TaskSnapshotLoader loader) {
|
||||
mService = service;
|
||||
@@ -55,7 +50,6 @@ class TaskSnapshotCache {
|
||||
final AppWindowToken top = task.getTopChild();
|
||||
mAppTaskMap.put(top, task.mTaskId);
|
||||
mRunningCache.put(task.mTaskId, new CacheEntry(snapshot, task.getTopChild()));
|
||||
mRetrievalCache.put(task.mTaskId, snapshot);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -70,12 +64,6 @@ class TaskSnapshotCache {
|
||||
if (entry != null) {
|
||||
return entry.snapshot;
|
||||
}
|
||||
|
||||
// Try the retrieval cache.
|
||||
final TaskSnapshot snapshot = mRetrievalCache.get(taskId);
|
||||
if (snapshot != null) {
|
||||
return snapshot;
|
||||
}
|
||||
}
|
||||
|
||||
// Try to restore from disk if asked.
|
||||
@@ -93,13 +81,6 @@ class TaskSnapshotCache {
|
||||
if (snapshot == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Only cache non-reduced snapshots.
|
||||
if (!reducedResolution) {
|
||||
synchronized (mService.mWindowMap) {
|
||||
mRetrievalCache.put(taskId, snapshot);
|
||||
}
|
||||
}
|
||||
return snapshot;
|
||||
}
|
||||
|
||||
@@ -111,9 +92,6 @@ class TaskSnapshotCache {
|
||||
if (taskId != null) {
|
||||
removeRunningEntry(taskId);
|
||||
}
|
||||
if (wtoken.getTask() != null) {
|
||||
mRetrievalCache.remove(wtoken.getTask().mTaskId);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -128,7 +106,6 @@ class TaskSnapshotCache {
|
||||
|
||||
void onTaskRemoved(int taskId) {
|
||||
removeRunningEntry(taskId);
|
||||
mRetrievalCache.remove(taskId);
|
||||
}
|
||||
|
||||
private void removeRunningEntry(int taskId) {
|
||||
@@ -142,20 +119,12 @@ class TaskSnapshotCache {
|
||||
void dump(PrintWriter pw, String prefix) {
|
||||
final String doublePrefix = prefix + " ";
|
||||
final String triplePrefix = doublePrefix + " ";
|
||||
final String quadruplePrefix = triplePrefix + " ";
|
||||
pw.println(prefix + "SnapshotCache");
|
||||
pw.println(doublePrefix + "RunningCache");
|
||||
for (int i = mRunningCache.size() - 1; i >= 0; i--) {
|
||||
final CacheEntry entry = mRunningCache.valueAt(i);
|
||||
pw.println(triplePrefix + "Entry taskId=" + mRunningCache.keyAt(i));
|
||||
pw.println(quadruplePrefix + "topApp=" + entry.topApp);
|
||||
pw.println(quadruplePrefix + "snapshot=" + entry.snapshot);
|
||||
}
|
||||
pw.println(doublePrefix + "RetrievalCache");
|
||||
final Map<Integer, TaskSnapshot> retrievalSnapshot = mRetrievalCache.snapshot();
|
||||
for (Entry<Integer, TaskSnapshot> entry : retrievalSnapshot.entrySet()) {
|
||||
pw.println(triplePrefix + "Entry taskId=" + entry.getKey());
|
||||
pw.println(quadruplePrefix + "snapshot=" + entry.getValue());
|
||||
pw.println(doublePrefix + "Entry taskId=" + mRunningCache.keyAt(i));
|
||||
pw.println(triplePrefix + "topApp=" + entry.topApp);
|
||||
pw.println(triplePrefix + "snapshot=" + entry.snapshot);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -79,18 +79,6 @@ public class TaskSnapshotCacheTest extends TaskSnapshotPersisterTestBase {
|
||||
assertNotNull(mCache.getSnapshot(window.getTask().mTaskId, 0 /* userId */,
|
||||
false /* restoreFromDisk */, false /* reducedResolution */));
|
||||
mCache.onAppDied(window.mAppToken);
|
||||
|
||||
// Should still be in the retrieval cache.
|
||||
assertNotNull(mCache.getSnapshot(window.getTask().mTaskId, 0 /* userId */,
|
||||
false /* restoreFromDisk */, false /* reducedResolution */));
|
||||
|
||||
// Trash retrieval cache.
|
||||
for (int i = 0; i < 20; i++) {
|
||||
mCache.putSnapshot(createWindow(null, FIRST_APPLICATION_WINDOW, "window").getTask(),
|
||||
createSnapshot());
|
||||
}
|
||||
|
||||
// Should not be in cache anymore
|
||||
assertNull(mCache.getSnapshot(window.getTask().mTaskId, 0 /* userId */,
|
||||
false /* restoreFromDisk */, false /* reducedResolution */));
|
||||
}
|
||||
@@ -134,9 +122,5 @@ public class TaskSnapshotCacheTest extends TaskSnapshotPersisterTestBase {
|
||||
// Load it from disk
|
||||
assertNotNull(mCache.getSnapshot(window.getTask().mTaskId, sWm.mCurrentUserId,
|
||||
true /* restoreFromDisk */, false /* reducedResolution */));
|
||||
|
||||
// Make sure it's in the cache now.
|
||||
assertNotNull(mCache.getSnapshot(window.getTask().mTaskId, sWm.mCurrentUserId,
|
||||
false /* restoreFromDisk */, false /* reducedResolution */));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user