Fixing crash when dragging tasks to docked state.

- Also tweaking animation when a task is first picked up.

Change-Id: Idf99c88fdb216823637e2436e54b392b661b9849
This commit is contained in:
Winson
2015-10-10 14:40:35 -07:00
parent 42be431c3d
commit 4165d336b6
4 changed files with 141 additions and 90 deletions

View File

@@ -183,16 +183,18 @@ public class TaskStack {
public enum DockState {
LEFT(DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT,
new RectF(0, 0, 0.25f, 1), new RectF(0, 0, 0.35f, 1), new RectF(0.65f, 0, 1, 1)),
TOP(DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT,
new RectF(0, 0, 1, 0.25f), new RectF(0, 0, 1, 0.35f), new RectF(0, 0.65f, 1, 1)),
RIGHT(DOCKED_STACK_CREATE_MODE_BOTTOM_OR_RIGHT,
new RectF(0.75f, 0, 1, 1), new RectF(0.65f, 0, 1, 1), new RectF(0, 0, 0.35f, 1)),
BOTTOM(DOCKED_STACK_CREATE_MODE_BOTTOM_OR_RIGHT,
new RectF(0, 0.75f, 1, 1), new RectF(0, 0.65f, 1, 1), new RectF(0, 0, 1, 0.35f));
NONE(-1, 96, null, null, null),
LEFT(DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT, 192,
new RectF(0, 0, 0.3f, 1), new RectF(0, 0, 0.3f, 1), new RectF(0.7f, 0, 1, 1)),
TOP(DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT, 192,
new RectF(0, 0, 1, 0.3f), new RectF(0, 0, 1, 0.3f), new RectF(0, 0.7f, 1, 1)),
RIGHT(DOCKED_STACK_CREATE_MODE_BOTTOM_OR_RIGHT, 192,
new RectF(0.7f, 0, 1, 1), new RectF(0.7f, 0, 1, 1), new RectF(0, 0, 0.3f, 1)),
BOTTOM(DOCKED_STACK_CREATE_MODE_BOTTOM_OR_RIGHT, 192,
new RectF(0, 0.7f, 1, 1), new RectF(0, 0.7f, 1, 1), new RectF(0, 0, 1, 0.3f));
public final int createMode;
public final int dockAreaAlpha;
private final RectF touchArea;
private final RectF dockArea;
private final RectF stackArea;
@@ -202,8 +204,10 @@ public class TaskStack {
* @param touchArea the area in which touch will initiate this dock state
* @param stackArea the area for the stack if a task is docked
*/
DockState(int createMode, RectF touchArea, RectF dockArea, RectF stackArea) {
DockState(int createMode, int dockAreaAlpha, RectF touchArea, RectF dockArea,
RectF stackArea) {
this.createMode = createMode;
this.dockAreaAlpha = dockAreaAlpha;
this.touchArea = touchArea;
this.dockArea = dockArea;
this.stackArea = stackArea;
@@ -232,9 +236,13 @@ public class TaskStack {
/**
* Returns the stack bounds with the given {@param width} and {@param height}.
*/
public Rect getStackBounds(int width, int height) {
return new Rect((int) (stackArea.left * width), (int) (stackArea.top * height),
(int) (stackArea.right * width), (int) (stackArea.bottom * height));
public Rect getStackBounds(Rect stackRect) {
int width = stackRect.width();
int height = stackRect.height();
return new Rect((int) (stackRect.left + stackArea.left * width),
(int) (stackRect.top + stackArea.top * height),
(int) (stackRect.left + (stackArea.right - stackArea.left) * width),
(int) (stackRect.top + (stackArea.bottom - stackArea.top) * height));
}
}

View File

@@ -16,6 +16,8 @@
package com.android.systemui.recents.views;
import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.app.ActivityManager;
import android.app.ActivityOptions;
import android.content.Context;
@@ -23,6 +25,7 @@ import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.os.IRemoteCallback;
import android.os.RemoteException;
@@ -89,6 +92,7 @@ public class RecentsView extends FrameLayout implements TaskStackView.TaskStackV
RecentsViewTouchHandler mTouchHandler;
DragView mDragView;
ColorDrawable mDockRegionOverlay;
ObjectAnimator mDockRegionOverlayAnimator;
Interpolator mFastOutSlowInInterpolator;
@@ -114,8 +118,9 @@ public class RecentsView extends FrameLayout implements TaskStackView.TaskStackV
mFastOutSlowInInterpolator = AnimationUtils.loadInterpolator(context,
com.android.internal.R.interpolator.fast_out_slow_in);
mTouchHandler = new RecentsViewTouchHandler(this);
mDockRegionOverlay = new ColorDrawable(0x66000000);
mDockRegionOverlay = new ColorDrawable(0xFFffffff);
mDockRegionOverlay.setAlpha(0);
mDockRegionOverlay.setCallback(this);
}
/** Sets the callbacks */
@@ -383,6 +388,11 @@ public class RecentsView extends FrameLayout implements TaskStackView.TaskStackV
}
}
@Override
protected boolean verifyDrawable(Drawable who) {
return super.verifyDrawable(who) || who == mDockRegionOverlay;
}
/** Notifies each task view of the user interaction. */
public void onUserInteraction() {
// Get the first stack view
@@ -764,19 +774,12 @@ public class RecentsView extends FrameLayout implements TaskStackView.TaskStackV
// Add the drag view
mDragView = event.dragView;
addView(mDragView);
updateDockRegion(TaskStack.DockState.NONE);
}
public final void onBusEvent(DragDockStateChangedEvent event) {
// Update the task stack positions, and then
if (event.dockState != null) {
// Draw an overlay on the bounds of the dock task
mDockRegionOverlay.setBounds(
event.dockState.getDockedBounds(getMeasuredWidth(), getMeasuredHeight()));
mDockRegionOverlay.setAlpha(255);
} else {
mDockRegionOverlay.setAlpha(0);
}
invalidate();
updateDockRegion(event.dockState);
}
public final void onBusEvent(final DragEndEvent event) {
@@ -791,7 +794,7 @@ public class RecentsView extends FrameLayout implements TaskStackView.TaskStackV
invalidate();
// Dock the new task if we are hovering over a valid dock state
if (event.dockState != null) {
if (event.dockState != TaskStack.DockState.NONE) {
SystemServicesProxy ssp = RecentsTaskLoader.getInstance().getSystemServicesProxy();
ssp.setTaskResizeable(event.task.key.id);
ssp.dockTask(event.task.key.id, event.dockState.createMode);
@@ -799,22 +802,49 @@ public class RecentsView extends FrameLayout implements TaskStackView.TaskStackV
}
}
});
if (event.dockState == null) {
if (event.dockState == TaskStack.DockState.NONE) {
// Animate the alpha back to what it was before
Rect taskBounds = mTaskStackView.getStackAlgorithm().getUntransformedTaskViewBounds();
int left = taskBounds.left + (int) ((1f - event.taskView.getScaleX()) * taskBounds.width()) / 2;
int top = taskBounds.top + (int) ((1f - event.taskView.getScaleY()) * taskBounds.height()) / 2;
event.dragView.animate()
.alpha(1f)
.scaleX(1f)
.scaleY(1f)
.translationX(left + event.taskView.getTranslationX())
.translationY(top + event.taskView.getTranslationY())
.setDuration(175)
.setInterpolator(new AccelerateInterpolator(1.5f))
.setInterpolator(mFastOutSlowInInterpolator)
.withEndAction(event.postAnimationTrigger.decrementAsRunnable())
.withLayer()
.start();
// Animate the overlay alpha back to 0
updateDockRegionAlpha(0);
} else {
event.postAnimationTrigger.decrement();
}
}
/**
* Updates the dock region to match the specified dock state.
*/
private void updateDockRegion(TaskStack.DockState dockState) {
TaskStack.DockState boundsDockState = dockState;
if (dockState == TaskStack.DockState.NONE) {
// If the dock state is null, then use the bounds of the preferred dock state for this
// orientation
boundsDockState = mTouchHandler.getPreferredDockStateForCurrentOrientation();
}
mDockRegionOverlay.setBounds(
boundsDockState.getDockedBounds(getMeasuredWidth(), getMeasuredHeight()));
updateDockRegionAlpha(dockState.dockAreaAlpha);
}
private void updateDockRegionAlpha(int alpha) {
if (mDockRegionOverlayAnimator != null) {
mDockRegionOverlayAnimator.cancel();
}
mDockRegionOverlayAnimator = ObjectAnimator.ofInt(mDockRegionOverlay, "alpha", alpha);
mDockRegionOverlayAnimator.setDuration(150);
mDockRegionOverlayAnimator.start();
}
}

View File

@@ -36,7 +36,8 @@ class DockRegion {
TaskStack.DockState.LEFT, TaskStack.DockState.RIGHT
};
public static TaskStack.DockState[] PORTRAIT = {
TaskStack.DockState.TOP, TaskStack.DockState.BOTTOM
// We only allow docking to the top for now
TaskStack.DockState.TOP
};
}
@@ -53,75 +54,30 @@ class RecentsViewTouchHandler {
private Point mDownPos = new Point();
private boolean mDragging;
private TaskStack.DockState mLastDockState;
private TaskStack.DockState mLastDockState = TaskStack.DockState.NONE;
public RecentsViewTouchHandler(RecentsView rv) {
mRv = rv;
}
public TaskStack.DockState getPreferredDockStateForCurrentOrientation() {
boolean isLandscape = mRv.getResources().getConfiguration().orientation ==
Configuration.ORIENTATION_LANDSCAPE;
TaskStack.DockState[] dockStates = isLandscape ?
DockRegion.LANDSCAPE : DockRegion.PORTRAIT;
return dockStates[0];
}
/** Touch preprocessing for handling below */
public boolean onInterceptTouchEvent(MotionEvent ev) {
int action = ev.getAction();
switch (action & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
mDownPos.set((int) ev.getX(), (int) ev.getY());
break;
}
handleTouchEvent(ev);
return mDragging;
}
/** Handles touch events once we have intercepted them */
public boolean onTouchEvent(MotionEvent ev) {
if (!mDragging) return false;
boolean isLandscape = mRv.getResources().getConfiguration().orientation ==
Configuration.ORIENTATION_LANDSCAPE;
int action = ev.getAction();
switch (action & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
mDownPos.set((int) ev.getX(), (int) ev.getY());
break;
case MotionEvent.ACTION_MOVE: {
int width = mRv.getMeasuredWidth();
int height = mRv.getMeasuredHeight();
float evX = ev.getX();
float evY = ev.getY();
float x = evX - mDragView.getTopLeftOffset().x;
float y = evY - mDragView.getTopLeftOffset().y;
// Update the dock state
TaskStack.DockState[] dockStates = isLandscape ?
DockRegion.LANDSCAPE : DockRegion.PORTRAIT;
TaskStack.DockState foundDockState = null;
for (int i = 0; i < dockStates.length; i++) {
TaskStack.DockState state = dockStates[i];
if (state.touchAreaContainsPoint(width, height, evX, evY)) {
foundDockState = state;
break;
}
}
if (mLastDockState != foundDockState) {
mLastDockState = foundDockState;
EventBus.getDefault().send(new DragDockStateChangedEvent(mDragTask,
foundDockState));
}
mDragView.setTranslationX(x);
mDragView.setTranslationY(y);
break;
}
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL: {
ReferenceCountedTrigger postAnimationTrigger = new ReferenceCountedTrigger(
mRv.getContext(), null, null, null);
postAnimationTrigger.increment();
EventBus.getDefault().send(new DragEndEvent(mDragTask, mTaskView, mDragView,
mLastDockState, postAnimationTrigger));
postAnimationTrigger.decrement();
break;
}
}
return true;
handleTouchEvent(ev);
return mDragging;
}
/**** Events ****/
@@ -144,6 +100,62 @@ class RecentsViewTouchHandler {
mDragTask = null;
mTaskView = null;
mDragView = null;
mLastDockState = null;
mLastDockState = TaskStack.DockState.NONE;
}
/**
* Handles dragging touch events
* @param ev
*/
private void handleTouchEvent(MotionEvent ev) {
boolean isLandscape = mRv.getResources().getConfiguration().orientation ==
Configuration.ORIENTATION_LANDSCAPE;
int action = ev.getAction();
switch (action & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
mDownPos.set((int) ev.getX(), (int) ev.getY());
break;
case MotionEvent.ACTION_MOVE: {
if (mDragging) {
int width = mRv.getMeasuredWidth();
int height = mRv.getMeasuredHeight();
float evX = ev.getX();
float evY = ev.getY();
float x = evX - mDragView.getTopLeftOffset().x;
float y = evY - mDragView.getTopLeftOffset().y;
// Update the dock state
TaskStack.DockState[] dockStates = isLandscape ?
DockRegion.LANDSCAPE : DockRegion.PORTRAIT;
TaskStack.DockState foundDockState = TaskStack.DockState.NONE;
for (int i = 0; i < dockStates.length; i++) {
TaskStack.DockState state = dockStates[i];
if (state.touchAreaContainsPoint(width, height, evX, evY)) {
foundDockState = state;
break;
}
}
if (mLastDockState != foundDockState) {
mLastDockState = foundDockState;
EventBus.getDefault().send(new DragDockStateChangedEvent(mDragTask,
foundDockState));
}
mDragView.setTranslationX(x);
mDragView.setTranslationY(y);
}
break;
}
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL: {
ReferenceCountedTrigger postAnimationTrigger = new ReferenceCountedTrigger(
mRv.getContext(), null, null, null);
postAnimationTrigger.increment();
EventBus.getDefault().send(new DragEndEvent(mDragTask, mTaskView, mDragView,
mLastDockState, postAnimationTrigger));
postAnimationTrigger.decrement();
break;
}
}
}
}

View File

@@ -807,15 +807,16 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks,
dragView.setElevation(getElevation());
dragView.setTranslationZ(getTranslationZ());
dragView.animate()
.alpha(0.75f)
.scaleX(1.05f)
.scaleY(1.05f)
.setDuration(175)
.setInterpolator(new AccelerateInterpolator(1.5f))
.withLayer()
.setInterpolator(mFastOutSlowInInterpolator)
.start();
}
@Override
public void onViewDetachedFromWindow(View v) {
// Do nothing
}
});
EventBus.getDefault().register(this, RecentsActivity.EVENT_BUS_PRIORITY + 1);