diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java index 33ad7fbb0e595..164138e4b1d3f 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java +++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java @@ -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; diff --git a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java index 3a43d304b1cab..397b78dbd281b 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java +++ b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java @@ -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); } diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java index f8d123b8fdde1..5c25bfd6441ca 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java +++ b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java @@ -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 */); } } } 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 e378d0ae51dee..e8ffb9150da7e 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java +++ b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java @@ -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 mThumbnailCache = new TaskKeyStrongCache<>(); + private final TaskKeyStrongCache 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); } } diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/TaskKeyCache.java b/packages/SystemUI/src/com/android/systemui/recents/model/TaskKeyCache.java new file mode 100644 index 0000000000000..be99f93028dcf --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/recents/model/TaskKeyCache.java @@ -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 { + + protected static final String TAG = "TaskKeyCache"; + + protected final SparseArray 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(); +} diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/TaskKeyLruCache.java b/packages/SystemUI/src/com/android/systemui/recents/model/TaskKeyLruCache.java index 23739a0838267..778df6be399b2 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/model/TaskKeyLruCache.java +++ b/packages/SystemUI/src/com/android/systemui/recents/model/TaskKeyLruCache.java @@ -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 { +public class TaskKeyLruCache extends TaskKeyCache { public interface EvictionCallback { public void onEntryEvicted(Task.TaskKey key); } - private static final String TAG = "TaskKeyLruCache"; - - private final SparseArray mKeys = new SparseArray<>(); private final LruCache mCache; private final EvictionCallback mEvictionCallback; @@ -61,57 +55,6 @@ public class TaskKeyLruCache { }; } - /** - * 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 { 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(); + } } diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/TaskKeyStrongCache.java b/packages/SystemUI/src/com/android/systemui/recents/model/TaskKeyStrongCache.java new file mode 100644 index 0000000000000..c84df8a14288a --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/recents/model/TaskKeyStrongCache.java @@ -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 extends TaskKeyCache { + + private static final String TAG = "TaskKeyCache"; + + private final ArrayMap mCache = new ArrayMap<>(); + + final void copyEntries(TaskKeyStrongCache 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(); + } +} diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java index 4fa7ecb5375dc..7ba705e47cf6d 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java @@ -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 ignoreTasksSet) { + void update(TaskStack stack, ArraySet 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 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++; } 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 b7cedf79e0886..32e3df6a7295b 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java @@ -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); diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/grid/TaskGridLayoutAlgorithm.java b/packages/SystemUI/src/com/android/systemui/recents/views/grid/TaskGridLayoutAlgorithm.java index 4f175368aceb3..c5132024d505a 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/grid/TaskGridLayoutAlgorithm.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/grid/TaskGridLayoutAlgorithm.java @@ -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 tasks) { + int visibleCount = Math.min(TaskGridLayoutAlgorithm.MAX_LAYOUT_TASK_COUNT, tasks.size()); + return new VisibilityReport(visibleCount, visibleCount); + } } diff --git a/services/core/java/com/android/server/wm/TaskSnapshotCache.java b/services/core/java/com/android/server/wm/TaskSnapshotCache.java index 1ec020180aa2b..7bf4edb2c97a3 100644 --- a/services/core/java/com/android/server/wm/TaskSnapshotCache.java +++ b/services/core/java/com/android/server/wm/TaskSnapshotCache.java @@ -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 mAppTaskMap = new ArrayMap<>(); private final ArrayMap mRunningCache = new ArrayMap<>(); - private final LruCache 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 retrievalSnapshot = mRetrievalCache.snapshot(); - for (Entry 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); } } diff --git a/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotCacheTest.java b/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotCacheTest.java index 290f69a7a7e7f..c61076d3b920c 100644 --- a/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotCacheTest.java +++ b/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotCacheTest.java @@ -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 */)); } }