Merge "Additional changes to improve performance when loading Recents. (Bug 16987565)" into lmp-dev
This commit is contained in:
@@ -123,10 +123,10 @@
|
||||
<!-- The min animation duration for animating views that are newly visible. -->
|
||||
<integer name="recents_filter_animate_new_views_duration">250</integer>
|
||||
<!-- The min animation duration for animating the task bar in. -->
|
||||
<integer name="recents_animate_task_bar_enter_duration">275</integer>
|
||||
<integer name="recents_animate_task_bar_enter_duration">225</integer>
|
||||
<!-- The animation delay for animating the first task in. This should roughly be the animation
|
||||
duration of the transition in to recents. -->
|
||||
<integer name="recents_animate_task_bar_enter_delay">300</integer>
|
||||
<integer name="recents_animate_task_bar_enter_delay">275</integer>
|
||||
<!-- The min animation duration for animating the task bar out. -->
|
||||
<integer name="recents_animate_task_exit_to_home_duration">225</integer>
|
||||
<!-- The min animation duration for animating the task bar out. -->
|
||||
@@ -143,6 +143,8 @@
|
||||
<integer name="recents_nav_bar_scrim_enter_duration">400</integer>
|
||||
<!-- The animation duration for animating the removal of a task view. -->
|
||||
<integer name="recents_animate_task_view_remove_duration">250</integer>
|
||||
<!-- The animation duration for scrolling the stack to a particular item. -->
|
||||
<integer name="recents_animate_task_stack_scroll_duration">225</integer>
|
||||
<!-- The minimum alpha for the dim applied to cards that go deeper into the stack. -->
|
||||
<integer name="recents_max_task_stack_view_dim">96</integer>
|
||||
<!-- The delay to enforce between each alt-tab key press. -->
|
||||
|
||||
@@ -195,17 +195,14 @@
|
||||
<!-- The size of the application icon in the recents task view. -->
|
||||
<dimen name="recents_task_view_application_icon_size">48dp</dimen>
|
||||
|
||||
<!-- The size of the activity icon in the recents task view. -->
|
||||
<dimen name="recents_task_view_activity_icon_size">60dp</dimen>
|
||||
|
||||
<!-- The radius of the rounded corners on a task view. -->
|
||||
<dimen name="recents_task_view_rounded_corners_radius">2dp</dimen>
|
||||
|
||||
<!-- The min translation in the Z index for the last task. -->
|
||||
<dimen name="recents_task_view_z_min">25dp</dimen>
|
||||
<dimen name="recents_task_view_z_min">20dp</dimen>
|
||||
|
||||
<!-- The max translation in the Z index for the last task. -->
|
||||
<dimen name="recents_task_view_z_max">100dp</dimen>
|
||||
<dimen name="recents_task_view_z_max">80dp</dimen>
|
||||
|
||||
<!-- The amount to translate when animating the removal of a task. -->
|
||||
<dimen name="recents_task_view_remove_anim_translation_x">100dp</dimen>
|
||||
@@ -231,6 +228,9 @@
|
||||
<!-- The side padding for the task stack as a percentage of the width. -->
|
||||
<item name="recents_stack_width_padding_percentage" format="float" type="dimen">0.04444</item>
|
||||
|
||||
<!-- The overscroll percentage allowed on the stack. -->
|
||||
<item name="recents_stack_overscroll_percentage" format="float" type="dimen">0.0875</item>
|
||||
|
||||
<!-- The top offset for the task stack. -->
|
||||
<dimen name="recents_stack_top_padding">16dp</dimen>
|
||||
|
||||
|
||||
@@ -33,8 +33,7 @@
|
||||
<item name="android:navigationBarColor">@android:color/transparent</item>
|
||||
<item name="android:windowDrawsSystemBarBackgrounds">true</item>
|
||||
<item name="android:windowAnimationStyle">@style/Animation.RecentsActivity</item>
|
||||
|
||||
<item name="android:ambientShadowAlpha">0.30</item>
|
||||
<item name="android:ambientShadowAlpha">0.35</item>
|
||||
</style>
|
||||
|
||||
<!-- Animations for a non-full-screen window or activity. -->
|
||||
|
||||
@@ -22,7 +22,6 @@ import android.content.ActivityNotFoundException;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.ActivityInfo;
|
||||
import android.content.res.Configuration;
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.Bitmap;
|
||||
@@ -36,7 +35,6 @@ import com.android.systemui.R;
|
||||
import com.android.systemui.RecentsComponent;
|
||||
import com.android.systemui.recents.misc.Console;
|
||||
import com.android.systemui.recents.misc.SystemServicesProxy;
|
||||
import com.android.systemui.recents.misc.Utilities;
|
||||
import com.android.systemui.recents.model.RecentsTaskLoader;
|
||||
import com.android.systemui.recents.model.Task;
|
||||
import com.android.systemui.recents.model.TaskGrouping;
|
||||
@@ -99,6 +97,7 @@ public class AlternateRecentsComponent implements ActivityOptions.OnAnimationSta
|
||||
long mLastToggleTime;
|
||||
|
||||
public AlternateRecentsComponent(Context context) {
|
||||
RecentsTaskLoader.initialize(context);
|
||||
Resources res = context.getResources();
|
||||
mContext = context;
|
||||
mSystemServicesProxy = new SystemServicesProxy(context);
|
||||
@@ -176,8 +175,9 @@ public class AlternateRecentsComponent implements ActivityOptions.OnAnimationSta
|
||||
}
|
||||
|
||||
void showRelativeAffiliatedTask(boolean showNextTask) {
|
||||
TaskStack stack = RecentsTaskLoader.getShallowTaskStack(mSystemServicesProxy,
|
||||
Integer.MAX_VALUE, mContext.getResources());
|
||||
RecentsTaskLoader loader = RecentsTaskLoader.getInstance();
|
||||
TaskStack stack = loader.getTaskStack(mSystemServicesProxy, mContext.getResources(),
|
||||
-1, -1, false, null, null);
|
||||
// Return early if there are no tasks
|
||||
if (stack.getTaskCount() == 0) return;
|
||||
|
||||
@@ -385,16 +385,8 @@ public class AlternateRecentsComponent implements ActivityOptions.OnAnimationSta
|
||||
toTask);
|
||||
if (toTransform != null && toTask.key != null) {
|
||||
Rect toTaskRect = toTransform.rect;
|
||||
ActivityInfo info = mSystemServicesProxy.getActivityInfo(
|
||||
toTask.key.baseIntent.getComponent(), toTask.key.userId);
|
||||
if (toTask.activityIcon == null) {
|
||||
toTask.activityIcon = mSystemServicesProxy.getActivityIcon(info,
|
||||
toTask.key.userId);
|
||||
}
|
||||
if (toTask.activityLabel == null) {
|
||||
toTask.activityLabel = mSystemServicesProxy.getActivityLabel(info);
|
||||
}
|
||||
|
||||
// XXX: Reduce the memory usage the to the task bar height
|
||||
Bitmap thumbnail = Bitmap.createBitmap(toTaskRect.width(), toTaskRect.height(),
|
||||
Bitmap.Config.ARGB_8888);
|
||||
if (Constants.DebugFlags.App.EnableTransitionThumbnailDebugMode) {
|
||||
@@ -420,8 +412,9 @@ public class AlternateRecentsComponent implements ActivityOptions.OnAnimationSta
|
||||
TaskViewTransform getThumbnailTransitionTransform(int runningTaskId, boolean isTopTaskHome,
|
||||
Task runningTaskOut) {
|
||||
// Get the stack of tasks that we are animating into
|
||||
TaskStack stack = RecentsTaskLoader.getShallowTaskStack(mSystemServicesProxy, -1,
|
||||
mContext.getResources());
|
||||
RecentsTaskLoader loader = RecentsTaskLoader.getInstance();
|
||||
TaskStack stack = loader.getTaskStack(mSystemServicesProxy, mContext.getResources(),
|
||||
runningTaskId, -1, false, null, null);
|
||||
if (stack.getTaskCount() == 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -343,7 +343,6 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
// Initialize the loader and the configuration
|
||||
RecentsTaskLoader.initialize(this);
|
||||
mConfig = RecentsConfiguration.reinitialize(this,
|
||||
RecentsTaskLoader.getInstance().getSystemServicesProxy());
|
||||
|
||||
|
||||
@@ -67,9 +67,11 @@ public class RecentsConfiguration {
|
||||
public int searchBarSpaceHeightPx;
|
||||
|
||||
/** Task stack */
|
||||
public int taskStackScrollDuration;
|
||||
public int taskStackMaxDim;
|
||||
public int taskStackTopPaddingPx;
|
||||
public float taskStackWidthPaddingPct;
|
||||
public float taskStackOverscrollPct;
|
||||
|
||||
/** Task view animation and styles */
|
||||
public int taskViewEnterFromHomeDuration;
|
||||
@@ -195,9 +197,14 @@ public class RecentsConfiguration {
|
||||
searchBarAppWidgetId = settings.getInt(Constants.Values.App.Key_SearchAppWidgetId, -1);
|
||||
|
||||
// Task stack
|
||||
taskStackScrollDuration =
|
||||
res.getInteger(R.integer.recents_animate_task_stack_scroll_duration);
|
||||
TypedValue widthPaddingPctValue = new TypedValue();
|
||||
res.getValue(R.dimen.recents_stack_width_padding_percentage, widthPaddingPctValue, true);
|
||||
taskStackWidthPaddingPct = widthPaddingPctValue.getFloat();
|
||||
TypedValue stackOverscrollPctValue = new TypedValue();
|
||||
res.getValue(R.dimen.recents_stack_overscroll_percentage, stackOverscrollPctValue, true);
|
||||
taskStackOverscrollPct = stackOverscrollPctValue.getFloat();
|
||||
taskStackMaxDim = res.getInteger(R.integer.recents_max_task_stack_view_dim);
|
||||
taskStackTopPaddingPx = res.getDimensionPixelSize(R.dimen.recents_stack_top_padding);
|
||||
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
|
||||
package com.android.systemui.recents.model;
|
||||
|
||||
import android.app.ActivityManager;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.os.Looper;
|
||||
@@ -36,7 +35,7 @@ public class RecentsPackageMonitor extends PackageMonitor {
|
||||
}
|
||||
|
||||
PackageCallbacks mCb;
|
||||
List<ActivityManager.RecentTaskInfo> mTasks;
|
||||
List<Task.TaskKey> mTasks;
|
||||
SystemServicesProxy mSystemServicesProxy;
|
||||
|
||||
/** Registers the broadcast receivers with the specified callbacks. */
|
||||
@@ -64,7 +63,7 @@ public class RecentsPackageMonitor extends PackageMonitor {
|
||||
}
|
||||
|
||||
/** Sets the list of tasks to match against package broadcast changes. */
|
||||
void setTasks(List<ActivityManager.RecentTaskInfo> tasks) {
|
||||
void setTasks(List<Task.TaskKey> tasks) {
|
||||
mTasks = tasks;
|
||||
}
|
||||
|
||||
@@ -75,7 +74,7 @@ public class RecentsPackageMonitor extends PackageMonitor {
|
||||
// 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 (ActivityManager.RecentTaskInfo t : mTasks) {
|
||||
for (Task.TaskKey t : mTasks) {
|
||||
ComponentName cn = t.baseIntent.getComponent();
|
||||
if (cn.getPackageName().equals(packageName)) {
|
||||
componentsToRemove.add(cn);
|
||||
@@ -99,7 +98,7 @@ public class RecentsPackageMonitor extends PackageMonitor {
|
||||
// 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 (ActivityManager.RecentTaskInfo t : mTasks) {
|
||||
for (Task.TaskKey t : mTasks) {
|
||||
ComponentName cn = t.baseIntent.getComponent();
|
||||
if (cn.getPackageName().equals(packageName)) {
|
||||
if (componentsKnownToExist.contains(cn)) {
|
||||
|
||||
@@ -35,11 +35,16 @@ import com.android.systemui.recents.misc.SystemServicesProxy;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||
|
||||
|
||||
/** Handle to an ActivityInfo */
|
||||
class ActivityInfoHandle {
|
||||
ActivityInfo info;
|
||||
}
|
||||
|
||||
/** A bitmap load queue */
|
||||
class TaskResourceLoadQueue {
|
||||
ConcurrentLinkedQueue<Task> mQueue = new ConcurrentLinkedQueue<Task>();
|
||||
@@ -230,7 +235,6 @@ public class RecentsTaskLoader {
|
||||
static RecentsTaskLoader sInstance;
|
||||
|
||||
SystemServicesProxy mSystemServicesProxy;
|
||||
DrawableLruCache mTaskDescriptionIconCache;
|
||||
DrawableLruCache mApplicationIconCache;
|
||||
BitmapLruCache mThumbnailCache;
|
||||
StringLruCache mActivityLabelCache;
|
||||
@@ -274,7 +278,6 @@ public class RecentsTaskLoader {
|
||||
mSystemServicesProxy = new SystemServicesProxy(context);
|
||||
mPackageMonitor = new RecentsPackageMonitor();
|
||||
mLoadQueue = new TaskResourceLoadQueue();
|
||||
mTaskDescriptionIconCache = new DrawableLruCache(iconCacheSize);
|
||||
mApplicationIconCache = new DrawableLruCache(iconCacheSize);
|
||||
mThumbnailCache = new BitmapLruCache(thumbnailCacheSize);
|
||||
mActivityLabelCache = new StringLruCache(100);
|
||||
@@ -301,103 +304,151 @@ public class RecentsTaskLoader {
|
||||
}
|
||||
|
||||
/** Gets the list of recent tasks, ordered from back to front. */
|
||||
private static List<ActivityManager.RecentTaskInfo> getRecentTasks(SystemServicesProxy ssp,
|
||||
int numTasks) {
|
||||
// Set a default number of tasks to query if none is provided
|
||||
if (numTasks < 0) {
|
||||
RecentsConfiguration config = RecentsConfiguration.getInstance();
|
||||
numTasks = config.maxNumTasksToLoad;
|
||||
}
|
||||
private static List<ActivityManager.RecentTaskInfo> getRecentTasks(SystemServicesProxy ssp) {
|
||||
RecentsConfiguration config = RecentsConfiguration.getInstance();
|
||||
List<ActivityManager.RecentTaskInfo> tasks =
|
||||
ssp.getRecentTasks(numTasks, UserHandle.CURRENT.getIdentifier());
|
||||
ssp.getRecentTasks(config.maxNumTasksToLoad,
|
||||
UserHandle.CURRENT.getIdentifier());
|
||||
Collections.reverse(tasks);
|
||||
return tasks;
|
||||
}
|
||||
|
||||
/** Returns the activity icon using as many cached values as we can. */
|
||||
public Drawable getAndUpdateActivityIcon(Task.TaskKey taskKey,
|
||||
ActivityManager.TaskDescription td, SystemServicesProxy ssp,
|
||||
Resources res, ActivityInfoHandle infoHandle, boolean preloadTask) {
|
||||
// Return the cached activity icon if it exists
|
||||
Drawable icon = mApplicationIconCache.getAndInvalidateIfModified(taskKey);
|
||||
if (icon != null) {
|
||||
return icon;
|
||||
}
|
||||
// Return the task description icon if it exists
|
||||
if (td != null && td.getIcon() != null) {
|
||||
icon = ssp.getBadgedIcon(new BitmapDrawable(res, td.getIcon()), taskKey.userId);
|
||||
mApplicationIconCache.put(taskKey, icon);
|
||||
return icon;
|
||||
}
|
||||
// If we are preloading this task, continue to load the activity icon
|
||||
if (preloadTask) {
|
||||
// All short paths failed, load the icon from the activity info and cache it
|
||||
if (infoHandle.info == null) {
|
||||
infoHandle.info = ssp.getActivityInfo(taskKey.baseIntent.getComponent(),
|
||||
taskKey.userId);
|
||||
}
|
||||
icon = ssp.getActivityIcon(infoHandle.info, taskKey.userId);
|
||||
mApplicationIconCache.put(taskKey, icon);
|
||||
return icon;
|
||||
}
|
||||
// If we are not preloading, return the default icon to show
|
||||
return null;
|
||||
}
|
||||
|
||||
/** Returns the activity label using as many cached values as we can. */
|
||||
public String getAndUpdateActivityLabel(Task.TaskKey taskKey,
|
||||
ActivityManager.TaskDescription td, SystemServicesProxy ssp,
|
||||
ActivityInfoHandle infoHandle) {
|
||||
// Return the task description label if it exists
|
||||
if (td != null && td.getLabel() != null) {
|
||||
return td.getLabel();
|
||||
}
|
||||
// Return the cached activity label if it exists
|
||||
String label = mActivityLabelCache.getAndInvalidateIfModified(taskKey);
|
||||
if (label != null) {
|
||||
return label;
|
||||
}
|
||||
// All short paths failed, load the label from the activity info and cache it
|
||||
if (infoHandle.info == null) {
|
||||
infoHandle.info = ssp.getActivityInfo(taskKey.baseIntent.getComponent(),
|
||||
taskKey.userId);
|
||||
}
|
||||
label = ssp.getActivityLabel(infoHandle.info);
|
||||
mActivityLabelCache.put(taskKey, label);
|
||||
return label;
|
||||
}
|
||||
|
||||
/** Returns the activity's primary color. */
|
||||
public int getActivityPrimaryColor(ActivityManager.TaskDescription td,
|
||||
RecentsConfiguration config) {
|
||||
if (td != null && td.getPrimaryColor() != 0) {
|
||||
return td.getPrimaryColor();
|
||||
}
|
||||
return config.taskBarViewDefaultBackgroundColor;
|
||||
}
|
||||
|
||||
/** Reload the set of recent tasks */
|
||||
public SpaceNode reload(Context context, int preloadCount) {
|
||||
RecentsConfiguration config = RecentsConfiguration.getInstance();
|
||||
Resources res = context.getResources();
|
||||
LinkedHashSet<Task> tasksToLoad = new LinkedHashSet<Task>();
|
||||
ArrayList<Task> tasksToAdd = new ArrayList<Task>();
|
||||
TaskStack stack = new TaskStack();
|
||||
ArrayList<Task.TaskKey> taskKeys = new ArrayList<Task.TaskKey>();
|
||||
ArrayList<Task> tasksToLoad = new ArrayList<Task>();
|
||||
TaskStack stack = getTaskStack(mSystemServicesProxy, context.getResources(),
|
||||
-1, preloadCount, true, taskKeys, tasksToLoad);
|
||||
SpaceNode root = new SpaceNode();
|
||||
root.setStack(stack);
|
||||
|
||||
// Get the recent tasks
|
||||
SystemServicesProxy ssp = mSystemServicesProxy;
|
||||
List<ActivityManager.RecentTaskInfo> tasks = getRecentTasks(ssp, -1);
|
||||
// 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;
|
||||
}
|
||||
|
||||
/** Creates a lightweight stack of the current recent tasks, without thumbnails and icons. */
|
||||
public TaskStack getTaskStack(SystemServicesProxy ssp, Resources res,
|
||||
int preloadTaskId, int preloadTaskCount,
|
||||
boolean loadTaskThumbnails, List<Task.TaskKey> taskKeysOut,
|
||||
List<Task> tasksToLoadOut) {
|
||||
RecentsConfiguration config = RecentsConfiguration.getInstance();
|
||||
List<ActivityManager.RecentTaskInfo> tasks = getRecentTasks(ssp);
|
||||
HashMap<ComponentName, ActivityInfoHandle> activityInfoCache =
|
||||
new HashMap<ComponentName, ActivityInfoHandle>();
|
||||
ArrayList<Task> tasksToAdd = new ArrayList<Task>();
|
||||
TaskStack stack = new TaskStack();
|
||||
|
||||
// From back to front, add each task to the task stack
|
||||
int taskCount = tasks.size();
|
||||
for (int i = 0; i < taskCount; i++) {
|
||||
ActivityManager.RecentTaskInfo t = tasks.get(i);
|
||||
|
||||
// Get an existing activity info handle if possible
|
||||
ComponentName cn = t.baseIntent.getComponent();
|
||||
ActivityInfoHandle infoHandle = new ActivityInfoHandle();
|
||||
boolean hasCachedActivityInfo = false;
|
||||
if (activityInfoCache.containsKey(cn)) {
|
||||
infoHandle = activityInfoCache.get(cn);
|
||||
hasCachedActivityInfo = true;
|
||||
}
|
||||
|
||||
// Compose the task key
|
||||
Task.TaskKey taskKey = new Task.TaskKey(t.persistentId, t.baseIntent, t.userId,
|
||||
t.firstActiveTime, t.lastActiveTime);
|
||||
ComponentName cn = t.baseIntent.getComponent();
|
||||
ActivityInfo info = null;
|
||||
|
||||
ActivityManager.TaskDescription av = t.taskDescription;
|
||||
String activityLabel = null;
|
||||
Drawable activityIcon = mDefaultApplicationIcon;
|
||||
int activityColor = config.taskBarViewDefaultBackgroundColor;
|
||||
boolean loadedActivityIcon = false;
|
||||
if (av != null) {
|
||||
activityLabel = av.getLabel();
|
||||
activityIcon = mTaskDescriptionIconCache.getAndInvalidateIfModified(taskKey);
|
||||
if (activityIcon == null) {
|
||||
activityIcon = (av.getIcon() != null) ?
|
||||
ssp.getBadgedIcon(new BitmapDrawable(res, av.getIcon()), t.userId) : null;
|
||||
if (activityIcon != null) {
|
||||
mTaskDescriptionIconCache.put(taskKey, activityIcon);
|
||||
}
|
||||
}
|
||||
if (av.getPrimaryColor() != 0) {
|
||||
activityColor = av.getPrimaryColor();
|
||||
}
|
||||
loadedActivityIcon = (activityIcon != null);
|
||||
}
|
||||
// If there is no activity label, then try and read it from the label cache before
|
||||
// loading it from the system
|
||||
if (activityLabel == null) {
|
||||
activityLabel = mActivityLabelCache.getAndInvalidateIfModified(taskKey);
|
||||
if (activityLabel == null) {
|
||||
if (info == null) {
|
||||
info = ssp.getActivityInfo(cn, t.userId);
|
||||
}
|
||||
activityLabel = ssp.getActivityLabel(info);
|
||||
mActivityLabelCache.put(taskKey, activityLabel);
|
||||
}
|
||||
// Determine whether to preload this task
|
||||
boolean preloadTask = false;
|
||||
if (preloadTaskId > 0) {
|
||||
preloadTask = (t.id == preloadTaskId);
|
||||
} else if (preloadTaskCount > 0) {
|
||||
preloadTask = (i >= (taskCount - preloadTaskCount));
|
||||
}
|
||||
|
||||
// Create a new task
|
||||
// Load the label, icon, and color
|
||||
String activityLabel = getAndUpdateActivityLabel(taskKey, t.taskDescription,
|
||||
ssp, infoHandle);
|
||||
Drawable activityIcon = getAndUpdateActivityIcon(taskKey, t.taskDescription,
|
||||
ssp, res, infoHandle, preloadTask);
|
||||
int activityColor = getActivityPrimaryColor(t.taskDescription, config);
|
||||
|
||||
// Update the activity info cache
|
||||
if (!hasCachedActivityInfo && infoHandle.info != null) {
|
||||
activityInfoCache.put(cn, infoHandle);
|
||||
}
|
||||
|
||||
// Add the task to the stack
|
||||
Task task = new Task(taskKey, (t.id > -1), t.affiliatedTaskId, t.affiliatedTaskColor,
|
||||
activityLabel, activityIcon, activityColor, (i == (taskCount - 1)),
|
||||
config.lockToAppEnabled);
|
||||
|
||||
// Preload the specified number of apps
|
||||
if (i >= (taskCount - preloadCount)) {
|
||||
// Load the icon from the cache if possible (only if we don't have an activity icon)
|
||||
if (!loadedActivityIcon) {
|
||||
task.applicationIcon =
|
||||
mApplicationIconCache.getAndInvalidateIfModified(taskKey);
|
||||
if (task.applicationIcon == null) {
|
||||
// Load the icon from the system
|
||||
if (info == null) {
|
||||
info = ssp.getActivityInfo(cn, t.userId);
|
||||
}
|
||||
task.applicationIcon = ssp.getActivityIcon(info, taskKey.userId);
|
||||
if (task.applicationIcon != null) {
|
||||
mApplicationIconCache.put(taskKey, task.applicationIcon);
|
||||
}
|
||||
}
|
||||
if (task.applicationIcon == null) {
|
||||
// Either the task has changed since the last active time, or it was not
|
||||
// previously cached, so try and load the task anew.
|
||||
tasksToLoad.add(task);
|
||||
}
|
||||
}
|
||||
|
||||
if (preloadTask && loadTaskThumbnails) {
|
||||
// Load the thumbnail from the cache if possible
|
||||
task.thumbnail = mThumbnailCache.getAndInvalidateIfModified(taskKey);
|
||||
if (task.thumbnail == null) {
|
||||
@@ -408,54 +459,20 @@ public class RecentsTaskLoader {
|
||||
mThumbnailCache.put(taskKey, task.thumbnail);
|
||||
}
|
||||
}
|
||||
if (task.thumbnail == null) {
|
||||
if (task.thumbnail == null && tasksToLoadOut != null) {
|
||||
// Either the task has changed since the last active time, or it was not
|
||||
// previously cached, so try and load the task anew.
|
||||
tasksToLoad.add(task);
|
||||
tasksToLoadOut.add(task);
|
||||
}
|
||||
}
|
||||
|
||||
// Add to the list of task keys
|
||||
if (taskKeysOut != null) {
|
||||
taskKeysOut.add(taskKey);
|
||||
}
|
||||
// Add the task to the stack
|
||||
tasksToAdd.add(task);
|
||||
}
|
||||
|
||||
// Simulate the groupings that we describe
|
||||
stack.setTasks(tasksToAdd);
|
||||
stack.createAffiliatedGroupings(config);
|
||||
|
||||
// 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(tasks);
|
||||
|
||||
return root;
|
||||
}
|
||||
|
||||
/** Creates a lightweight stack of the current recent tasks, without thumbnails and icons. */
|
||||
public static TaskStack getShallowTaskStack(SystemServicesProxy ssp, int numTasks,
|
||||
Resources resources) {
|
||||
RecentsConfiguration config = RecentsConfiguration.getInstance();
|
||||
List<ActivityManager.RecentTaskInfo> tasks = getRecentTasks(ssp, numTasks);
|
||||
ArrayList<Task> tasksToAdd = new ArrayList<Task>();
|
||||
TaskStack stack = new TaskStack();
|
||||
|
||||
int taskCount = tasks.size();
|
||||
for (int i = 0; i < taskCount; i++) {
|
||||
ActivityManager.RecentTaskInfo t = tasks.get(i);
|
||||
ActivityManager.TaskDescription av = t.taskDescription;
|
||||
|
||||
BitmapDrawable icon = null;
|
||||
if (av.getIcon() != null) {
|
||||
icon = new BitmapDrawable(resources, av.getIcon());
|
||||
}
|
||||
Task.TaskKey taskKey = new Task.TaskKey(t.persistentId, t.baseIntent, t.userId,
|
||||
t.firstActiveTime, t.lastActiveTime);
|
||||
tasksToAdd.add(new Task(taskKey, true, t.affiliatedTaskId, t.affiliatedTaskColor,
|
||||
av.getLabel(), icon, av.getPrimaryColor(), (i == (taskCount - 1)),
|
||||
config.lockToAppEnabled));
|
||||
}
|
||||
stack.setTasks(tasksToAdd);
|
||||
stack.createAffiliatedGroupings(config);
|
||||
return stack;
|
||||
@@ -525,21 +542,18 @@ public class RecentsTaskLoader {
|
||||
// We are leaving recents, so trim the data a bit
|
||||
mThumbnailCache.trimToSize(mMaxThumbnailCacheSize / 2);
|
||||
mApplicationIconCache.trimToSize(mMaxIconCacheSize / 2);
|
||||
mTaskDescriptionIconCache.trimToSize(mMaxIconCacheSize / 2);
|
||||
break;
|
||||
case ComponentCallbacks2.TRIM_MEMORY_RUNNING_LOW:
|
||||
case ComponentCallbacks2.TRIM_MEMORY_MODERATE:
|
||||
// We are going to be low on memory
|
||||
mThumbnailCache.trimToSize(mMaxThumbnailCacheSize / 4);
|
||||
mApplicationIconCache.trimToSize(mMaxIconCacheSize / 4);
|
||||
mTaskDescriptionIconCache.trimToSize(mMaxIconCacheSize / 4);
|
||||
break;
|
||||
case ComponentCallbacks2.TRIM_MEMORY_RUNNING_CRITICAL:
|
||||
case ComponentCallbacks2.TRIM_MEMORY_COMPLETE:
|
||||
// We are low on memory, so release everything
|
||||
mThumbnailCache.evictAll();
|
||||
mApplicationIconCache.evictAll();
|
||||
mTaskDescriptionIconCache.evictAll();
|
||||
// The cache is small, only clear the label cache when we are critical
|
||||
mActivityLabelCache.evictAll();
|
||||
break;
|
||||
|
||||
@@ -33,6 +33,8 @@ public class AnimateableViewBounds extends ViewOutlineProvider {
|
||||
Rect mClipRect = new Rect();
|
||||
Rect mOutlineClipRect = new Rect();
|
||||
int mCornerRadius;
|
||||
float mAlpha = 1f;
|
||||
final float mMinAlpha = 0.25f;
|
||||
|
||||
ObjectAnimator mClipTopAnimator;
|
||||
ObjectAnimator mClipRightAnimator;
|
||||
@@ -51,6 +53,7 @@ public class AnimateableViewBounds extends ViewOutlineProvider {
|
||||
|
||||
@Override
|
||||
public void getOutline(View view, Outline outline) {
|
||||
outline.setAlpha(mMinAlpha + mAlpha / (1f - mMinAlpha));
|
||||
outline.setRoundRect(Math.max(mClipRect.left, mOutlineClipRect.left),
|
||||
Math.max(mClipRect.top, mOutlineClipRect.top),
|
||||
mSourceView.getMeasuredWidth() - Math.max(mClipRect.right, mOutlineClipRect.right),
|
||||
@@ -58,6 +61,14 @@ public class AnimateableViewBounds extends ViewOutlineProvider {
|
||||
mCornerRadius);
|
||||
}
|
||||
|
||||
/** Sets the view outline alpha. */
|
||||
void setAlpha(float alpha) {
|
||||
if (Float.compare(alpha, mAlpha) != 0) {
|
||||
mAlpha = alpha;
|
||||
mSourceView.invalidateOutline();
|
||||
}
|
||||
}
|
||||
|
||||
/** Animates the top clip. */
|
||||
void animateClipTop(int top, int duration, ValueAnimator.AnimatorUpdateListener updateListener) {
|
||||
if (mClipTopAnimator != null) {
|
||||
|
||||
@@ -477,10 +477,10 @@ public class RecentsView extends FrameLayout implements TaskStackView.TaskStackV
|
||||
if (!task.group.isFrontMostTask(task)) {
|
||||
// For affiliated tasks that are behind other tasks, we must animate the front cards
|
||||
// out of view before starting the task transition
|
||||
stackView.startLaunchTaskAnimation(tv, launchRunnable);
|
||||
stackView.startLaunchTaskAnimation(tv, launchRunnable, lockToTask);
|
||||
} else {
|
||||
// Otherwise, we can start the task transition immediately
|
||||
stackView.startLaunchTaskAnimation(tv, null);
|
||||
stackView.startLaunchTaskAnimation(tv, null, lockToTask);
|
||||
postDelayed(launchRunnable, 17);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,6 +28,7 @@ import android.view.MotionEvent;
|
||||
import android.view.VelocityTracker;
|
||||
import android.view.View;
|
||||
import android.view.animation.LinearInterpolator;
|
||||
import com.android.systemui.recents.RecentsConfiguration;
|
||||
|
||||
/**
|
||||
* This class facilitates swipe to dismiss. It defines an interface to be implemented by the
|
||||
@@ -50,7 +51,7 @@ public class SwipeHelper {
|
||||
private int DEFAULT_ESCAPE_ANIMATION_DURATION = 75; // ms
|
||||
private int MAX_ESCAPE_ANIMATION_DURATION = 150; // ms
|
||||
private int MAX_DISMISS_VELOCITY = 2000; // dp/sec
|
||||
private static final int SNAP_ANIM_LEN = SLOW_ANIMATIONS ? 1000 : 150; // ms
|
||||
private static final int SNAP_ANIM_LEN = SLOW_ANIMATIONS ? 1000 : 250; // ms
|
||||
|
||||
public static float ALPHA_FADE_START = 0.15f; // fraction of thumbnail width
|
||||
// where fade starts
|
||||
@@ -265,6 +266,7 @@ public class SwipeHelper {
|
||||
ValueAnimator anim = createTranslationAnimation(view, 0);
|
||||
int duration = SNAP_ANIM_LEN;
|
||||
anim.setDuration(duration);
|
||||
anim.setInterpolator(RecentsConfiguration.getInstance().linearOutSlowInInterpolator);
|
||||
anim.addUpdateListener(new AnimatorUpdateListener() {
|
||||
@Override
|
||||
public void onAnimationUpdate(ValueAnimator animation) {
|
||||
|
||||
@@ -105,7 +105,7 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
|
||||
mFilterAlgorithm = new TaskStackViewFilterAlgorithm(mConfig, this, mViewPool);
|
||||
mStackScroller = new TaskStackViewScroller(context, mConfig, mLayoutAlgorithm);
|
||||
mStackScroller.setCallbacks(this);
|
||||
mTouchHandler = new TaskStackViewTouchHandler(context, this, mStackScroller);
|
||||
mTouchHandler = new TaskStackViewTouchHandler(context, this, mConfig, mStackScroller);
|
||||
mUIDozeTrigger = new DozeTrigger(mConfig.taskBarDismissDozeDelaySeconds, new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
@@ -647,17 +647,17 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
|
||||
}
|
||||
|
||||
/** Animates a task view in this stack as it launches. */
|
||||
public void startLaunchTaskAnimation(TaskView tv, final Runnable r) {
|
||||
public void startLaunchTaskAnimation(TaskView tv, Runnable r, boolean lockToTask) {
|
||||
Task launchTargetTask = tv.getTask();
|
||||
int childCount = getChildCount();
|
||||
for (int i = 0; i < childCount; i++) {
|
||||
TaskView t = (TaskView) getChildAt(i);
|
||||
if (t == tv) {
|
||||
t.startLaunchTaskAnimation(r, true, true);
|
||||
t.startLaunchTaskAnimation(r, true, true, lockToTask);
|
||||
} else {
|
||||
boolean occludesLaunchTarget = launchTargetTask.group.isTaskAboveTask(t.getTask(),
|
||||
launchTargetTask);
|
||||
t.startLaunchTaskAnimation(null, false, occludesLaunchTarget);
|
||||
t.startLaunchTaskAnimation(null, false, occludesLaunchTarget, lockToTask);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -133,12 +133,8 @@ public class TaskStackViewScroller {
|
||||
stopBoundScrollAnimation();
|
||||
|
||||
mScrollAnimator = ObjectAnimator.ofFloat(this, "stackScroll", curScroll, newScroll);
|
||||
mScrollAnimator.setDuration(200);
|
||||
// We would have to project the difference into the screen coords, and then use that as the
|
||||
// duration
|
||||
// mScrollAnimator.setDuration(Utilities.calculateTranslationAnimationDuration(newScroll -
|
||||
// curScroll, 250));
|
||||
mScrollAnimator.setInterpolator(mConfig.fastOutSlowInInterpolator);
|
||||
mScrollAnimator.setDuration(mConfig.taskStackScrollDuration);
|
||||
mScrollAnimator.setInterpolator(mConfig.linearOutSlowInInterpolator);
|
||||
mScrollAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
|
||||
@Override
|
||||
public void onAnimationUpdate(ValueAnimator animation) {
|
||||
|
||||
@@ -23,11 +23,13 @@ import android.view.View;
|
||||
import android.view.ViewConfiguration;
|
||||
import android.view.ViewParent;
|
||||
import com.android.systemui.recents.Constants;
|
||||
import com.android.systemui.recents.RecentsConfiguration;
|
||||
|
||||
/* Handles touch events for a TaskStackView. */
|
||||
class TaskStackViewTouchHandler implements SwipeHelper.Callback {
|
||||
static int INACTIVE_POINTER_ID = -1;
|
||||
|
||||
RecentsConfiguration mConfig;
|
||||
TaskStackView mSv;
|
||||
TaskStackViewScroller mScroller;
|
||||
VelocityTracker mVelocityTracker;
|
||||
@@ -52,7 +54,8 @@ class TaskStackViewTouchHandler implements SwipeHelper.Callback {
|
||||
SwipeHelper mSwipeHelper;
|
||||
boolean mInterceptedBySwipeHelper;
|
||||
|
||||
public TaskStackViewTouchHandler(Context context, TaskStackView sv, TaskStackViewScroller scroller) {
|
||||
public TaskStackViewTouchHandler(Context context, TaskStackView sv,
|
||||
RecentsConfiguration config, TaskStackViewScroller scroller) {
|
||||
ViewConfiguration configuration = ViewConfiguration.get(context);
|
||||
mMinimumVelocity = configuration.getScaledMinimumFlingVelocity();
|
||||
mMaximumVelocity = configuration.getScaledMaximumFlingVelocity();
|
||||
@@ -60,6 +63,7 @@ class TaskStackViewTouchHandler implements SwipeHelper.Callback {
|
||||
mPagingTouchSlop = configuration.getScaledPagingTouchSlop();
|
||||
mSv = sv;
|
||||
mScroller = scroller;
|
||||
mConfig = config;
|
||||
|
||||
float densityScale = context.getResources().getDisplayMetrics().density;
|
||||
mSwipeHelper = new SwipeHelper(SwipeHelper.X, this, densityScale, mPagingTouchSlop);
|
||||
@@ -258,7 +262,7 @@ class TaskStackViewTouchHandler implements SwipeHelper.Callback {
|
||||
if (Float.compare(overScrollAmount, 0f) != 0) {
|
||||
// Bound the overscroll to a fixed amount, and inversely scale the y-movement
|
||||
// relative to how close we are to the max overscroll
|
||||
float maxOverScroll = 0.25f;
|
||||
float maxOverScroll = mConfig.taskStackOverscrollPct;
|
||||
deltaP *= (1f - (Math.min(maxOverScroll, overScrollAmount)
|
||||
/ maxOverScroll));
|
||||
}
|
||||
@@ -280,7 +284,6 @@ class TaskStackViewTouchHandler implements SwipeHelper.Callback {
|
||||
velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity);
|
||||
int velocity = (int) velocityTracker.getYVelocity(mActivePointerId);
|
||||
if (mIsScrolling && (Math.abs(velocity) > mMinimumVelocity)) {
|
||||
// XXX: Should this be calculated as a percentage of a curve?
|
||||
int overscrollRange = (int) (Math.min(1f,
|
||||
Math.abs((float) velocity / mMaximumVelocity)) *
|
||||
Constants.Values.TaskStackView.TaskStackOverscrollRange);
|
||||
|
||||
@@ -471,7 +471,7 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks,
|
||||
|
||||
/** Animates this task view as it exits recents */
|
||||
void startLaunchTaskAnimation(final Runnable postAnimRunnable, boolean isLaunchingTask,
|
||||
boolean occludesLaunchTarget) {
|
||||
boolean occludesLaunchTarget, boolean lockToTask) {
|
||||
if (isLaunchingTask) {
|
||||
// Disable the thumbnail clip
|
||||
mThumbnailView.disableTaskBarClip();
|
||||
@@ -487,11 +487,14 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks,
|
||||
}
|
||||
|
||||
// Animate the action button away
|
||||
float toScale = 0.9f;
|
||||
if (!lockToTask) {
|
||||
float toScale = 0.9f;
|
||||
mActionButtonView.animate()
|
||||
.scaleX(toScale)
|
||||
.scaleY(toScale);
|
||||
}
|
||||
mActionButtonView.animate()
|
||||
.alpha(0f)
|
||||
.scaleX(toScale)
|
||||
.scaleY(toScale)
|
||||
.setStartDelay(0)
|
||||
.setDuration(mConfig.taskBarExitAnimDuration)
|
||||
.setInterpolator(mConfig.fastOutLinearInInterpolator)
|
||||
@@ -621,6 +624,7 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks,
|
||||
/** Sets the current task progress. */
|
||||
public void setTaskProgress(float p) {
|
||||
mTaskProgress = p;
|
||||
mViewBounds.setAlpha(p);
|
||||
updateDimFromTaskProgress();
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user