Implement parallax when dismissing docked/fullscreen stack
When moving the docked or the fullscreen task close to the side, we add a nice parallax to indicate that this task will be dismissed. Change-Id: Ide195876942c1614c186fd5f3ff3e86f6fdfec61
This commit is contained in:
@ -118,6 +118,22 @@ public class DividerSnapAlgorithm {
|
||||
}
|
||||
}
|
||||
|
||||
public SnapTarget getFirstSplitTarget() {
|
||||
return mFirstSplitTarget;
|
||||
}
|
||||
|
||||
public SnapTarget getLastSplitTarget() {
|
||||
return mLastSplitTarget;
|
||||
}
|
||||
|
||||
public SnapTarget getDismissStartTarget() {
|
||||
return mDismissStartTarget;
|
||||
}
|
||||
|
||||
public SnapTarget getDismissEndTarget() {
|
||||
return mDismissEndTarget;
|
||||
}
|
||||
|
||||
private SnapTarget snap(int position) {
|
||||
int minIndex = -1;
|
||||
int minDistance = Integer.MAX_VALUE;
|
||||
|
@ -28,6 +28,7 @@ import android.graphics.Rect;
|
||||
import android.graphics.Region.Op;
|
||||
import android.hardware.display.DisplayManager;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.MathUtils;
|
||||
import android.view.Display;
|
||||
import android.view.DisplayInfo;
|
||||
import android.view.MotionEvent;
|
||||
@ -37,6 +38,7 @@ import android.view.View;
|
||||
import android.view.View.OnTouchListener;
|
||||
import android.view.ViewTreeObserver.InternalInsetsInfo;
|
||||
import android.view.ViewTreeObserver.OnComputeInternalInsetsListener;
|
||||
import android.view.Window;
|
||||
import android.view.WindowInsets;
|
||||
import android.view.WindowManager;
|
||||
import android.view.animation.AnimationUtils;
|
||||
@ -64,6 +66,9 @@ public class DividerView extends FrameLayout implements OnTouchListener,
|
||||
private static final float DIM_START_FRACTION = 0.5f;
|
||||
private static final float DIM_DAMP_FACTOR = 1.7f;
|
||||
|
||||
private static final PathInterpolator SLOWDOWN_INTERPOLATOR =
|
||||
new PathInterpolator(0.5f, 1f, 0.5f, 1f);
|
||||
|
||||
private ImageButton mHandle;
|
||||
private View mBackground;
|
||||
private int mStartX;
|
||||
@ -202,7 +207,7 @@ public class DividerView extends FrameLayout implements OnTouchListener,
|
||||
int position = calculatePosition(x, y);
|
||||
SnapTarget snapTarget = mSnapAlgorithm.calculateSnapTarget(position,
|
||||
0 /* velocity */);
|
||||
resizeStack(calculatePosition(x, y), snapTarget.position);
|
||||
resizeStack(calculatePosition(x, y), snapTarget.position, snapTarget);
|
||||
}
|
||||
break;
|
||||
case MotionEvent.ACTION_UP:
|
||||
@ -235,7 +240,7 @@ public class DividerView extends FrameLayout implements OnTouchListener,
|
||||
resizeStack((Integer) animation.getAnimatedValue(),
|
||||
animation.getAnimatedFraction() == 1f
|
||||
? TASK_POSITION_SAME
|
||||
: snapTarget.position);
|
||||
: snapTarget.position, snapTarget);
|
||||
}
|
||||
});
|
||||
anim.addListener(new AnimatorListenerAdapter() {
|
||||
@ -393,7 +398,7 @@ public class DividerView extends FrameLayout implements OnTouchListener,
|
||||
containingRect.right, containingRect.bottom);
|
||||
}
|
||||
|
||||
public void resizeStack(int position, int taskPosition) {
|
||||
public void resizeStack(int position, int taskPosition, SnapTarget taskSnapTarget) {
|
||||
calculateBoundsForPosition(position, mDockSide, mDockedRect);
|
||||
|
||||
if (mDockedRect.equals(mLastResizeRect)) {
|
||||
@ -406,19 +411,28 @@ public class DividerView extends FrameLayout implements OnTouchListener,
|
||||
mLastResizeRect.set(mDockedRect);
|
||||
if (taskPosition != TASK_POSITION_SAME) {
|
||||
calculateBoundsForPosition(position, invertDockSide(mDockSide), mOtherRect);
|
||||
calculateBoundsForPosition(taskPosition, mDockSide, mDockedTaskRect);
|
||||
calculateBoundsForPosition(taskPosition, invertDockSide(mDockSide), mOtherTaskRect);
|
||||
int dockSideInverted = invertDockSide(mDockSide);
|
||||
int taskPositionDocked =
|
||||
restrictDismissingTaskPosition(taskPosition, mDockSide, taskSnapTarget);
|
||||
int taskPositionOther =
|
||||
restrictDismissingTaskPosition(taskPosition, dockSideInverted, taskSnapTarget);
|
||||
calculateBoundsForPosition(taskPositionDocked, mDockSide, mDockedTaskRect);
|
||||
calculateBoundsForPosition(taskPositionOther, dockSideInverted, mOtherTaskRect);
|
||||
alignTopLeft(mDockedRect, mDockedTaskRect);
|
||||
alignTopLeft(mOtherRect, mOtherTaskRect);
|
||||
mDockedInsetRect.set(mDockedTaskRect);
|
||||
mOtherInsetRect.set(mOtherTaskRect);
|
||||
if (mDockSide == WindowManager.DOCKED_LEFT || mDockSide == WindowManager.DOCKED_TOP) {
|
||||
if (dockSideTopLeft(mDockSide)) {
|
||||
alignTopLeft(mDockedRect, mDockedInsetRect);
|
||||
alignBottomRight(mOtherRect, mOtherInsetRect);
|
||||
} else {
|
||||
alignBottomRight(mDockedRect, mDockedInsetRect);
|
||||
alignTopLeft(mOtherRect, mOtherInsetRect);
|
||||
}
|
||||
applyDismissingParallax(mDockedTaskRect, mDockSide, taskSnapTarget, position,
|
||||
taskPositionDocked);
|
||||
applyDismissingParallax(mOtherTaskRect, dockSideInverted, taskSnapTarget, position,
|
||||
taskPositionOther);
|
||||
mWindowManagerProxy.resizeDockedStack(mDockedRect, mDockedTaskRect, mDockedInsetRect,
|
||||
mOtherTaskRect, mOtherInsetRect);
|
||||
} else {
|
||||
@ -432,6 +446,86 @@ public class DividerView extends FrameLayout implements OnTouchListener,
|
||||
fraction);
|
||||
}
|
||||
|
||||
/**
|
||||
* When the snap target is dismissing one side, make sure that the dismissing side doesn't get
|
||||
* 0 size.
|
||||
*/
|
||||
private int restrictDismissingTaskPosition(int taskPosition, int dockSide,
|
||||
SnapTarget snapTarget) {
|
||||
if (snapTarget.flag == SnapTarget.FLAG_DISMISS_START && dockSideTopLeft(dockSide)) {
|
||||
return mSnapAlgorithm.getFirstSplitTarget().position;
|
||||
} else if (snapTarget.flag == SnapTarget.FLAG_DISMISS_END
|
||||
&& dockSideBottomRight(dockSide)) {
|
||||
return mSnapAlgorithm.getLastSplitTarget().position;
|
||||
} else {
|
||||
return taskPosition;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies a parallax to the task when dismissing.
|
||||
*/
|
||||
private void applyDismissingParallax(Rect taskRect, int dockSide, SnapTarget snapTarget,
|
||||
int position, int taskPosition) {
|
||||
float fraction = Math.min(1, Math.max(0,
|
||||
mSnapAlgorithm.calculateDismissingFraction(position)));
|
||||
SnapTarget dismissTarget = null;
|
||||
SnapTarget splitTarget = null;
|
||||
if ((snapTarget.flag == SnapTarget.FLAG_DISMISS_START
|
||||
|| snapTarget == mSnapAlgorithm.getFirstSplitTarget())
|
||||
&& dockSideTopLeft(dockSide)) {
|
||||
dismissTarget = mSnapAlgorithm.getDismissStartTarget();
|
||||
splitTarget = mSnapAlgorithm.getFirstSplitTarget();
|
||||
} else if ((snapTarget.flag == SnapTarget.FLAG_DISMISS_END
|
||||
|| snapTarget == mSnapAlgorithm.getLastSplitTarget())
|
||||
&& dockSideBottomRight(dockSide)) {
|
||||
dismissTarget = mSnapAlgorithm.getDismissEndTarget();
|
||||
splitTarget = mSnapAlgorithm.getLastSplitTarget();
|
||||
}
|
||||
if (dismissTarget != null && fraction > 0f
|
||||
&& isDismissing(splitTarget, position, dockSide)) {
|
||||
fraction = calculateParallaxDismissingFraction(fraction);
|
||||
int offsetPosition = (int) (taskPosition +
|
||||
fraction * (dismissTarget.position - splitTarget.position));
|
||||
int width = taskRect.width();
|
||||
int height = taskRect.height();
|
||||
switch (dockSide) {
|
||||
case WindowManager.DOCKED_LEFT:
|
||||
taskRect.left = offsetPosition - width;
|
||||
taskRect.right = offsetPosition;
|
||||
break;
|
||||
case WindowManager.DOCKED_RIGHT:
|
||||
taskRect.left = offsetPosition + mDividerSize;
|
||||
taskRect.right = offsetPosition + width + mDividerSize;
|
||||
break;
|
||||
case WindowManager.DOCKED_TOP:
|
||||
taskRect.top = offsetPosition - height;
|
||||
taskRect.bottom = offsetPosition;
|
||||
break;
|
||||
case WindowManager.DOCKED_BOTTOM:
|
||||
taskRect.top = offsetPosition + mDividerSize;
|
||||
taskRect.bottom = offsetPosition + height + mDividerSize;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return for a specified {@code fraction}, this returns an adjusted value that simulates a
|
||||
* slowing down parallax effect
|
||||
*/
|
||||
private static float calculateParallaxDismissingFraction(float fraction) {
|
||||
return SLOWDOWN_INTERPOLATOR.getInterpolation(fraction) / 3.5f;
|
||||
}
|
||||
|
||||
private static boolean isDismissing(SnapTarget snapTarget, int position, int dockSide) {
|
||||
if (dockSide == WindowManager.DOCKED_TOP || dockSide == WindowManager.DOCKED_LEFT) {
|
||||
return position < snapTarget.position;
|
||||
} else {
|
||||
return position > snapTarget.position;
|
||||
}
|
||||
}
|
||||
|
||||
private int getStackIdForDismissTarget(SnapTarget dismissTarget) {
|
||||
if (dismissTarget.flag == SnapTarget.FLAG_DISMISS_START &&
|
||||
(mDockSide == WindowManager.DOCKED_LEFT || mDockSide == WindowManager.DOCKED_TOP)) {
|
||||
@ -441,6 +535,20 @@ public class DividerView extends FrameLayout implements OnTouchListener,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if and only if {@code dockSide} is top or left
|
||||
*/
|
||||
private static boolean dockSideTopLeft(int dockSide) {
|
||||
return dockSide == WindowManager.DOCKED_TOP || dockSide == WindowManager.DOCKED_LEFT;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if and only if {@code dockSide} is bottom or right
|
||||
*/
|
||||
private static boolean dockSideBottomRight(int dockSide) {
|
||||
return dockSide == WindowManager.DOCKED_BOTTOM || dockSide == WindowManager.DOCKED_RIGHT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onComputeInternalInsets(InternalInsetsInfo inoutInfo) {
|
||||
inoutInfo.setTouchableInsets(InternalInsetsInfo.TOUCHABLE_INSETS_REGION);
|
||||
|
@ -29,6 +29,7 @@ import com.android.internal.logging.MetricsLogger;
|
||||
import com.android.systemui.R;
|
||||
import com.android.systemui.RecentsComponent;
|
||||
import com.android.systemui.stackdivider.Divider;
|
||||
import com.android.systemui.stackdivider.DividerSnapAlgorithm.SnapTarget;
|
||||
import com.android.systemui.stackdivider.DividerView;
|
||||
import com.android.systemui.tuner.TunerService;
|
||||
|
||||
@ -200,9 +201,9 @@ public class NavigationBarGestureHelper extends GestureDetector.SimpleOnGestureL
|
||||
} else {
|
||||
if (mDragMode == DRAG_MODE_DIVIDER) {
|
||||
int position = !mIsVertical ? (int) event.getRawY() : (int) event.getRawX();
|
||||
mDivider.getView().resizeStack(
|
||||
position, mDivider.getView().getSnapAlgorithm()
|
||||
.calculateSnapTarget(position, 0f /* velocity */).position);
|
||||
SnapTarget snapTarget = mDivider.getView().getSnapAlgorithm()
|
||||
.calculateSnapTarget(position, 0f /* velocity */);
|
||||
mDivider.getView().resizeStack(position, snapTarget.position, snapTarget);
|
||||
} else if (mDragMode == DRAG_MODE_RECENTS) {
|
||||
mRecentsComponent.onDraggingInRecents(event.getRawY());
|
||||
}
|
||||
|
Reference in New Issue
Block a user