Initial layout/behaviour for freeform workspace.
Change-Id: Idc878862747d0d726cbf10be9893c48736673d0e
This commit is contained in:
@@ -616,15 +616,17 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView
|
||||
ViewAnimation.TaskViewEnterContext ctx = new ViewAnimation.TaskViewEnterContext(t);
|
||||
ctx.postAnimationTrigger.increment();
|
||||
if (mSearchWidgetInfo != null) {
|
||||
ctx.postAnimationTrigger.addLastDecrementRunnable(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
// Start listening for widget package changes if there is one bound
|
||||
if (!Constants.DebugFlags.App.DisableSearchBar && mAppWidgetHost != null) {
|
||||
mAppWidgetHost.startListening();
|
||||
if (!Constants.DebugFlags.App.DisableSearchBar) {
|
||||
ctx.postAnimationTrigger.addLastDecrementRunnable(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
// Start listening for widget package changes if there is one bound
|
||||
if (mAppWidgetHost != null) {
|
||||
mAppWidgetHost.startListening();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
ctx.postAnimationTrigger.addLastDecrementRunnable(new Runnable() {
|
||||
@Override
|
||||
|
||||
@@ -53,7 +53,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.TaskStackView;
|
||||
import com.android.systemui.recents.views.TaskStackViewLayoutAlgorithm;
|
||||
import com.android.systemui.recents.views.TaskStackLayoutAlgorithm;
|
||||
import com.android.systemui.recents.views.TaskViewHeader;
|
||||
import com.android.systemui.recents.views.TaskViewTransform;
|
||||
import com.android.systemui.statusbar.phone.PhoneStatusBar;
|
||||
@@ -465,10 +465,10 @@ public class RecentsImpl extends IRecentsNonSystemUserCallbacks.Stub
|
||||
mSearchBarBounds, mTaskStackBounds);
|
||||
|
||||
// Rebind the header bar and draw it for the transition
|
||||
TaskStackViewLayoutAlgorithm algo = mDummyStackView.getStackAlgorithm();
|
||||
TaskStackLayoutAlgorithm algo = mDummyStackView.getStackAlgorithm();
|
||||
Rect taskStackBounds = new Rect(mTaskStackBounds);
|
||||
algo.setSystemInsets(systemInsets);
|
||||
algo.computeRects(taskStackBounds);
|
||||
algo.initialize(taskStackBounds);
|
||||
Rect taskViewBounds = algo.getUntransformedTaskViewBounds();
|
||||
if (!taskViewBounds.equals(mLastTaskViewBounds)) {
|
||||
mLastTaskViewBounds.set(taskViewBounds);
|
||||
@@ -666,7 +666,7 @@ public class RecentsImpl extends IRecentsNonSystemUserCallbacks.Stub
|
||||
|
||||
// Prepare the dummy stack for the transition
|
||||
mDummyStackView.updateMinMaxScrollForStack(stack);
|
||||
TaskStackViewLayoutAlgorithm.VisibilityReport stackVr =
|
||||
TaskStackLayoutAlgorithm.VisibilityReport stackVr =
|
||||
mDummyStackView.computeStackVisibilityReport();
|
||||
boolean hasRecentTasks = stack.getTaskCount() > 0;
|
||||
boolean useThumbnailTransition = (topTask != null) && !isTopTaskHome && hasRecentTasks;
|
||||
@@ -713,7 +713,7 @@ public class RecentsImpl extends IRecentsNonSystemUserCallbacks.Stub
|
||||
*/
|
||||
private void startRecentsActivity(ActivityManager.RunningTaskInfo topTask,
|
||||
ActivityOptions opts, boolean fromHome, boolean fromSearchHome, boolean fromThumbnail,
|
||||
TaskStackViewLayoutAlgorithm.VisibilityReport vr) {
|
||||
TaskStackLayoutAlgorithm.VisibilityReport vr) {
|
||||
mStartAnimationTriggered = false;
|
||||
|
||||
// Update the configuration based on the launch options
|
||||
|
||||
@@ -137,12 +137,19 @@ public class RecentsTaskLoadPlan {
|
||||
task.thumbnail = loader.getAndUpdateThumbnail(taskKey, ssp, false);
|
||||
if (DEBUG) Log.d(TAG, "\tthumbnail: " + taskKey + ", " + task.thumbnail);
|
||||
|
||||
stackTasks.add(task);
|
||||
if (task.isFreeformTask()) {
|
||||
freeformTasks.add(task);
|
||||
} else {
|
||||
stackTasks.add(task);
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize the stacks
|
||||
ArrayList<Task> allTasks = new ArrayList<>();
|
||||
allTasks.addAll(stackTasks);
|
||||
allTasks.addAll(freeformTasks);
|
||||
mStack = new TaskStack();
|
||||
mStack.setTasks(stackTasks);
|
||||
mStack.setTasks(allTasks);
|
||||
mStack.createAffiliatedGroupings(mContext);
|
||||
}
|
||||
|
||||
|
||||
@@ -399,6 +399,21 @@ public class TaskStack {
|
||||
return mTaskList.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the task in this stack which is the launch target.
|
||||
*/
|
||||
public Task getLaunchTarget() {
|
||||
ArrayList<Task> tasks = mTaskList.getTasks();
|
||||
int taskCount = tasks.size();
|
||||
for (int i = 0; i < taskCount; i++) {
|
||||
Task task = tasks.get(i);
|
||||
if (task.isLaunchTarget) {
|
||||
return task;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/** Returns the index of this task in this current task stack */
|
||||
public int indexOfTask(Task t) {
|
||||
return mTaskList.indexOf(t);
|
||||
@@ -417,6 +432,21 @@ public class TaskStack {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether this stack has freeform tasks.
|
||||
*/
|
||||
public boolean hasFreeformTasks() {
|
||||
ArrayList<Task> tasks = mTaskList.getTasks();
|
||||
int taskCount = tasks.size();
|
||||
for (int i = 0; i < taskCount; i++) {
|
||||
Task task = tasks.get(i);
|
||||
if (task.isFreeformTask()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/******** Filtering ********/
|
||||
|
||||
/** Filters the stack into tasks similar to the one specified */
|
||||
|
||||
@@ -0,0 +1,108 @@
|
||||
/*
|
||||
* Copyright (C) 2014 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.views;
|
||||
|
||||
import android.util.Log;
|
||||
import com.android.systemui.recents.model.Task;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
|
||||
/**
|
||||
* The layout logic for the contents of the freeform workspace.
|
||||
*/
|
||||
public class FreeformWorkspaceLayoutAlgorithm {
|
||||
|
||||
private static final String TAG = "FreeformWorkspaceLayoutAlgorithm";
|
||||
private static final boolean DEBUG = false;
|
||||
|
||||
// The number of cells in the freeform workspace
|
||||
private int mFreeformCellXCount;
|
||||
private int mFreeformCellYCount;
|
||||
// The width and height of the cells in the freeform workspace
|
||||
private int mFreeformCellWidth;
|
||||
private int mFreeformCellHeight;
|
||||
|
||||
// Optimization, allows for quick lookup of task -> index
|
||||
private HashMap<Task.TaskKey, Integer> mTaskIndexMap = new HashMap<>();
|
||||
|
||||
/**
|
||||
* Updates the layout for each of the freeform workspace tasks. This is called after the stack
|
||||
* layout is updated.
|
||||
*/
|
||||
public void update(ArrayList<Task> freeformTasks, TaskStackLayoutAlgorithm stackLayout) {
|
||||
int numFreeformTasks = stackLayout.mNumFreeformTasks;
|
||||
if (!freeformTasks.isEmpty()) {
|
||||
// Calculate the cell width/height depending on the number of freeform tasks
|
||||
mFreeformCellXCount = Math.max(2, (int) Math.ceil(Math.sqrt(numFreeformTasks)));
|
||||
mFreeformCellYCount = Math.max(2, (int) Math.ceil((float) numFreeformTasks / mFreeformCellXCount));
|
||||
mFreeformCellWidth = stackLayout.mFreeformRect.width() / mFreeformCellXCount;
|
||||
// For now, make the cells square
|
||||
mFreeformCellHeight = mFreeformCellWidth;
|
||||
|
||||
// Put each of the tasks in the progress map at a fixed index (does not need to actually
|
||||
// map to a scroll position, just by index)
|
||||
int taskCount = freeformTasks.size();
|
||||
for (int i = 0; i < taskCount; i++) {
|
||||
Task task = freeformTasks.get(i);
|
||||
mTaskIndexMap.put(task.key, i);
|
||||
}
|
||||
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "mFreeformCellXCount: " + mFreeformCellXCount);
|
||||
Log.d(TAG, "mFreeformCellYCount: " + mFreeformCellYCount);
|
||||
Log.d(TAG, "mFreeformCellWidth: " + mFreeformCellWidth);
|
||||
Log.d(TAG, "mFreeformCellHeight: " + mFreeformCellHeight);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the transform is available for the given task.
|
||||
*/
|
||||
public boolean isTransformAvailable(Task task, float stackScroll,
|
||||
TaskStackLayoutAlgorithm stackLayout) {
|
||||
if (stackLayout.mNumFreeformTasks == 0 || task == null ||
|
||||
!mTaskIndexMap.containsKey(task.key)) {
|
||||
return false;
|
||||
}
|
||||
return stackScroll > stackLayout.mStackEndScrollP;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the transform for the given task. Any rect returned will be offset by the actual
|
||||
* transform for the freeform workspace.
|
||||
*/
|
||||
public TaskViewTransform getTransform(Task task, float stackScroll,
|
||||
TaskViewTransform transformOut, TaskStackLayoutAlgorithm stackLayout) {
|
||||
if (Float.compare(stackScroll, stackLayout.mStackEndScrollP) > 0) {
|
||||
// This is a freeform task, so lay it out in the freeform workspace
|
||||
int taskIndex = mTaskIndexMap.get(task.key);
|
||||
int x = taskIndex % mFreeformCellXCount;
|
||||
int y = taskIndex / mFreeformCellXCount;
|
||||
float scale = (float) mFreeformCellWidth / stackLayout.mTaskRect.width();
|
||||
int scaleXOffset = (int) (((1f - scale) * stackLayout.mTaskRect.width()) / 2);
|
||||
int scaleYOffset = (int) (((1f - scale) * stackLayout.mTaskRect.height()) / 2);
|
||||
transformOut.scale = scale * 0.9f;
|
||||
transformOut.translationX = x * mFreeformCellWidth - scaleXOffset;
|
||||
transformOut.translationY = y * mFreeformCellHeight - scaleYOffset;
|
||||
transformOut.visible = true;
|
||||
return transformOut;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -26,6 +26,7 @@ import com.android.systemui.recents.RecentsConfiguration;
|
||||
import com.android.systemui.recents.misc.ParametricCurve;
|
||||
import com.android.systemui.recents.misc.Utilities;
|
||||
import com.android.systemui.recents.model.Task;
|
||||
import com.android.systemui.recents.model.TaskStack;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
@@ -33,9 +34,8 @@ import java.util.HashMap;
|
||||
|
||||
/**
|
||||
* The layout logic for a TaskStackView.
|
||||
*
|
||||
*/
|
||||
public class TaskStackViewLayoutAlgorithm {
|
||||
public class TaskStackLayoutAlgorithm {
|
||||
|
||||
private static final String TAG = "TaskStackViewLayoutAlgorithm";
|
||||
private static final boolean DEBUG = false;
|
||||
@@ -46,6 +46,10 @@ public class TaskStackViewLayoutAlgorithm {
|
||||
private static final float SINGLE_TASK_SCALE = 0.95f;
|
||||
// The percentage of height of task to show between tasks
|
||||
private static final float VISIBLE_TASK_HEIGHT_BETWEEN_TASKS = 0.5f;
|
||||
// The percentage between the maxStackScroll and the maxScroll where a given scroll will still
|
||||
// snap back to the maxStackScroll instead of to the maxScroll (which shows the freeform
|
||||
// workspace)
|
||||
private static final float SNAP_TO_MAX_STACK_SCROLL_FACTOR = 0.3f;
|
||||
|
||||
// A report of the visibility state of the stack
|
||||
public class VisibilityReport {
|
||||
@@ -64,11 +68,9 @@ public class TaskStackViewLayoutAlgorithm {
|
||||
// This is the view bounds inset exactly by the search bar, but without the bottom inset
|
||||
// see RecentsConfiguration.getTaskStackBounds()
|
||||
public Rect mStackRect = new Rect();
|
||||
|
||||
// This is the task view bounds for layout (untransformed), the rect is top-aligned to the top
|
||||
// of the stack rect
|
||||
public Rect mTaskRect = new Rect();
|
||||
|
||||
// The bounds of the freeform workspace, the rect is top-aligned to the top of the stack rect
|
||||
public Rect mFreeformRect = new Rect();
|
||||
// This is the current system insets
|
||||
@@ -79,10 +81,14 @@ public class TaskStackViewLayoutAlgorithm {
|
||||
// The largest scroll progress, at this value, the front most task will be visible above the
|
||||
// navigation bar
|
||||
float mMaxScrollP;
|
||||
// The scroll progress at which the stack scroll ends and the overscroll begins. This serves
|
||||
// as the point at which we can show the freeform space.
|
||||
float mMaxStackScrollP;
|
||||
// The initial progress that the scroller is set
|
||||
// The scroll progress at which bottom of the first task of the stack is aligned with the bottom
|
||||
// of the stack
|
||||
float mStackEndScrollP;
|
||||
// The scroll progress that we actually want to scroll the user to when they want to go to the
|
||||
// end of the stack (it accounts for the nav bar, so that the bottom of the task is offset from
|
||||
// the bottom of the stack)
|
||||
float mPreferredStackEndScrollP;
|
||||
// The initial progress that the scroller is set when you first enter recents
|
||||
float mInitialScrollP;
|
||||
// The task progress for the front-most task in the stack
|
||||
float mFrontMostTaskP;
|
||||
@@ -96,20 +102,18 @@ public class TaskStackViewLayoutAlgorithm {
|
||||
float mTaskHeightPOffset;
|
||||
// The relative progress to ensure that the half task height is respected
|
||||
float mTaskHalfHeightPOffset;
|
||||
// The front-most task bottom offset
|
||||
int mStackBottomOffset;
|
||||
// The relative progress to ensure that the offset from the bottom of the stack to the bottom
|
||||
// of the task is respected
|
||||
float mTaskBottomPOffset;
|
||||
// The relative progress to ensure that the freeform workspace height is respected
|
||||
float mStackBottomPOffset;
|
||||
// The freeform workspace gap
|
||||
int mFreeformWorkspaceGapOffset;
|
||||
float mFreeformWorkspaceGapPOffset;
|
||||
// The relative progress to ensure that the freeform workspace height + gap + stack bottom
|
||||
// padding is respected
|
||||
int mFreeformWorkspaceOffset;
|
||||
float mFreeformWorkspacePOffset;
|
||||
// The front-most task bottom offset
|
||||
int mTaskBottomOffset;
|
||||
|
||||
// The number of cells in the freeform workspace
|
||||
int mFreeformCellXCount;
|
||||
int mFreeformCellYCount;
|
||||
// The width and height of the cells in the freeform workspace
|
||||
int mFreeformCellWidth;
|
||||
int mFreeformCellHeight;
|
||||
|
||||
// The last computed task counts
|
||||
int mNumStackTasks;
|
||||
@@ -121,14 +125,21 @@ public class TaskStackViewLayoutAlgorithm {
|
||||
// Optimization, allows for quick lookup of task -> progress
|
||||
HashMap<Task.TaskKey, Float> mTaskProgressMap = new HashMap<>();
|
||||
|
||||
// The freeform workspace layout
|
||||
FreeformWorkspaceLayoutAlgorithm mFreeformLayoutAlgorithm;
|
||||
|
||||
// Temporary task view transform
|
||||
TaskViewTransform mTmpTransform = new TaskViewTransform();
|
||||
|
||||
// Log function
|
||||
static ParametricCurve sCurve;
|
||||
|
||||
public TaskStackViewLayoutAlgorithm(Context context) {
|
||||
public TaskStackLayoutAlgorithm(Context context) {
|
||||
Resources res = context.getResources();
|
||||
mMinTranslationZ = res.getDimensionPixelSize(R.dimen.recents_task_view_z_min);
|
||||
mMaxTranslationZ = res.getDimensionPixelSize(R.dimen.recents_task_view_z_max);
|
||||
mContext = context;
|
||||
mFreeformLayoutAlgorithm = new FreeformWorkspaceLayoutAlgorithm();
|
||||
if (sCurve == null) {
|
||||
sCurve = new ParametricCurve(new ParametricCurve.CurveFunction() {
|
||||
// The large the XScale, the longer the flat area of the curve
|
||||
@@ -151,6 +162,11 @@ public class TaskStackViewLayoutAlgorithm {
|
||||
}, new ParametricCurve.ParametricCurveFunction() {
|
||||
@Override
|
||||
public float f(float p) {
|
||||
// Don't scale when there are freeform tasks
|
||||
if (mNumFreeformTasks > 0) {
|
||||
return 1f;
|
||||
}
|
||||
|
||||
if (p < 0) return STACK_PEEK_MIN_SCALE;
|
||||
if (p > 1) return 1f;
|
||||
float scaleRange = (1f - STACK_PEEK_MIN_SCALE);
|
||||
@@ -174,7 +190,7 @@ public class TaskStackViewLayoutAlgorithm {
|
||||
/**
|
||||
* Computes the stack and task rects.
|
||||
*/
|
||||
public void computeRects(Rect taskStackBounds) {
|
||||
public void initialize(Rect taskStackBounds) {
|
||||
RecentsConfiguration config = Recents.getConfiguration();
|
||||
int widthPadding = (int) (config.taskStackWidthPaddingPct * taskStackBounds.width());
|
||||
int heightPadding = mContext.getResources().getDimensionPixelSize(
|
||||
@@ -183,14 +199,17 @@ public class TaskStackViewLayoutAlgorithm {
|
||||
// Compute the stack rect, inset from the given task stack bounds
|
||||
mStackRect.set(taskStackBounds.left + widthPadding, taskStackBounds.top + heightPadding,
|
||||
taskStackBounds.right - widthPadding, taskStackBounds.bottom);
|
||||
mTaskBottomOffset = mSystemInsets.bottom + heightPadding;
|
||||
mStackBottomOffset = mSystemInsets.bottom + heightPadding;
|
||||
|
||||
// Compute the task rect, align it to the top-center square in the stack rect
|
||||
int size = Math.min(mStackRect.width(), mStackRect.height() - mTaskBottomOffset);
|
||||
int size = Math.min(mStackRect.width(), mStackRect.height() - mStackBottomOffset);
|
||||
int xOffset = (mStackRect.width() - size) / 2;
|
||||
mTaskRect.set(mStackRect.left + xOffset, mStackRect.top,
|
||||
mStackRect.right - xOffset, mStackRect.top + size);
|
||||
mFreeformRect.set(mTaskRect);
|
||||
|
||||
// Compute the freeform rect, align it to the top-left of the stack rect
|
||||
mFreeformRect.set(mStackRect);
|
||||
mFreeformRect.bottom = taskStackBounds.bottom - mStackBottomOffset;
|
||||
|
||||
// Compute the progress offsets
|
||||
int withinAffiliationOffset = mContext.getResources().getDimensionPixelSize(
|
||||
@@ -204,12 +223,17 @@ public class TaskStackViewLayoutAlgorithm {
|
||||
mStackRect);
|
||||
mTaskHalfHeightPOffset = sCurve.computePOffsetForScaledHeight(mTaskRect.height() / 2,
|
||||
mStackRect);
|
||||
mTaskBottomPOffset = sCurve.computePOffsetForHeight(mTaskBottomOffset, mStackRect);
|
||||
mFreeformWorkspacePOffset = sCurve.computePOffsetForHeight(mFreeformRect.height(),
|
||||
mStackBottomPOffset = sCurve.computePOffsetForHeight(mStackBottomOffset, mStackRect);
|
||||
mFreeformWorkspaceGapOffset = mStackBottomOffset;
|
||||
mFreeformWorkspaceGapPOffset = sCurve.computePOffsetForHeight(mFreeformWorkspaceGapOffset,
|
||||
mStackRect);
|
||||
mFreeformWorkspaceOffset = mFreeformWorkspaceGapOffset + mFreeformRect.height() +
|
||||
mStackBottomOffset;
|
||||
mFreeformWorkspacePOffset = sCurve.computePOffsetForHeight(mFreeformWorkspaceOffset,
|
||||
mStackRect);
|
||||
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "computeRects");
|
||||
Log.d(TAG, "initialize");
|
||||
Log.d(TAG, "\tarclength: " + sCurve.getArcLength());
|
||||
Log.d(TAG, "\tmStackRect: " + mStackRect);
|
||||
Log.d(TAG, "\tmTaskRect: " + mTaskRect);
|
||||
@@ -219,12 +243,14 @@ public class TaskStackViewLayoutAlgorithm {
|
||||
Log.d(TAG, "\tpBetweenAffiliateOffset: " + mBetweenAffiliationPOffset);
|
||||
Log.d(TAG, "\tmTaskHeightPOffset: " + mTaskHeightPOffset);
|
||||
Log.d(TAG, "\tmTaskHalfHeightPOffset: " + mTaskHalfHeightPOffset);
|
||||
Log.d(TAG, "\tmTaskBottomPOffset: " + mTaskBottomPOffset);
|
||||
Log.d(TAG, "\tmStackBottomPOffset: " + mStackBottomPOffset);
|
||||
Log.d(TAG, "\tmFreeformWorkspacePOffset: " + mFreeformWorkspacePOffset);
|
||||
Log.d(TAG, "\tmFreeformWorkspaceGapPOffset: " + mFreeformWorkspaceGapPOffset);
|
||||
|
||||
Log.d(TAG, "\ty at p=0: " + sCurve.pToX(0f, mStackRect));
|
||||
Log.d(TAG, "\ty at p=1: " + sCurve.pToX(1f, mStackRect));
|
||||
|
||||
for (int height = 0; height <= 1000; height += 50) {
|
||||
for (int height = 0; height <= 2000; height += 50) {
|
||||
float p = sCurve.computePOffsetForScaledHeight(height, mStackRect);
|
||||
float p2 = sCurve.computePOffsetForHeight(height, mStackRect);
|
||||
Log.d(TAG, "offset: " + height + ", " +
|
||||
@@ -236,20 +262,22 @@ public class TaskStackViewLayoutAlgorithm {
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the minimum and maximum scroll progress values. This method may be called before
|
||||
* the RecentsConfiguration is set, so we need to pass in the alt-tab state.
|
||||
* Computes the minimum and maximum scroll progress values and the progress values for each task
|
||||
* in the stack.
|
||||
*/
|
||||
void computeMinMaxScroll(ArrayList<Task> tasks) {
|
||||
void update(TaskStack stack) {
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "computeMinMaxScroll");
|
||||
Log.d(TAG, "update");
|
||||
}
|
||||
|
||||
// Clear the progress map
|
||||
mTaskProgressMap.clear();
|
||||
|
||||
// Return early if we have no tasks
|
||||
ArrayList<Task> tasks = stack.getTasks();
|
||||
if (tasks.isEmpty()) {
|
||||
mMinScrollP = mMaxScrollP = mMaxStackScrollP = 0;
|
||||
mFrontMostTaskP = 0;
|
||||
mMinScrollP = mMaxScrollP = mStackEndScrollP = mPreferredStackEndScrollP = 0;
|
||||
mNumStackTasks = mNumFreeformTasks = 0;
|
||||
return;
|
||||
}
|
||||
@@ -268,9 +296,6 @@ public class TaskStackViewLayoutAlgorithm {
|
||||
mNumStackTasks = stackTasks.size();
|
||||
mNumFreeformTasks = freeformTasks.size();
|
||||
|
||||
// TODO: In the case where there is only freeform tasks, then the scrolls should be set to
|
||||
// zero
|
||||
|
||||
if (!stackTasks.isEmpty()) {
|
||||
// Update the for each task from back to front.
|
||||
float pAtBackMostTaskTop = 0;
|
||||
@@ -289,52 +314,47 @@ public class TaskStackViewLayoutAlgorithm {
|
||||
}
|
||||
|
||||
mFrontMostTaskP = pAtFrontMostTaskTop;
|
||||
// Set the max scroll progress to the point at which the top of the front-most task
|
||||
// is aligned to the bottom of the stack (offset by nav bar, padding, and task height)
|
||||
mMaxStackScrollP = getBottomAlignedScrollProgress(pAtFrontMostTaskTop,
|
||||
mTaskBottomPOffset + mTaskHeightPOffset);
|
||||
// Set the stack end scroll progress to the point at which the bottom of the front-most
|
||||
// task is aligned to the bottom of the stack
|
||||
mStackEndScrollP = alignToStackBottom(pAtFrontMostTaskTop,
|
||||
mTaskHeightPOffset);
|
||||
// Set the preferred stack end scroll progress to the point where the bottom of the
|
||||
// front-most task is offset by the navbar and padding from the bottom of the stack
|
||||
mPreferredStackEndScrollP = mStackEndScrollP + mStackBottomPOffset;
|
||||
// Basically align the back-most task such that its progress is the same as the top of
|
||||
// the front most task at the max stack scroll
|
||||
mMinScrollP = getBottomAlignedScrollProgress(pAtBackMostTaskTop,
|
||||
mTaskBottomPOffset + mTaskHeightPOffset);
|
||||
mMinScrollP = alignToStackBottom(pAtBackMostTaskTop,
|
||||
mStackBottomPOffset + mTaskHeightPOffset);
|
||||
} else {
|
||||
// TODO: In the case where there is only freeform tasks, then the scrolls should be
|
||||
// set to zero
|
||||
}
|
||||
|
||||
if (!freeformTasks.isEmpty()) {
|
||||
// Calculate the cell width/height depending on the number of freeform tasks
|
||||
mFreeformCellXCount = Math.max(2, (int) Math.ceil(Math.sqrt(mNumFreeformTasks)));
|
||||
mFreeformCellYCount = Math.max(2, (int) Math.ceil((float) mNumFreeformTasks / mFreeformCellXCount));
|
||||
mFreeformCellWidth = mFreeformRect.width() / mFreeformCellXCount;
|
||||
mFreeformCellHeight = mFreeformRect.height() / mFreeformCellYCount;
|
||||
|
||||
// Put each of the tasks in the progress map at a fixed index (does not need to actually
|
||||
// map to a scroll position, just by index)
|
||||
int taskCount = freeformTasks.size();
|
||||
for (int i = 0; i < taskCount; i++) {
|
||||
Task task = freeformTasks.get(i);
|
||||
mTaskProgressMap.put(task.key, (mFrontMostTaskP + 1) + i);
|
||||
}
|
||||
|
||||
// The max scroll includes the freeform workspace offset. As the scroll progress exceeds
|
||||
// mMaxStackScrollP up to mMaxScrollP, the stack will translate upwards and the freeform
|
||||
// mStackEndScrollP up to mMaxScrollP, the stack will translate upwards and the freeform
|
||||
// workspace will be visible
|
||||
mMaxScrollP = mMaxStackScrollP + mFreeformWorkspacePOffset;
|
||||
mInitialScrollP = mMaxScrollP;
|
||||
mFreeformLayoutAlgorithm.update(freeformTasks, this);
|
||||
mMaxScrollP = mStackEndScrollP + mFreeformWorkspacePOffset;
|
||||
mInitialScrollP = isInitialStateFreeform(stack) ?
|
||||
mMaxScrollP : mPreferredStackEndScrollP;
|
||||
} else {
|
||||
mMaxScrollP = mMaxStackScrollP;
|
||||
mInitialScrollP = Math.max(mMinScrollP, mMaxStackScrollP - mTaskHalfHeightPOffset);
|
||||
mMaxScrollP = mPreferredStackEndScrollP;
|
||||
mInitialScrollP = Math.max(mMinScrollP, mMaxScrollP - mTaskHalfHeightPOffset);
|
||||
}
|
||||
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "mNumStackTasks: " + mNumStackTasks);
|
||||
Log.d(TAG, "mNumFreeformTasks: " + mNumFreeformTasks);
|
||||
Log.d(TAG, "mMinScrollP: " + mMinScrollP);
|
||||
Log.d(TAG, "mMaxStackScrollP: " + mMaxStackScrollP);
|
||||
Log.d(TAG, "mStackEndScrollP: " + mStackEndScrollP);
|
||||
Log.d(TAG, "mMaxScrollP: " + mMaxScrollP);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the maximum number of visible tasks and thumbnails. Requires that
|
||||
* computeMinMaxScroll() is called first.
|
||||
* update() is called first.
|
||||
*/
|
||||
public VisibilityReport computeStackVisibilityReport(ArrayList<Task> tasks) {
|
||||
// Ensure minimum visibility count
|
||||
@@ -380,7 +400,7 @@ public class TaskStackViewLayoutAlgorithm {
|
||||
prevScreenY = screenY;
|
||||
} else {
|
||||
// Once we hit the next front most task that does not have a visible thumbnail,
|
||||
// walk through remaining visible set
|
||||
// w alk through remaining visible set
|
||||
for (int j = i; j >= 0; j--) {
|
||||
numVisibleTasks++;
|
||||
progress = mTaskProgressMap.get(tasks.get(j).key) - mInitialScrollP;
|
||||
@@ -404,50 +424,42 @@ public class TaskStackViewLayoutAlgorithm {
|
||||
*/
|
||||
public TaskViewTransform getStackTransform(Task task, float stackScroll,
|
||||
TaskViewTransform transformOut, TaskViewTransform prevTransform) {
|
||||
// Return early if we have an invalid index
|
||||
if (task == null || !mTaskProgressMap.containsKey(task.key)) {
|
||||
transformOut.reset();
|
||||
if (mFreeformLayoutAlgorithm.isTransformAvailable(task, stackScroll, this)) {
|
||||
mFreeformLayoutAlgorithm.getTransform(task, stackScroll, transformOut, this);
|
||||
if (transformOut.visible) {
|
||||
getFreeformWorkspaceBounds(stackScroll, mTmpTransform);
|
||||
transformOut.translationY += mTmpTransform.translationY;
|
||||
transformOut.translationZ = mMaxTranslationZ;
|
||||
transformOut.rect.set(mTaskRect);
|
||||
transformOut.rect.offset(0, transformOut.translationY);
|
||||
Utilities.scaleRectAboutCenter(transformOut.rect, transformOut.scale);
|
||||
transformOut.p = 0;
|
||||
}
|
||||
return transformOut;
|
||||
} else {
|
||||
// Return early if we have an invalid index
|
||||
if (task == null || !mTaskProgressMap.containsKey(task.key)) {
|
||||
transformOut.reset();
|
||||
return transformOut;
|
||||
}
|
||||
return getStackTransform(mTaskProgressMap.get(task.key), stackScroll, transformOut,
|
||||
prevTransform);
|
||||
}
|
||||
return getStackTransform(mTaskProgressMap.get(task.key), stackScroll, transformOut,
|
||||
prevTransform);
|
||||
}
|
||||
|
||||
/** Update/get the transform */
|
||||
public TaskViewTransform getStackTransform(float taskProgress, float stackScroll,
|
||||
TaskViewTransform transformOut, TaskViewTransform prevTransform) {
|
||||
float stackOverscroll = (stackScroll - mMaxStackScrollP) / mFreeformWorkspacePOffset;
|
||||
int overscrollYOffset = 0;
|
||||
if (mNumFreeformTasks > 0) {
|
||||
overscrollYOffset = (int) (Math.max(0, stackOverscroll) * mFreeformRect.height());
|
||||
}
|
||||
|
||||
if ((mNumFreeformTasks > 0) && (stackScroll > mMaxStackScrollP) &&
|
||||
(taskProgress > mFrontMostTaskP)) {
|
||||
// This is a freeform task, so lay it out in the freeform workspace
|
||||
int taskIndex = Math.round(taskProgress - (mFrontMostTaskP + 1));
|
||||
int x = taskIndex % mFreeformCellXCount;
|
||||
int y = taskIndex / mFreeformCellXCount;
|
||||
int frontTaskBottom = mStackRect.height() - mTaskBottomOffset;
|
||||
float scale = (float) mFreeformCellWidth / mTaskRect.width();
|
||||
int scaleXOffset = (int) (((1f - scale) * mTaskRect.width()) / 2);
|
||||
int scaleYOffset = (int) (((1f - scale) * mTaskRect.height()) / 2);
|
||||
transformOut.scale = scale;
|
||||
transformOut.translationX = x * mFreeformCellWidth - scaleXOffset;
|
||||
transformOut.translationY = frontTaskBottom - overscrollYOffset +
|
||||
(y * mFreeformCellHeight) - scaleYOffset;
|
||||
transformOut.visible = true;
|
||||
return transformOut;
|
||||
|
||||
} else if (mNumStackTasks == 1) {
|
||||
if (mNumStackTasks == 1) {
|
||||
// Center the task in the stack, changing the scale will not follow the curve, but just
|
||||
// modulate some values directly
|
||||
float pTaskRelative = mMinScrollP - stackScroll;
|
||||
float scale = SINGLE_TASK_SCALE;
|
||||
int topOffset = (mStackRect.height() - mTaskBottomOffset - mTaskRect.height()) / 2;
|
||||
int topOffset = (mStackRect.height() - mTaskRect.height()) / 2;
|
||||
transformOut.scale = scale;
|
||||
transformOut.translationY = (int) (topOffset + (pTaskRelative * mStackRect.height())) -
|
||||
overscrollYOffset;
|
||||
transformOut.translationX = 0;
|
||||
transformOut.translationY = (int) (topOffset + (pTaskRelative * mStackRect.height()));
|
||||
transformOut.translationZ = mMaxTranslationZ;
|
||||
transformOut.rect.set(mTaskRect);
|
||||
transformOut.rect.offset(0, transformOut.translationY);
|
||||
@@ -457,11 +469,20 @@ public class TaskStackViewLayoutAlgorithm {
|
||||
return transformOut;
|
||||
|
||||
} else {
|
||||
float pTaskRelative = taskProgress - stackScroll;
|
||||
if (mNumFreeformTasks > 0) {
|
||||
pTaskRelative = Math.min(mMaxStackScrollP, pTaskRelative);
|
||||
// Once we scroll past the preferred stack end scroll, then we should start translating
|
||||
// the cards in screen space and lock their final state at the end stack progress
|
||||
int overscrollYOffset = 0;
|
||||
if (mNumFreeformTasks > 0 && stackScroll > mStackEndScrollP) {
|
||||
float stackOverscroll = (stackScroll - mPreferredStackEndScrollP) /
|
||||
(mFreeformWorkspacePOffset - mFreeformWorkspaceGapPOffset);
|
||||
overscrollYOffset = (int) (Math.max(0, stackOverscroll) *
|
||||
(mFreeformWorkspaceOffset - mFreeformWorkspaceGapPOffset));
|
||||
stackScroll = Math.min(mPreferredStackEndScrollP, stackScroll);
|
||||
}
|
||||
|
||||
float pTaskRelative = taskProgress - stackScroll;
|
||||
float pBounded = Math.max(0, Math.min(pTaskRelative, 1f));
|
||||
|
||||
// If the task top is outside of the bounds below the screen, then immediately reset it
|
||||
if (pTaskRelative > 1f) {
|
||||
transformOut.reset();
|
||||
@@ -480,6 +501,7 @@ public class TaskStackViewLayoutAlgorithm {
|
||||
float scale = sCurve.pToScale(pBounded);
|
||||
int scaleYOffset = (int) (((1f - scale) * mTaskRect.height()) / 2);
|
||||
transformOut.scale = scale;
|
||||
transformOut.translationX = 0;
|
||||
transformOut.translationY = sCurve.pToX(pBounded, mStackRect) - mStackRect.top -
|
||||
scaleYOffset - overscrollYOffset;
|
||||
transformOut.translationZ = Math.max(mMinTranslationZ,
|
||||
@@ -489,10 +511,30 @@ public class TaskStackViewLayoutAlgorithm {
|
||||
Utilities.scaleRectAboutCenter(transformOut.rect, transformOut.scale);
|
||||
transformOut.visible = true;
|
||||
transformOut.p = pTaskRelative;
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "getStackTransform (normal): " + taskProgress + ", " + stackScroll);
|
||||
Log.d(TAG, "\t" + transformOut);
|
||||
}
|
||||
|
||||
return transformOut;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether this stack should be initialized to show the freeform workspace or not.
|
||||
*/
|
||||
public boolean isInitialStateFreeform(TaskStack stack) {
|
||||
Task launchTarget = stack.getLaunchTarget();
|
||||
if (launchTarget != null) {
|
||||
return launchTarget.isFreeformTask();
|
||||
}
|
||||
Task frontTask = stack.getFrontMostTask();
|
||||
if (frontTask != null) {
|
||||
return frontTask.isFreeformTask();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update/get the transform
|
||||
*/
|
||||
@@ -503,17 +545,36 @@ public class TaskStackViewLayoutAlgorithm {
|
||||
return transformOut;
|
||||
}
|
||||
|
||||
if (stackScroll > mMaxStackScrollP) {
|
||||
float stackOverscroll = (stackScroll - mMaxStackScrollP) / mFreeformWorkspacePOffset;
|
||||
int overscrollYOffset = (int) (stackOverscroll * mFreeformRect.height());
|
||||
int frontTaskBottom = mStackRect.height() - mTaskBottomOffset;
|
||||
if (stackScroll > mStackEndScrollP) {
|
||||
// mStackEndScroll is the point at which the first stack task is bottom aligned with the
|
||||
// stack, so we offset from on the stack rect height.
|
||||
float stackOverscroll = (Math.max(0, stackScroll - mStackEndScrollP)) /
|
||||
mFreeformWorkspacePOffset;
|
||||
int overscrollYOffset = (int) (stackOverscroll * mFreeformWorkspaceOffset);
|
||||
transformOut.scale = 1f;
|
||||
transformOut.alpha = 1f;
|
||||
transformOut.translationY = mStackRect.height() + mFreeformWorkspaceGapOffset -
|
||||
overscrollYOffset;
|
||||
transformOut.rect.set(mFreeformRect);
|
||||
transformOut.rect.offset(0, transformOut.translationY);
|
||||
Utilities.scaleRectAboutCenter(transformOut.rect, transformOut.scale);
|
||||
transformOut.visible = true;
|
||||
transformOut.alpha =
|
||||
transformOut.translationY = frontTaskBottom - overscrollYOffset;
|
||||
}
|
||||
return transformOut;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the preferred maximum scroll position for a stack at the given {@param scroll}.
|
||||
*/
|
||||
public float getPreferredMaxScrollPosition(float scroll) {
|
||||
float maxStackScrollBounds = mStackEndScrollP + SNAP_TO_MAX_STACK_SCROLL_FACTOR *
|
||||
(mMaxScrollP - mStackEndScrollP);
|
||||
if (scroll < maxStackScrollBounds) {
|
||||
return mPreferredStackEndScrollP;
|
||||
}
|
||||
return mMaxScrollP;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the untransformed task view bounds.
|
||||
*/
|
||||
@@ -549,7 +610,12 @@ public class TaskStackViewLayoutAlgorithm {
|
||||
return -y;
|
||||
}
|
||||
|
||||
private float getBottomAlignedScrollProgress(float p, float pOffsetFromBottom) {
|
||||
private float alignToStackTop(float p) {
|
||||
// At scroll progress == p, then p is at the top of the stack
|
||||
return p;
|
||||
}
|
||||
|
||||
private float alignToStackBottom(float p, float pOffsetFromBottom) {
|
||||
// At scroll progress == p, then p is at the top of the stack
|
||||
// At scroll progress == p + 1, then p is at the bottom of the stack
|
||||
return p - (1 - pOffsetFromBottom);
|
||||
@@ -22,12 +22,12 @@ import android.content.Context;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.RectF;
|
||||
import android.graphics.drawable.ColorDrawable;
|
||||
import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.accessibility.AccessibilityEvent;
|
||||
import android.view.accessibility.AccessibilityNodeInfo;
|
||||
import android.widget.FrameLayout;
|
||||
@@ -79,11 +79,12 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
|
||||
}
|
||||
|
||||
TaskStack mStack;
|
||||
TaskStackViewLayoutAlgorithm mLayoutAlgorithm;
|
||||
TaskStackLayoutAlgorithm mLayoutAlgorithm;
|
||||
TaskStackViewFilterAlgorithm mFilterAlgorithm;
|
||||
TaskStackViewScroller mStackScroller;
|
||||
TaskStackViewTouchHandler mTouchHandler;
|
||||
TaskStackViewCallbacks mCb;
|
||||
ColorDrawable mFreeformWorkspaceBackground;
|
||||
ViewPool<TaskView, Task> mViewPool;
|
||||
ArrayList<TaskViewTransform> mCurrentTaskTransforms = new ArrayList<>();
|
||||
DozeTrigger mUIDozeTrigger;
|
||||
@@ -101,6 +102,8 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
|
||||
Rect mTmpRect = new Rect();
|
||||
RectF mTmpTaskRect = new RectF();
|
||||
TaskViewTransform mTmpTransform = new TaskViewTransform();
|
||||
TaskViewTransform mTmpStackBackTransform = new TaskViewTransform();
|
||||
TaskViewTransform mTmpStackFrontTransform = new TaskViewTransform();
|
||||
HashMap<Task, TaskView> mTmpTaskViewMap = new HashMap<>();
|
||||
ArrayList<TaskView> mTaskViews = new ArrayList<>();
|
||||
List<TaskView> mImmutableTaskViews = new ArrayList<>();
|
||||
@@ -122,7 +125,7 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
|
||||
setStack(stack);
|
||||
mViewPool = new ViewPool<>(context, this);
|
||||
mInflater = LayoutInflater.from(context);
|
||||
mLayoutAlgorithm = new TaskStackViewLayoutAlgorithm(context);
|
||||
mLayoutAlgorithm = new TaskStackLayoutAlgorithm(context);
|
||||
mFilterAlgorithm = new TaskStackViewFilterAlgorithm(this, mViewPool);
|
||||
mStackScroller = new TaskStackViewScroller(context, mLayoutAlgorithm);
|
||||
mStackScroller.setCallbacks(this);
|
||||
@@ -143,6 +146,8 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
|
||||
}
|
||||
});
|
||||
setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_YES);
|
||||
|
||||
mFreeformWorkspaceBackground = new ColorDrawable(0x33000000);
|
||||
}
|
||||
|
||||
/** Sets the callbacks */
|
||||
@@ -270,7 +275,7 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
|
||||
}
|
||||
|
||||
/** Returns the stack algorithm for this task stack. */
|
||||
public TaskStackViewLayoutAlgorithm getStackAlgorithm() {
|
||||
public TaskStackLayoutAlgorithm getStackAlgorithm() {
|
||||
return mLayoutAlgorithm;
|
||||
}
|
||||
|
||||
@@ -342,6 +347,11 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
|
||||
int[] visibleRange = mTmpVisibleRange;
|
||||
boolean isValidVisibleRange = updateStackTransforms(mCurrentTaskTransforms, tasks,
|
||||
stackScroll, visibleRange, false);
|
||||
boolean hasStackBackTransform = false;
|
||||
boolean hasStackFrontTransform = false;
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "visibleRange: " + visibleRange[0] + " to " + visibleRange[1]);
|
||||
}
|
||||
|
||||
// Return all the invisible children to the pool
|
||||
mTmpTaskViewMap.clear();
|
||||
@@ -381,11 +391,20 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
|
||||
// For items in the list, put them in start animating them from the
|
||||
// approriate ends of the list where they are expected to appear
|
||||
if (Float.compare(transform.p, 0f) <= 0) {
|
||||
mLayoutAlgorithm.getStackTransform(0f, 0f, mTmpTransform, null);
|
||||
if (!hasStackBackTransform) {
|
||||
hasStackBackTransform = true;
|
||||
mLayoutAlgorithm.getStackTransform(0f, 0f, mTmpStackBackTransform,
|
||||
null);
|
||||
}
|
||||
tv.updateViewPropertiesToTaskTransform(mTmpStackBackTransform, 0);
|
||||
} else {
|
||||
mLayoutAlgorithm.getStackTransform(1f, 0f, mTmpTransform, null);
|
||||
if (!hasStackFrontTransform) {
|
||||
hasStackFrontTransform = true;
|
||||
mLayoutAlgorithm.getStackTransform(1f, 0f, mTmpStackFrontTransform,
|
||||
null);
|
||||
}
|
||||
tv.updateViewPropertiesToTaskTransform(mTmpStackFrontTransform, 0);
|
||||
}
|
||||
tv.updateViewPropertiesToTaskTransform(mTmpTransform, 0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -403,6 +422,16 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
|
||||
}
|
||||
}
|
||||
|
||||
// Update the freeform workspace
|
||||
mLayoutAlgorithm.getFreeformWorkspaceBounds(stackScroll, mTmpTransform);
|
||||
if (mTmpTransform.visible) {
|
||||
mTmpTransform.rect.roundOut(mTmpRect);
|
||||
mFreeformWorkspaceBackground.setAlpha(255);
|
||||
mFreeformWorkspaceBackground.setBounds(mTmpRect);
|
||||
} else {
|
||||
mFreeformWorkspaceBackground.setAlpha(0);
|
||||
}
|
||||
|
||||
// Reset the request-synchronize params
|
||||
mStackViewsAnimationDuration = 0;
|
||||
mStackViewsDirty = false;
|
||||
@@ -460,7 +489,7 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
|
||||
/** Updates the min and max virtual scroll bounds */
|
||||
void updateMinMaxScroll(boolean boundScrollToNewMinMax) {
|
||||
// Compute the min and max scroll values
|
||||
mLayoutAlgorithm.computeMinMaxScroll(mStack.getTasks());
|
||||
mLayoutAlgorithm.update(mStack);
|
||||
|
||||
// Debug logging
|
||||
if (boundScrollToNewMinMax) {
|
||||
@@ -512,7 +541,7 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
|
||||
};
|
||||
|
||||
if (scrollToTask) {
|
||||
// TODO: Center the newly focused task view
|
||||
// TODO: Center the newly focused task view, only if not freeform
|
||||
float newScroll = mLayoutAlgorithm.getStackScrollForTask(newFocusedTask) - 0.5f;
|
||||
newScroll = mStackScroller.getBoundedStackScroll(newScroll);
|
||||
mStackScroller.animateScroll(mStackScroller.getStackScroll(), newScroll,
|
||||
@@ -633,7 +662,7 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
|
||||
/** Computes the stack and task rects */
|
||||
public void computeRects(Rect taskStackBounds) {
|
||||
// Compute the rects in the stack algorithm
|
||||
mLayoutAlgorithm.computeRects(taskStackBounds);
|
||||
mLayoutAlgorithm.initialize(taskStackBounds);
|
||||
|
||||
// Update the scroll bounds
|
||||
updateMinMaxScroll(false);
|
||||
@@ -652,7 +681,7 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
|
||||
* Computes the maximum number of visible tasks and thumbnails. Requires that
|
||||
* updateMinMaxScrollForStack() is called first.
|
||||
*/
|
||||
public TaskStackViewLayoutAlgorithm.VisibilityReport computeStackVisibilityReport() {
|
||||
public TaskStackLayoutAlgorithm.VisibilityReport computeStackVisibilityReport() {
|
||||
return mLayoutAlgorithm.computeStackVisibilityReport(mStack.getTasks());
|
||||
}
|
||||
|
||||
@@ -710,7 +739,7 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
|
||||
*/
|
||||
@Override
|
||||
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
|
||||
// Layout each of the children
|
||||
// Layout each of the TaskViews
|
||||
List<TaskView> taskViews = getTaskViews();
|
||||
int taskViewCount = taskViews.size();
|
||||
for (int i = 0; i < taskViewCount; i++) {
|
||||
@@ -720,10 +749,9 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
|
||||
} else {
|
||||
mTmpRect.setEmpty();
|
||||
}
|
||||
tv.layout(mLayoutAlgorithm.mTaskRect.left - mTmpRect.left,
|
||||
mLayoutAlgorithm.mTaskRect.top - mTmpRect.top,
|
||||
mLayoutAlgorithm.mTaskRect.right + mTmpRect.right,
|
||||
mLayoutAlgorithm.mTaskRect.bottom + mTmpRect.bottom);
|
||||
Rect taskRect = mLayoutAlgorithm.mTaskRect;
|
||||
tv.layout(taskRect.left - mTmpRect.left, taskRect.top - mTmpRect.top,
|
||||
taskRect.right + mTmpRect.right, taskRect.bottom + mTmpRect.bottom);
|
||||
}
|
||||
|
||||
if (mAwaitingFirstLayout) {
|
||||
@@ -737,17 +765,9 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
|
||||
int offscreenY = mLayoutAlgorithm.mStackRect.bottom;
|
||||
|
||||
// Find the launch target task
|
||||
Task launchTargetTask = null;
|
||||
Task launchTargetTask = mStack.getLaunchTarget();
|
||||
List<TaskView> taskViews = getTaskViews();
|
||||
int taskViewCount = taskViews.size();
|
||||
for (int i = taskViewCount - 1; i >= 0; i--) {
|
||||
TaskView tv = taskViews.get(i);
|
||||
Task task = tv.getTask();
|
||||
if (task.isLaunchTarget) {
|
||||
launchTargetTask = task;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Prepare the first view for its enter animation
|
||||
for (int i = taskViewCount - 1; i >= 0; i--) {
|
||||
@@ -755,7 +775,8 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
|
||||
Task task = tv.getTask();
|
||||
boolean occludesLaunchTarget = (launchTargetTask != null) &&
|
||||
launchTargetTask.group.isTaskAboveTask(task, launchTargetTask);
|
||||
tv.prepareEnterRecentsAnimation(task.isLaunchTarget, occludesLaunchTarget, offscreenY);
|
||||
tv.prepareEnterRecentsAnimation(task.isLaunchTarget, occludesLaunchTarget,
|
||||
offscreenY);
|
||||
}
|
||||
|
||||
// If the enter animation started already and we haven't completed a layout yet, do the
|
||||
@@ -794,17 +815,9 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
|
||||
|
||||
if (mStack.getTaskCount() > 0) {
|
||||
// Find the launch target task
|
||||
Task launchTargetTask = null;
|
||||
Task launchTargetTask = mStack.getLaunchTarget();
|
||||
List<TaskView> taskViews = getTaskViews();
|
||||
int taskViewCount = taskViews.size();
|
||||
for (int i = taskViewCount - 1; i >= 0; i--) {
|
||||
TaskView tv = taskViews.get(i);
|
||||
Task task = tv.getTask();
|
||||
if (task.isLaunchTarget) {
|
||||
launchTargetTask = task;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Animate all the task views into view
|
||||
for (int i = taskViewCount - 1; i >= 0; i--) {
|
||||
@@ -817,7 +830,8 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
|
||||
ctx.currentTaskOccludesLaunchTarget = (launchTargetTask != null) &&
|
||||
launchTargetTask.group.isTaskAboveTask(task, launchTargetTask);
|
||||
ctx.updateListener = mRequestUpdateClippingListener;
|
||||
mLayoutAlgorithm.getStackTransform(task, mStackScroller.getStackScroll(), ctx.currentTaskTransform, null);
|
||||
mLayoutAlgorithm.getStackTransform(task, mStackScroller.getStackScroll(),
|
||||
ctx.currentTaskTransform, null);
|
||||
tv.startEnterRecentsAnimation(ctx);
|
||||
}
|
||||
|
||||
@@ -898,6 +912,12 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
|
||||
@Override
|
||||
protected void dispatchDraw(Canvas canvas) {
|
||||
mLayersDisabled = false;
|
||||
|
||||
// Draw the freeform workspace background
|
||||
if (mFreeformWorkspaceBackground.getAlpha() > 0) {
|
||||
mFreeformWorkspaceBackground.draw(canvas);
|
||||
}
|
||||
|
||||
super.dispatchDraw(canvas);
|
||||
}
|
||||
|
||||
@@ -919,42 +939,44 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
|
||||
@Override
|
||||
public void onStackTaskRemoved(TaskStack stack, Task removedTask, boolean wasFrontMostTask,
|
||||
Task newFrontMostTask) {
|
||||
// Remove the view associated with this task, we can't rely on updateTransforms
|
||||
// to work here because the task is no longer in the list
|
||||
TaskView tv = getChildViewForTask(removedTask);
|
||||
if (tv != null) {
|
||||
mViewPool.returnViewToPool(tv);
|
||||
if (!removedTask.isFreeformTask()) {
|
||||
// Remove the view associated with this task, we can't rely on updateTransforms
|
||||
// to work here because the task is no longer in the list
|
||||
TaskView tv = getChildViewForTask(removedTask);
|
||||
if (tv != null) {
|
||||
mViewPool.returnViewToPool(tv);
|
||||
}
|
||||
|
||||
// Get the stack scroll of the task to anchor to (since we are removing something, the front
|
||||
// most task will be our anchor task)
|
||||
Task anchorTask = null;
|
||||
float prevAnchorTaskScroll = 0;
|
||||
boolean pullStackForward = stack.getTaskCount() > 0;
|
||||
if (pullStackForward) {
|
||||
anchorTask = mStack.getFrontMostTask();
|
||||
prevAnchorTaskScroll = mLayoutAlgorithm.getStackScrollForTask(anchorTask);
|
||||
}
|
||||
|
||||
// Update the min/max scroll and animate other task views into their new positions
|
||||
updateMinMaxScroll(true);
|
||||
|
||||
if (wasFrontMostTask) {
|
||||
// Since the max scroll progress is offset from the bottom of the stack, just scroll
|
||||
// to ensure that the new front most task is now fully visible
|
||||
mStackScroller.setStackScroll(mLayoutAlgorithm.mMaxScrollP);
|
||||
} else if (pullStackForward) {
|
||||
// Otherwise, offset the scroll by half the movement of the anchor task to allow the
|
||||
// tasks behind the removed task to move forward, and the tasks in front to move back
|
||||
float anchorTaskScroll = mLayoutAlgorithm.getStackScrollForTask(anchorTask);
|
||||
mStackScroller.setStackScroll(mStackScroller.getStackScroll() + (anchorTaskScroll
|
||||
- prevAnchorTaskScroll) / 2);
|
||||
mStackScroller.boundScroll();
|
||||
}
|
||||
|
||||
// Animate all the tasks into place
|
||||
requestSynchronizeStackViewsWithModel(200);
|
||||
}
|
||||
|
||||
// Get the stack scroll of the task to anchor to (since we are removing something, the front
|
||||
// most task will be our anchor task)
|
||||
Task anchorTask = null;
|
||||
float prevAnchorTaskScroll = 0;
|
||||
boolean pullStackForward = stack.getTaskCount() > 0;
|
||||
if (pullStackForward) {
|
||||
anchorTask = mStack.getFrontMostTask();
|
||||
prevAnchorTaskScroll = mLayoutAlgorithm.getStackScrollForTask(anchorTask);
|
||||
}
|
||||
|
||||
// Update the min/max scroll and animate other task views into their new positions
|
||||
updateMinMaxScroll(true);
|
||||
|
||||
if (wasFrontMostTask) {
|
||||
// Since the max scroll progress is offset from the bottom of the stack, just scroll
|
||||
// to ensure that the new front most task is now fully visible
|
||||
mStackScroller.setStackScroll(mLayoutAlgorithm.mMaxScrollP);
|
||||
} else if (pullStackForward) {
|
||||
// Otherwise, offset the scroll by half the movement of the anchor task to allow the
|
||||
// tasks behind the removed task to move forward, and the tasks in front to move back
|
||||
float anchorTaskScroll = mLayoutAlgorithm.getStackScrollForTask(anchorTask);
|
||||
mStackScroller.setStackScroll(mStackScroller.getStackScroll() + (anchorTaskScroll
|
||||
- prevAnchorTaskScroll) / 2);
|
||||
mStackScroller.boundScroll();
|
||||
}
|
||||
|
||||
// Animate all the tasks into place
|
||||
requestSynchronizeStackViewsWithModel(200);
|
||||
|
||||
// Update the new front most task
|
||||
if (newFrontMostTask != null) {
|
||||
TaskView frontTv = getChildViewForTask(newFrontMostTask);
|
||||
@@ -1103,7 +1125,6 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
|
||||
int insertIndex = -1;
|
||||
int taskIndex = mStack.indexOfTask(task);
|
||||
if (taskIndex != -1) {
|
||||
|
||||
List<TaskView> taskViews = getTaskViews();
|
||||
int taskViewCount = taskViews.size();
|
||||
for (int i = 0; i < taskViewCount; i++) {
|
||||
@@ -1252,7 +1273,9 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
|
||||
// the next task
|
||||
RecentsConfiguration config = Recents.getConfiguration();
|
||||
RecentsActivityLaunchState launchState = config.getLaunchState();
|
||||
setFocusedTask(taskIndex - 1, true /* scrollToTask */, launchState.launchedWithAltTab);
|
||||
setFocusedTask(taskIndex - 1,
|
||||
!mStack.getTasks().get(taskIndex - 1).isFreeformTask() /* scrollToTask */,
|
||||
launchState.launchedWithAltTab);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,7 +39,7 @@ public class TaskStackViewScroller {
|
||||
}
|
||||
|
||||
Context mContext;
|
||||
TaskStackViewLayoutAlgorithm mLayoutAlgorithm;
|
||||
TaskStackLayoutAlgorithm mLayoutAlgorithm;
|
||||
TaskStackViewScrollerCallbacks mCb;
|
||||
|
||||
float mStackScrollP;
|
||||
@@ -52,7 +52,7 @@ public class TaskStackViewScroller {
|
||||
|
||||
Interpolator mLinearOutSlowInInterpolator;
|
||||
|
||||
public TaskStackViewScroller(Context context, TaskStackViewLayoutAlgorithm layoutAlgorithm) {
|
||||
public TaskStackViewScroller(Context context, TaskStackLayoutAlgorithm layoutAlgorithm) {
|
||||
mContext = context;
|
||||
mScroller = new OverScroller(context);
|
||||
mLayoutAlgorithm = layoutAlgorithm;
|
||||
@@ -121,7 +121,8 @@ public class TaskStackViewScroller {
|
||||
|
||||
/** Returns the bounded stack scroll */
|
||||
float getBoundedStackScroll(float scroll) {
|
||||
return Math.max(mLayoutAlgorithm.mMinScrollP, Math.min(mLayoutAlgorithm.mMaxScrollP, scroll));
|
||||
return Math.max(mLayoutAlgorithm.mMinScrollP,
|
||||
Math.min(mLayoutAlgorithm.getPreferredMaxScrollPosition(scroll), scroll));
|
||||
}
|
||||
|
||||
/** Returns the amount that the absolute value of how much the scroll is out of bounds. */
|
||||
|
||||
@@ -16,8 +16,10 @@
|
||||
|
||||
package com.android.systemui.recents.views;
|
||||
|
||||
import android.animation.ValueAnimator;
|
||||
import android.content.Context;
|
||||
import android.content.res.Resources;
|
||||
import android.util.Log;
|
||||
import android.view.InputDevice;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.VelocityTracker;
|
||||
@@ -30,6 +32,8 @@ import com.android.systemui.recents.Constants;
|
||||
import com.android.systemui.recents.events.EventBus;
|
||||
import com.android.systemui.recents.events.activity.HideRecentsEvent;
|
||||
import com.android.systemui.recents.events.ui.DismissTaskViewEvent;
|
||||
import com.android.systemui.recents.misc.Utilities;
|
||||
import com.android.systemui.statusbar.FlingAnimationUtils;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@@ -37,7 +41,7 @@ import java.util.List;
|
||||
class TaskStackViewTouchHandler implements SwipeHelper.Callback {
|
||||
|
||||
private static final String TAG = "TaskStackViewTouchHandler";
|
||||
private static final boolean DEBUG = true;
|
||||
private static final boolean DEBUG = false;
|
||||
|
||||
private static int INACTIVE_POINTER_ID = -1;
|
||||
|
||||
@@ -45,6 +49,8 @@ class TaskStackViewTouchHandler implements SwipeHelper.Callback {
|
||||
TaskStackView mSv;
|
||||
TaskStackViewScroller mScroller;
|
||||
VelocityTracker mVelocityTracker;
|
||||
FlingAnimationUtils mFlingAnimUtils;
|
||||
ValueAnimator mScrollFlingAnimator;
|
||||
|
||||
boolean mIsScrolling;
|
||||
float mDownScrollP;
|
||||
@@ -74,6 +80,7 @@ class TaskStackViewTouchHandler implements SwipeHelper.Callback {
|
||||
mWindowTouchSlop = configuration.getScaledWindowTouchSlop();
|
||||
mSv = sv;
|
||||
mScroller = scroller;
|
||||
mFlingAnimUtils = new FlingAnimationUtils(context, 0.2f);
|
||||
|
||||
float densityScale = res.getDisplayMetrics().density;
|
||||
mOverscrollSize = res.getDimensionPixelSize(R.dimen.recents_stack_overscroll);
|
||||
@@ -140,7 +147,7 @@ class TaskStackViewTouchHandler implements SwipeHelper.Callback {
|
||||
return false;
|
||||
}
|
||||
|
||||
TaskStackViewLayoutAlgorithm layoutAlgorithm = mSv.mLayoutAlgorithm;
|
||||
final TaskStackLayoutAlgorithm layoutAlgorithm = mSv.mLayoutAlgorithm;
|
||||
int action = ev.getAction();
|
||||
switch (action & MotionEvent.ACTION_MASK) {
|
||||
case MotionEvent.ACTION_DOWN: {
|
||||
@@ -154,6 +161,7 @@ class TaskStackViewTouchHandler implements SwipeHelper.Callback {
|
||||
// Stop the current scroll if it is still flinging
|
||||
mScroller.stopScroller();
|
||||
mScroller.stopBoundScrollAnimation();
|
||||
Utilities.cancelAnimationWithoutCallbacks(mScrollFlingAnimator);
|
||||
|
||||
// Initialize the velocity tracker
|
||||
initOrResetVelocityTracker();
|
||||
@@ -189,6 +197,9 @@ class TaskStackViewTouchHandler implements SwipeHelper.Callback {
|
||||
float deltaP = layoutAlgorithm.getDeltaPForY(mDownY, y);
|
||||
float curScrollP = mDownScrollP + deltaP;
|
||||
mScroller.setStackScroll(curScrollP);
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "scroll: " + curScrollP);
|
||||
}
|
||||
}
|
||||
|
||||
mVelocityTracker.addMovement(ev);
|
||||
@@ -211,21 +222,53 @@ class TaskStackViewTouchHandler implements SwipeHelper.Callback {
|
||||
int activePointerIndex = ev.findPointerIndex(mActivePointerId);
|
||||
int y = (int) ev.getY(activePointerIndex);
|
||||
int velocity = (int) mVelocityTracker.getYVelocity(mActivePointerId);
|
||||
float curScrollP = mScroller.getStackScroll();
|
||||
if (mIsScrolling) {
|
||||
if (mScroller.isScrollOutOfBounds()) {
|
||||
// Animate the scroll back into bounds
|
||||
boolean hasFreeformTasks = mSv.mStack.hasFreeformTasks();
|
||||
if (hasFreeformTasks && velocity > 0 &&
|
||||
curScrollP > layoutAlgorithm.mStackEndScrollP) {
|
||||
// Snap to workspace
|
||||
float finalY = mDownY + layoutAlgorithm.getYForDeltaP(mDownScrollP,
|
||||
layoutAlgorithm.mPreferredStackEndScrollP);
|
||||
mScrollFlingAnimator = ValueAnimator.ofInt(y, (int) finalY);
|
||||
mScrollFlingAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
|
||||
@Override
|
||||
public void onAnimationUpdate(ValueAnimator animation) {
|
||||
float deltaP = layoutAlgorithm.getDeltaPForY(mDownY,
|
||||
(Integer) animation.getAnimatedValue());
|
||||
float scroll = mDownScrollP + deltaP;
|
||||
mScroller.setStackScroll(scroll);
|
||||
}
|
||||
});
|
||||
mFlingAnimUtils.apply(mScrollFlingAnimator, y, finalY, velocity);
|
||||
mScrollFlingAnimator.start();
|
||||
} else if (hasFreeformTasks && velocity < 0 &&
|
||||
curScrollP > (layoutAlgorithm.mStackEndScrollP -
|
||||
layoutAlgorithm.mTaskHalfHeightPOffset)) {
|
||||
// Snap to stack
|
||||
float finalY = mDownY + layoutAlgorithm.getYForDeltaP(mDownScrollP,
|
||||
layoutAlgorithm.mMaxScrollP);
|
||||
mScrollFlingAnimator = ValueAnimator.ofInt(y, (int) finalY);
|
||||
mScrollFlingAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
|
||||
@Override
|
||||
public void onAnimationUpdate(ValueAnimator animation) {
|
||||
float deltaP = layoutAlgorithm.getDeltaPForY(mDownY,
|
||||
(Integer) animation.getAnimatedValue());
|
||||
float scroll = mDownScrollP + deltaP;
|
||||
mScroller.setStackScroll(scroll);
|
||||
}
|
||||
});
|
||||
mFlingAnimUtils.apply(mScrollFlingAnimator, y, finalY, velocity);
|
||||
mScrollFlingAnimator.start();
|
||||
} else if (mScroller.isScrollOutOfBounds()) {
|
||||
mScroller.animateBoundScroll();
|
||||
} else if (Math.abs(velocity) > mMinimumVelocity) {
|
||||
float deltaP = layoutAlgorithm.getDeltaPForY(mDownY, y);
|
||||
float curScrollP = mDownScrollP + deltaP;
|
||||
float downToCurY = mDownY + layoutAlgorithm.getYForDeltaP(mDownScrollP,
|
||||
curScrollP);
|
||||
float downToMinY = mDownY + layoutAlgorithm.getYForDeltaP(mDownScrollP,
|
||||
layoutAlgorithm.mMaxScrollP);
|
||||
float downToMaxY = mDownY + layoutAlgorithm.getYForDeltaP(mDownScrollP,
|
||||
float minY = mDownY + layoutAlgorithm.getYForDeltaP(mDownScrollP,
|
||||
layoutAlgorithm.mPreferredStackEndScrollP);
|
||||
float maxY = mDownY + layoutAlgorithm.getYForDeltaP(mDownScrollP,
|
||||
layoutAlgorithm.mMinScrollP);
|
||||
mScroller.fling(mDownScrollP, mDownY, (int) downToCurY, velocity,
|
||||
(int) downToMinY, (int) downToMaxY, mOverscrollSize);
|
||||
mScroller.fling(mDownScrollP, mDownY, y, velocity, (int) minY, (int) maxY,
|
||||
mOverscrollSize);
|
||||
mSv.invalidate();
|
||||
}
|
||||
} else if (mActiveTaskView == null) {
|
||||
@@ -239,10 +282,6 @@ class TaskStackViewTouchHandler implements SwipeHelper.Callback {
|
||||
break;
|
||||
}
|
||||
case MotionEvent.ACTION_CANCEL: {
|
||||
if (mScroller.isScrollOutOfBounds()) {
|
||||
// Animate the scroll back into bounds
|
||||
mScroller.animateBoundScroll();
|
||||
}
|
||||
mActivePointerId = INACTIVE_POINTER_ID;
|
||||
mIsScrolling = false;
|
||||
recycleVelocityTracker();
|
||||
@@ -308,9 +347,6 @@ class TaskStackViewTouchHandler implements SwipeHelper.Callback {
|
||||
|
||||
@Override
|
||||
public boolean canChildBeDismissed(View v) {
|
||||
if (v instanceof TaskView) {
|
||||
return !((TaskView) v).getTask().isFreeformTask();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -552,7 +552,11 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks,
|
||||
* view.
|
||||
*/
|
||||
boolean shouldClipViewInStack() {
|
||||
return mClipViewInStack && (getVisibility() == View.VISIBLE);
|
||||
// Never clip for freeform tasks or if invisible
|
||||
if (mTask.isFreeformTask() || getVisibility() != View.VISIBLE) {
|
||||
return false;
|
||||
}
|
||||
return mClipViewInStack;
|
||||
}
|
||||
|
||||
/** Sets whether this view should be clipped, or clipped against. */
|
||||
|
||||
@@ -255,6 +255,10 @@ public class TaskViewHeader extends FrameLayout
|
||||
mApplicationIcon.setImageDrawable(null);
|
||||
mApplicationIcon.setOnClickListener(null);
|
||||
mMoveTaskButton.setOnClickListener(null);
|
||||
|
||||
// Stop any focus animations
|
||||
Utilities.cancelAnimationWithoutCallbacks(mFocusAnimator);
|
||||
mBackground.jumpToCurrentState();
|
||||
}
|
||||
|
||||
/** Updates the resize task bar button. */
|
||||
@@ -370,8 +374,9 @@ public class TaskViewHeader extends FrameLayout
|
||||
boolean isRunning = false;
|
||||
if (mFocusAnimator != null) {
|
||||
isRunning = mFocusAnimator.isRunning();
|
||||
Utilities.cancelAnimationWithoutCallbacks(mFocusAnimator);
|
||||
}
|
||||
Utilities.cancelAnimationWithoutCallbacks(mFocusAnimator);
|
||||
mBackground.jumpToCurrentState();
|
||||
|
||||
if (focused) {
|
||||
// If we are not animating the visible state, just return
|
||||
|
||||
Reference in New Issue
Block a user