Merge changes If7b8ed3f,I309c3825,Iafd06419,I59f73caf into nyc-dev

* changes:
  Fixes several animation issues related to a dismissing task.
  Pipe the dismiss button logic through the touch handler.
  Skip scroll-to animation when undocking and there are no tasks.
  Fixing issue with docking being disallowed for secondary user.
This commit is contained in:
Winson Chung
2016-05-03 21:57:01 +00:00
committed by Android (Google) Code Review
10 changed files with 132 additions and 54 deletions

View File

@@ -86,7 +86,7 @@ public class DividerSnapAlgorithm {
return new DividerSnapAlgorithm(ctx.getResources(), return new DividerSnapAlgorithm(ctx.getResources(),
displayInfo.logicalWidth, displayInfo.logicalHeight, displayInfo.logicalWidth, displayInfo.logicalHeight,
dividerWindowWidth - 2 * dividerInsets, dividerWindowWidth - 2 * dividerInsets,
ctx.getResources().getConfiguration().orientation ctx.getApplicationContext().getResources().getConfiguration().orientation
== Configuration.ORIENTATION_PORTRAIT, == Configuration.ORIENTATION_PORTRAIT,
insets); insets);
} }

View File

@@ -451,11 +451,13 @@ public class RecentsActivity extends Activity implements ViewTreeObserver.OnPreD
TaskStack stack = loadPlan.getTaskStack(); TaskStack stack = loadPlan.getTaskStack();
int numStackTasks = stack.getStackTaskCount(); int numStackTasks = stack.getStackTaskCount();
boolean showDeferredAnimation = numStackTasks > 0;
EventBus.getDefault().send(new ConfigurationChangedEvent(true /* fromMultiWindow */, EventBus.getDefault().send(new ConfigurationChangedEvent(true /* fromMultiWindow */,
false /* fromDeviceOrientationChange */, false /* fromDisplayDensityChange */, false /* fromDeviceOrientationChange */, false /* fromDisplayDensityChange */,
numStackTasks > 0)); numStackTasks > 0));
EventBus.getDefault().send(new MultiWindowStateChangedEvent(isInMultiWindowMode, stack)); EventBus.getDefault().send(new MultiWindowStateChangedEvent(isInMultiWindowMode,
showDeferredAnimation, stack));
} }
@Override @Override

View File

@@ -25,10 +25,14 @@ import com.android.systemui.recents.model.TaskStack;
public class MultiWindowStateChangedEvent extends EventBus.AnimatedEvent { public class MultiWindowStateChangedEvent extends EventBus.AnimatedEvent {
public final boolean inMultiWindow; public final boolean inMultiWindow;
// This flag is only used when undocking a task
public final boolean showDeferredAnimation;
public final TaskStack stack; public final TaskStack stack;
public MultiWindowStateChangedEvent(boolean inMultiWindow, TaskStack stack) { public MultiWindowStateChangedEvent(boolean inMultiWindow, boolean showDeferredAnimation,
TaskStack stack) {
this.inMultiWindow = inMultiWindow; this.inMultiWindow = inMultiWindow;
this.showDeferredAnimation = showDeferredAnimation;
this.stack = stack; this.stack = stack;
} }
} }

View File

@@ -18,6 +18,7 @@ package com.android.systemui.recents.events.ui;
import com.android.systemui.recents.events.EventBus; import com.android.systemui.recents.events.EventBus;
import com.android.systemui.recents.model.Task; import com.android.systemui.recents.model.Task;
import com.android.systemui.recents.views.AnimationProps;
import com.android.systemui.recents.views.TaskView; import com.android.systemui.recents.views.TaskView;
/** /**
@@ -27,9 +28,11 @@ public class TaskViewDismissedEvent extends EventBus.Event {
public final Task task; public final Task task;
public final TaskView taskView; public final TaskView taskView;
public final AnimationProps animation;
public TaskViewDismissedEvent(Task task, TaskView taskView) { public TaskViewDismissedEvent(Task task, TaskView taskView, AnimationProps animation) {
this.task = task; this.task = task;
this.taskView = taskView; this.taskView = taskView;
this.animation = animation;
} }
} }

View File

@@ -193,7 +193,7 @@ public class RecentsViewTouchHandler {
} }
public final void onBusEvent(ConfigurationChangedEvent event) { public final void onBusEvent(ConfigurationChangedEvent event) {
if (event.fromDisplayDensityChange) { if (event.fromDisplayDensityChange || event.fromDeviceOrientationChange) {
updateSnapAlgorithm(); updateSnapAlgorithm();
} }
} }

View File

@@ -19,6 +19,7 @@ package com.android.systemui.recents.views;
import android.animation.Animator; import android.animation.Animator;
import android.animation.AnimatorListenerAdapter; import android.animation.AnimatorListenerAdapter;
import android.animation.TimeInterpolator; import android.animation.TimeInterpolator;
import android.animation.ValueAnimator;
import android.content.Context; import android.content.Context;
import android.content.res.Configuration; import android.content.res.Configuration;
import android.content.res.Resources; import android.content.res.Resources;
@@ -309,6 +310,11 @@ public class TaskStackAnimationHelper {
for (int i = 0; i < taskViewCount; i++) { for (int i = 0; i < taskViewCount; i++) {
int taskIndexFromFront = taskViewCount - i - 1; int taskIndexFromFront = taskViewCount - i - 1;
TaskView tv = taskViews.get(i); TaskView tv = taskViews.get(i);
Task task = tv.getTask();
if (mStackView.isIgnoredTask(task)) {
continue;
}
// Animate the tasks down // Animate the tasks down
AnimationProps taskAnimation; AnimationProps taskAnimation;
@@ -384,29 +390,29 @@ public class TaskStackAnimationHelper {
*/ */
public void startDeleteTaskAnimation(final TaskView deleteTaskView, public void startDeleteTaskAnimation(final TaskView deleteTaskView,
final ReferenceCountedTrigger postAnimationTrigger) { final ReferenceCountedTrigger postAnimationTrigger) {
Resources res = mStackView.getResources(); TaskStackViewTouchHandler touchHandler = mStackView.getTouchHandler();
TaskStackLayoutAlgorithm stackLayout = mStackView.getStackAlgorithm(); touchHandler.onBeginManualDrag(deleteTaskView);
int offscreenXOffset = mStackView.getMeasuredWidth() - stackLayout.mTaskRect.left; postAnimationTrigger.increment();
postAnimationTrigger.addLastDecrementRunnable(() -> {
touchHandler.onChildDismissed(deleteTaskView);
});
// Disabling clipping with the stack while the view is animating away, this will get final float dismissSize = touchHandler.getScaledDismissSize();
// restored when the task is next picked up from the view pool ValueAnimator animator = ValueAnimator.ofFloat(0f, 1f);
deleteTaskView.setClipViewInStack(false); animator.setDuration(400);
animator.addUpdateListener((animation) -> {
// Compose the new animation and transform and star the animation float progress = (Float) animation.getAnimatedValue();
AnimationProps taskAnimation = new AnimationProps(DISMISS_TASK_DURATION, deleteTaskView.setTranslationX(progress * dismissSize);
Interpolators.ALPHA_OUT, new AnimatorListenerAdapter() { touchHandler.updateSwipeProgress(deleteTaskView, true, progress);
});
animator.addListener(new AnimatorListenerAdapter() {
@Override @Override
public void onAnimationEnd(Animator animation) { public void onAnimationEnd(Animator animation) {
postAnimationTrigger.decrement(); postAnimationTrigger.decrement();
} }
}); });
postAnimationTrigger.increment(); animator.start();
mTmpTransform.fillIn(deleteTaskView);
mTmpTransform.alpha = 0f;
mTmpTransform.rect.offset(offscreenXOffset, 0);
mStackView.updateTaskViewToTransform(deleteTaskView, mTmpTransform, taskAnimation);
} }
/** /**
@@ -419,7 +425,6 @@ public class TaskStackAnimationHelper {
int offscreenXOffset = mStackView.getMeasuredWidth() - stackLayout.mTaskRect.left; int offscreenXOffset = mStackView.getMeasuredWidth() - stackLayout.mTaskRect.left;
int taskViewCount = taskViews.size(); int taskViewCount = taskViews.size();
for (int i = taskViewCount - 1; i >= 0; i--) { for (int i = taskViewCount - 1; i >= 0; i--) {
TaskView tv = taskViews.get(i); TaskView tv = taskViews.get(i);
int taskIndexFromFront = taskViewCount - i - 1; int taskIndexFromFront = taskViewCount - i - 1;

View File

@@ -623,6 +623,24 @@ public class TaskStackLayoutAlgorithm {
} }
} }
/**
* Adds and override task progress for the given task when transitioning from focused to
* unfocused state.
*/
public void addUnfocusedTaskOverride(TaskView taskView, float stackScroll) {
mFocusedRange.offset(stackScroll);
mUnfocusedRange.offset(stackScroll);
Task task = taskView.getTask();
int top = taskView.getTop() - mTaskRect.top;
float focusedRangeX = getNormalizedXFromFocusedY(top, FROM_TOP);
float unfocusedRangeX = getNormalizedXFromUnfocusedY(top, FROM_TOP);
float unfocusedTaskProgress = stackScroll + mUnfocusedRange.getAbsoluteX(unfocusedRangeX);
if (Float.compare(focusedRangeX, unfocusedRangeX) != 0) {
mTaskIndexOverrideMap.put(task.key.id, unfocusedTaskProgress);
}
}
public void clearUnfocusedTaskOverrides() { public void clearUnfocusedTaskOverrides() {
mTaskIndexOverrideMap.clear(); mTaskIndexOverrideMap.clear();
} }

View File

@@ -419,6 +419,13 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
return mLayoutAlgorithm; return mLayoutAlgorithm;
} }
/**
* Returns the touch handler for this task stack.
*/
public TaskStackViewTouchHandler getTouchHandler() {
return mTouchHandler;
}
/** /**
* Adds a task to the ignored set. * Adds a task to the ignored set.
*/ */
@@ -1664,7 +1671,7 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
public final void onBusEvent(DismissRecentsToHomeAnimationStarted event) { public final void onBusEvent(DismissRecentsToHomeAnimationStarted event) {
// Stop any scrolling // Stop any scrolling
mTouchHandler.finishAnimations(); mTouchHandler.cancelNonDismissTaskAnimations();
mStackScroller.stopScroller(); mStackScroller.stopScroller();
mStackScroller.stopBoundScrollAnimation(); mStackScroller.stopBoundScrollAnimation();
cancelDeferredTaskViewLayoutAnimation(); cancelDeferredTaskViewLayoutAnimation();
@@ -1722,8 +1729,7 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
R.string.accessibility_recents_item_dismissed, event.task.title)); R.string.accessibility_recents_item_dismissed, event.task.title));
// Remove the task from the stack // Remove the task from the stack
mStack.removeTask(event.task, new AnimationProps(DEFAULT_SYNC_STACK_DURATION, mStack.removeTask(event.task, event.animation, false /* fromDockGesture */);
Interpolators.FAST_OUT_SLOW_IN), false /* fromDockGesture */);
EventBus.getDefault().send(new DeleteTaskDataEvent(event.task)); EventBus.getDefault().send(new DeleteTaskDataEvent(event.task));
MetricsLogger.action(getContext(), MetricsEvent.OVERVIEW_DISMISS, MetricsLogger.action(getContext(), MetricsEvent.OVERVIEW_DISMISS,
@@ -1938,7 +1944,7 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
} }
public final void onBusEvent(final MultiWindowStateChangedEvent event) { public final void onBusEvent(final MultiWindowStateChangedEvent event) {
if (event.inMultiWindow) { if (event.inMultiWindow || !event.showDeferredAnimation) {
setTasks(event.stack, true /* allowNotifyStackChanges */); setTasks(event.stack, true /* allowNotifyStackChanges */);
} else { } else {
// Reset the launch state before handling the multiwindow change // Reset the launch state before handling the multiwindow change

View File

@@ -32,7 +32,6 @@ import android.view.ViewConfiguration;
import android.view.ViewDebug; import android.view.ViewDebug;
import android.view.ViewParent; import android.view.ViewParent;
import android.view.animation.Interpolator; import android.view.animation.Interpolator;
import android.view.animation.PathInterpolator;
import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.MetricsProto.MetricsEvent; import com.android.internal.logging.MetricsProto.MetricsEvent;
@@ -189,15 +188,30 @@ class TaskStackViewTouchHandler implements SwipeHelper.Callback {
} }
/** /**
* Finishes all scroll-fling and swipe animations currently running. * Finishes all scroll-fling and non-dismissing animations currently running.
*/ */
public void finishAnimations() { public void cancelNonDismissTaskAnimations() {
Utilities.cancelAnimationWithoutCallbacks(mScrollFlingAnimator); Utilities.cancelAnimationWithoutCallbacks(mScrollFlingAnimator);
ArrayMap<View, Animator> existingAnimators = new ArrayMap<>(mSwipeHelperAnimations); if (!mSwipeHelperAnimations.isEmpty()) {
for (int i = 0; i < existingAnimators.size(); i++) { // For the non-dismissing tasks, freeze the position into the task overrides
existingAnimators.get(existingAnimators.keyAt(i)).end(); List<TaskView> taskViews = mSv.getTaskViews();
for (int i = taskViews.size() - 1; i >= 0; i--) {
TaskView tv = taskViews.get(i);
if (mSv.isIgnoredTask(tv.getTask())) {
continue;
}
tv.cancelTransformAnimation();
mSv.getStackAlgorithm().addUnfocusedTaskOverride(tv, mTargetStackScroll);
}
mSv.getStackAlgorithm().setFocusState(TaskStackLayoutAlgorithm.STATE_UNFOCUSED);
// Update the scroll to the final scroll position from onBeginDrag()
mSv.getScroller().setStackScroll(mTargetStackScroll, null);
mSwipeHelperAnimations.clear();
} }
mSwipeHelperAnimations.clear(); mActiveTaskView = null;
} }
private boolean handleTouchEvent(MotionEvent ev) { private boolean handleTouchEvent(MotionEvent ev) {
@@ -210,6 +224,13 @@ class TaskStackViewTouchHandler implements SwipeHelper.Callback {
int action = ev.getAction(); int action = ev.getAction();
switch (action & MotionEvent.ACTION_MASK) { switch (action & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN: { case MotionEvent.ACTION_DOWN: {
// Stop the current scroll if it is still flinging
mScroller.stopScroller();
mScroller.stopBoundScrollAnimation();
mScroller.resetDeltaScroll();
cancelNonDismissTaskAnimations();
mSv.cancelDeferredTaskViewLayoutAnimation();
// Save the touch down info // Save the touch down info
mDownX = (int) ev.getX(); mDownX = (int) ev.getX();
mDownY = (int) ev.getY(); mDownY = (int) ev.getY();
@@ -218,13 +239,6 @@ class TaskStackViewTouchHandler implements SwipeHelper.Callback {
mActivePointerId = ev.getPointerId(0); mActivePointerId = ev.getPointerId(0);
mActiveTaskView = findViewAtPoint(mDownX, mDownY); mActiveTaskView = findViewAtPoint(mDownX, mDownY);
// Stop the current scroll if it is still flinging
mSv.cancelDeferredTaskViewLayoutAnimation();
mScroller.stopScroller();
mScroller.stopBoundScrollAnimation();
mScroller.resetDeltaScroll();
finishAnimations();
// Initialize the velocity tracker // Initialize the velocity tracker
initOrResetVelocityTracker(); initOrResetVelocityTracker();
mVelocityTracker.addMovement(ev); mVelocityTracker.addMovement(ev);
@@ -431,8 +445,18 @@ class TaskStackViewTouchHandler implements SwipeHelper.Callback {
public boolean canChildBeDismissed(View v) { public boolean canChildBeDismissed(View v) {
// Disallow dismissing an already dismissed task // Disallow dismissing an already dismissed task
TaskView tv = (TaskView) v; TaskView tv = (TaskView) v;
Task task = tv.getTask();
return !mSwipeHelperAnimations.containsKey(v) && return !mSwipeHelperAnimations.containsKey(v) &&
(mSv.getStack().indexOfStackTask(tv.getTask()) != -1); (mSv.getStack().indexOfStackTask(task) != -1);
}
/**
* Starts a manual drag that goes through the same swipe helper path.
*/
public void onBeginManualDrag(TaskView v) {
mActiveTaskView = v;
mSwipeHelperAnimations.put(v, null);
onBeginDrag(v);
} }
@Override @Override
@@ -453,7 +477,7 @@ class TaskStackViewTouchHandler implements SwipeHelper.Callback {
mSv.addIgnoreTask(tv.getTask()); mSv.addIgnoreTask(tv.getTask());
// Determine if we are animating the other tasks while dismissing this task // Determine if we are animating the other tasks while dismissing this task
mCurrentTasks = mSv.getStack().getStackTasks(); mCurrentTasks = new ArrayList<Task>(mSv.getStack().getStackTasks());
MutableBoolean isFrontMostTask = new MutableBoolean(false); MutableBoolean isFrontMostTask = new MutableBoolean(false);
Task anchorTask = mSv.findAnchorTask(mCurrentTasks, isFrontMostTask); Task anchorTask = mSv.findAnchorTask(mCurrentTasks, isFrontMostTask);
TaskStackLayoutAlgorithm layoutAlgorithm = mSv.getStackAlgorithm(); TaskStackLayoutAlgorithm layoutAlgorithm = mSv.getStackAlgorithm();
@@ -513,7 +537,12 @@ class TaskStackViewTouchHandler implements SwipeHelper.Callback {
@Override @Override
public boolean updateSwipeProgress(View v, boolean dismissable, float swipeProgress) { public boolean updateSwipeProgress(View v, boolean dismissable, float swipeProgress) {
updateTaskViewTransforms(Interpolators.FAST_OUT_SLOW_IN.getInterpolation(swipeProgress)); // Only update the swipe progress for the surrounding tasks if the dismiss animation was not
// preempted from a call to cancelNonDismissTaskAnimations
if (mActiveTaskView == v || mSwipeHelperAnimations.containsKey(v)) {
updateTaskViewTransforms(
Interpolators.FAST_OUT_SLOW_IN.getInterpolation(swipeProgress));
}
return true; return true;
} }
@@ -528,15 +557,24 @@ class TaskStackViewTouchHandler implements SwipeHelper.Callback {
tv.setClipViewInStack(true); tv.setClipViewInStack(true);
// Re-enable touch events from this task view // Re-enable touch events from this task view
tv.setTouchEnabled(true); tv.setTouchEnabled(true);
// Remove the task view from the stack // Remove the task view from the stack, ignoring the animation if we've started dragging
EventBus.getDefault().send(new TaskViewDismissedEvent(tv.getTask(), tv)); // again
// Update the scroll to the final scroll position from onBeginDrag() EventBus.getDefault().send(new TaskViewDismissedEvent(tv.getTask(), tv,
mSv.getScroller().setStackScroll(mTargetStackScroll, null); mSwipeHelperAnimations.containsKey(v)
// Update the focus state to the final focus state ? new AnimationProps(TaskStackView.DEFAULT_SYNC_STACK_DURATION,
mSv.getStackAlgorithm().setFocusState(TaskStackLayoutAlgorithm.STATE_UNFOCUSED); Interpolators.FAST_OUT_SLOW_IN)
mSv.getStackAlgorithm().clearUnfocusedTaskOverrides(); : null));
// Stop tracking this deletion animation // Only update the final scroll and layout state (set in onBeginDrag()) if the dismiss
mSwipeHelperAnimations.remove(v); // animation was not preempted from a call to cancelNonDismissTaskAnimations
if (mSwipeHelperAnimations.containsKey(v)) {
// Update the scroll to the final scroll position
mSv.getScroller().setStackScroll(mTargetStackScroll, null);
// Update the focus state to the final focus state
mSv.getStackAlgorithm().setFocusState(TaskStackLayoutAlgorithm.STATE_UNFOCUSED);
mSv.getStackAlgorithm().clearUnfocusedTaskOverrides();
// Stop tracking this deletion animation
mSwipeHelperAnimations.remove(v);
}
// Keep track of deletions by keyboard // Keep track of deletions by keyboard
MetricsLogger.histogram(tv.getContext(), "overview_task_dismissed_source", MetricsLogger.histogram(tv.getContext(), "overview_task_dismissed_source",
Constants.Metrics.DismissSourceSwipeGesture); Constants.Metrics.DismissSourceSwipeGesture);
@@ -631,7 +669,7 @@ class TaskStackViewTouchHandler implements SwipeHelper.Callback {
/** /**
* Returns the scaled size used to calculate the dismiss fraction. * Returns the scaled size used to calculate the dismiss fraction.
*/ */
private float getScaledDismissSize() { public float getScaledDismissSize() {
return 1.5f * Math.max(mSv.getWidth(), mSv.getHeight()); return 1.5f * Math.max(mSv.getWidth(), mSv.getHeight());
} }
} }

View File

@@ -388,7 +388,9 @@ public class TaskView extends FixedSizeFrameLayout implements Task.TaskCallbacks
dismissEvent.addPostAnimationCallback(new Runnable() { dismissEvent.addPostAnimationCallback(new Runnable() {
@Override @Override
public void run() { public void run() {
EventBus.getDefault().send(new TaskViewDismissedEvent(mTask, tv)); EventBus.getDefault().send(new TaskViewDismissedEvent(mTask, tv,
new AnimationProps(TaskStackView.DEFAULT_SYNC_STACK_DURATION,
Interpolators.FAST_OUT_SLOW_IN)));
} }
}); });
EventBus.getDefault().send(dismissEvent); EventBus.getDefault().send(dismissEvent);