Merge "Enable Grid Preview flag" into ub-launcher3-master
diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java
index 51ee216..7728207 100644
--- a/quickstep/recents_ui_overrides/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java
+++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java
@@ -16,7 +16,6 @@
package com.android.launcher3;
-import static com.android.launcher3.LauncherAnimUtils.VIEW_TRANSLATE_X;
import static com.android.launcher3.LauncherState.BACKGROUND_APP;
import static com.android.launcher3.LauncherState.HOTSEAT_ICONS;
import static com.android.launcher3.LauncherState.NORMAL;
@@ -39,6 +38,7 @@
import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.content.Context;
+import android.util.FloatProperty;
import android.view.View;
import androidx.annotation.NonNull;
@@ -50,6 +50,7 @@
import com.android.launcher3.anim.AnimatorSetBuilder;
import com.android.launcher3.anim.Interpolators;
import com.android.launcher3.anim.SpringAnimationBuilder;
+import com.android.launcher3.touch.PagedOrientationHandler;
import com.android.quickstep.util.AppWindowAnimationHelper;
import com.android.quickstep.views.RecentsView;
import com.android.quickstep.views.TaskView;
@@ -88,7 +89,8 @@
TaskView taskView = findTaskViewToLaunch(mLauncher, v, appTargets);
- AppWindowAnimationHelper helper = new AppWindowAnimationHelper(mLauncher);
+ AppWindowAnimationHelper helper =
+ new AppWindowAnimationHelper(recentsView.getPagedViewOrientedState(), mLauncher);
anim.play(getRecentsWindowAnimator(taskView, skipLauncherChanges, appTargets,
wallpaperTargets, helper).setDuration(RECENTS_LAUNCH_DURATION));
@@ -197,7 +199,11 @@
return ObjectAnimator.ofFloat(mLauncher.getOverviewPanel(),
RecentsView.CONTENT_ALPHA, values);
case INDEX_RECENTS_TRANSLATE_X_ANIM:
- return new SpringAnimationBuilder<>(mLauncher.getOverviewPanel(), VIEW_TRANSLATE_X)
+ PagedOrientationHandler orientationHandler =
+ ((RecentsView)mLauncher.getOverviewPanel()).getPagedViewOrientedState()
+ .getOrientationHandler();
+ FloatProperty<View> translate = orientationHandler.getPrimaryViewTranslate();
+ return new SpringAnimationBuilder<>(mLauncher.getOverviewPanel(), translate)
.setDampingRatio(0.8f)
.setStiffness(250)
.setValues(values)
diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/FlingAndHoldTouchController.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/FlingAndHoldTouchController.java
index 519939e..9cbe11a 100644
--- a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/FlingAndHoldTouchController.java
+++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/FlingAndHoldTouchController.java
@@ -80,10 +80,10 @@
}
@Override
- public void onDragStart(boolean start) {
+ public void onDragStart(boolean start, float startDisplacement) {
mMotionPauseDetector.clear();
- super.onDragStart(start);
+ super.onDragStart(start, startDisplacement);
if (handlingOverviewAnim()) {
mMotionPauseDetector.setOnMotionPauseListener(this::onMotionPauseChanged);
diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/NavBarToHomeTouchController.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/NavBarToHomeTouchController.java
index ad4a343..19a2bae 100644
--- a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/NavBarToHomeTouchController.java
+++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/NavBarToHomeTouchController.java
@@ -126,7 +126,7 @@
}
@Override
- public void onDragStart(boolean start) {
+ public void onDragStart(boolean start, float startDisplacement) {
initCurrentAnimation();
}
diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonNavbarToOverviewTouchController.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonNavbarToOverviewTouchController.java
index 34fc3e4..ab634a4 100644
--- a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonNavbarToOverviewTouchController.java
+++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonNavbarToOverviewTouchController.java
@@ -94,8 +94,8 @@
}
@Override
- public void onDragStart(boolean start) {
- super.onDragStart(start);
+ public void onDragStart(boolean start, float startDisplacement) {
+ super.onDragStart(start, startDisplacement);
mReachedOverview = false;
}
diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java
index 799f1ad..715529e 100644
--- a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java
+++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java
@@ -116,12 +116,13 @@
mLauncher = launcher;
mSwipeDetector = new BothAxesSwipeDetector(mLauncher, this);
mShelfPeekAnim = mLauncher.getShelfPeekAnim();
+ mRecentsView = mLauncher.getOverviewPanel();
mXRange = mLauncher.getDeviceProfile().widthPx / 2f;
- mYRange = LayoutUtils.getShelfTrackingDistance(mLauncher, mLauncher.getDeviceProfile());
+ mYRange = LayoutUtils.getShelfTrackingDistance(
+ mLauncher, mLauncher.getDeviceProfile());
mMotionPauseDetector = new MotionPauseDetector(mLauncher);
mMotionPauseMinDisplacement = mLauncher.getResources().getDimension(
R.dimen.motion_pause_detector_min_displacement_from_app);
- mRecentsView = mLauncher.getOverviewPanel();
}
@Override
diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/QuickSwitchTouchController.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/QuickSwitchTouchController.java
index 912be98..d5b221d 100644
--- a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/QuickSwitchTouchController.java
+++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/QuickSwitchTouchController.java
@@ -92,8 +92,8 @@
}
@Override
- public void onDragStart(boolean start) {
- super.onDragStart(start);
+ public void onDragStart(boolean start, float startDisplacement) {
+ super.onDragStart(start, startDisplacement);
mStartContainerType = LauncherLogProto.ContainerType.NAVBAR;
mTaskToLaunch = mLauncher.<RecentsView>getOverviewPanel().getTaskViewAt(0);
ActivityManagerWrapper.getInstance()
diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/TaskViewTouchController.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/TaskViewTouchController.java
index f79ad25..e0532ac 100644
--- a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/TaskViewTouchController.java
+++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/TaskViewTouchController.java
@@ -36,6 +36,7 @@
import com.android.launcher3.anim.AnimatorPlaybackController;
import com.android.launcher3.anim.Interpolators;
import com.android.launcher3.touch.BaseSwipeDetector;
+import com.android.launcher3.touch.PagedOrientationHandler;
import com.android.launcher3.touch.SingleAxisSwipeDetector;
import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch;
import com.android.launcher3.util.FlingBlockCheck;
@@ -77,7 +78,9 @@
public TaskViewTouchController(T activity) {
mActivity = activity;
mRecentsView = activity.getOverviewPanel();
- mDetector = new SingleAxisSwipeDetector(activity, this, SingleAxisSwipeDetector.VERTICAL);
+ SingleAxisSwipeDetector.Direction dir =
+ mRecentsView.getPagedOrientationHandler().getOppositeSwipeDirection();
+ mDetector = new SingleAxisSwipeDetector(activity, this, dir);
}
private boolean canInterceptTouch() {
@@ -190,15 +193,18 @@
mPendingAnimation = null;
}
+ PagedOrientationHandler orientationHandler = mRecentsView.getPagedOrientationHandler();
mCurrentAnimationIsGoingUp = goingUp;
BaseDragLayer dl = mActivity.getDragLayer();
- long maxDuration = (long) (2 * dl.getHeight());
-
+ final int secondaryLayerDimension = orientationHandler.getSecondaryDimension(dl);
+ long maxDuration = (long) (2 * secondaryLayerDimension);
+ int verticalFactor = -orientationHandler.getTaskDismissDirectionFactor();
+ int secondaryTaskDimension = orientationHandler.getSecondaryDimension(mTaskBeingDragged);
if (goingUp) {
mPendingAnimation = mRecentsView.createTaskDismissAnimation(mTaskBeingDragged,
true /* animateTaskView */, true /* removeTask */, maxDuration);
- mEndDisplacement = -mTaskBeingDragged.getHeight();
+ mEndDisplacement = -secondaryTaskDimension;
} else {
mPendingAnimation = mRecentsView.createTaskLaunchAnimation(
mTaskBeingDragged, maxDuration, Interpolators.ZOOM_IN);
@@ -207,6 +213,7 @@
dl.getDescendantCoordRelativeToSelf(mTaskBeingDragged, mTempCords);
mEndDisplacement = dl.getHeight() - mTempCords[1];
}
+ mEndDisplacement *= verticalFactor;
if (mCurrentAnimation != null) {
mCurrentAnimation.setOnCancelRunnable(null);
@@ -220,9 +227,10 @@
}
@Override
- public void onDragStart(boolean start) {
+ public void onDragStart(boolean start, float startDisplacement) {
+ PagedOrientationHandler orientationHandler = mRecentsView.getPagedOrientationHandler();
if (mCurrentAnimation == null) {
- reInitAnimationController(mDetector.wasInitialTouchPositive());
+ reInitAnimationController(orientationHandler.isGoingUp(startDisplacement));
mDisplacementShift = 0;
} else {
mDisplacementShift = mCurrentAnimation.getProgressFraction() / mProgressMultiplier;
@@ -233,9 +241,10 @@
@Override
public boolean onDrag(float displacement) {
+ PagedOrientationHandler orientationHandler = mRecentsView.getPagedOrientationHandler();
float totalDisplacement = displacement + mDisplacementShift;
- boolean isGoingUp =
- totalDisplacement == 0 ? mCurrentAnimationIsGoingUp : totalDisplacement < 0;
+ boolean isGoingUp = totalDisplacement == 0 ? mCurrentAnimationIsGoingUp :
+ orientationHandler.isGoingUp(totalDisplacement);
if (isGoingUp != mCurrentAnimationIsGoingUp) {
reInitAnimationController(isGoingUp);
mFlingBlockCheck.blockFling();
@@ -262,11 +271,12 @@
if (blockedFling) {
fling = false;
}
+ PagedOrientationHandler orientationHandler = mRecentsView.getPagedOrientationHandler();
float progress = mCurrentAnimation.getProgressFraction();
float interpolatedProgress = mCurrentAnimation.getInterpolatedProgress();
if (fling) {
logAction = Touch.FLING;
- boolean goingUp = velocity < 0;
+ boolean goingUp = orientationHandler.isGoingUp(velocity);
goingToEnd = goingUp == mCurrentAnimationIsGoingUp;
} else {
logAction = Touch.SWIPE;
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/AppToOverviewAnimationProvider.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/AppToOverviewAnimationProvider.java
index 59b117f..375f160 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/AppToOverviewAnimationProvider.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/AppToOverviewAnimationProvider.java
@@ -125,7 +125,8 @@
return anim;
}
- final AppWindowAnimationHelper clipHelper = new AppWindowAnimationHelper(mActivity);
+ final AppWindowAnimationHelper clipHelper = new AppWindowAnimationHelper(
+ mRecentsView.getPagedViewOrientedState(), mActivity);
// At this point, the activity is already started and laid-out. Get the home-bounds
// relative to the screen using the rootView of the activity.
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/BaseSwipeUpHandler.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/BaseSwipeUpHandler.java
index 3601af2..f50bb3e 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/BaseSwipeUpHandler.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/BaseSwipeUpHandler.java
@@ -45,7 +45,9 @@
import com.android.launcher3.Utilities;
import com.android.launcher3.anim.AnimationSuccessListener;
import com.android.launcher3.anim.AnimatorPlaybackController;
-import com.android.launcher3.graphics.RotationMode;
+import com.android.launcher3.model.PagedViewOrientedState;
+import com.android.launcher3.states.RotationHelper;
+import com.android.launcher3.touch.PagedOrientationHandler;
import com.android.launcher3.util.VibratorWrapper;
import com.android.launcher3.views.FloatingIconView;
import com.android.quickstep.BaseActivityInterface.HomeAnimationFactory;
@@ -94,7 +96,7 @@
protected final BaseActivityInterface<T> mActivityInterface;
protected final InputConsumerController mInputConsumer;
- protected final AppWindowAnimationHelper mAppWindowAnimationHelper;
+ protected AppWindowAnimationHelper mAppWindowAnimationHelper;
protected final TransformParams mTransformParams = new TransformParams();
// Shift in the range of [0, 1].
@@ -123,6 +125,8 @@
protected boolean mCanceled;
protected int mFinishingRecentsAnimationForNewTaskId = -1;
+ private PagedViewOrientedState mOrientedState;
+
protected BaseSwipeUpHandler(Context context, RecentsAnimationDeviceState deviceState,
GestureState gestureState, InputConsumerController inputConsumer) {
mContext = context;
@@ -132,20 +136,18 @@
mActivityInitListener =
mActivityInterface.createActivityInitListener(this::onActivityInit);
mInputConsumer = inputConsumer;
-
mAppWindowAnimationHelper = new AppWindowAnimationHelper(context);
mPageSpacing = context.getResources().getDimensionPixelSize(R.dimen.recents_page_spacing);
-
initTransitionEndpoints(InvariantDeviceProfile.INSTANCE.get(mContext)
- .getDeviceProfile(mContext));
+ .getDeviceProfile(mContext));
}
protected void performHapticFeedback() {
VibratorWrapper.INSTANCE.get(mContext).vibrate(OVERVIEW_HAPTIC);
}
- public Consumer<MotionEvent> getRecentsViewDispatcher(RotationMode rotationMode) {
- return mRecentsView != null ? mRecentsView.getEventDispatcher(rotationMode) : null;
+ public Consumer<MotionEvent> getRecentsViewDispatcher() {
+ return mRecentsView != null ? mRecentsView.getEventDispatcher() : null;
}
@UiThread
@@ -326,10 +328,21 @@
// we otherwise use the minimized home bounds provided by the system.
mAppWindowAnimationHelper.updateHomeBounds(getStackBounds(dp));
}
+ int displayRotation = 0;
+ if (mOrientedState != null) {
+ // TODO(b/150300347): The first recents animation after launcher is started with the
+ // foreground app not in landscape will look funky until that bug is fixed
+ displayRotation = mOrientedState.getDisplayRotation();
+ }
+ RotationHelper.getTargetRectForRotation(TEMP_RECT, dp.widthPx, dp.heightPx,
+ displayRotation);
mAppWindowAnimationHelper.updateTargetRect(TEMP_RECT);
if (mDeviceState.isFullyGesturalNavMode()) {
// We can drag all the way to the top of the screen.
- mDragLengthFactor = (float) dp.heightPx / mTransitionDragLength;
+ // TODO(b/149609070): Landscape apps are currently limited in
+ // their ability to scale past the target rect.
+ float dragFactor = (float) dp.heightPx / mTransitionDragLength;
+ mDragLengthFactor = displayRotation == 0 ? dragFactor : Math.min(1.0f, dragFactor);
}
}
@@ -338,7 +351,17 @@
*/
protected abstract boolean moveWindowWithRecentsScroll();
- protected abstract boolean onActivityInit(Boolean alreadyOnHome);
+ protected boolean onActivityInit(Boolean alreadyOnHome) {
+ T createdActivity = mActivityInterface.getCreatedActivity();
+ if (createdActivity != null) {
+ mOrientedState = ((RecentsView) createdActivity.getOverviewPanel())
+ .getPagedViewOrientedState();
+ mAppWindowAnimationHelper = new AppWindowAnimationHelper(mOrientedState, mContext);
+ initTransitionEndpoints(InvariantDeviceProfile.INSTANCE.get(mContext)
+ .getDeviceProfile(mContext));
+ }
+ return true;
+ }
/**
* Called to create a input proxy for the running task
@@ -382,23 +405,29 @@
*/
protected void applyTransformUnchecked() {
float shift = mCurrentShift.value;
- float offsetX = mRecentsView == null ? 0 : mRecentsView.getScrollOffset();
- float offsetScale = getTaskCurveScaleForOffsetX(offsetX,
- mAppWindowAnimationHelper.getTargetRect().width());
+ float offset = mRecentsView == null ? 0 : mRecentsView.getScrollOffset();
+ float taskSize = getOrientationHandler()
+ .getPrimarySize(mAppWindowAnimationHelper.getTargetRect());
+ float offsetScale = getTaskCurveScaleForOffset(offset, taskSize);
mTransformParams.setProgress(shift)
- .setOffsetX(offsetX)
+ .setOffset(offset)
.setOffsetScale(offsetScale)
.setTargetSet(mRecentsAnimationTargets)
.setLauncherOnTop(true);
mAppWindowAnimationHelper.applyTransform(mTransformParams);
}
- private float getTaskCurveScaleForOffsetX(float offsetX, float taskWidth) {
- float distanceToReachEdge = mDp.widthPx / 2 + taskWidth / 2 + mPageSpacing;
- float interpolation = Math.min(1, offsetX / distanceToReachEdge);
+ private float getTaskCurveScaleForOffset(float offset, float taskSize) {
+ int dpPixel = getOrientationHandler().getShortEdgeLength(mDp);
+ float distanceToReachEdge = dpPixel / 2 + taskSize / 2 + mPageSpacing;
+ float interpolation = Math.min(1, offset / distanceToReachEdge);
return TaskView.getCurveScaleForInterpolation(interpolation);
}
+ protected PagedOrientationHandler getOrientationHandler() {
+ return mOrientedState.getOrientationHandler();
+ }
+
/**
* Creates an animation that transforms the current app window into the home app.
* @param startProgress The progress of {@link #mCurrentShift} to start the window from.
@@ -406,15 +435,18 @@
*/
protected RectFSpringAnim createWindowAnimationToHome(float startProgress,
HomeAnimationFactory homeAnimationFactory) {
- final RectF startRect = new RectF(
- mAppWindowAnimationHelper.applyTransform(
- mTransformParams.setProgress(startProgress)
- .setTargetSet(mRecentsAnimationTargets)
- .setLauncherOnTop(false)));
final RectF targetRect = homeAnimationFactory.getWindowTargetRect();
-
final View floatingView = homeAnimationFactory.getFloatingView();
final boolean isFloatingIconView = floatingView instanceof FloatingIconView;
+ final RectF startRect = new RectF(
+ mAppWindowAnimationHelper.applyTransform(
+ mTransformParams.setProgress(startProgress)
+ .setTargetSet(mRecentsAnimationTargets)
+ .setLauncherOnTop(false)));
+ if (isFloatingIconView) {
+ RotationHelper.mapInverseRectFromNormalOrientation(startRect,
+ mDp.widthPx, mDp.heightPx, mOrientedState.getDisplayRotation());
+ }
RectFSpringAnim anim = new RectFSpringAnim(startRect, targetRect, mContext.getResources());
if (isFloatingIconView) {
FloatingIconView fiv = (FloatingIconView) floatingView;
@@ -435,6 +467,7 @@
// We want the window alpha to be 0 once this threshold is met, so that the
// FolderIconView can be seen morphing into the icon shape.
final float windowAlphaThreshold = isFloatingIconView ? 1f - SHAPE_PROGRESS_DURATION : 1f;
+ final RectF rotatedRect = new RectF();
anim.addOnUpdateListener(new RectFSpringAnim.OnUpdateListener() {
@Override
@@ -445,9 +478,12 @@
Utilities.mapRange(progress, startTransformProgress, endTransformProgress))
.setCurrentRect(currentRect)
.setTargetAlpha(getWindowAlpha(progress));
+ rotatedRect.set(currentRect);
if (isFloatingIconView) {
+ RotationHelper.mapRectFromNormalOrientation(rotatedRect,
+ mDp.widthPx, mDp.heightPx, mOrientedState.getDisplayRotation());
mTransformParams.setCornerRadius(endRadius * progress + startRadius
- * (1f - progress));
+ * (1f - progress));
}
mAppWindowAnimationHelper.applyTransform(mTransformParams);
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/FallbackActivityInterface.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/FallbackActivityInterface.java
index 6574d22..71580ca 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/FallbackActivityInterface.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/FallbackActivityInterface.java
@@ -30,10 +30,11 @@
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
-import com.android.launcher3.BaseActivity;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.anim.AnimationSuccessListener;
import com.android.launcher3.anim.AnimatorPlaybackController;
+import com.android.launcher3.touch.PortraitPagedViewHandler;
+import com.android.launcher3.touch.PagedOrientationHandler;
import com.android.launcher3.userevent.nano.LauncherLogProto;
import com.android.quickstep.fallback.FallbackRecentsView;
import com.android.quickstep.util.ActivityInitListener;
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/FallbackSwipeHandler.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/FallbackSwipeHandler.java
index cd001a1..65fba08 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/FallbackSwipeHandler.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/FallbackSwipeHandler.java
@@ -161,12 +161,12 @@
@Override
protected boolean onActivityInit(Boolean alreadyOnHome) {
+ super.onActivityInit(alreadyOnHome);
mActivity = mActivityInterface.getCreatedActivity();
mRecentsView = mActivity.getOverviewPanel();
linkRecentsViewScroll();
mRecentsView.setDisallowScrollToClearAll(true);
mRecentsView.getClearAllButton().setVisibilityAlpha(0);
-
mRecentsView.setZoomProgress(1);
if (!mContinuingLastGesture) {
@@ -177,6 +177,7 @@
}
}
mStateCallback.setStateOnUiThread(STATE_RECENTS_PRESENT);
+ mDeviceState.enableMultipleRegions(false);
return true;
}
@@ -419,7 +420,7 @@
this::createNewInputProxyHandler);
RectFSpringAnim anim = createWindowAnimationToHome(mCurrentShift.value, duration);
anim.addAnimatorListener(endListener);
- anim.start(mEndVelocityPxPerMs);
+ anim.start(mContext, mEndVelocityPxPerMs);
mFinishAnimation = RunningWindowAnim.wrap(anim);
} else {
@@ -469,7 +470,8 @@
HomeAnimationFactory factory = new HomeAnimationFactory() {
@Override
public RectF getWindowTargetRect() {
- return HomeAnimationFactory.getDefaultWindowTargetRect(mDp);
+ return HomeAnimationFactory
+ .getDefaultWindowTargetRect(mRecentsView.getPagedOrientationHandler(), mDp);
}
@Override
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityInterface.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityInterface.java
index 1b6d291..f19ec69 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityInterface.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityInterface.java
@@ -54,6 +54,8 @@
import com.android.launcher3.allapps.DiscoveryBounce;
import com.android.launcher3.anim.AnimatorPlaybackController;
import com.android.launcher3.appprediction.PredictionUiStateManager;
+import com.android.launcher3.touch.PortraitPagedViewHandler;
+import com.android.launcher3.touch.PagedOrientationHandler;
import com.android.launcher3.userevent.nano.LauncherLogProto;
import com.android.launcher3.views.FloatingIconView;
import com.android.quickstep.SysUINavigationMode.Mode;
@@ -176,7 +178,8 @@
if (canUseWorkspaceView) {
return iconLocation;
} else {
- return HomeAnimationFactory.getDefaultWindowTargetRect(dp);
+ return HomeAnimationFactory
+ .getDefaultWindowTargetRect(recentsView.getPagedOrientationHandler(), dp);
}
}
@@ -268,23 +271,28 @@
float scrollOffsetX = recentsView.getScrollOffset();
float offscreenX = recentsView.getOffscreenTranslationX(currScale);
- float fromTranslationX = attached ? offscreenX - scrollOffsetX : 0;
- float toTranslationX = attached ? 0 : offscreenX - scrollOffsetX;
+ float fromTranslation = attached ? offscreenX - scrollOffsetX : 0;
+ float toTranslation = attached ? 0 : offscreenX - scrollOffsetX;
launcher.getStateManager()
.cancelStateElementAnimation(INDEX_RECENTS_TRANSLATE_X_ANIM);
+ PagedOrientationHandler pagedOrientationHandler =
+ recentsView.getPagedViewOrientedState().getOrientationHandler();
if (!recentsView.isShown() && animate) {
- recentsView.setTranslationX(fromTranslationX);
+ pagedOrientationHandler
+ .getPrimaryViewTranslate().set(recentsView, fromTranslation);
} else {
- fromTranslationX = recentsView.getTranslationX();
+ fromTranslation =
+ pagedOrientationHandler.getPrimaryViewTranslate().get(recentsView);
}
if (!animate) {
- recentsView.setTranslationX(toTranslationX);
+ pagedOrientationHandler
+ .getPrimaryViewTranslate().set(recentsView, toTranslation);
} else {
launcher.getStateManager().createStateElementAnimation(
INDEX_RECENTS_TRANSLATE_X_ANIM,
- fromTranslationX, toTranslationX).start();
+ fromTranslation, toTranslation).start();
}
fadeAnim.setInterpolator(attached ? INSTANT : ACCEL_2);
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherSwipeHandler.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherSwipeHandler.java
index 646d01f..3807e45 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherSwipeHandler.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherSwipeHandler.java
@@ -261,6 +261,7 @@
@Override
protected boolean onActivityInit(Boolean alreadyOnHome) {
+ super.onActivityInit(alreadyOnHome);
final T activity = mActivityInterface.getCreatedActivity();
if (mActivity == activity) {
return true;
@@ -770,6 +771,16 @@
}
}
+ if (endTarget == NEW_TASK) {
+ SystemUiProxy.INSTANCE.get(mContext).onQuickSwitchToNewTask();
+ }
+
+ if (endTarget == RECENTS || endTarget == HOME) {
+ // Since we're now done quickStepping, we want to only listen for touch events
+ // for the main orientation's nav bar, instead of multiple
+ mDeviceState.enableMultipleRegions(false);
+ }
+
if (mDeviceState.isOverviewDisabled() && (endTarget == RECENTS || endTarget == LAST_TASK)) {
return LAST_TASK;
}
@@ -929,7 +940,8 @@
mGestureState.setState(STATE_END_TARGET_ANIMATION_FINISHED);
}
});
- windowAnim.start(velocityPxPerMs);
+ getOrientationHandler().adjustFloatingIconStartVelocity(velocityPxPerMs);
+ windowAnim.start(mContext, velocityPxPerMs);
homeAnimFactory.playAtomicAnimation(velocityPxPerMs.y);
mRunningWindowAnim = RunningWindowAnim.wrap(windowAnim);
mLauncherTransitionController = null;
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/RecentsActivity.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/RecentsActivity.java
index 3f5179f..94b0051 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/RecentsActivity.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/RecentsActivity.java
@@ -183,7 +183,8 @@
RemoteAnimationTargetCompat[] wallpaperTargets) {
AnimatorSet target = new AnimatorSet();
boolean activityClosing = taskIsATargetWithMode(appTargets, getTaskId(), MODE_CLOSING);
- AppWindowAnimationHelper helper = new AppWindowAnimationHelper(this);
+ AppWindowAnimationHelper helper = new AppWindowAnimationHelper(
+ mFallbackRecentsView.getPagedViewOrientedState(), this);
target.play(getRecentsWindowAnimator(taskView, !activityClosing, appTargets,
wallpaperTargets, helper).setDuration(RECENTS_LAUNCH_DURATION));
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java
index 28e8fb6..ffa17ce 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java
@@ -17,13 +17,7 @@
import static android.view.MotionEvent.ACTION_DOWN;
-import static com.android.launcher3.config.FeatureFlags.ADAPTIVE_ICON_WINDOW_ANIM;
-import static com.android.launcher3.config.FeatureFlags.APPLY_CONFIG_AT_RUNTIME;
-import static com.android.launcher3.config.FeatureFlags.ENABLE_HINTS_IN_OVERVIEW;
import static com.android.launcher3.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TILE;
-import static com.android.launcher3.config.FeatureFlags.FAKE_LANDSCAPE_UI;
-import static com.android.launcher3.config.FeatureFlags.QUICKSTEP_SPRINGS;
-import static com.android.launcher3.config.FeatureFlags.UNSTABLE_SPRINGS;
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_INPUT_MONITOR;
@@ -56,6 +50,8 @@
import androidx.annotation.WorkerThread;
import com.android.launcher3.BaseDraggingActivity;
+import com.android.launcher3.Launcher;
+import com.android.launcher3.PagedView;
import com.android.launcher3.Utilities;
import com.android.launcher3.allapps.DiscoveryBounce;
import com.android.launcher3.config.FeatureFlags;
@@ -80,6 +76,7 @@
import com.android.quickstep.util.ActiveGestureLog;
import com.android.quickstep.util.AssistantUtilities;
import com.android.quickstep.util.ProtoTracer;
+import com.android.quickstep.views.RecentsView;
import com.android.systemui.plugins.OverscrollPlugin;
import com.android.systemui.plugins.PluginListener;
import com.android.systemui.shared.recents.IOverviewProxy;
@@ -449,6 +446,8 @@
Object traceToken = TraceHelper.INSTANCE.beginFlagsOverride(
TraceHelper.FLAG_ALLOW_BINDER_TRACKING);
+ mDeviceState.setOrientationTransformIfNeeded(event);
+
if (event.getAction() == ACTION_DOWN) {
GestureState newGestureState = new GestureState(mOverviewComponentObserver,
ActiveGestureLog.INSTANCE.generateAndSetLogId());
@@ -502,7 +501,9 @@
|| previousGestureState.isRecentsAnimationRunning()
? newBaseConsumer(previousGestureState, newGestureState, event)
: mResetGestureInputConsumer;
+ // TODO(b/149880412): 2 button landscape mode is wrecked. Fixit!
if (mDeviceState.isFullyGesturalNavMode()) {
+ handleOrientationSetup(base);
if (mDeviceState.canTriggerAssistantAction(event)) {
base = new AssistantInputConsumer(this, newGestureState, base, mInputMonitorCompat);
}
@@ -533,6 +534,22 @@
return base;
}
+ private void handleOrientationSetup(InputConsumer baseInputConsumer) {
+ if (!PagedView.sFlagForcedRotation) {
+ return;
+ }
+ mDeviceState.enableMultipleRegions(baseInputConsumer instanceof OtherActivityInputConsumer);
+ Launcher l = (Launcher) mOverviewComponentObserver
+ .getActivityInterface().getCreatedActivity();
+ if (l == null || !(l.getOverviewPanel() instanceof RecentsView)) {
+ return;
+ }
+ ((RecentsView)l.getOverviewPanel())
+ .setLayoutRotation(mDeviceState.getCurrentActiveRotation(),
+ mDeviceState.getDisplayRotation());
+ l.getDragLayer().recreateControllers();
+ }
+
private InputConsumer newBaseConsumer(GestureState previousGestureState,
GestureState gestureState, MotionEvent event) {
if (mDeviceState.isKeyguardShowingOccluded()) {
@@ -732,10 +749,18 @@
FeatureFlags.dump(pw);
PluginManagerWrapper.INSTANCE.get(getBaseContext()).dump(pw);
mDeviceState.dump(pw);
- mOverviewComponentObserver.dump(pw);
+ if (mOverviewComponentObserver != null) {
+ mOverviewComponentObserver.dump(pw);
+ }
+ if (mGestureState != null) {
+ mGestureState.dump(pw);
+ }
pw.println("TouchState:");
+ BaseDraggingActivity createdOverviewActivity = mOverviewComponentObserver == null ? null
+ : mOverviewComponentObserver.getActivityInterface().getCreatedActivity();
boolean resumed = mOverviewComponentObserver != null
&& mOverviewComponentObserver.getActivityInterface().isResumed();
+ pw.println(" createdOverviewActivity=" + createdOverviewActivity);
pw.println(" resumed=" + resumed);
pw.println(" mConsumer=" + mConsumer.getName());
ActiveGestureLog.INSTANCE.dump("", pw);
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/fallback/FallbackRecentsView.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/fallback/FallbackRecentsView.java
index 79e71a1..dc0c194 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/fallback/FallbackRecentsView.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/fallback/FallbackRecentsView.java
@@ -195,4 +195,9 @@
}
super.applyLoadPlan(tasks);
}
+
+ @Override
+ protected boolean supportsVerticalLandscape() {
+ return false;
+ }
}
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java
index 8e7074d..bd9f330 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java
@@ -176,8 +176,7 @@
// Proxy events to recents view
if (mPassedWindowMoveSlop && mInteractionHandler != null
&& !mRecentsViewDispatcher.hasConsumer()) {
- mRecentsViewDispatcher.setConsumer(mInteractionHandler.getRecentsViewDispatcher(
- mNavBarPosition.getRotationMode()));
+ mRecentsViewDispatcher.setConsumer(mInteractionHandler.getRecentsViewDispatcher());
}
int edgeFlags = ev.getEdgeFlags();
ev.setEdgeFlags(edgeFlags | EDGE_NAV_BAR);
@@ -364,7 +363,6 @@
: mNavBarPosition.isLeftEdge()
? -velocityX
: velocityY;
-
mInteractionHandler.updateDisplacement(getDisplacement(ev) - mStartDisplacement);
mInteractionHandler.onGestureEnded(velocity, new PointF(velocityX, velocityY),
mDownPos);
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/util/AppWindowAnimationHelper.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/util/AppWindowAnimationHelper.java
index 5a9c2fe..91af156 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/util/AppWindowAnimationHelper.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/util/AppWindowAnimationHelper.java
@@ -15,12 +15,6 @@
*/
package com.android.quickstep.util;
-import static com.android.launcher3.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TILE;
-import static com.android.systemui.shared.system.QuickStepContract.getWindowCornerRadius;
-import static com.android.systemui.shared.system.QuickStepContract.supportsRoundedCornersOnWindows;
-import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.MODE_CLOSING;
-import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.MODE_OPENING;
-
import android.annotation.TargetApi;
import android.content.Context;
import android.graphics.Matrix;
@@ -28,6 +22,7 @@
import android.graphics.Rect;
import android.graphics.RectF;
import android.os.Build;
+import android.view.Surface;
import androidx.annotation.Nullable;
@@ -37,6 +32,7 @@
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
import com.android.launcher3.anim.Interpolators;
+import com.android.launcher3.model.PagedViewOrientedState;
import com.android.launcher3.views.BaseDragLayer;
import com.android.quickstep.RemoteAnimationTargets;
import com.android.quickstep.SystemUiProxy;
@@ -50,6 +46,12 @@
import com.android.systemui.shared.system.TransactionCompat;
import com.android.systemui.shared.system.WindowManagerWrapper;
+import static com.android.launcher3.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TILE;
+import static com.android.systemui.shared.system.QuickStepContract.getWindowCornerRadius;
+import static com.android.systemui.shared.system.QuickStepContract.supportsRoundedCornersOnWindows;
+import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.MODE_CLOSING;
+import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.MODE_OPENING;
+
/**
* Utility class to handle window clip animation
*/
@@ -82,6 +84,7 @@
private final Rect mTmpRect = new Rect();
private final RectF mTmpRectF = new RectF();
private final RectF mCurrentRectWithInsets = new RectF();
+ private PagedViewOrientedState mOrientedState;
// Corner radius of windows, in pixels
private final float mWindowCornerRadius;
// Corner radius of windows when they're in overview mode.
@@ -100,20 +103,24 @@
private TargetAlphaProvider mTaskAlphaCallback = (t, a) -> a;
private TargetAlphaProvider mBaseAlphaCallback = (t, a) -> 1;
- public AppWindowAnimationHelper(Context context) {
+ public AppWindowAnimationHelper(PagedViewOrientedState orientedState, Context context) {
+ mOrientedState = orientedState;
mWindowCornerRadius = getWindowCornerRadius(context.getResources());
mSupportsRoundedCornersOnWindows = supportsRoundedCornersOnWindows(context.getResources());
mTaskCornerRadius = TaskCornerRadius.get(context);
mUseRoundedCornersOnWindows = mSupportsRoundedCornersOnWindows;
}
+ public AppWindowAnimationHelper(Context context) {
+ this(null, context);
+ }
+
private void updateSourceStack(RemoteAnimationTargetCompat target) {
mSourceInsets.set(target.contentInsets);
mSourceStackBounds.set(target.sourceContainerBounds);
// TODO: Should sourceContainerBounds already have this offset?
mSourceStackBounds.offsetTo(target.position.x, target.position.y);
-
}
public void updateSource(Rect homeStackBounds, RemoteAnimationTargetCompat target) {
@@ -138,8 +145,9 @@
// from the source rect. The difference between the target rect (scaled to the
// source rect) is the amount to clip on each edge.
RectF scaledTargetRect = new RectF(mTargetRect);
- Utilities.scaleRectFAboutCenter(scaledTargetRect,
- mSourceRect.width() / mTargetRect.width());
+ float scale = getSrcToTargetScale();
+ Utilities.scaleRectFAboutCenter(scaledTargetRect, scale);
+
scaledTargetRect.offsetTo(mSourceRect.left, mSourceRect.top);
mSourceWindowClipInsets.set(
Math.max(scaledTargetRect.left, 0),
@@ -149,6 +157,16 @@
mSourceRect.set(scaledTargetRect);
}
+ private float getSrcToTargetScale() {
+ if (mOrientedState == null ||
+ (mOrientedState.getDisplayRotation() == Surface.ROTATION_0
+ || mOrientedState.getDisplayRotation() == Surface.ROTATION_180)) {
+ return mSourceRect.width() / mTargetRect.width();
+ } else {
+ return mSourceRect.height() / mTargetRect.height();
+ }
+ }
+
public void prepareAnimation(DeviceProfile dp, boolean isOpening) {
mBoostModeTargetLayers = isOpening ? MODE_OPENING : MODE_CLOSING;
mUseRoundedCornersOnWindows = mSupportsRoundedCornersOnWindows && !dp.isMultiWindowMode;
@@ -221,7 +239,6 @@
layer = Integer.MAX_VALUE;
}
}
-
// Since radius is in Surface space, but we draw the rounded corners in screen space, we
// have to undo the scale.
surfaceParams[i] = new SurfaceParams(app.leash, alpha, mTmpMatrix, crop, layer,
@@ -237,11 +254,16 @@
mTmpRectF.set(mTargetRect);
Utilities.scaleRectFAboutCenter(mTmpRectF, params.mOffsetScale);
mCurrentRect.set(mRectFEvaluator.evaluate(params.mProgress, mSourceRect, mTmpRectF));
- mCurrentRect.offset(params.mOffsetX, 0);
+ if (mOrientedState == null || mOrientedState.areMultipleLayoutOrientationsDisabled()) {
+ mCurrentRect.offset(params.mOffset, 0);
+ } else {
+ int displayRotation = mOrientedState.getDisplayRotation();
+ mOrientedState.getOrientationHandler().offsetTaskRect(mCurrentRect,
+ params.mOffset, displayRotation);
+ }
}
updateClipRect(params);
-
return mCurrentRect;
}
@@ -340,7 +362,7 @@
* @return The source rect's scale and translation relative to the target rect.
*/
public LauncherState.ScaleAndTranslation getScaleAndTranslation() {
- float scale = mSourceRect.width() / mTargetRect.width();
+ float scale = getSrcToTargetScale();
float translationY = mSourceRect.centerY() - mSourceRect.top - mTargetRect.centerY();
return new LauncherState.ScaleAndTranslation(scale, 0, translationY);
}
@@ -390,7 +412,7 @@
public static class TransformParams {
private float mProgress;
- private float mOffsetX;
+ private float mOffset;
private float mOffsetScale;
private @Nullable RectF mCurrentRect;
private float mTargetAlpha;
@@ -401,7 +423,7 @@
public TransformParams() {
mProgress = 0;
- mOffsetX = 0;
+ mOffset = 0;
mOffsetScale = 1;
mCurrentRect = null;
mTargetAlpha = 1;
@@ -453,8 +475,8 @@
* the default), then offset the current rect by this amount after computing the rect based
* on {@link #mProgress}.
*/
- public TransformParams setOffsetX(float offsetX) {
- mOffsetX = offsetX;
+ public TransformParams setOffset(float offset) {
+ mOffset = offset;
return this;
}
@@ -504,8 +526,8 @@
return mProgress;
}
- public float getOffsetX() {
- return mOffsetX;
+ public float getOffset() {
+ return mOffset;
}
public float getOffsetScale() {
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/util/RectFSpringAnim.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/util/RectFSpringAnim.java
index a59c99c..682c92c 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/util/RectFSpringAnim.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/util/RectFSpringAnim.java
@@ -16,6 +16,7 @@
package com.android.quickstep.util;
import android.animation.Animator;
+import android.content.Context;
import android.content.res.Resources;
import android.graphics.PointF;
import android.graphics.RectF;
@@ -28,6 +29,8 @@
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
import com.android.launcher3.anim.FlingSpringAnim;
+import com.android.launcher3.util.DynamicResource;
+import com.android.systemui.plugins.ResourceProvider;
import java.util.ArrayList;
import java.util.List;
@@ -137,7 +140,12 @@
mAnimatorListeners.add(animatorListener);
}
- public void start(PointF velocityPxPerMs) {
+ /**
+ * Starts the fling/spring animation.
+ * @param context The activity context.
+ * @param velocityPxPerMs Velocity of swipe in px/ms.
+ */
+ public void start(Context context, PointF velocityPxPerMs) {
// Only tell caller that we ended if both x and y animations have ended.
OnAnimationEndListener onXEndListener = ((animation, canceled, centerX, velocityX) -> {
mRectXAnimEnded = true;
@@ -166,10 +174,14 @@
mMinVisChange, minYValue, maxYValue, springVelocityFactor, onYEndListener);
float minVisibleChange = Math.abs(1f / mStartRect.height());
+ ResourceProvider rp = DynamicResource.provider(context);
+ float damping = rp.getFloat(R.dimen.swipe_up_rect_damping_ratio);
+ float stiffness = rp.getFloat(R.dimen.swipe_up_rect_stiffness);
+
mRectScaleAnim = new SpringAnimation(this, RECT_SCALE_PROGRESS)
.setSpring(new SpringForce(1f)
- .setDampingRatio(SpringForce.DAMPING_RATIO_LOW_BOUNCY)
- .setStiffness(SpringForce.STIFFNESS_LOW))
+ .setDampingRatio(damping)
+ .setStiffness(stiffness))
.setStartVelocity(velocityPxPerMs.y * minVisibleChange)
.setMaxValue(1f)
.setMinimumVisibleChange(minVisibleChange)
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/util/StaggeredWorkspaceAnim.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/util/StaggeredWorkspaceAnim.java
index babf13e..d2805ed 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/util/StaggeredWorkspaceAnim.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/util/StaggeredWorkspaceAnim.java
@@ -41,7 +41,9 @@
import com.android.launcher3.anim.PropertySetter;
import com.android.launcher3.anim.SpringAnimationBuilder;
import com.android.launcher3.graphics.OverviewScrim;
+import com.android.launcher3.util.DynamicResource;
import com.android.quickstep.views.RecentsView;
+import com.android.systemui.plugins.ResourceProvider;
/**
* Creates an animation where all the workspace items are moved into their final location,
@@ -55,9 +57,6 @@
private static final float MAX_VELOCITY_PX_PER_S = 22f;
- private static final float DAMPING_RATIO = 0.7f;
- private static final float STIFFNESS = 150f;
-
private final float mVelocity;
private final float mSpringTransY;
@@ -177,9 +176,12 @@
v.setTranslationY(mSpringTransY);
+ ResourceProvider rp = DynamicResource.provider(v.getContext());
+ float stiffness = rp.getFloat(R.dimen.staggered_stiffness);
+ float damping = rp.getFloat(R.dimen.staggered_damping_ratio);
ObjectAnimator springTransY = new SpringAnimationBuilder<>(v, VIEW_TRANSLATE_Y)
- .setStiffness(STIFFNESS)
- .setDampingRatio(DAMPING_RATIO)
+ .setStiffness(stiffness)
+ .setDampingRatio(damping)
.setMinimumVisibleChange(1f)
.setEndValue(0)
.setStartVelocity(mVelocity)
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/ClearAllButton.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/ClearAllButton.java
index 9db0c09..d0819c1 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/ClearAllButton.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/ClearAllButton.java
@@ -21,7 +21,7 @@
import android.util.Property;
import android.widget.Button;
-import com.android.launcher3.Utilities;
+import com.android.launcher3.touch.PagedOrientationHandler;
import com.android.quickstep.views.RecentsView.PageCallbacks;
import com.android.quickstep.views.RecentsView.ScrollState;
@@ -44,21 +44,26 @@
private float mContentAlpha = 1;
private float mVisibilityAlpha = 1;
- private final boolean mIsRtl;
+ private boolean mIsRtl;
private int mScrollOffset;
+ private RecentsView mParent;
public ClearAllButton(Context context, AttributeSet attrs) {
super(context, attrs);
- mIsRtl = Utilities.isRtl(context.getResources());
}
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
+ mScrollOffset = mIsRtl ? mParent.getPaddingRight() / 2 : - mParent.getPaddingLeft() / 2;
+ }
- RecentsView parent = (RecentsView) getParent();
- mScrollOffset = mIsRtl ? parent.getPaddingRight() / 2 : - parent.getPaddingLeft() / 2;
+ @Override
+ protected void onAttachedToWindow() {
+ super.onAttachedToWindow();
+ mParent = (RecentsView) getParent();
+ mIsRtl = !mParent.getPagedOrientationHandler().getRecentsRtlSetting(getResources());
}
@Override
@@ -73,6 +78,21 @@
}
}
+ public void onLayoutChanged() {
+ if (mParent == null) {
+ return;
+ }
+ setRotation(mParent.getPagedOrientationHandler().getDegreesRotated());
+ }
+
+ public void setRtl(boolean rtl) {
+ if (mIsRtl == rtl) {
+ return;
+ }
+ mIsRtl = rtl;
+ invalidate();
+ }
+
public void setVisibilityAlpha(float alpha) {
if (mVisibilityAlpha != alpha) {
mVisibilityAlpha = alpha;
@@ -82,14 +102,16 @@
@Override
public void onPageScroll(ScrollState scrollState) {
- float width = getWidth();
- if (width == 0) {
+ PagedOrientationHandler orientationHandler = mParent.getPagedOrientationHandler();
+ float orientationSize = orientationHandler.getPrimaryValue(getWidth(), getHeight());
+ if (orientationSize == 0) {
return;
}
- float shift = Math.min(scrollState.scrollFromEdge, width);
- setTranslationX(mIsRtl ? (mScrollOffset - shift) : (mScrollOffset + shift));
- mScrollAlpha = 1 - shift / width;
+ float shift = Math.min(scrollState.scrollFromEdge, orientationSize);
+ float translation = mIsRtl ? (mScrollOffset - shift) : (mScrollOffset + shift);
+ orientationHandler.setPrimaryAndResetSecondaryTranslate(this, translation);
+ mScrollAlpha = 1 - shift / orientationSize;
updateAlpha();
}
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/LauncherRecentsView.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/LauncherRecentsView.java
index 3e106aa..b2d182b 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/LauncherRecentsView.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/LauncherRecentsView.java
@@ -42,6 +42,7 @@
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherState;
import com.android.launcher3.LauncherStateManager.StateListener;
+import com.android.launcher3.PagedView;
import com.android.launcher3.R;
import com.android.launcher3.anim.Interpolators;
import com.android.launcher3.appprediction.PredictionUiStateManager;
@@ -180,19 +181,21 @@
* @return The translationX to apply to this view so that the first task is just offscreen.
*/
public float getOffscreenTranslationX(float recentsScale) {
- float offscreenX = NORMAL.getOverviewScaleAndTranslation(mActivity).translationX;
+ LauncherState.ScaleAndTranslation overviewScaleAndTranslation =
+ NORMAL.getOverviewScaleAndTranslation(mActivity);
+ float offscreen = mOrientationHandler.getTranslationValue(overviewScaleAndTranslation);
// Offset since scale pushes tasks outwards.
getTaskSize(sTempRect);
- int taskWidth = sTempRect.width();
- offscreenX += taskWidth * (recentsScale - 1) / 2;
+ int taskSize = mOrientationHandler.getPrimarySize(sTempRect);
+ offscreen += taskSize * (recentsScale - 1) / 2;
if (mRunningTaskTileHidden) {
// The first task is hidden, so offset by its width.
- offscreenX -= (taskWidth + getPageSpacing()) * recentsScale;
+ offscreen -= (taskSize + getPageSpacing()) * recentsScale;
}
if (isRtl()) {
- offscreenX = -offscreenX;
+ offscreen = -offscreen;
}
- return offscreenX;
+ return offscreen;
}
@Override
@@ -277,6 +280,11 @@
}
@Override
+ protected boolean supportsVerticalLandscape() {
+ return PagedView.sFlagForcedRotation;
+ }
+
+ @Override
public void reset() {
super.reset();
@@ -339,19 +347,19 @@
}
@Override
- protected int computeMinScrollX() {
+ protected int computeMinScroll() {
if (canComputeScrollX() && !mIsRtl) {
return computeScrollX();
}
- return super.computeMinScrollX();
+ return super.computeMinScroll();
}
@Override
- protected int computeMaxScrollX() {
+ protected int computeMaxScroll() {
if (canComputeScrollX() && mIsRtl) {
return computeScrollX();
}
- return super.computeMaxScrollX();
+ return super.computeMaxScroll();
}
private boolean canComputeScrollX() {
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsView.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsView.java
index 27ef93c..c201455 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsView.java
@@ -22,7 +22,6 @@
import static com.android.launcher3.InvariantDeviceProfile.CHANGE_FLAG_ICON_PARAMS;
import static com.android.launcher3.LauncherAnimUtils.SCALE_PROPERTY;
import static com.android.launcher3.LauncherAnimUtils.VIEW_TRANSLATE_X;
-import static com.android.launcher3.LauncherAnimUtils.VIEW_TRANSLATE_Y;
import static com.android.launcher3.Utilities.EDGE_NAV_BAR;
import static com.android.launcher3.Utilities.squaredHypot;
import static com.android.launcher3.Utilities.squaredTouchSlop;
@@ -52,7 +51,6 @@
import android.content.Context;
import android.content.Intent;
import android.graphics.Canvas;
-import android.graphics.Matrix;
import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.RectF;
@@ -66,11 +64,13 @@
import android.text.TextPaint;
import android.util.AttributeSet;
import android.util.FloatProperty;
+import android.util.Property;
import android.util.SparseBooleanArray;
import android.view.HapticFeedbackConstants;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.MotionEvent;
+import android.view.OrientationEventListener;
import android.view.View;
import android.view.ViewDebug;
import android.view.ViewGroup;
@@ -80,7 +80,6 @@
import android.widget.ListView;
import androidx.annotation.Nullable;
-import androidx.dynamicanimation.animation.SpringForce;
import com.android.launcher3.BaseActivity;
import com.android.launcher3.DeviceProfile;
@@ -90,16 +89,20 @@
import com.android.launcher3.PagedView;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
+import com.android.launcher3.anim.AnimationSuccessListener;
import com.android.launcher3.anim.AnimatorPlaybackController;
import com.android.launcher3.anim.PropertyListBuilder;
import com.android.launcher3.anim.SpringObjectAnimator;
import com.android.launcher3.compat.AccessibilityManagerCompat;
import com.android.launcher3.config.FeatureFlags;
-import com.android.launcher3.graphics.RotationMode;
+import com.android.launcher3.dragndrop.DragLayer;
+import com.android.launcher3.states.RotationHelper;
+import com.android.launcher3.touch.PagedOrientationHandler.CurveProperties;
import com.android.launcher3.userevent.nano.LauncherLogProto;
import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Direction;
import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch;
import com.android.launcher3.util.ComponentKey;
+import com.android.launcher3.util.DynamicResource;
import com.android.launcher3.util.OverScroller;
import com.android.launcher3.util.PendingAnimation;
import com.android.launcher3.util.Themes;
@@ -114,6 +117,7 @@
import com.android.quickstep.ViewUtils;
import com.android.quickstep.util.AppWindowAnimationHelper;
import com.android.quickstep.util.LayoutUtils;
+import com.android.systemui.plugins.ResourceProvider;
import com.android.systemui.shared.recents.IPinnedStackAnimationListener;
import com.android.systemui.shared.recents.model.Task;
import com.android.systemui.shared.recents.model.ThumbnailData;
@@ -162,6 +166,8 @@
}
};
+ private final OrientationEventListener mOrientationListener;
+ private int mPreviousRotation;
protected RecentsAnimationController mRecentsAnimationController;
protected RecentsAnimationTargets mRecentsAnimationTargets;
protected AppWindowAnimationHelper mAppWindowAnimationHelper;
@@ -268,15 +274,8 @@
}
};
- private final IPinnedStackAnimationListener mIPinnedStackAnimationListener =
- new IPinnedStackAnimationListener.Stub() {
- @Override
- public void onPinnedStackAnimationStarted() {
- // Needed for activities that auto-enter PiP, which will not trigger a remote
- // animation to be created
- mActivity.clearForceInvisibleFlag(STATE_HANDLER_INVISIBILITY_FLAGS);
- }
- };
+ private final PinnedStackAnimationListener mIPinnedStackAnimationListener =
+ new PinnedStackAnimationListener();
// Used to keep track of the last requested task list id, so that we do not request to load the
// tasks again if we have already requested it and the task list has not changed
@@ -340,7 +339,8 @@
mActivity = (T) BaseActivity.fromContext(context);
mModel = RecentsModel.INSTANCE.get(context);
mIdp = InvariantDeviceProfile.INSTANCE.get(context);
- mTempAppWindowAnimationHelper = new AppWindowAnimationHelper(context);
+ mTempAppWindowAnimationHelper =
+ new AppWindowAnimationHelper(getPagedViewOrientedState(), context);
mClearAllButton = (ClearAllButton) LayoutInflater.from(context)
.inflate(R.layout.overview_clear_all_button, this, false);
@@ -348,7 +348,7 @@
mTaskViewPool = new ViewPool<>(context, this, R.layout.task, 20 /* max size */,
10 /* initial size */);
- mIsRtl = !Utilities.isRtl(getResources());
+ mIsRtl = mOrientationHandler.getRecentsRtlSetting(getResources());
setLayoutDirection(mIsRtl ? View.LAYOUT_DIRECTION_RTL : View.LAYOUT_DIRECTION_LTR);
mTaskTopMargin = getResources()
.getDimensionPixelSize(R.dimen.task_thumbnail_top_margin);
@@ -368,9 +368,21 @@
.getDimensionPixelSize(R.dimen.recents_empty_message_text_padding);
setWillNotDraw(false);
updateEmptyMessage();
+ disableMultipleLayoutRotations(!supportsVerticalLandscape());
// Initialize quickstep specific cache params here, as this is constructed only once
mActivity.getViewCache().setCacheSize(R.layout.digital_wellbeing_toast, 5);
+ mOrientationListener = new OrientationEventListener(getContext()) {
+ @Override
+ public void onOrientationChanged(int i) {
+ int rotation = RotationHelper.getRotationFromDegrees(i);
+ if (mPreviousRotation != rotation) {
+ animateRecentsRotationInPlace(rotation);
+ mPreviousRotation = rotation;
+ }
+ }
+ };
+
}
public OverScroller getScroller() {
@@ -451,6 +463,7 @@
mSyncTransactionApplier = new SyncRtSurfaceTransactionApplierCompat(this);
RecentsModel.INSTANCE.get(getContext()).addThumbnailChangeListener(this);
mIdp.addOnChangeListener(this);
+ mIPinnedStackAnimationListener.setActivity(mActivity);
SystemUiProxy.INSTANCE.get(getContext()).setPinnedStackAnimationListener(
mIPinnedStackAnimationListener);
}
@@ -466,6 +479,7 @@
RecentsModel.INSTANCE.get(getContext()).removeThumbnailChangeListener(this);
mIdp.removeOnChangeListener(this);
SystemUiProxy.INSTANCE.get(getContext()).setPinnedStackAnimationListener(null);
+ mIPinnedStackAnimationListener.setActivity(null);
}
@Override
@@ -496,6 +510,13 @@
}
public void setOverviewStateEnabled(boolean enabled) {
+ if (supportsVerticalLandscape() && mOrientationListener.canDetectOrientation()) {
+ if (enabled) {
+ mOrientationListener.enable();
+ } else {
+ mOrientationListener.disable();
+ }
+ }
mOverviewStateEnabled = enabled;
updateTaskStackListenerState();
if (!enabled) {
@@ -623,7 +644,7 @@
final int pageIndex = requiredTaskCount - i - 1 + mTaskViewStartIndex;
final Task task = tasks.get(i);
final TaskView taskView = (TaskView) getChildAt(pageIndex);
- taskView.bind(task);
+ taskView.bind(task, mLayoutRotation);
}
if (mNextPage == INVALID_PAGE) {
@@ -755,19 +776,21 @@
if (getPageCount() == 0 || getPageAt(0).getMeasuredWidth() == 0) {
return;
}
- int scrollX = getScrollX();
- final int halfPageWidth = getNormalChildWidth() / 2;
- final int screenCenter = mInsets.left + getPaddingLeft() + scrollX + halfPageWidth;
- final int halfScreenWidth = getMeasuredWidth() / 2;
+ CurveProperties curveProperties = mOrientationHandler
+ .getCurveProperties(this, mInsets);
+ int scroll = curveProperties.scroll;
+ final int halfPageSize = curveProperties.halfPageSize;
+ final int screenCenter = curveProperties.screenCenter;
+ final int halfScreenSize = curveProperties.halfScreenSize;
final int pageSpacing = mPageSpacing;
- mScrollState.scrollFromEdge = mIsRtl ? scrollX : (mMaxScrollX - scrollX);
+ mScrollState.scrollFromEdge = mIsRtl ? scroll : (mMaxScroll - scroll);
final int pageCount = getPageCount();
for (int i = 0; i < pageCount; i++) {
View page = getPageAt(i);
- float pageCenter = page.getLeft() + page.getTranslationX() + halfPageWidth;
+ float pageCenter = mOrientationHandler.getViewCenterPosition(page) + halfPageSize;
float distanceFromScreenCenter = screenCenter - pageCenter;
- float distanceToReachEdge = halfScreenWidth + halfPageWidth + pageSpacing;
+ float distanceToReachEdge = halfScreenSize + halfPageSize + pageSpacing;
mScrollState.linearInterpolation = Math.min(1,
Math.abs(distanceFromScreenCenter) / distanceToReachEdge);
((PageCallbacks) page).onPageScroll(mScrollState);
@@ -915,6 +938,47 @@
setSwipeDownShouldLaunchApp(true);
}
+ private void animateRecentsRotationInPlace(int newRotation) {
+ if (!supportsVerticalLandscape()) {
+ return;
+ }
+
+ AnimatorSet pa = setRecentsChangedOrientation(true);
+ pa.addListener(new AnimationSuccessListener() {
+ @Override
+ public void onAnimationSuccess(Animator animator) {
+ updateLayoutRotation(newRotation);
+ ((DragLayer)mActivity.getDragLayer()).recreateControllers();
+ rotateAllChildTasks();
+ setRecentsChangedOrientation(false).start();
+ }
+ });
+ pa.start();
+ }
+
+ public AnimatorSet setRecentsChangedOrientation(boolean fadeInChildren) {
+ getRunningTaskIndex();
+ int runningIndex = getCurrentPage();
+ AnimatorSet as = new AnimatorSet();
+ for (int i = 0; i < getTaskViewCount(); i++) {
+ if (runningIndex == i) {
+ continue;
+ }
+ View taskView = getTaskViewAt(i);
+ as.play(ObjectAnimator.ofFloat(taskView, View.ALPHA, fadeInChildren ? 0 : 1));
+ }
+ return as;
+ }
+
+ abstract protected boolean supportsVerticalLandscape();
+
+ private void rotateAllChildTasks() {
+ for (int i = 0; i < getTaskViewCount(); i++) {
+ TaskView taskView = getTaskViewAt(i);
+ taskView.setOverviewRotation(mLayoutRotation);
+ }
+ }
+
/**
* Called when a gesture from an app has finished.
*/
@@ -950,7 +1014,7 @@
new ComponentName(getContext(), getClass()), 0, 0), null, null, "", "", 0, 0,
false, true, false, false, new ActivityManager.TaskDescription(), 0,
new ComponentName("", ""), false);
- taskView.bind(mTmpRunningTask);
+ taskView.bind(mTmpRunningTask, mLayoutRotation);
}
boolean runningTaskTileHidden = mRunningTaskTileHidden;
@@ -1126,15 +1190,22 @@
private void addDismissedTaskAnimations(View taskView, AnimatorSet anim, long duration) {
addAnim(ObjectAnimator.ofFloat(taskView, ALPHA, 0), duration, ACCEL_2, anim);
+ FloatProperty<View> secondaryViewTranslate =
+ mOrientationHandler.getSecondaryViewTranslate();
+ int secondaryTaskDimension = mOrientationHandler.getSecondaryDimension(taskView);
+ int verticalFactor = mOrientationHandler.getTaskDismissDirectionFactor();
if (UNSTABLE_SPRINGS.get() && taskView instanceof TaskView) {
- addAnim(new SpringObjectAnimator<>(taskView, VIEW_TRANSLATE_Y,
- MIN_VISIBLE_CHANGE_PIXELS, SpringForce.DAMPING_RATIO_MEDIUM_BOUNCY,
- SpringForce.STIFFNESS_MEDIUM,
- 0, -taskView.getHeight()),
+ ResourceProvider rp = DynamicResource.provider(mActivity);
+ float dampingRatio = rp.getFloat(R.dimen.dismiss_task_trans_y_damping_ratio);
+ float stiffness = rp.getFloat(R.dimen.dismiss_task_trans_y_stiffness);
+
+ addAnim(new SpringObjectAnimator<>(taskView, secondaryViewTranslate,
+ MIN_VISIBLE_CHANGE_PIXELS, dampingRatio,
+ stiffness, 0, verticalFactor * secondaryTaskDimension),
duration, LINEAR, anim);
} else {
- addAnim(ObjectAnimator.ofFloat(taskView, TRANSLATION_Y, -taskView.getHeight()),
- duration, LINEAR, anim);
+ addAnim(ObjectAnimator.ofFloat(taskView, secondaryViewTranslate,
+ verticalFactor * secondaryTaskDimension), duration, LINEAR, anim);
}
}
@@ -1165,11 +1236,9 @@
}
int[] oldScroll = new int[count];
- getPageScrolls(oldScroll, false, SIMPLE_SCROLL_LOGIC);
-
int[] newScroll = new int[count];
+ getPageScrolls(oldScroll, false, SIMPLE_SCROLL_LOGIC);
getPageScrolls(newScroll, false, (v) -> v.getVisibility() != GONE && v != taskView);
-
int taskCount = getTaskViewCount();
int scrollDiffPerPage = 0;
if (count > 1) {
@@ -1207,13 +1276,17 @@
int scrollDiff = newScroll[i] - oldScroll[i] + offset;
if (scrollDiff != 0) {
if (UNSTABLE_SPRINGS.get() && child instanceof TaskView) {
+ ResourceProvider rp = DynamicResource.provider(mActivity);
+ float damping = rp.getFloat(R.dimen.dismiss_task_trans_x_damping_ratio);
+ float stiffness = rp.getFloat(R.dimen.dismiss_task_trans_x_stiffness);
+
addAnim(new SpringObjectAnimator<>(child, VIEW_TRANSLATE_X,
- MIN_VISIBLE_CHANGE_PIXELS, SpringForce.DAMPING_RATIO_MEDIUM_BOUNCY,
- SpringForce.STIFFNESS_MEDIUM,
- 0, scrollDiff), duration, ACCEL, anim);
+ MIN_VISIBLE_CHANGE_PIXELS, damping,
+ stiffness, 0, scrollDiff), duration, ACCEL, anim);
} else {
- addAnim(ObjectAnimator.ofFloat(child, TRANSLATION_X, scrollDiff), duration,
- ACCEL, anim);
+ Property translationProperty = mOrientationHandler.getPrimaryViewTranslate();
+ addAnim(ObjectAnimator.ofFloat(child, translationProperty, scrollDiff),
+ duration, ACCEL, anim);
}
needsCurveUpdates = true;
@@ -1430,6 +1503,18 @@
}
@Override
+ public void setLayoutRotation(int touchRotation, int displayRotation) {
+ if (!sFlagForcedRotation) {
+ return;
+ }
+
+ super.setLayoutRotation(touchRotation, displayRotation);
+ mClearAllButton.onLayoutChanged();
+ mIsRtl = mOrientationHandler.getRecentsRtlSetting(getResources());
+ setLayoutDirection(mIsRtl ? View.LAYOUT_DIRECTION_RTL : View.LAYOUT_DIRECTION_LTR);
+ }
+
+ @Override
public void onViewAdded(View child) {
super.onViewAdded(child);
child.setAlpha(mContentAlpha);
@@ -1649,7 +1734,8 @@
}
});
- AppWindowAnimationHelper appWindowAnimationHelper = new AppWindowAnimationHelper(mActivity);
+ AppWindowAnimationHelper appWindowAnimationHelper = new AppWindowAnimationHelper(
+ getPagedViewOrientedState(), mActivity);
appWindowAnimationHelper.fromTaskThumbnailView(tv.getThumbnail(), this);
appWindowAnimationHelper.prepareAnimation(mActivity.getDeviceProfile(), true /* isOpening */);
AnimatorSet anim = createAdjacentPageAnimForTaskLaunch(tv, appWindowAnimationHelper);
@@ -1806,7 +1892,7 @@
}
@Override
- protected int computeMinScrollX() {
+ protected int computeMinScroll() {
if (getTaskViewCount() > 0) {
if (mDisallowScrollToClearAll) {
// We aren't showing the clear all button,
@@ -1821,11 +1907,11 @@
}
return getScrollForPage(mTaskViewStartIndex);
}
- return super.computeMinScrollX();
+ return super.computeMinScroll();
}
@Override
- protected int computeMaxScrollX() {
+ protected int computeMaxScroll() {
if (getTaskViewCount() > 0) {
if (mDisallowScrollToClearAll) {
// We aren't showing the clear all button,
@@ -1840,7 +1926,7 @@
}
return getScrollForPage(indexOfChild(getTaskViewAt(getTaskViewCount() - 1)) + 1);
}
- return super.computeMaxScrollX();
+ return super.computeMaxScroll();
}
public ClearAllButton getClearAllButton() {
@@ -1855,31 +1941,25 @@
return 0;
}
int startScroll = getScrollForPage(getRunningTaskIndex());
- int offsetX = startScroll - getScrollX();
- offsetX *= getScaleX();
+ int offsetX = startScroll - mOrientationHandler.getPrimaryScroll(this);
+ offsetX *= mOrientationHandler.getPrimaryScale(this);
return offsetX;
}
- public Consumer<MotionEvent> getEventDispatcher(RotationMode rotationMode) {
- if (rotationMode.isTransposed) {
- Matrix transform = new Matrix();
- transform.setRotate(-rotationMode.surfaceRotation);
-
- if (getWidth() > 0 && getHeight() > 0) {
- float scale = ((float) getWidth()) / getHeight();
- transform.postScale(scale, 1 / scale);
- }
-
- Matrix inverse = new Matrix();
- transform.invert(inverse);
- return e -> {
- e.transform(transform);
- super.onTouchEvent(e);
- e.transform(inverse);
- };
- } else {
+ public Consumer<MotionEvent> getEventDispatcher() {
+ int degreesRotated = RotationHelper.getDegreesFromRotation(mLayoutRotation);
+ if (degreesRotated == 0) {
return super::onTouchEvent;
}
+
+ // At this point the event coordinates have already been transformed, so we need to
+ // undo that transformation since PagedView also accommodates for the transformation via
+ // PagedOrientationHandler
+ return e -> {
+ RotationHelper.transformEvent(-degreesRotated, e, true);
+ super.onTouchEvent(e);
+ RotationHelper.transformEvent(-degreesRotated, e, false);
+ };
}
public AppWindowAnimationHelper getClipAnimationHelper() {
@@ -1962,4 +2042,20 @@
/** @param isEmpty Whether RecentsView is empty (i.e. has no children) */
void onEmptyMessageUpdated(boolean isEmpty);
}
+
+ private static class PinnedStackAnimationListener<T extends BaseActivity> extends
+ IPinnedStackAnimationListener.Stub {
+ private T mActivity;
+
+ public void setActivity(T activity) {
+ mActivity = activity;
+ }
+
+ @Override
+ public void onPinnedStackAnimationStarted() {
+ // Needed for activities that auto-enter PiP, which will not trigger a remote
+ // animation to be created
+ mActivity.clearForceInvisibleFlag(STATE_HANDLER_INVISIBILITY_FLAGS);
+ }
+ }
}
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskThumbnailView.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskThumbnailView.java
index 8ed1392..178ff32 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskThumbnailView.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskThumbnailView.java
@@ -36,6 +36,7 @@
import android.graphics.Shader;
import android.util.AttributeSet;
import android.util.FloatProperty;
+import android.util.Log;
import android.util.Property;
import android.view.Surface;
import android.view.View;
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskView.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskView.java
index 79b9a9d..9150cc7 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskView.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskView.java
@@ -16,15 +16,6 @@
package com.android.quickstep.views;
-import static android.widget.Toast.LENGTH_SHORT;
-
-import static com.android.launcher3.QuickstepAppTransitionManagerImpl.RECENTS_LAUNCH_DURATION;
-import static com.android.launcher3.anim.Interpolators.FAST_OUT_SLOW_IN;
-import static com.android.launcher3.anim.Interpolators.LINEAR;
-import static com.android.launcher3.anim.Interpolators.TOUCH_RESPONSE_INTERPOLATOR;
-import static com.android.launcher3.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TILE;
-import static com.android.quickstep.SysUINavigationMode.removeShelfFromOverview;
-
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ObjectAnimator;
@@ -41,7 +32,7 @@
import android.util.AttributeSet;
import android.util.FloatProperty;
import android.util.Log;
-import android.view.Gravity;
+import android.view.Surface;
import android.view.View;
import android.view.ViewOutlineProvider;
import android.view.accessibility.AccessibilityNodeInfo;
@@ -58,8 +49,10 @@
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.logging.UserEventDispatcher;
import com.android.launcher3.popup.SystemShortcut;
+import com.android.launcher3.states.RotationHelper;
import com.android.launcher3.testing.TestLogging;
import com.android.launcher3.testing.TestProtocol;
+import com.android.launcher3.touch.PagedOrientationHandler;
import com.android.launcher3.userevent.nano.LauncherLogProto;
import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Direction;
import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch;
@@ -83,6 +76,20 @@
import java.util.List;
import java.util.function.Consumer;
+import static android.view.Gravity.BOTTOM;
+import static android.view.Gravity.CENTER_HORIZONTAL;
+import static android.view.Gravity.CENTER_VERTICAL;
+import static android.view.Gravity.END;
+import static android.view.Gravity.START;
+import static android.view.Gravity.TOP;
+import static android.widget.Toast.LENGTH_SHORT;
+import static com.android.launcher3.QuickstepAppTransitionManagerImpl.RECENTS_LAUNCH_DURATION;
+import static com.android.launcher3.anim.Interpolators.FAST_OUT_SLOW_IN;
+import static com.android.launcher3.anim.Interpolators.LINEAR;
+import static com.android.launcher3.anim.Interpolators.TOUCH_RESPONSE_INTERPOLATOR;
+import static com.android.launcher3.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TILE;
+import static com.android.quickstep.SysUINavigationMode.removeShelfFromOverview;
+
/**
* A task in the Recents view.
*/
@@ -186,6 +193,8 @@
private float mFooterVerticalOffset = 0;
private float mFooterAlpha = 1;
private int mStackHeight;
+ private boolean mHideActionsView;
+ private PagedOrientationHandler mOrientationHandler;
public TaskView(Context context) {
this(context, null);
@@ -244,7 +253,7 @@
if (mActionsView != null) {
TaskView.LayoutParams params = new TaskView.LayoutParams(LayoutParams.MATCH_PARENT,
getResources().getDimensionPixelSize(R.dimen.overview_actions_height),
- Gravity.BOTTOM);
+ BOTTOM);
addView(mActionsView, params);
mActionsView.setAlpha(0);
}
@@ -266,10 +275,11 @@
/**
* Updates this task view to the given {@param task}.
*/
- public void bind(Task task) {
+ public void bind(Task task, int recentsRotation) {
cancelPendingLoadTasks();
mTask = task;
mSnapshotView.bind(task);
+ setOverviewRotation(recentsRotation);
}
public Task getTask() {
@@ -439,6 +449,45 @@
}
}
+ void setOverviewRotation(int iconRotation) {
+ PagedOrientationHandler orientationHandler = getRecentsView().getPagedOrientationHandler();
+ boolean isRtl = orientationHandler.getRecentsRtlSetting(getResources());
+ LayoutParams snapshotParams = (LayoutParams) mSnapshotView.getLayoutParams();
+ snapshotParams.bottomMargin = LayoutUtils.thumbnailBottomMargin(getContext());
+ int thumbnailPadding = (int) getResources().getDimension(R.dimen.task_thumbnail_top_margin);
+ LayoutParams iconParams = (LayoutParams) mIconView.getLayoutParams();
+ int rotation = RotationHelper.getDegreesFromRotation(iconRotation);
+ mHideActionsView = true;
+ switch (iconRotation) {
+ case Surface.ROTATION_90:
+ iconParams.gravity = (isRtl ? END : START) | CENTER_VERTICAL;
+ iconParams.rightMargin = -thumbnailPadding;
+ iconParams.leftMargin = iconParams.topMargin = iconParams.bottomMargin = 0;
+ break;
+ case Surface.ROTATION_180:
+ iconParams.gravity = BOTTOM | CENTER_HORIZONTAL;
+ iconParams.bottomMargin = -thumbnailPadding;
+ iconParams.leftMargin = iconParams.topMargin = iconParams.rightMargin = 0;
+ break;
+ case Surface.ROTATION_270:
+ iconParams.gravity = (isRtl ? END : START) | CENTER_VERTICAL;
+ iconParams.leftMargin = -thumbnailPadding;
+ iconParams.rightMargin = iconParams.topMargin = iconParams.bottomMargin = 0;
+ break;
+ case Surface.ROTATION_0:
+ default:
+ iconParams.gravity = TOP | CENTER_HORIZONTAL;
+ iconParams.leftMargin = iconParams.topMargin = iconParams.rightMargin =
+ iconParams.bottomMargin = 0;
+ mHideActionsView = false;
+ break;
+ }
+ mSnapshotView.setLayoutParams(snapshotParams);
+ mIconView.setLayoutParams(iconParams);
+ mIconView.setRotation(rotation);
+ updateActionsViewVisibility(!mHideActionsView);
+ }
+
private void setIconAndDimTransitionProgress(float progress, boolean invert) {
if (invert) {
progress = 1 - progress;
@@ -601,8 +650,7 @@
addView(view, indexToAdd);
LayoutParams layoutParams = (LayoutParams) view.getLayoutParams();
- layoutParams.gravity =
- Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL;
+ layoutParams.gravity = BOTTOM | CENTER_HORIZONTAL;
layoutParams.bottomMargin =
((MarginLayoutParams) mSnapshotView.getLayoutParams()).bottomMargin;
view.setAlpha(mFooterAlpha);
@@ -855,9 +903,7 @@
mFullscreenProgress = progress;
boolean isFullscreen = mFullscreenProgress > 0;
mIconView.setVisibility(progress < 1 ? VISIBLE : INVISIBLE);
- if (mActionsView != null) {
- mActionsView.setVisibility(progress < 1 ? VISIBLE : INVISIBLE);
- }
+ updateActionsViewVisibility(progress < 1 && !mHideActionsView);
setClipChildren(!isFullscreen);
setClipToPadding(!isFullscreen);
@@ -891,6 +937,12 @@
invalidateOutline();
}
+ private void updateActionsViewVisibility(boolean isVisible) {
+ if (mActionsView != null) {
+ mActionsView.setVisibility(isVisible ? VISIBLE : GONE);
+ }
+ }
+
public boolean isRunningTask() {
if (getRecentsView() == null) {
return false;
diff --git a/quickstep/res/layout/task.xml b/quickstep/res/layout/task.xml
index 60cfa0c..f9bb2f2 100644
--- a/quickstep/res/layout/task.xml
+++ b/quickstep/res/layout/task.xml
@@ -31,7 +31,6 @@
android:id="@+id/icon"
android:layout_width="@dimen/task_thumbnail_icon_size"
android:layout_height="@dimen/task_thumbnail_icon_size"
- android:layout_gravity="top|center_horizontal"
android:focusable="false"
android:importantForAccessibility="no"/>
</com.android.quickstep.views.TaskView>
\ No newline at end of file
diff --git a/quickstep/robolectric_tests/src/com/android/quickstep/OrientationTouchTransformerTest.java b/quickstep/robolectric_tests/src/com/android/quickstep/OrientationTouchTransformerTest.java
new file mode 100644
index 0000000..53f37c1
--- /dev/null
+++ b/quickstep/robolectric_tests/src/com/android/quickstep/OrientationTouchTransformerTest.java
@@ -0,0 +1,194 @@
+/*
+ * Copyright (C) 2019 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.quickstep;
+
+import static com.android.quickstep.SysUINavigationMode.Mode.NO_BUTTON;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import android.content.res.Resources;
+import android.graphics.Point;
+import android.util.DisplayMetrics;
+import android.view.MotionEvent;
+import android.view.Surface;
+
+import com.android.launcher3.ResourceUtils;
+import com.android.launcher3.util.DefaultDisplay;
+
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RobolectricTestRunner;
+
+@RunWith(RobolectricTestRunner.class)
+public class OrientationTouchTransformerTest {
+ private static final int SIZE_WIDTH = 1080;
+ private static final int SIZE_HEIGHT = 2280;
+ private static final float DENSITY_DISPLAY_METRICS = 3.0f;
+
+ private OrientationTouchTransformer mTouchTransformer;
+
+ Resources mResources;
+ private DefaultDisplay.Info mInfo;
+
+
+ @Before
+ public void setup() {
+ MockitoAnnotations.initMocks(this);
+ mResources = mock(Resources.class);
+ when(mResources.getBoolean(anyInt())).thenReturn(true);
+ when(mResources.getDimension(anyInt())).thenReturn(10.0f);
+ DisplayMetrics mockDisplayMetrics = new DisplayMetrics();
+ mockDisplayMetrics.density = DENSITY_DISPLAY_METRICS;
+ when(mResources.getDisplayMetrics()).thenReturn(mockDisplayMetrics);
+ mInfo = createDisplayInfo(Surface.ROTATION_0);
+ mTouchTransformer = new OrientationTouchTransformer(mResources, NO_BUTTON, () -> 0);
+ }
+
+ @Test
+ public void disabledMultipeRegions_shouldOverrideFirstRegion() {
+ mTouchTransformer.createOrAddTouchRegion(mInfo);
+ DefaultDisplay.Info info2 = createDisplayInfo(Surface.ROTATION_90);
+ mTouchTransformer.createOrAddTouchRegion(info2);
+
+ float y = generateTouchRegionHeight(Surface.ROTATION_0) + 1;
+ MotionEvent inOldRegion = generateMotionEvent(MotionEvent.ACTION_DOWN, 100, y);
+ mTouchTransformer.transform(inOldRegion);
+ assertFalse(mTouchTransformer.touchInValidSwipeRegions(inOldRegion.getX(), inOldRegion.getY()));
+
+ // Override region
+ mTouchTransformer.createOrAddTouchRegion(mInfo);
+ inOldRegion = generateMotionEvent(MotionEvent.ACTION_DOWN, 100, y);
+ mTouchTransformer.transform(inOldRegion);
+ assertTrue(mTouchTransformer.touchInValidSwipeRegions(inOldRegion.getX(), inOldRegion.getY()));
+ }
+
+ @Test
+ public void allowMultipeRegions_shouldOverrideFirstRegion() {
+ DefaultDisplay.Info info2 = createDisplayInfo(Surface.ROTATION_90);
+ mTouchTransformer.createOrAddTouchRegion(info2);
+ // We have to add 0 rotation second so that gets set as the current rotation, otherwise
+ // matrix transform will fail (tests only work in Portrait at the moment)
+ mTouchTransformer.enableMultipleRegions(true, mInfo);
+ mTouchTransformer.createOrAddTouchRegion(mInfo);
+
+ float y = generateTouchRegionHeight(Surface.ROTATION_0) + 1;
+ MotionEvent inNewRegion = generateMotionEvent(MotionEvent.ACTION_DOWN, 100, y);
+ mTouchTransformer.transform(inNewRegion);
+ assertTrue(mTouchTransformer.touchInValidSwipeRegions(inNewRegion.getX(), inNewRegion.getY()));
+ }
+
+ @Test
+ public void applyTransform_taskNotFrozen_notInRegion() {
+ mTouchTransformer.createOrAddTouchRegion(mInfo);
+ MotionEvent outOfRegion = generateMotionEvent(MotionEvent.ACTION_DOWN, 100, 100);
+ mTouchTransformer.transform(outOfRegion);
+ assertFalse(mTouchTransformer.touchInValidSwipeRegions(outOfRegion.getX(), outOfRegion.getY()));
+ }
+
+ @Test
+ public void applyTransform_taskFrozen_noRotate_outOfRegion() {
+ mTouchTransformer.createOrAddTouchRegion(mInfo);
+ mTouchTransformer.enableMultipleRegions(true, mInfo);
+ MotionEvent outOfRegion = generateMotionEvent(MotionEvent.ACTION_DOWN, 100, 100);
+ mTouchTransformer.transform(outOfRegion);
+ assertFalse(mTouchTransformer.touchInValidSwipeRegions(outOfRegion.getX(), outOfRegion.getY()));
+ }
+
+ @Test
+ public void applyTransform_taskFrozen_noRotate_inRegion() {
+ mTouchTransformer.createOrAddTouchRegion(mInfo);
+ mTouchTransformer.enableMultipleRegions(true, mInfo);
+ float y = generateTouchRegionHeight(Surface.ROTATION_0) + 1;
+ MotionEvent inRegion = generateMotionEvent(MotionEvent.ACTION_DOWN, 100, y);
+ mTouchTransformer.transform(inRegion);
+ assertTrue(mTouchTransformer.touchInValidSwipeRegions(inRegion.getX(), inRegion.getY()));
+ }
+
+ @Test
+ public void applyTransform_taskNotFrozen_noRotate_inDefaultRegion() {
+ mTouchTransformer.createOrAddTouchRegion(mInfo);
+ float y = generateTouchRegionHeight(Surface.ROTATION_0) + 1;
+ MotionEvent inRegion = generateMotionEvent(MotionEvent.ACTION_DOWN, 100, y);
+ mTouchTransformer.transform(inRegion);
+ assertTrue(mTouchTransformer.touchInValidSwipeRegions(inRegion.getX(), inRegion.getY()));
+ }
+
+ @Test
+ public void applyTransform_taskNotFrozen_90Rotate_inRegion() {
+ mTouchTransformer.createOrAddTouchRegion(createDisplayInfo(Surface.ROTATION_90));
+ float y = generateTouchRegionHeight(Surface.ROTATION_90) + 1;
+ MotionEvent inRegion = generateMotionEvent(MotionEvent.ACTION_DOWN, 100, y);
+ mTouchTransformer.transform(inRegion);
+ assertTrue(mTouchTransformer.touchInValidSwipeRegions(inRegion.getX(), inRegion.getY()));
+ }
+
+ @Test
+ @Ignore("There's too much that goes into needing to mock a real motion event so the "
+ + "transforms in native code get applied correctly. Once that happens then maybe we can"
+ + " write slightly more complex unit tests")
+ public void applyTransform_taskNotFrozen_90Rotate_inTwoRegions() {
+ mTouchTransformer.createOrAddTouchRegion(mInfo);
+ mTouchTransformer.enableMultipleRegions(true, mInfo);
+ mTouchTransformer.createOrAddTouchRegion(createDisplayInfo(Surface.ROTATION_90));
+ // Landscape point
+ float y1 = generateTouchRegionHeight(Surface.ROTATION_90) + 1;
+ MotionEvent inRegion1_down = generateMotionEvent(MotionEvent.ACTION_DOWN, 10, y1);
+ MotionEvent inRegion1_up = generateMotionEvent(MotionEvent.ACTION_UP, 10, y1);
+ // Portrait point in landscape orientation axis
+ MotionEvent inRegion2 = generateMotionEvent(MotionEvent.ACTION_DOWN, 10, 10);
+ mTouchTransformer.transform(inRegion1_down);
+ mTouchTransformer.transform(inRegion2);
+ assertTrue(mTouchTransformer.touchInValidSwipeRegions(inRegion1_down.getX(), inRegion1_down.getY()));
+ // We only process one gesture region until we see a MotionEvent.ACTION_UP
+ assertFalse(mTouchTransformer.touchInValidSwipeRegions(inRegion2.getX(), inRegion2.getY()));
+
+ mTouchTransformer.transform(inRegion1_up);
+
+ // Set the new region with this MotionEvent.ACTION_DOWN
+ inRegion2 = generateMotionEvent(MotionEvent.ACTION_DOWN, 10, 370);
+ mTouchTransformer.transform(inRegion2);
+ assertTrue(mTouchTransformer.touchInValidSwipeRegions(inRegion2.getX(), inRegion2.getY()));
+ }
+
+ private DefaultDisplay.Info createDisplayInfo(int rotation) {
+ Point p = new Point(SIZE_WIDTH, SIZE_HEIGHT);
+ if (rotation == Surface.ROTATION_90 || rotation == Surface.ROTATION_270) {
+ p = new Point(SIZE_HEIGHT, SIZE_WIDTH);
+ }
+ return new DefaultDisplay.Info(0, rotation, 0, p, p, p, null);
+ }
+
+ private float generateTouchRegionHeight(int rotation) {
+ float height = SIZE_HEIGHT;
+ if (rotation == Surface.ROTATION_90 || rotation == Surface.ROTATION_270) {
+ height = SIZE_WIDTH;
+ }
+ return height - ResourceUtils.DEFAULT_NAVBAR_VALUE * DENSITY_DISPLAY_METRICS;
+ }
+
+ private MotionEvent generateMotionEvent(int motionAction, float x, float y) {
+ return MotionEvent.obtain(0, 0, motionAction, x, y, 0);
+ }
+}
diff --git a/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java b/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java
index 07d2381..fa0e840 100644
--- a/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java
+++ b/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java
@@ -41,6 +41,7 @@
import com.android.launcher3.popup.SystemShortcut;
import com.android.launcher3.proxy.ProxyActivityStarter;
import com.android.launcher3.proxy.StartActivityParams;
+import com.android.launcher3.touch.PagedOrientationHandler;
import com.android.launcher3.uioverrides.BackButtonAlphaHandler;
import com.android.launcher3.uioverrides.RecentsViewStateController;
import com.android.launcher3.util.UiThreadHelper;
@@ -51,6 +52,7 @@
import com.android.quickstep.SystemUiProxy;
import com.android.quickstep.util.RemoteFadeOutAnimationListener;
import com.android.quickstep.util.ShelfPeekAnim;
+import com.android.quickstep.views.RecentsView;
import java.util.stream.Stream;
@@ -210,9 +212,10 @@
@Override
protected ScaleAndTranslation getOverviewScaleAndTranslationForNormalState() {
if (SysUINavigationMode.getMode(this) == Mode.NO_BUTTON) {
- float offscreenTranslationX = getDeviceProfile().widthPx
- - getOverviewPanel().getPaddingStart();
- return new ScaleAndTranslation(1f, offscreenTranslationX, 0f);
+ PagedOrientationHandler layoutVertical =
+ ((RecentsView)getOverviewPanel()).getPagedViewOrientedState().getOrientationHandler();
+ return layoutVertical.getScaleAndTranslation(getDeviceProfile(),
+ getOverviewPanel());
}
return super.getOverviewScaleAndTranslationForNormalState();
}
diff --git a/quickstep/src/com/android/quickstep/BaseActivityInterface.java b/quickstep/src/com/android/quickstep/BaseActivityInterface.java
index fd55e07..64e053f 100644
--- a/quickstep/src/com/android/quickstep/BaseActivityInterface.java
+++ b/quickstep/src/com/android/quickstep/BaseActivityInterface.java
@@ -31,6 +31,7 @@
import com.android.launcher3.BaseDraggingActivity;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.anim.AnimatorPlaybackController;
+import com.android.launcher3.touch.PagedOrientationHandler;
import com.android.quickstep.util.ActivityInitListener;
import com.android.quickstep.util.ShelfPeekAnim;
import com.android.systemui.shared.recents.model.ThumbnailData;
@@ -148,13 +149,18 @@
// No-op
}
- static RectF getDefaultWindowTargetRect(DeviceProfile dp) {
+ static RectF getDefaultWindowTargetRect(PagedOrientationHandler orientationHandler,
+ DeviceProfile dp) {
final int halfIconSize = dp.iconSizePx / 2;
- final float targetCenterX = dp.availableWidthPx / 2f;
- final float targetCenterY = dp.availableHeightPx - dp.hotseatBarSizePx;
+ float primaryDimension = orientationHandler
+ .getPrimaryValue(dp.availableWidthPx, dp.availableHeightPx);
+ float secondaryDimension = orientationHandler
+ .getSecondaryValue(dp.availableWidthPx, dp.availableHeightPx);
+ final float targetX = primaryDimension / 2f;
+ final float targetY = secondaryDimension - dp.hotseatBarSizePx;
// Fallback to animate to center of screen.
- return new RectF(targetCenterX - halfIconSize, targetCenterY - halfIconSize,
- targetCenterX + halfIconSize, targetCenterY + halfIconSize);
+ return new RectF(targetX - halfIconSize, targetY - halfIconSize,
+ targetX + halfIconSize, targetY + halfIconSize);
}
}
diff --git a/quickstep/src/com/android/quickstep/GestureState.java b/quickstep/src/com/android/quickstep/GestureState.java
index ae0886b..501c6f0 100644
--- a/quickstep/src/com/android/quickstep/GestureState.java
+++ b/quickstep/src/com/android/quickstep/GestureState.java
@@ -19,10 +19,12 @@
import android.app.ActivityManager;
import android.content.Intent;
+
import com.android.launcher3.BaseDraggingActivity;
-import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
import com.android.systemui.shared.recents.model.ThumbnailData;
+
+import java.io.PrintWriter;
import java.util.ArrayList;
/**
@@ -281,4 +283,13 @@
mStateCallback.setState(STATE_RECENTS_ANIMATION_FINISHED);
mStateCallback.setState(STATE_RECENTS_ANIMATION_ENDED);
}
+
+ public void dump(PrintWriter pw) {
+ pw.println("GestureState:");
+ pw.println(" gestureID=" + mGestureId);
+ pw.println(" runningTask=" + mRunningTask);
+ pw.println(" endTarget=" + mEndTarget);
+ pw.println(" finishingRecentsAnimationTaskId=" + mFinishingRecentsAnimationTaskId);
+ pw.println(" isRecentsAnimationRunning=" + isRecentsAnimationRunning());
+ }
}
diff --git a/quickstep/src/com/android/quickstep/OrientationTouchTransformer.java b/quickstep/src/com/android/quickstep/OrientationTouchTransformer.java
new file mode 100644
index 0000000..832baf5
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/OrientationTouchTransformer.java
@@ -0,0 +1,341 @@
+/*
+ * Copyright (C) 2019 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.quickstep;
+
+import static android.view.MotionEvent.ACTION_CANCEL;
+import static android.view.MotionEvent.ACTION_DOWN;
+import static android.view.MotionEvent.ACTION_MOVE;
+import static android.view.MotionEvent.ACTION_POINTER_DOWN;
+import static android.view.MotionEvent.ACTION_UP;
+
+import android.content.res.Resources;
+import android.graphics.Matrix;
+import android.graphics.Point;
+import android.graphics.RectF;
+import android.util.Log;
+import android.util.SparseArray;
+import android.view.MotionEvent;
+import android.view.Surface;
+
+import com.android.launcher3.R;
+import com.android.launcher3.ResourceUtils;
+import com.android.launcher3.states.RotationHelper;
+import com.android.launcher3.util.DefaultDisplay;
+
+import java.io.PrintWriter;
+
+/**
+ * Maintains state for supporting nav bars and tracking their gestures in multiple orientations.
+ * See {@link OrientationRectF#applyTransform(MotionEvent, boolean)} for transformation of
+ * MotionEvents from one orientation's coordinate space to another's.
+ *
+ * This class only supports single touch/pointer gesture tracking for touches started in a supported
+ * nav bar region.
+ */
+class OrientationTouchTransformer {
+
+ private static final String TAG = "OrientationTouchTransformer";
+ private static final boolean DEBUG = true;
+ private static final int MAX_ORIENTATIONS = 4;
+
+ private SparseArray<OrientationRectF> mSwipeTouchRegions = new SparseArray<>(MAX_ORIENTATIONS);
+ private final RectF mAssistantLeftRegion = new RectF();
+ private final RectF mAssistantRightRegion = new RectF();
+ private int mCurrentRotation;
+ private boolean mEnableMultipleRegions;
+ private Resources mResources;
+ private OrientationRectF mLastRectTouched;
+ private SysUINavigationMode.Mode mMode;
+ private QuickStepContractInfo mContractInfo;
+ private int mQuickStepStartingRotation = -1;
+
+ /** For testability */
+ interface QuickStepContractInfo {
+ float getWindowCornerRadius();
+ }
+
+ OrientationTouchTransformer(Resources resources, SysUINavigationMode.Mode mode,
+ QuickStepContractInfo contractInfo) {
+ mResources = resources;
+ mMode = mode;
+ mContractInfo = contractInfo;
+ }
+
+ void setNavigationMode(SysUINavigationMode.Mode newMode) {
+ this.mMode = newMode;
+ }
+
+ /**
+ * Sets the current nav bar region to listen to events for as determined by
+ * {@param info}. If multiple nav bar regions are enabled, then this region will be added
+ * alongside other regions.
+ * Ok to call multiple times
+ *
+ * @see #enableMultipleRegions(boolean, DefaultDisplay.Info)
+ */
+ void createOrAddTouchRegion(DefaultDisplay.Info info) {
+ mCurrentRotation = info.rotation;
+ if (mQuickStepStartingRotation > -1 && mCurrentRotation == mQuickStepStartingRotation) {
+ // Ignore nav bars in other rotations except for the one we started out in
+ resetSwipeRegions(info);
+ return;
+ }
+
+ OrientationRectF region = mSwipeTouchRegions.get(mCurrentRotation);
+ if (region != null) {
+ return;
+ }
+
+ if (mEnableMultipleRegions) {
+ mSwipeTouchRegions.put(mCurrentRotation, createRegionForDisplay(info));
+ } else {
+ resetSwipeRegions(info);
+ }
+ }
+
+ /**
+ * Call when we want to start tracking nav bar touch regions in multiple orientations.
+ * ALSO, you BETTER call this with {@param enableMultipleRegions} set to false once you're done.
+ *
+ * @param enableMultipleRegions Set to true to start tracking multiple nav bar regions
+ * @param info The current displayInfo
+ */
+ void enableMultipleRegions(boolean enableMultipleRegions, DefaultDisplay.Info info) {
+ mEnableMultipleRegions = enableMultipleRegions;
+ if (!enableMultipleRegions) {
+ mQuickStepStartingRotation = -1;
+ resetSwipeRegions(info);
+ } else {
+ if (mQuickStepStartingRotation < 0) {
+ mQuickStepStartingRotation = mLastRectTouched.mRotation;
+ }
+ }
+ }
+
+ /**
+ * Only saves the swipe region represented by {@param region}, clears the
+ * rest from {@link #mSwipeTouchRegions}
+ * To be called whenever we want to stop tracking more than one swipe region.
+ * Ok to call multiple times.
+ */
+ private void resetSwipeRegions(DefaultDisplay.Info region) {
+ if (DEBUG) {
+ Log.d(TAG, "clearing all regions except rotation: " + mCurrentRotation);
+ }
+
+ mCurrentRotation = region.rotation;
+ OrientationRectF regionToKeep = mSwipeTouchRegions.get(mCurrentRotation);
+ mSwipeTouchRegions.clear();
+ mSwipeTouchRegions.put(mCurrentRotation,
+ regionToKeep != null ? regionToKeep : createRegionForDisplay(region));
+ }
+
+ private OrientationRectF createRegionForDisplay(DefaultDisplay.Info display) {
+ if (DEBUG) {
+ Log.d(TAG, "creating rotation region for: " + mCurrentRotation);
+ }
+
+ Point size = display.realSize;
+ int rotation = display.rotation;
+ OrientationRectF orientationRectF =
+ new OrientationRectF(0, 0, size.x, size.y, rotation);
+ if (mMode == SysUINavigationMode.Mode.NO_BUTTON) {
+ int touchHeight = getNavbarSize(ResourceUtils.NAVBAR_BOTTOM_GESTURE_SIZE);
+ orientationRectF.top = orientationRectF.bottom - touchHeight;
+
+ final int assistantWidth = mResources
+ .getDimensionPixelSize(R.dimen.gestures_assistant_width);
+ final float assistantHeight = Math.max(touchHeight,
+ mContractInfo.getWindowCornerRadius());
+ mAssistantLeftRegion.bottom = mAssistantRightRegion.bottom = orientationRectF.bottom;
+ mAssistantLeftRegion.top = mAssistantRightRegion.top =
+ orientationRectF.bottom - assistantHeight;
+
+ mAssistantLeftRegion.left = 0;
+ mAssistantLeftRegion.right = assistantWidth;
+
+ mAssistantRightRegion.right = orientationRectF.right;
+ mAssistantRightRegion.left = orientationRectF.right - assistantWidth;
+ } else {
+ mAssistantLeftRegion.setEmpty();
+ mAssistantRightRegion.setEmpty();
+ switch (rotation) {
+ case Surface.ROTATION_90:
+ orientationRectF.left = orientationRectF.right
+ - getNavbarSize(ResourceUtils.NAVBAR_LANDSCAPE_LEFT_RIGHT_SIZE);
+ break;
+ case Surface.ROTATION_270:
+ orientationRectF.right = orientationRectF.left
+ + getNavbarSize(ResourceUtils.NAVBAR_LANDSCAPE_LEFT_RIGHT_SIZE);
+ break;
+ default:
+ orientationRectF.top = orientationRectF.bottom
+ - getNavbarSize(ResourceUtils.NAVBAR_BOTTOM_GESTURE_SIZE);
+ }
+ }
+
+ return orientationRectF;
+ }
+
+ boolean touchInAssistantRegion(MotionEvent ev) {
+ return mAssistantLeftRegion.contains(ev.getX(), ev.getY())
+ || mAssistantRightRegion.contains(ev.getX(), ev.getY());
+
+ }
+
+ private int getNavbarSize(String resName) {
+ return ResourceUtils.getNavbarSize(resName, mResources);
+ }
+
+ boolean touchInValidSwipeRegions(float x, float y) {
+ if (mLastRectTouched != null) {
+ return mLastRectTouched.contains(x, y);
+ }
+ return false;
+ }
+
+ int getCurrentActiveRotation() {
+ if (mLastRectTouched == null) {
+ return 0;
+ } else {
+ return mLastRectTouched.mRotation;
+ }
+ }
+
+ public void transform(MotionEvent event) {
+ int eventAction = event.getActionMasked();
+ switch (eventAction) {
+ case ACTION_MOVE: {
+ if (mLastRectTouched == null) {
+ return;
+ }
+ mLastRectTouched.applyTransform(event, true);
+ break;
+ }
+ case ACTION_CANCEL:
+ case ACTION_UP: {
+ if (mLastRectTouched == null) {
+ return;
+ }
+ mLastRectTouched.applyTransform(event, true);
+ mLastRectTouched = null;
+ break;
+ }
+ case ACTION_POINTER_DOWN:
+ case ACTION_DOWN: {
+ if (mLastRectTouched != null) {
+ return;
+ }
+
+ for (int i = 0; i < MAX_ORIENTATIONS; i++) {
+ OrientationRectF rect = mSwipeTouchRegions.get(i);
+ if (rect == null) {
+ continue;
+ }
+ if (rect.applyTransform(event, false)) {
+ mLastRectTouched = rect;
+ if (DEBUG) {
+ Log.d(TAG, "set active region: " + rect);
+ }
+ return;
+ }
+ }
+ break;
+ }
+ }
+ }
+
+ public void dump(PrintWriter pw) {
+ pw.println("OrientationTouchTransformerState: ");
+ pw.println(" currentActiveRotation=" + getCurrentActiveRotation());
+ pw.println(" lastTouchedRegion=" + mLastRectTouched);
+ pw.println(" multipleRegionsEnabled=" + mEnableMultipleRegions);
+ StringBuilder regions = new StringBuilder(" currentTouchableRotations=");
+ for(int i = 0; i < mSwipeTouchRegions.size(); i++) {
+ OrientationRectF rectF = mSwipeTouchRegions.get(mSwipeTouchRegions.keyAt(i));
+ regions.append(rectF.mRotation).append(" ");
+ }
+ pw.println(regions.toString());
+ }
+
+ private class OrientationRectF extends RectF {
+
+ /**
+ * Delta to subtract width and height by because if we report the translated touch
+ * bounds as the width and height, calling {@link RectF#contains(float, float)} will
+ * be false
+ */
+ private float maxDelta = 0.001f;
+
+ private int mRotation;
+ private float mHeight;
+ private float mWidth;
+
+ OrientationRectF(float left, float top, float right, float bottom, int rotation) {
+ super(left, top, right, bottom);
+ this.mRotation = rotation;
+ mHeight = bottom - maxDelta;
+ mWidth = right - maxDelta;
+ }
+
+ @Override
+ public String toString() {
+ String s = super.toString();
+ s += " rotation: " + mRotation;
+ return s;
+ }
+
+ boolean applyTransform(MotionEvent event, boolean forceTransform) {
+ // TODO(b/149658423): See if we can use RotationHelper.getRotationMatrix here
+ MotionEvent tmp = MotionEvent.obtain(event);
+ Matrix outMatrix = new Matrix();
+ int delta = RotationHelper.deltaRotation(mCurrentRotation, mRotation);
+ switch (delta) {
+ case Surface.ROTATION_0:
+ outMatrix.reset();
+ break;
+ case Surface.ROTATION_90:
+ outMatrix.setRotate(270);
+ outMatrix.postTranslate(0, mHeight);
+ break;
+ case Surface.ROTATION_180:
+ outMatrix.setRotate(180);
+ outMatrix.postTranslate(mHeight, mWidth);
+ break;
+ case Surface.ROTATION_270:
+ outMatrix.setRotate(90);
+ outMatrix.postTranslate(mWidth, 0);
+ break;
+ }
+
+ tmp.transform(outMatrix);
+ if (DEBUG) {
+ Log.d(TAG, "original: " + event.getX() + ", " + event.getY()
+ + " new: " + tmp.getX() + ", " + tmp.getY()
+ + " rect: " + this + " forceTransform: " + forceTransform
+ + " contains: " + contains(tmp.getX(), tmp.getY()));
+ }
+
+ if (forceTransform || contains(tmp.getX(), tmp.getY())) {
+ event.transform(outMatrix);
+ tmp.recycle();
+ return true;
+ }
+ return false;
+ }
+ }
+}
diff --git a/quickstep/src/com/android/quickstep/RecentsAnimationController.java b/quickstep/src/com/android/quickstep/RecentsAnimationController.java
index 21a4918..8dd4aa4 100644
--- a/quickstep/src/com/android/quickstep/RecentsAnimationController.java
+++ b/quickstep/src/com/android/quickstep/RecentsAnimationController.java
@@ -39,7 +39,7 @@
import java.util.function.Supplier;
/**
- * Wrapper around RecentsAnimationController to help with some synchronization
+ * Wrapper around RecentsAnimationControllerCompat to help with some synchronization
*/
public class RecentsAnimationController {
diff --git a/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java b/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java
index abe1592..d845650 100644
--- a/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java
+++ b/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java
@@ -17,8 +17,6 @@
import static android.content.Intent.ACTION_USER_UNLOCKED;
-import static com.android.launcher3.ResourceUtils.NAVBAR_BOTTOM_GESTURE_SIZE;
-import static com.android.launcher3.ResourceUtils.NAVBAR_LANDSCAPE_LEFT_RIGHT_SIZE;
import static com.android.quickstep.SysUINavigationMode.Mode.NO_BUTTON;
import static com.android.quickstep.SysUINavigationMode.Mode.THREE_BUTTONS;
import static com.android.quickstep.SysUINavigationMode.Mode.TWO_BUTTONS;
@@ -40,20 +38,17 @@
import android.content.Intent;
import android.content.IntentFilter;
import android.content.res.Resources;
-import android.graphics.Point;
-import android.graphics.RectF;
import android.graphics.Region;
import android.os.Process;
import android.os.UserManager;
import android.text.TextUtils;
import android.util.Log;
import android.view.MotionEvent;
-import android.view.Surface;
import androidx.annotation.BinderThread;
+import com.android.launcher3.PagedView;
import com.android.launcher3.R;
-import com.android.launcher3.ResourceUtils;
import com.android.launcher3.Utilities;
import com.android.launcher3.testing.TestProtocol;
import com.android.launcher3.util.DefaultDisplay;
@@ -63,6 +58,7 @@
import com.android.systemui.shared.system.QuickStepContract;
import com.android.systemui.shared.system.QuickStepContract.SystemUiStateFlags;
import com.android.systemui.shared.system.SystemGestureExclusionListenerCompat;
+import com.android.systemui.shared.system.TaskStackChangeListener;
import java.io.PrintWriter;
import java.util.ArrayList;
@@ -80,6 +76,7 @@
private final SysUINavigationMode mSysUiNavMode;
private final DefaultDisplay mDefaultDisplay;
private final int mDisplayId;
+ private int mDisplayRotation;
private final ArrayList<Runnable> mOnDestroyActions = new ArrayList<>();
@@ -87,10 +84,7 @@
private SysUINavigationMode.Mode mMode = THREE_BUTTONS;
private NavBarPosition mNavBarPosition;
- private final RectF mSwipeUpTouchRegion = new RectF();
private final Region mDeferredGestureRegion = new Region();
- private final RectF mAssistantLeftRegion = new RectF();
- private final RectF mAssistantRightRegion = new RectF();
private boolean mAssistantAvailable;
private float mAssistantVisibility;
@@ -106,10 +100,13 @@
}
};
+ private OrientationTouchTransformer mOrientationTouchTransformer;
+
private Region mExclusionRegion;
private SystemGestureExclusionListenerCompat mExclusionListener;
private final List<ComponentName> mGestureBlockedActivities;
+ private TaskStackChangeListener mFrozenTaskListener;
public RecentsAnimationDeviceState(Context context) {
final ContentResolver resolver = context.getContentResolver();
@@ -139,6 +136,8 @@
};
runOnDestroy(mExclusionListener::unregister);
+ setupOrientationSwipeHandler(context);
+
// Register for navigation mode changes
onNavigationModeChanged(mSysUiNavMode.addModeChangeListener(this));
runOnDestroy(() -> mSysUiNavMode.removeModeChangeListener(this));
@@ -160,6 +159,26 @@
}
}
+ private void setupOrientationSwipeHandler(Context context) {
+ final Resources resources = context.getResources();
+ mOrientationTouchTransformer = new OrientationTouchTransformer(resources, mMode,
+ () -> QuickStepContract.getWindowCornerRadius(resources));
+
+ if (!PagedView.sFlagForcedRotation) {
+ return;
+ }
+
+ mFrozenTaskListener = new TaskStackChangeListener() {
+ @Override
+ public void onRecentTaskListFrozenChanged(boolean frozen) {
+ mOrientationTouchTransformer.enableMultipleRegions(frozen, mDefaultDisplay.getInfo());
+ }
+ };
+ ActivityManagerWrapper.getInstance().registerTaskStackListener(mFrozenTaskListener);
+ runOnDestroy(() -> ActivityManagerWrapper.getInstance()
+ .unregisterTaskStackListener(mFrozenTaskListener));
+ }
+
private void runOnDestroy(Runnable action) {
mOnDestroyActions.add(action);
}
@@ -198,7 +217,10 @@
mExclusionListener.unregister();
}
mMode = newMode;
+
mNavBarPosition = new NavBarPosition(mMode, mDefaultDisplay.getInfo());
+
+ mOrientationTouchTransformer.setNavigationMode(mMode);
}
@Override
@@ -207,8 +229,10 @@
return;
}
+ mDisplayRotation = info.rotation;
mNavBarPosition = new NavBarPosition(mMode, info);
updateGestureTouchRegions();
+ mOrientationTouchTransformer.createOrAddTouchRegion(info);
}
/**
@@ -380,50 +404,14 @@
return;
}
- Resources res = mContext.getResources();
- DefaultDisplay.Info displayInfo = mDefaultDisplay.getInfo();
- Point realSize = new Point(displayInfo.realSize);
- mSwipeUpTouchRegion.set(0, 0, realSize.x, realSize.y);
- if (mMode == NO_BUTTON) {
- int touchHeight = ResourceUtils.getNavbarSize(NAVBAR_BOTTOM_GESTURE_SIZE, res);
- mSwipeUpTouchRegion.top = mSwipeUpTouchRegion.bottom - touchHeight;
-
- final int assistantWidth = res.getDimensionPixelSize(R.dimen.gestures_assistant_width);
- final float assistantHeight = Math.max(touchHeight,
- QuickStepContract.getWindowCornerRadius(res));
- mAssistantLeftRegion.bottom = mAssistantRightRegion.bottom = mSwipeUpTouchRegion.bottom;
- mAssistantLeftRegion.top = mAssistantRightRegion.top =
- mSwipeUpTouchRegion.bottom - assistantHeight;
-
- mAssistantLeftRegion.left = 0;
- mAssistantLeftRegion.right = assistantWidth;
-
- mAssistantRightRegion.right = mSwipeUpTouchRegion.right;
- mAssistantRightRegion.left = mSwipeUpTouchRegion.right - assistantWidth;
- } else {
- mAssistantLeftRegion.setEmpty();
- mAssistantRightRegion.setEmpty();
- switch (displayInfo.rotation) {
- case Surface.ROTATION_90:
- mSwipeUpTouchRegion.left = mSwipeUpTouchRegion.right
- - ResourceUtils.getNavbarSize(NAVBAR_LANDSCAPE_LEFT_RIGHT_SIZE, res);
- break;
- case Surface.ROTATION_270:
- mSwipeUpTouchRegion.right = mSwipeUpTouchRegion.left
- + ResourceUtils.getNavbarSize(NAVBAR_LANDSCAPE_LEFT_RIGHT_SIZE, res);
- break;
- default:
- mSwipeUpTouchRegion.top = mSwipeUpTouchRegion.bottom
- - ResourceUtils.getNavbarSize(NAVBAR_BOTTOM_GESTURE_SIZE, res);
- }
- }
+ mOrientationTouchTransformer.createOrAddTouchRegion(mDefaultDisplay.getInfo());
}
/**
* @return whether the coordinates of the {@param event} is in the swipe up gesture region.
*/
public boolean isInSwipeUpTouchRegion(MotionEvent event) {
- return mSwipeUpTouchRegion.contains(event.getX(), event.getY());
+ return mOrientationTouchTransformer.touchInValidSwipeRegions(event.getX(), event.getY());
}
/**
@@ -431,7 +419,8 @@
* is in the swipe up gesture region.
*/
public boolean isInSwipeUpTouchRegion(MotionEvent event, int pointerIndex) {
- return mSwipeUpTouchRegion.contains(event.getX(pointerIndex), event.getY(pointerIndex));
+ return mOrientationTouchTransformer.touchInValidSwipeRegions(event.getX(pointerIndex),
+ event.getY(pointerIndex));
}
/**
@@ -490,11 +479,34 @@
public boolean canTriggerAssistantAction(MotionEvent ev) {
return mAssistantAvailable
&& !QuickStepContract.isAssistantGestureDisabled(mSystemUiStateFlags)
- && (mAssistantLeftRegion.contains(ev.getX(), ev.getY())
- || mAssistantRightRegion.contains(ev.getX(), ev.getY()))
+ && mOrientationTouchTransformer.touchInAssistantRegion(ev)
&& !isLockToAppActive();
}
+ /**
+ * *May* apply a transform on the motion event if it lies in the nav bar region for another
+ * orientation that is currently being tracked as a part of quickstep
+ */
+ public void setOrientationTransformIfNeeded(MotionEvent event) {
+ // negative coordinates bug b/143901881
+ if (event.getX() < 0 || event.getY() < 0) {
+ event.setLocation(Math.max(0, event.getX()), Math.max(0, event.getY()));
+ }
+ mOrientationTouchTransformer.transform(event);
+ }
+
+ public void enableMultipleRegions(boolean enable) {
+ mOrientationTouchTransformer.enableMultipleRegions(enable, mDefaultDisplay.getInfo());
+ }
+
+ public int getCurrentActiveRotation() {
+ return mOrientationTouchTransformer.getCurrentActiveRotation();
+ }
+
+ public int getDisplayRotation() {
+ return mDisplayRotation;
+ }
+
public void dump(PrintWriter pw) {
pw.println("DeviceState:");
pw.println(" canStartSystemGesture=" + canStartSystemGesture());
@@ -504,5 +516,8 @@
pw.println(" assistantAvailable=" + mAssistantAvailable);
pw.println(" assistantDisabled="
+ QuickStepContract.isAssistantGestureDisabled(mSystemUiStateFlags));
+ pw.println(" currentActiveRotation=" + getCurrentActiveRotation());
+ pw.println(" displayRotation=" + getDisplayRotation());
+ mOrientationTouchTransformer.dump(pw);
}
}
diff --git a/quickstep/src/com/android/quickstep/SystemUiProxy.java b/quickstep/src/com/android/quickstep/SystemUiProxy.java
index eb60601..0210a81 100644
--- a/quickstep/src/com/android/quickstep/SystemUiProxy.java
+++ b/quickstep/src/com/android/quickstep/SystemUiProxy.java
@@ -333,4 +333,15 @@
}
}
}
+
+ public void onQuickSwitchToNewTask() {
+ //TODO(b/150250451) add back in after big CL goes through
+// if (mSystemUiProxy != null) {
+// try {
+// mSystemUiProxy.onQuickSwitchToNewTask();
+// } catch (RemoteException e) {
+// Log.w(TAG, "Failed call onQuickstepStarted", e);
+// }
+// }
+ }
}
diff --git a/quickstep/src/com/android/quickstep/util/LayoutUtils.java b/quickstep/src/com/android/quickstep/util/LayoutUtils.java
index 1d8a79f..ba99016 100644
--- a/quickstep/src/com/android/quickstep/util/LayoutUtils.java
+++ b/quickstep/src/com/android/quickstep/util/LayoutUtils.java
@@ -33,6 +33,9 @@
import java.lang.annotation.Retention;
+import static com.android.launcher3.config.FeatureFlags.ENABLE_OVERVIEW_ACTIONS;
+import static java.lang.annotation.RetentionPolicy.SOURCE;
+
public class LayoutUtils {
private static final int MULTI_WINDOW_STRATEGY_HALF_SCREEN = 1;
diff --git a/res/values/config.xml b/res/values/config.xml
index 8aff6da..35e5e6d 100644
--- a/res/values/config.xml
+++ b/res/values/config.xml
@@ -121,5 +121,41 @@
<bool name="config_enableTaskSnapshotPreloading">true</bool>
<!-- Configuration resources -->
- <array name="dynamic_resources"> </array>
+ <item name="all_apps_spring_damping_ratio" type="dimen" format="float">0.75</item>
+ <item name="all_apps_spring_stiffness" type="dimen" format="float">600</item>
+
+ <item name="dismiss_task_trans_y_damping_ratio" type="dimen" format="float">0.5</item>
+ <item name="dismiss_task_trans_y_stiffness" type="dimen" format="float">1500</item>
+
+ <item name="dismiss_task_trans_x_damping_ratio" type="dimen" format="float">0.5</item>
+ <item name="dismiss_task_trans_x_stiffness" type="dimen" format="float">1500</item>
+
+ <item name="horizontal_spring_damping_ratio" type="dimen" format="float">0.75</item>
+ <item name="horizontal_spring_stiffness" type="dimen" format="float">200</item>
+
+ <item name="swipe_up_rect_damping_ratio" type="dimen" format="float">0.75</item>
+ <item name="swipe_up_rect_stiffness" type="dimen" format="float">200</item>
+
+ <item name="staggered_damping_ratio" type="dimen" format="float">0.7</item>
+ <item name="staggered_stiffness" type="dimen" format="float">150</item>
+
+ <array name="dynamic_resources">
+ <item>@dimen/all_apps_spring_damping_ratio</item>
+ <item>@dimen/all_apps_spring_stiffness</item>
+
+ <item>@dimen/dismiss_task_trans_y_damping_ratio</item>
+ <item>@dimen/dismiss_task_trans_y_stiffness</item>
+
+ <item>@dimen/dismiss_task_trans_x_damping_ratio</item>
+ <item>@dimen/dismiss_task_trans_x_stiffness</item>
+
+ <item>@dimen/horizontal_spring_damping_ratio</item>
+ <item>@dimen/horizontal_spring_stiffness</item>
+
+ <item>@dimen/swipe_up_rect_damping_ratio</item>
+ <item>@dimen/swipe_up_rect_stiffness</item>
+
+ <item>@dimen/staggered_damping_ratio</item>
+ <item>@dimen/staggered_stiffness</item>
+ </array>
</resources>
diff --git a/src/com/android/launcher3/PagedView.java b/src/com/android/launcher3/PagedView.java
index 01893e9..ef6bd3d 100644
--- a/src/com/android/launcher3/PagedView.java
+++ b/src/com/android/launcher3/PagedView.java
@@ -16,11 +16,6 @@
package com.android.launcher3;
-import static com.android.launcher3.compat.AccessibilityManagerCompat.isAccessibilityEnabled;
-import static com.android.launcher3.compat.AccessibilityManagerCompat.isObservedEventType;
-import static com.android.launcher3.config.FeatureFlags.QUICKSTEP_SPRINGS;
-import static com.android.launcher3.touch.OverScroll.OVERSCROLL_DAMP_FACTOR;
-
import android.animation.LayoutTransition;
import android.animation.TimeInterpolator;
import android.annotation.SuppressLint;
@@ -35,6 +30,7 @@
import android.view.InputDevice;
import android.view.KeyEvent;
import android.view.MotionEvent;
+import android.view.Surface;
import android.view.VelocityTracker;
import android.view.View;
import android.view.ViewConfiguration;
@@ -49,13 +45,25 @@
import com.android.launcher3.anim.Interpolators;
import com.android.launcher3.compat.AccessibilityManagerCompat;
import com.android.launcher3.config.FeatureFlags;
+import com.android.launcher3.model.PagedViewOrientedState;
import com.android.launcher3.pageindicators.PageIndicator;
+import com.android.launcher3.touch.PortraitPagedViewHandler;
import com.android.launcher3.touch.OverScroll;
+import com.android.launcher3.touch.PagedOrientationHandler;
+import com.android.launcher3.touch.PagedOrientationHandler.ChildBounds;
import com.android.launcher3.util.OverScroller;
import com.android.launcher3.util.Thunk;
import java.util.ArrayList;
+import static com.android.launcher3.compat.AccessibilityManagerCompat.isAccessibilityEnabled;
+import static com.android.launcher3.compat.AccessibilityManagerCompat.isObservedEventType;
+import static com.android.launcher3.config.FeatureFlags.QUICKSTEP_SPRINGS;
+import static com.android.launcher3.touch.OverScroll.OVERSCROLL_DAMP_FACTOR;
+import static com.android.launcher3.touch.PagedOrientationHandler.CANVAS_TRANSLATE;
+import static com.android.launcher3.touch.PagedOrientationHandler.VIEW_SCROLL_BY;
+import static com.android.launcher3.touch.PagedOrientationHandler.VIEW_SCROLL_TO;
+
/**
* An abstraction of the original Workspace which supports browsing through a
* sequential list of "pages"
@@ -64,6 +72,8 @@
private static final String TAG = "PagedView";
private static final boolean DEBUG = false;
+ public static boolean sFlagForcedRotation = false;
+
public static final int INVALID_PAGE = -1;
protected static final ComputePageScrollsLogic SIMPLE_SCROLL_LOGIC = (v) -> v.getVisibility() != GONE;
@@ -97,8 +107,8 @@
@ViewDebug.ExportedProperty(category = "launcher")
protected int mNextPage = INVALID_PAGE;
- protected int mMinScrollX;
- protected int mMaxScrollX;
+ protected int mMaxScroll;
+ protected int mMinScroll;
protected OverScroller mScroller;
private Interpolator mDefaultInterpolator;
private VelocityTracker mVelocityTracker;
@@ -106,9 +116,12 @@
private float mDownMotionX;
private float mDownMotionY;
- private float mLastMotionX;
- private float mLastMotionXRemainder;
- private float mTotalMotionX;
+ private float mDownMotionPrimary;
+ private float mLastMotion;
+ private float mLastMotionRemainder;
+ private float mTotalMotion;
+ protected PagedOrientationHandler mOrientationHandler = new PortraitPagedViewHandler();
+ protected final PagedViewOrientedState mOrientationState = new PagedViewOrientedState();
protected int[] mPageScrolls;
private boolean mIsBeingDragged;
@@ -123,11 +136,14 @@
protected boolean mIsPageInTransition = false;
- protected float mSpringOverScrollX;
+ protected float mSpringOverScroll;
protected boolean mWasInOverscroll = false;
- protected int mUnboundedScrollX;
+ protected int mUnboundedScroll;
+
+ protected int mLayoutRotation = Surface.ROTATION_0;
+ protected int mDisplayRotation = Surface.ROTATION_0;
// Page Indicator
@Thunk int mPageIndicatorViewId;
@@ -166,11 +182,12 @@
* Initializes various states for this workspace.
*/
protected void init() {
- mScroller = new OverScroller(getContext());
+ Context context = getContext();
+ mScroller = new OverScroller(context);
setDefaultInterpolator(Interpolators.SCROLL);
mCurrentPage = 0;
- final ViewConfiguration configuration = ViewConfiguration.get(getContext());
+ final ViewConfiguration configuration = ViewConfiguration.get(context);
mTouchSlop = configuration.getScaledPagingTouchSlop();
mMaximumVelocity = configuration.getScaledMaximumFlingVelocity();
@@ -182,6 +199,8 @@
if (Utilities.ATLEAST_OREO) {
setDefaultFocusHighlightEnabled(false);
}
+
+ sFlagForcedRotation = Utilities.isForcedRotation(context);
}
protected void setDefaultInterpolator(Interpolator interpolator) {
@@ -236,12 +255,12 @@
*/
protected void updateCurrentPageScroll() {
// If the current page is invalid, just reset the scroll position to zero
- int newX = 0;
+ int newPosition = 0;
if (0 <= mCurrentPage && mCurrentPage < getPageCount()) {
- newX = getScrollForPage(mCurrentPage);
+ newPosition = getScrollForPage(mCurrentPage);
}
- scrollTo(newX, 0);
- mScroller.startScroll(mScroller.getCurrPos(), newX - mScroller.getCurrPos());
+ mOrientationHandler.set(this, VIEW_SCROLL_TO, newPosition);
+ mOrientationHandler.scrollerStartScroll(mScroller, newPosition);
forceFinishScroller(true);
}
@@ -285,7 +304,7 @@
int dir = !mIsRtl ? 1 : - 1;
int currScroll = getScrollForPage(page);
int prevScroll;
- while (currScroll < mMinScrollX) {
+ while (currScroll < mMinScroll) {
page += dir;
prevScroll = currScroll;
currScroll = getScrollForPage(page);
@@ -294,7 +313,7 @@
break;
}
}
- while (currScroll > mMaxScrollX) {
+ while (currScroll > mMaxScroll) {
page -= dir;
prevScroll = currScroll;
currScroll = getScrollForPage(page);
@@ -378,45 +397,73 @@
AccessibilityEvent.TYPE_VIEW_FOCUSED, null);
}
- protected int getUnboundedScrollX() {
- return mUnboundedScrollX;
+ protected int getUnboundedScroll() {
+ return mUnboundedScroll;
+ }
+
+ protected void updateLayoutRotation(int touchRotation) {
+ setLayoutRotation(touchRotation, mDisplayRotation);
+ }
+
+ /** @param touchRotation Must be one of {@link android.view.Surface.ROTATION_0/90/180/270} */
+ public void setLayoutRotation(int touchRotation, int displayRotation) {
+ if (mLayoutRotation == touchRotation && mDisplayRotation == displayRotation) {
+ return;
+ }
+
+ mOrientationState.update(touchRotation, displayRotation);
+ mOrientationHandler = mOrientationState.getOrientationHandler();
+ mLayoutRotation = touchRotation;
+ mDisplayRotation = displayRotation;
+ requestLayout();
+ }
+
+ public PagedViewOrientedState getPagedViewOrientedState() {
+ return mOrientationState;
+ }
+
+ public PagedOrientationHandler getPagedOrientationHandler() {
+ return getPagedViewOrientedState().getOrientationHandler();
+ }
+
+ public void disableMultipleLayoutRotations(boolean disable) {
+ mOrientationState.disableMultipleOrientations(disable);
+ mOrientationHandler = mOrientationState.getOrientationHandler();
+ requestLayout();
}
@Override
public void scrollBy(int x, int y) {
- scrollTo(getUnboundedScrollX() + x, getScrollY() + y);
+ mOrientationHandler.delegateScrollBy(this, getUnboundedScroll(), x, y);
}
@Override
public void scrollTo(int x, int y) {
- mUnboundedScrollX = x;
+ int primaryScroll = mOrientationHandler.getPrimaryValue(x, y);
+ int secondaryScroll = mOrientationHandler.getSecondaryValue(x, y);
+ mUnboundedScroll = primaryScroll;
- boolean isXBeforeFirstPage = mIsRtl ? (x > mMaxScrollX) : (x < mMinScrollX);
- boolean isXAfterLastPage = mIsRtl ? (x < mMinScrollX) : (x > mMaxScrollX);
-
- if (!isXBeforeFirstPage && !isXAfterLastPage) {
- mSpringOverScrollX = 0;
+ boolean isBeforeFirstPage = mIsRtl ?
+ (primaryScroll > mMaxScroll) : (primaryScroll < mMinScroll);
+ boolean isAfterLastPage = mIsRtl ?
+ (primaryScroll < mMinScroll) : (primaryScroll > mMaxScroll);
+ if (!isBeforeFirstPage && !isAfterLastPage) {
+ mSpringOverScroll = 0;
}
- if (isXBeforeFirstPage) {
- super.scrollTo(mIsRtl ? mMaxScrollX : mMinScrollX, y);
+ if (isBeforeFirstPage) {
+ mOrientationHandler.delegateScrollTo(this,
+ secondaryScroll, mIsRtl ? mMaxScroll : mMinScroll);
if (mAllowOverScroll) {
mWasInOverscroll = true;
- if (mIsRtl) {
- overScroll(x - mMaxScrollX);
- } else {
- overScroll(x - mMinScrollX);
- }
+ overScroll(primaryScroll - (mIsRtl ? mMaxScroll : mMinScroll));
}
- } else if (isXAfterLastPage) {
- super.scrollTo(mIsRtl ? mMinScrollX : mMaxScrollX, y);
+ } else if (isAfterLastPage) {
+ mOrientationHandler.delegateScrollTo(this,
+ secondaryScroll, mIsRtl ? mMinScroll : mMaxScroll);
if (mAllowOverScroll) {
mWasInOverscroll = true;
- if (mIsRtl) {
- overScroll(x - mMinScrollX);
- } else {
- overScroll(x - mMaxScrollX);
- }
+ overScroll(primaryScroll - (mIsRtl ? mMinScroll : mMaxScroll));
}
} else {
if (mWasInOverscroll) {
@@ -425,7 +472,13 @@
}
super.scrollTo(x, y);
}
+ }
+ /**
+ * Helper for {@link PagedOrientationHandler} to be able to call parent's scrollTo method
+ */
+ public void superScrollTo(int x, int y) {
+ super.scrollTo(x, y);
}
private void sendScrollAccessibilityEvent() {
@@ -436,9 +489,7 @@
ev.setScrollable(true);
ev.setScrollX(getScrollX());
ev.setScrollY(getScrollY());
- ev.setMaxScrollX(mMaxScrollX);
- ev.setMaxScrollY(0);
-
+ mOrientationHandler.setMaxScroll(ev, mMaxScroll);
sendAccessibilityEventUnchecked(ev);
}
}
@@ -459,9 +510,10 @@
protected boolean computeScrollHelper(boolean shouldInvalidate) {
if (mScroller.computeScrollOffset()) {
// Don't bother scrolling if the page does not need to be moved
- if (getUnboundedScrollX() != mScroller.getCurrPos()
- || getScrollX() != mScroller.getCurrPos()) {
- scrollTo(mScroller.getCurrPos(), 0);
+ int currentScroll = mOrientationHandler.getPrimaryScroll(this);
+ if (mUnboundedScroll != mScroller.getCurrPos()
+ || currentScroll != mScroller.getCurrPos()) {
+ mOrientationHandler.set(this, VIEW_SCROLL_TO, mScroller.getCurrPos());
}
if (shouldInvalidate) {
invalidate();
@@ -580,7 +632,8 @@
if (DEBUG) Log.d(TAG, "PagedView.onLayout()");
- if (getPageScrolls(mPageScrolls, true, SIMPLE_SCROLL_LOGIC)) {
+ boolean isScrollChanged = getPageScrolls(mPageScrolls, true, SIMPLE_SCROLL_LOGIC);
+ if (isScrollChanged) {
pageScrollChanged = true;
}
@@ -621,7 +674,6 @@
/**
* Initializes {@code outPageScrolls} with scroll positions for view at that index. The length
* of {@code outPageScrolls} should be same as the the childCount
- *
*/
protected boolean getPageScrolls(int[] outPageScrolls, boolean layoutChildren,
ComputePageScrollsLogic scrollLogic) {
@@ -631,36 +683,30 @@
final int endIndex = mIsRtl ? -1 : childCount;
final int delta = mIsRtl ? -1 : 1;
- final int verticalCenter = (getPaddingTop() + getMeasuredHeight() + mInsets.top
- - mInsets.bottom - getPaddingBottom()) / 2;
+ final int pageCenter = mOrientationHandler.getCenterForPage(this, mInsets);
- final int scrollOffsetLeft = mInsets.left + getPaddingLeft();
- final int scrollOffsetRight = getWidth() - getPaddingRight() - mInsets.right;
+ final int scrollOffsetStart = mOrientationHandler.getScrollOffsetStart(this, mInsets);
+ final int scrollOffsetEnd = mOrientationHandler.getScrollOffsetEnd(this, mInsets);
boolean pageScrollChanged = false;
- for (int i = startIndex, childLeft = scrollOffsetLeft; i != endIndex; i += delta) {
+ for (int i = startIndex, childStart = scrollOffsetStart; i != endIndex; i += delta) {
final View child = getPageAt(i);
if (scrollLogic.shouldIncludeView(child)) {
- final int childWidth = child.getMeasuredWidth();
- final int childRight = childLeft + childWidth;
-
- if (layoutChildren) {
- final int childHeight = child.getMeasuredHeight();
- final int childTop = verticalCenter - childHeight / 2;
- child.layout(childLeft, childTop, childRight, childTop + childHeight);
- }
+ ChildBounds bounds = mOrientationHandler.getChildBounds(child, childStart,
+ pageCenter, layoutChildren);
+ final int primaryDimension = bounds.primaryDimension;
+ final int childPrimaryEnd = bounds.childPrimaryEnd;
// In case the pages are of different width, align the page to left or right edge
// based on the orientation.
final int pageScroll = mIsRtl
- ? (childLeft - scrollOffsetLeft)
- : Math.max(0, childRight - scrollOffsetRight);
+ ? (childStart - scrollOffsetStart)
+ : Math.max(0, childPrimaryEnd - scrollOffsetEnd);
if (outPageScrolls[i] != pageScroll) {
pageScrollChanged = true;
outPageScrolls[i] = pageScroll;
}
-
- childLeft += childWidth + mPageSpacing + getChildGap();
+ childStart += primaryDimension + mPageSpacing + getChildGap();
}
}
return pageScrollChanged;
@@ -671,15 +717,15 @@
}
protected void updateMinAndMaxScrollX() {
- mMinScrollX = computeMinScrollX();
- mMaxScrollX = computeMaxScrollX();
+ mMinScroll = computeMinScroll();
+ mMaxScroll = computeMaxScroll();
}
- protected int computeMinScrollX() {
+ protected int computeMinScroll() {
return 0;
}
- protected int computeMaxScrollX() {
+ protected int computeMaxScroll() {
int childCount = getChildCount();
if (childCount > 0) {
final int index = mIsRtl ? 0 : childCount - 1;
@@ -722,7 +768,8 @@
protected int getChildOffset(int index) {
if (index < 0 || index > getChildCount() - 1) return 0;
- return getPageAt(index).getLeft();
+ View pageAtIndex = getPageAt(index);
+ return mOrientationHandler.getChildStart(pageAtIndex);
}
@Override
@@ -873,13 +920,13 @@
case MotionEvent.ACTION_MOVE: {
/*
* mIsBeingDragged == false, otherwise the shortcut would have caught it. Check
- * whether the user has moved far enough from his original down touch.
+ * whether the user has moved far enough from their original down touch.
*/
if (mActivePointerId != INVALID_POINTER) {
determineScrollingStart(ev);
}
// if mActivePointerId is INVALID_POINTER, then we must have missed an ACTION_DOWN
- // event. in that case, treat the first occurence of a move event as a ACTION_DOWN
+ // event. in that case, treat the first occurrence of a move event as a ACTION_DOWN
// i.e. fall through to the next case (don't break)
// (We sometimes miss ACTION_DOWN events in Workspace because it ignores all events
// while it's small- this was causing a crash before we checked for INVALID_POINTER)
@@ -892,9 +939,9 @@
// Remember location of down touch
mDownMotionX = x;
mDownMotionY = y;
- mLastMotionX = x;
- mLastMotionXRemainder = 0;
- mTotalMotionX = 0;
+ mLastMotion = mOrientationHandler.getPrimaryDirection(ev, 0);
+ mLastMotionRemainder = 0;
+ mTotalMotion = 0;
mActivePointerId = ev.getPointerId(0);
updateIsBeingDraggedOnTouchDown();
@@ -956,17 +1003,17 @@
final int pointerIndex = ev.findPointerIndex(mActivePointerId);
if (pointerIndex == -1) return;
- final float x = ev.getX(pointerIndex);
- final int xDiff = (int) Math.abs(x - mLastMotionX);
+ final float primaryDirection = mOrientationHandler.getPrimaryDirection(ev, pointerIndex);
+ final int diff = (int) Math.abs(primaryDirection - mLastMotion);
final int touchSlop = Math.round(touchSlopScale * mTouchSlop);
- boolean xMoved = xDiff > touchSlop;
+ boolean moved = diff > touchSlop;
- if (xMoved) {
+ if (moved) {
// Scroll if the user moved far enough along the X axis
mIsBeingDragged = true;
- mTotalMotionX += Math.abs(mLastMotionX - x);
- mLastMotionX = x;
- mLastMotionXRemainder = 0;
+ mTotalMotion += Math.abs(mLastMotion - primaryDirection);
+ mLastMotion = primaryDirection;
+ mLastMotionRemainder = 0;
onScrollInteractionBegin();
pageBeginTransition();
// Stop listening for things like pinches.
@@ -1033,10 +1080,9 @@
@Override
protected void dispatchDraw(Canvas canvas) {
- if (mScroller.isSpringing() && mSpringOverScrollX != 0) {
+ if (mScroller.isSpringing() && mSpringOverScroll != 0) {
int saveCount = canvas.save();
-
- canvas.translate(-mSpringOverScrollX, 0);
+ mOrientationHandler.set(canvas, CANVAS_TRANSLATE, -mSpringOverScroll);
super.dispatchDraw(canvas);
canvas.restoreToCount(saveCount);
@@ -1046,25 +1092,27 @@
}
protected void dampedOverScroll(int amount) {
- mSpringOverScrollX = amount;
+ mSpringOverScroll = amount;
if (amount == 0) {
return;
}
- int overScrollAmount = OverScroll.dampedScroll(amount, getMeasuredWidth());
- mSpringOverScrollX = overScrollAmount;
+ int size = mOrientationHandler.getMeasuredSize(this);
+ int overScrollAmount = OverScroll.dampedScroll(amount, size);
+ mSpringOverScroll = overScrollAmount;
if (mScroller.isSpringing()) {
invalidate();
return;
}
- int x = Utilities.boundToRange(getScrollX(), mMinScrollX, mMaxScrollX);
- super.scrollTo(x + overScrollAmount, getScrollY());
+ int primaryScroll = mOrientationHandler.getPrimaryScroll(this);
+ int boundedScroll = Utilities.boundToRange(primaryScroll, mMinScroll, mMaxScroll);
+ mOrientationHandler.delegateScrollTo(this, boundedScroll + overScrollAmount);
invalidate();
}
protected void overScroll(int amount) {
- mSpringOverScrollX = amount;
+ mSpringOverScroll = amount;
if (mScroller.isSpringing()) {
invalidate();
return;
@@ -1073,11 +1121,8 @@
if (amount == 0) return;
if (mFreeScroll && !mScroller.isFinished()) {
- if (amount < 0) {
- super.scrollTo(mMinScrollX + amount, getScrollY());
- } else {
- super.scrollTo(mMaxScrollX + amount, getScrollY());
- }
+ int scrollAmount = amount < 0 ? mMinScroll + amount : mMaxScroll + amount;
+ mOrientationHandler.delegateScrollTo(this, scrollAmount);
} else {
dampedOverScroll(amount);
}
@@ -1127,37 +1172,37 @@
}
// Remember where the motion event started
- mDownMotionX = mLastMotionX = ev.getX();
+ mDownMotionX = ev.getX();
mDownMotionY = ev.getY();
- mLastMotionXRemainder = 0;
- mTotalMotionX = 0;
+ mDownMotionPrimary = mLastMotion = mOrientationHandler.getPrimaryDirection(ev, 0);
+ mLastMotionRemainder = 0;
+ mTotalMotion = 0;
mActivePointerId = ev.getPointerId(0);
-
if (mIsBeingDragged) {
onScrollInteractionBegin();
pageBeginTransition();
}
break;
- case MotionEvent.ACTION_MOVE:
- if (mIsBeingDragged) {
+ case MotionEvent.ACTION_MOVE:
+ if (mIsBeingDragged) {
// Scroll to follow the motion event
final int pointerIndex = ev.findPointerIndex(mActivePointerId);
if (pointerIndex == -1) return true;
- final float x = ev.getX(pointerIndex);
- final float deltaX = mLastMotionX + mLastMotionXRemainder - x;
-
- mTotalMotionX += Math.abs(deltaX);
+ float direction = mOrientationHandler.getPrimaryDirection(ev, pointerIndex);
+ float delta = mLastMotion + mLastMotionRemainder - direction;
+ mTotalMotion += Math.abs(delta);
// Only scroll and update mLastMotionX if we have moved some discrete amount. We
// keep the remainder because we are actually testing if we've moved from the last
// scrolled position (which is discrete).
- if (Math.abs(deltaX) >= 1.0f) {
- scrollBy((int) deltaX, 0);
- mLastMotionX = x;
- mLastMotionXRemainder = deltaX - (int) deltaX;
+ if (Math.abs(delta) >= 1.0f) {
+ mLastMotion = direction;
+ mLastMotionRemainder = delta - (int) delta;
+
+ mOrientationHandler.set(this, VIEW_SCROLL_BY, (int) delta);
} else {
awakenScrollBars();
}
@@ -1170,27 +1215,31 @@
if (mIsBeingDragged) {
final int activePointerId = mActivePointerId;
final int pointerIndex = ev.findPointerIndex(activePointerId);
- final float x = ev.getX(pointerIndex);
+ final float primaryDirection = mOrientationHandler.getPrimaryDirection(ev,
+ pointerIndex);
final VelocityTracker velocityTracker = mVelocityTracker;
velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity);
- int velocityX = (int) velocityTracker.getXVelocity(mActivePointerId);
- final int deltaX = (int) (x - mDownMotionX);
- final int pageWidth = getPageAt(mCurrentPage).getMeasuredWidth();
- boolean isSignificantMove = Math.abs(deltaX) > pageWidth *
- SIGNIFICANT_MOVE_THRESHOLD;
- mTotalMotionX += Math.abs(mLastMotionX + mLastMotionXRemainder - x);
- boolean isFling = mTotalMotionX > mTouchSlop && shouldFlingForVelocity(velocityX);
- boolean isDeltaXLeft = mIsRtl ? deltaX > 0 : deltaX < 0;
- boolean isVelocityXLeft = mIsRtl ? velocityX > 0 : velocityX < 0;
+ int velocity = (int) mOrientationHandler.getPrimaryVelocity(velocityTracker,
+ mActivePointerId);
+ int delta = (int) (primaryDirection - mDownMotionPrimary);
+ int pageOrientedSize = mOrientationHandler.getMeasuredSize(getPageAt(mCurrentPage));
+
+ boolean isSignificantMove = Math.abs(delta) > pageOrientedSize *
+ SIGNIFICANT_MOVE_THRESHOLD;
+
+ mTotalMotion += Math.abs(mLastMotion + mLastMotionRemainder - primaryDirection);
+ boolean isFling = mTotalMotion > mTouchSlop && shouldFlingForVelocity(velocity);
+ boolean isDeltaLeft = mIsRtl ? delta > 0 : delta < 0;
+ boolean isVelocityLeft = mIsRtl ? velocity > 0 : velocity < 0;
if (!mFreeScroll) {
// In the case that the page is moved far to one direction and then is flung
// in the opposite direction, we use a threshold to determine whether we should
// just return to the starting page, or if we should skip one further.
boolean returnToOriginalPage = false;
- if (Math.abs(deltaX) > pageWidth * RETURN_TO_ORIGINAL_PAGE_THRESHOLD &&
- Math.signum(velocityX) != Math.signum(deltaX) && isFling) {
+ if (Math.abs(delta) > pageOrientedSize * RETURN_TO_ORIGINAL_PAGE_THRESHOLD &&
+ Math.signum(velocity) != Math.signum(delta) && isFling) {
returnToOriginalPage = true;
}
@@ -1199,15 +1248,15 @@
// test for a large move if a fling has been registered. That is, a large
// move to the left and fling to the right will register as a fling to the right.
- if (((isSignificantMove && !isDeltaXLeft && !isFling) ||
- (isFling && !isVelocityXLeft)) && mCurrentPage > 0) {
+ if (((isSignificantMove && !isDeltaLeft && !isFling) ||
+ (isFling && !isVelocityLeft)) && mCurrentPage > 0) {
finalPage = returnToOriginalPage ? mCurrentPage : mCurrentPage - 1;
- snapToPageWithVelocity(finalPage, velocityX);
- } else if (((isSignificantMove && isDeltaXLeft && !isFling) ||
- (isFling && isVelocityXLeft)) &&
+ snapToPageWithVelocity(finalPage, velocity);
+ } else if (((isSignificantMove && isDeltaLeft && !isFling) ||
+ (isFling && isVelocityLeft)) &&
mCurrentPage < getChildCount() - 1) {
finalPage = returnToOriginalPage ? mCurrentPage : mCurrentPage + 1;
- snapToPageWithVelocity(finalPage, velocityX);
+ snapToPageWithVelocity(finalPage, velocity);
} else {
snapToDestination();
}
@@ -1216,38 +1265,40 @@
abortScrollerAnimation(true);
}
- int initialScrollX = getScrollX();
+ int initialScroll = mOrientationHandler.getPrimaryScroll(this);
+ int maxScroll = mMaxScroll;
+ int minScroll = mMinScroll;
- if (((initialScrollX >= mMaxScrollX) && (isVelocityXLeft || !isFling)) ||
- ((initialScrollX <= mMinScrollX) && (!isVelocityXLeft || !isFling))) {
- mScroller.springBack(getScrollX(), mMinScrollX, mMaxScrollX);
+ if (((initialScroll >= maxScroll) && (isVelocityLeft || !isFling)) ||
+ ((initialScroll <= minScroll) && (!isVelocityLeft || !isFling))) {
+ mScroller.springBack(initialScroll, minScroll, maxScroll);
mNextPage = getPageNearestToCenterOfScreen();
} else {
mScroller.setInterpolator(mDefaultInterpolator);
- mScroller.fling(initialScrollX, -velocityX,
- mMinScrollX, mMaxScrollX,
- Math.round(getWidth() * 0.5f * OVERSCROLL_DAMP_FACTOR));
+ mScroller.fling(initialScroll, -velocity,
+ minScroll, maxScroll,
+ Math.round(getWidth() * 0.5f * OVERSCROLL_DAMP_FACTOR));
- int finalX = mScroller.getFinalPos();
- mNextPage = getPageNearestToCenterOfScreen(finalX);
+ int finalPos = mScroller.getFinalPos();
+ mNextPage = getPageNearestToCenterOfScreen(finalPos);
int firstPageScroll = getScrollForPage(!mIsRtl ? 0 : getPageCount() - 1);
int lastPageScroll = getScrollForPage(!mIsRtl ? getPageCount() - 1 : 0);
- if (finalX > mMinScrollX && finalX < mMaxScrollX) {
+ if (finalPos > minScroll && finalPos < maxScroll) {
// If scrolling ends in the half of the added space that is closer to
// the end, settle to the end. Otherwise snap to the nearest page.
// If flinging past one of the ends, don't change the velocity as it
// will get stopped at the end anyway.
- int pageSnappedX = finalX < (firstPageScroll + mMinScrollX) / 2
- ? mMinScrollX
- : finalX > (lastPageScroll + mMaxScrollX) / 2
- ? mMaxScrollX
- : getScrollForPage(mNextPage);
+ int pageSnapped = finalPos < (firstPageScroll + minScroll) / 2
+ ? minScroll
+ : finalPos > (lastPageScroll + maxScroll) / 2
+ ? maxScroll
+ : getScrollForPage(mNextPage);
- mScroller.setFinalPos(pageSnappedX);
+ mScroller.setFinalPos(pageSnapped);
// Ensure the scroll/snap doesn't happen too fast;
int extraScrollDuration = OVERSCROLL_PAGE_SNAP_ANIMATION_DURATION
- - mScroller.getDuration();
+ - mScroller.getDuration();
if (extraScrollDuration > 0) {
mScroller.extendDuration(extraScrollDuration);
}
@@ -1279,8 +1330,8 @@
return true;
}
- protected boolean shouldFlingForVelocity(int velocityX) {
- return Math.abs(velocityX) > mFlingThresholdVelocity;
+ protected boolean shouldFlingForVelocity(int velocity) {
+ return Math.abs(velocity) > mFlingThresholdVelocity;
}
private void resetTouchState() {
@@ -1364,8 +1415,9 @@
// active pointer and adjust accordingly.
// TODO: Make this decision more intelligent.
final int newPointerIndex = pointerIndex == 0 ? 1 : 0;
- mLastMotionX = mDownMotionX = ev.getX(newPointerIndex);
- mLastMotionXRemainder = 0;
+ mLastMotion = mDownMotionPrimary = mOrientationHandler.getPrimaryDirection(ev,
+ newPointerIndex);
+ mLastMotionRemainder = 0;
mActivePointerId = ev.getPointerId(newPointerIndex);
if (mVelocityTracker != null) {
mVelocityTracker.clear();
@@ -1383,19 +1435,20 @@
}
public int getPageNearestToCenterOfScreen() {
- return getPageNearestToCenterOfScreen(getScrollX());
+ return getPageNearestToCenterOfScreen(mOrientationHandler.getPrimaryScroll(this));
}
- private int getPageNearestToCenterOfScreen(int scaledScrollX) {
- int screenCenter = scaledScrollX + (getMeasuredWidth() / 2);
+ private int getPageNearestToCenterOfScreen(int scaledScroll) {
+ int pageOrientationSize = mOrientationHandler.getMeasuredSize(this);
+ int screenCenter = scaledScroll + (pageOrientationSize / 2);
int minDistanceFromScreenCenter = Integer.MAX_VALUE;
int minDistanceFromScreenCenterIndex = -1;
final int childCount = getChildCount();
for (int i = 0; i < childCount; ++i) {
View layout = getPageAt(i);
- int childWidth = layout.getMeasuredWidth();
- int halfChildWidth = (childWidth / 2);
- int childCenter = getChildOffset(i) + halfChildWidth;
+ int childSize = mOrientationHandler.getMeasuredSize(layout);
+ int halfChildSize = (childSize / 2);
+ int childCenter = getChildOffset(i) + halfChildSize;
int distanceFromScreenCenter = Math.abs(childCenter - screenCenter);
if (distanceFromScreenCenter < minDistanceFromScreenCenter) {
minDistanceFromScreenCenter = distanceFromScreenCenter;
@@ -1410,7 +1463,8 @@
}
protected boolean isInOverScroll() {
- return (getScrollX() > mMaxScrollX || getScrollX() < mMinScrollX);
+ int scroll = mOrientationHandler.getPrimaryScroll(this);
+ return scroll > mMaxScroll || scroll < mMinScroll;
}
protected int getPageSnapDuration() {
@@ -1432,10 +1486,10 @@
protected boolean snapToPageWithVelocity(int whichPage, int velocity) {
whichPage = validateNewPage(whichPage);
- int halfScreenSize = getMeasuredWidth() / 2;
+ int halfScreenSize = mOrientationHandler.getMeasuredSize(this) / 2;
- final int newX = getScrollForPage(whichPage);
- int delta = newX - getUnboundedScrollX();
+ final int newLoc = getScrollForPage(whichPage);
+ int delta = newLoc - getUnboundedScroll();
int duration = 0;
if (Math.abs(velocity) < mMinFlingVelocity) {
@@ -1462,7 +1516,7 @@
if (QUICKSTEP_SPRINGS.get()) {
return snapToPage(whichPage, delta, duration, false, null,
- velocity * Math.signum(newX - getUnboundedScrollX()), true);
+ velocity * Math.signum(delta), true);
} else {
return snapToPage(whichPage, delta, duration);
}
@@ -1488,8 +1542,8 @@
TimeInterpolator interpolator) {
whichPage = validateNewPage(whichPage);
- int newX = getScrollForPage(whichPage);
- final int delta = newX - getUnboundedScrollX();
+ int newLoc = getScrollForPage(whichPage);
+ final int delta = newLoc - getUnboundedScroll();
return snapToPage(whichPage, delta, duration, immediate, interpolator, 0, false);
}
@@ -1535,9 +1589,9 @@
}
if (spring && QUICKSTEP_SPRINGS.get()) {
- mScroller.startScrollSpring(getUnboundedScrollX(), delta, duration, velocity);
+ mScroller.startScrollSpring(getUnboundedScroll(), delta, duration, velocity);
} else {
- mScroller.startScroll(getUnboundedScrollX(), delta, duration);
+ mScroller.startScroll(getUnboundedScroll(), delta, duration);
}
updatePageIndicator();
diff --git a/src/com/android/launcher3/ResourceUtils.java b/src/com/android/launcher3/ResourceUtils.java
index 7f327a5..403d779 100644
--- a/src/com/android/launcher3/ResourceUtils.java
+++ b/src/com/android/launcher3/ResourceUtils.java
@@ -21,12 +21,12 @@
import android.util.TypedValue;
public class ResourceUtils {
+ public static final int DEFAULT_NAVBAR_VALUE = 48;
public static final String NAVBAR_LANDSCAPE_LEFT_RIGHT_SIZE = "navigation_bar_width";
public static final String NAVBAR_BOTTOM_GESTURE_SIZE = "navigation_bar_gesture_height";
-
public static int getNavbarSize(String resName, Resources res) {
- return getDimenByName(resName, res, 48);
+ return getDimenByName(resName, res, DEFAULT_NAVBAR_VALUE);
}
public static int getDimenByName(String resName, Resources res, int defaultValue) {
diff --git a/src/com/android/launcher3/Utilities.java b/src/com/android/launcher3/Utilities.java
index e0e4cc0..9780630 100644
--- a/src/com/android/launcher3/Utilities.java
+++ b/src/com/android/launcher3/Utilities.java
@@ -17,6 +17,7 @@
package com.android.launcher3;
import static com.android.launcher3.ItemInfoWithIcon.FLAG_ICON_BADGED;
+import static com.android.launcher3.states.RotationHelper.FIXED_ROTATION_TRANSFORM_SETTING_NAME;
import android.animation.ValueAnimator;
import android.annotation.TargetApi;
@@ -127,6 +128,11 @@
Settings.Global.DEVELOPMENT_SETTINGS_ENABLED, 0) != 0;
}
+ public static boolean isForcedRotation(Context context) {
+ return Settings.Global.getInt(context.getContentResolver(),
+ FIXED_ROTATION_TRANSFORM_SETTING_NAME, 0) != 0;
+ }
+
// An intent extra to indicate the horizontal scroll of the wallpaper.
public static final String EXTRA_WALLPAPER_OFFSET = "com.android.launcher3.WALLPAPER_OFFSET";
public static final String EXTRA_WALLPAPER_FLAVOR = "com.android.launcher3.WALLPAPER_FLAVOR";
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index a8f492f..590c620 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -966,8 +966,8 @@
private boolean isScrollingOverlay() {
return mLauncherOverlay != null &&
- ((mIsRtl && getUnboundedScrollX() > mMaxScrollX)
- || (!mIsRtl && getUnboundedScrollX() < mMinScrollX));
+ ((mIsRtl && getUnboundedScroll() > mMaxScroll)
+ || (!mIsRtl && getUnboundedScroll() < mMinScroll));
}
@Override
@@ -1003,7 +1003,7 @@
public void showPageIndicatorAtCurrentScroll() {
if (mPageIndicator != null) {
- mPageIndicator.setScroll(getScrollX(), computeMaxScrollX());
+ mPageIndicator.setScroll(getScrollX(), computeMaxScroll());
}
}
diff --git a/src/com/android/launcher3/allapps/AllAppsPagedView.java b/src/com/android/launcher3/allapps/AllAppsPagedView.java
index 5b73940..ab4cb6b 100644
--- a/src/com/android/launcher3/allapps/AllAppsPagedView.java
+++ b/src/com/android/launcher3/allapps/AllAppsPagedView.java
@@ -48,7 +48,7 @@
@Override
protected void onScrollChanged(int l, int t, int oldl, int oldt) {
super.onScrollChanged(l, t, oldl, oldt);
- mPageIndicator.setScroll(l, mMaxScrollX);
+ mPageIndicator.setScroll(l, mMaxScroll);
}
@Override
diff --git a/src/com/android/launcher3/allapps/AllAppsTransitionController.java b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
index e49ff30..2179162 100644
--- a/src/com/android/launcher3/allapps/AllAppsTransitionController.java
+++ b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
@@ -32,8 +32,10 @@
import com.android.launcher3.anim.AnimatorSetBuilder;
import com.android.launcher3.anim.PropertySetter;
import com.android.launcher3.anim.SpringObjectAnimator;
+import com.android.launcher3.util.DynamicResource;
import com.android.launcher3.util.Themes;
import com.android.launcher3.views.ScrimView;
+import com.android.systemui.plugins.ResourceProvider;
/**
* Handles AllApps view transition.
@@ -47,9 +49,6 @@
*/
public class AllAppsTransitionController implements StateHandler, OnDeviceProfileChangeListener {
- private static final float SPRING_DAMPING_RATIO = 0.75f;
- private static final float SPRING_STIFFNESS = 600f;
-
public static final FloatProperty<AllAppsTransitionController> ALL_APPS_PROGRESS =
new FloatProperty<AllAppsTransitionController>("allAppsProgress") {
@@ -187,8 +186,12 @@
public Animator createSpringAnimation(float... progressValues) {
if (UNSTABLE_SPRINGS.get()) {
+ ResourceProvider rp = DynamicResource.provider(mLauncher);
+ float damping = rp.getFloat(R.dimen.all_apps_spring_damping_ratio);
+ float stiffness = rp.getFloat(R.dimen.all_apps_spring_stiffness);
+
return new SpringObjectAnimator<>(this, ALL_APPS_PROGRESS, 1f / mShiftRange,
- SPRING_DAMPING_RATIO, SPRING_STIFFNESS, progressValues);
+ damping, stiffness, progressValues);
}
return ObjectAnimator.ofFloat(this, ALL_APPS_PROGRESS, progressValues);
}
diff --git a/src/com/android/launcher3/folder/FolderPagedView.java b/src/com/android/launcher3/folder/FolderPagedView.java
index 3b5fd59..c6d62f8 100644
--- a/src/com/android/launcher3/folder/FolderPagedView.java
+++ b/src/com/android/launcher3/folder/FolderPagedView.java
@@ -258,7 +258,7 @@
@Override
protected void onScrollChanged(int l, int t, int oldl, int oldt) {
super.onScrollChanged(l, t, oldl, oldt);
- mPageIndicator.setScroll(l, mMaxScrollX);
+ mPageIndicator.setScroll(l, mMaxScroll);
}
/**
diff --git a/src/com/android/launcher3/model/PagedViewOrientedState.java b/src/com/android/launcher3/model/PagedViewOrientedState.java
new file mode 100644
index 0000000..1349eff
--- /dev/null
+++ b/src/com/android/launcher3/model/PagedViewOrientedState.java
@@ -0,0 +1,104 @@
+/*
+ *
+ * * Copyright (C) 2020 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.launcher3.model;
+
+import android.view.Surface;
+
+import com.android.launcher3.states.RotationHelper;
+import com.android.launcher3.touch.PortraitPagedViewHandler;
+import com.android.launcher3.touch.LandscapePagedViewHandler;
+import com.android.launcher3.touch.PagedOrientationHandler;
+import com.android.launcher3.touch.SeascapePagedViewHandler;
+
+/**
+ * Container to hold orientation/rotation related information for Launcher.
+ * This is not meant to be an abstraction layer for applying different functionality between
+ * the different orientation/rotations. For that see {@link PagedOrientationHandler}
+ *
+ * This class has initial default state assuming the device and foreground app have
+ * no ({@link Surface.ROTATION_0} rotation.
+ *
+ * Currently this class resides in {@link com.android.launcher3.PagedView}, but there's a ticket
+ * to disassociate it from Launcher since it's needed before Launcher is instantiated
+ * See TODO(b/150300347)
+ */
+public final class PagedViewOrientedState {
+
+ private PagedOrientationHandler mOrientationHandler = new PortraitPagedViewHandler();
+
+ private int mTouchRotation = Surface.ROTATION_0;
+ private int mDisplayRotation = Surface.ROTATION_0;
+ /**
+ * If {@code true} we default to {@link PortraitPagedViewHandler} and don't support any fake
+ * launcher orientations.
+ */
+ private boolean mDisableMultipleOrientations;
+
+ public void update(int touchRotation, int displayRotation) {
+ mDisplayRotation = displayRotation;
+ mTouchRotation = touchRotation;
+ if (mTouchRotation == Surface.ROTATION_90) {
+ mOrientationHandler = new LandscapePagedViewHandler();
+ } else if (mTouchRotation == Surface.ROTATION_270) {
+ mOrientationHandler = new SeascapePagedViewHandler();
+ } else {
+ mOrientationHandler = new PortraitPagedViewHandler();
+ }
+ }
+
+ /**
+ * @return {@code true} if the area where the user touched the nav bar is the expected
+ * location for the given display rotation. Ex. bottom of phone in portrait, or left side of
+ * phone in landscape, right side in seascape, etc.
+ * False otherwise
+ */
+ public boolean isTouchRegionNaturalForDisplay() {
+ return mTouchRotation == mDisplayRotation;
+ }
+
+ public boolean areMultipleLayoutOrientationsDisabled() {
+ return mDisableMultipleOrientations;
+ }
+
+ public void disableMultipleOrientations(boolean disable) {
+ mDisableMultipleOrientations = disable;
+ if (disable) {
+ mOrientationHandler = new PortraitPagedViewHandler();
+ }
+ }
+
+ public int getDisplayRotation() {
+ return mDisplayRotation;
+ }
+
+ /**
+ * Gets the difference between the rotation of the device/display and which region the
+ * user is currently interacting with in factors of 90 degree clockwise rotations.
+ * Ex. Display is in portrait -> 0, user touches landscape region -> 1, this
+ * method would return 3 because it takes 3 clockwise 90 degree rotations from normal to
+ * landscape (portrait -> seascape -> reverse portrait -> landscape)
+ */
+ public int getTouchDisplayDelta() {
+ return RotationHelper.deltaRotation(mTouchRotation, mDisplayRotation);
+ }
+
+ public PagedOrientationHandler getOrientationHandler() {
+ return mOrientationHandler;
+ }
+}
diff --git a/src/com/android/launcher3/notification/NotificationMainView.java b/src/com/android/launcher3/notification/NotificationMainView.java
index 812268a..b193ffd 100644
--- a/src/com/android/launcher3/notification/NotificationMainView.java
+++ b/src/com/android/launcher3/notification/NotificationMainView.java
@@ -176,7 +176,7 @@
// SingleAxisSwipeDetector.Listener's
@Override
- public void onDragStart(boolean start) { }
+ public void onDragStart(boolean start, float startDisplacement) { }
@Override
diff --git a/src/com/android/launcher3/states/RotationHelper.java b/src/com/android/launcher3/states/RotationHelper.java
index 852928b..3b134b0 100644
--- a/src/com/android/launcher3/states/RotationHelper.java
+++ b/src/com/android/launcher3/states/RotationHelper.java
@@ -17,15 +17,26 @@
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LOCKED;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_NOSENSOR;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
import static android.util.DisplayMetrics.DENSITY_DEVICE_STABLE;
+import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
+import android.content.ContentResolver;
import android.content.SharedPreferences;
import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
import android.content.res.Resources;
+import android.database.ContentObserver;
+import android.graphics.Matrix;
+import android.graphics.Rect;
+import android.graphics.RectF;
+import android.provider.Settings;
+import android.view.MotionEvent;
+import android.view.Surface;
import android.view.WindowManager;
import com.android.launcher3.Launcher;
+import com.android.launcher3.PagedView;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
import com.android.launcher3.config.FeatureFlags;
@@ -38,6 +49,8 @@
public static final String ALLOW_ROTATION_PREFERENCE_KEY = "pref_allowRotation";
+ public static final String FIXED_ROTATION_TRANSFORM_SETTING_NAME = "fixed_rotation_transform";
+
public static boolean getAllowRotationDefaultValue() {
// If the device was scaled, used the original dimensions to determine if rotation
// is allowed of not.
@@ -92,6 +105,18 @@
} else {
mPrefs = null;
}
+
+ // TODO(b/150260456) Add this in home settings as well
+ final ContentResolver resolver = launcher.getContentResolver();
+ final ContentObserver observer = new ContentObserver(MAIN_EXECUTOR.getHandler()) {
+ @Override
+ public void onChange(boolean selfChange) {
+ PagedView.sFlagForcedRotation = Utilities.isForcedRotation(mLauncher);
+ }
+ };
+ resolver.registerContentObserver(Settings.Global.getUriFor(
+ FIXED_ROTATION_TRANSFORM_SETTING_NAME),
+ false, observer);
}
public void setRotationHadDifferentUI(boolean rotationHasDifferentUI) {
@@ -204,6 +229,118 @@
}
}
+ public static int getDegreesFromRotation(int rotation) {
+ int degrees;
+ switch (rotation) {
+ case Surface.ROTATION_90:
+ degrees = 90;
+ break;
+ case Surface.ROTATION_180:
+ degrees = 180;
+ break;
+ case Surface.ROTATION_270:
+ degrees = 270;
+ break;
+ case Surface.ROTATION_0:
+ default:
+ degrees = 0;
+ break;
+ }
+ return degrees;
+ }
+
+ public static int getRotationFromDegrees(int degrees) {
+ int threshold = 70;
+ if (degrees >= (360 - threshold) || degrees < (threshold)) {
+ return Surface.ROTATION_0;
+ } else if (degrees < (90 + threshold)) {
+ return Surface.ROTATION_270;
+ } else if (degrees < 180 + threshold) {
+ return Surface.ROTATION_180;
+ } else {
+ return Surface.ROTATION_90;
+ }
+ }
+
+ /**
+ * @return how many factors {@param newRotation} is rotated 90 degrees clockwise.
+ * E.g. 1->Rotated by 90 degrees clockwise, 2->Rotated 180 clockwise...
+ * A value of 0 means no rotation has been applied
+ */
+ public static int deltaRotation(int oldRotation, int newRotation) {
+ int delta = newRotation - oldRotation;
+ if (delta < 0) delta += 4;
+ return delta;
+ }
+
+ /**
+ * Creates a matrix to transform the given motion event specified by degrees.
+ * If {@param inverse} is {@code true}, the inverse of that matrix will be applied
+ */
+ public static void transformEvent(int degrees, MotionEvent ev, boolean inverse) {
+ Matrix transform = new Matrix();
+ transform.setRotate(degrees);
+ if (inverse) {
+ Matrix inv = new Matrix();
+ transform.invert(inv);
+ ev.transform(inv);
+ } else {
+ ev.transform(transform);
+ }
+ // TODO: Add scaling back in based on degrees
+// if (getWidth() > 0 && getHeight() > 0) {
+// float scale = ((float) getWidth()) / getHeight();
+// transform.postScale(scale, 1 / scale);
+// }
+ }
+
+ /**
+ * TODO(b/149658423): Have {@link com.android.quickstep.OrientationTouchTransformer
+ * also use this}
+ */
+ public static Matrix getRotationMatrix(int screenWidth, int screenHeight, int displayRotation) {
+ Matrix m = new Matrix();
+ switch (displayRotation) {
+ case Surface.ROTATION_0:
+ return m;
+ case Surface.ROTATION_90:
+ m.setRotate(360 - RotationHelper.getDegreesFromRotation(displayRotation));
+ m.postTranslate(0, screenWidth);
+ break;
+ case Surface.ROTATION_270:
+ m.setRotate(360 - RotationHelper.getDegreesFromRotation(displayRotation));
+ m.postTranslate(screenHeight, 0);
+ break;
+ }
+ return m;
+ }
+
+ public static void mapRectFromNormalOrientation(RectF src, int screenWidth, int screenHeight,
+ int displayRotation) {
+ Matrix m = RotationHelper.getRotationMatrix(screenWidth, screenHeight, displayRotation);
+ m.mapRect(src);
+ }
+
+ public static void mapInverseRectFromNormalOrientation(RectF src, int screenWidth,
+ int screenHeight, int displayRotation) {
+ Matrix m = RotationHelper.getRotationMatrix(screenWidth, screenHeight, displayRotation);
+ Matrix inverse = new Matrix();
+ m.invert(inverse);
+ inverse.mapRect(src);
+ }
+
+ public static void getTargetRectForRotation(Rect srcOut, int screenWidth, int screenHeight,
+ int displayRotation) {
+ RectF wrapped = new RectF(srcOut);
+ Matrix m = RotationHelper.getRotationMatrix(screenWidth, screenHeight, displayRotation);
+ m.mapRect(wrapped);
+ wrapped.round(srcOut);
+ }
+
+ public static boolean isRotationLandscape(int rotation) {
+ return rotation == Surface.ROTATION_270 || rotation == Surface.ROTATION_90;
+ }
+
@Override
public String toString() {
return String.format("[mStateHandlerRequest=%d, mCurrentStateRequest=%d,"
diff --git a/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java b/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java
index 9df6241..34d69e9 100644
--- a/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java
+++ b/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java
@@ -230,7 +230,7 @@
}
@Override
- public void onDragStart(boolean start) {
+ public void onDragStart(boolean start, float startDisplacement) {
mStartState = mLauncher.getStateManager().getState();
mIsLogContainerSet = false;
if (mCurrentAnimation == null) {
diff --git a/src/com/android/launcher3/touch/BaseSwipeDetector.java b/src/com/android/launcher3/touch/BaseSwipeDetector.java
index 30283da..1276ece 100644
--- a/src/com/android/launcher3/touch/BaseSwipeDetector.java
+++ b/src/com/android/launcher3/touch/BaseSwipeDetector.java
@@ -236,7 +236,7 @@
} else {
mSubtractDisplacement.x = mDisplacement.x > 0 ? mTouchSlop : -mTouchSlop;
mSubtractDisplacement.y = mDisplacement.y > 0 ? mTouchSlop : -mTouchSlop;
- }
+ }
}
protected abstract boolean shouldScrollStart(PointF displacement);
diff --git a/src/com/android/launcher3/touch/LandscapePagedViewHandler.java b/src/com/android/launcher3/touch/LandscapePagedViewHandler.java
new file mode 100644
index 0000000..1db65b9
--- /dev/null
+++ b/src/com/android/launcher3/touch/LandscapePagedViewHandler.java
@@ -0,0 +1,253 @@
+/*
+ * Copyright (C) 2019 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.launcher3.touch;
+
+import android.content.res.Resources;
+import android.graphics.Matrix;
+import android.graphics.PointF;
+import android.graphics.Rect;
+import android.graphics.RectF;
+import android.util.FloatProperty;
+import android.view.MotionEvent;
+import android.view.Surface;
+import android.view.VelocityTracker;
+import android.view.View;
+import android.view.accessibility.AccessibilityEvent;
+
+import com.android.launcher3.DeviceProfile;
+import com.android.launcher3.LauncherState.ScaleAndTranslation;
+import com.android.launcher3.PagedView;
+import com.android.launcher3.Utilities;
+import com.android.launcher3.states.RotationHelper;
+import com.android.launcher3.util.OverScroller;
+
+import static com.android.launcher3.LauncherAnimUtils.VIEW_TRANSLATE_X;
+import static com.android.launcher3.LauncherAnimUtils.VIEW_TRANSLATE_Y;
+import static com.android.launcher3.touch.SingleAxisSwipeDetector.HORIZONTAL;
+
+public class LandscapePagedViewHandler implements PagedOrientationHandler {
+
+ @Override
+ public int getPrimaryValue(int x, int y) {
+ return y;
+ }
+
+ @Override
+ public int getSecondaryValue(int x, int y) {
+ return x;
+ }
+
+ @Override
+ public void delegateScrollTo(PagedView pagedView, int secondaryScroll, int minMaxScroll) {
+ pagedView.superScrollTo(secondaryScroll, minMaxScroll);
+ }
+
+ @Override
+ public void delegateScrollBy(PagedView pagedView, int unboundedScroll, int x, int y) {
+ pagedView.scrollTo(pagedView.getScrollX() + x, unboundedScroll + y);
+ }
+
+ @Override
+ public void scrollerStartScroll(OverScroller scroller, int newPosition) {
+ scroller.startScroll(scroller.getCurrPos(), newPosition - scroller.getCurrPos());
+ }
+
+ @Override
+ public CurveProperties getCurveProperties(PagedView pagedView, Rect mInsets) {
+ int scroll = pagedView.getScrollY();
+ final int halfPageSize = pagedView.getNormalChildHeight() / 2;
+ final int screenCenter = mInsets.top + pagedView.getPaddingTop() + scroll + halfPageSize;
+ final int halfScreenSize = pagedView.getMeasuredHeight() / 2;
+ return new CurveProperties(scroll, halfPageSize, screenCenter, halfScreenSize);
+ }
+
+ @Override
+ public boolean isGoingUp(float displacement) {
+ return displacement > 0;
+ }
+
+ @Override
+ public void adjustFloatingIconStartVelocity(PointF velocity) {
+ float oldX = velocity.x;
+ float oldY = velocity.y;
+ velocity.set(-oldY, oldX);
+ }
+
+ @Override
+ public void delegateScrollTo(PagedView pagedView, int primaryScroll) {
+ pagedView.superScrollTo(pagedView.getScrollX(), primaryScroll);
+ }
+
+ @Override
+ public <T> void set(T target, Int2DAction<T> action, int param) {
+ action.call(target, 0, param);
+ }
+
+ @Override
+ public <T> void set(T target, Float2DAction<T> action, float param) {
+ action.call(target, 0, param);
+ }
+
+ @Override
+ public float getPrimaryDirection(MotionEvent event, int pointerIndex) {
+ return event.getY(pointerIndex);
+ }
+
+ @Override
+ public float getPrimaryVelocity(VelocityTracker velocityTracker, int pointerId) {
+ return velocityTracker.getYVelocity(pointerId);
+ }
+
+ @Override
+ public int getMeasuredSize(View view) {
+ return view.getMeasuredHeight();
+ }
+
+ @Override
+ public int getPrimarySize(Rect rect) {
+ return rect.height();
+ }
+
+ @Override
+ public float getPrimarySize(RectF rect) {
+ return rect.height();
+ }
+
+ @Override
+ public int getSecondaryDimension(View view) {
+ return view.getWidth();
+ }
+
+ @Override
+ public ScaleAndTranslation getScaleAndTranslation(DeviceProfile dp, View view) {
+ float offscreenTranslationY = dp.heightPx - view.getPaddingTop();
+ return new ScaleAndTranslation(1f, 0f, offscreenTranslationY);
+ }
+
+ @Override
+ public float getTranslationValue(ScaleAndTranslation scaleAndTranslation) {
+ return scaleAndTranslation.translationY;
+ }
+
+ @Override
+ public FloatProperty<View> getPrimaryViewTranslate() {
+ return VIEW_TRANSLATE_Y;
+ }
+
+ @Override
+ public FloatProperty<View> getSecondaryViewTranslate() {
+ return VIEW_TRANSLATE_X;
+ }
+
+ @Override
+ public void setPrimaryAndResetSecondaryTranslate(View view, float translation) {
+ view.setTranslationX(0);
+ view.setTranslationY(translation);
+ }
+
+ @Override
+ public float getViewCenterPosition(View view) {
+ return view.getTop() + view.getTranslationY();
+ }
+
+ @Override
+ public int getPrimaryScroll(View view) {
+ return view.getScrollY();
+ }
+
+ @Override
+ public float getPrimaryScale(View view) {
+ return view.getScaleY();
+ }
+
+ @Override
+ public void setMaxScroll(AccessibilityEvent event, int maxScroll) {
+ event.setMaxScrollY(maxScroll);
+ }
+
+ @Override
+ public boolean getRecentsRtlSetting(Resources resources) {
+ return !Utilities.isRtl(resources);
+ }
+
+ @Override
+ public float getDegreesRotated() {
+ return 90;
+ }
+
+ @Override
+ public void offsetTaskRect(RectF rect, float value, int displayRotation) {
+ if (displayRotation == Surface.ROTATION_0) {
+ rect.offset(0, value);
+ } else if (displayRotation == Surface.ROTATION_90) {
+ rect.offset(value, 0);
+ } else if (displayRotation == Surface.ROTATION_180) {
+ rect.offset(0, -value);
+ } else {
+ rect.offset(-value, 0);
+ }
+ }
+
+ @Override
+ public int getChildStart(View view) {
+ return view.getTop();
+ }
+
+ @Override
+ public int getCenterForPage(View view, Rect insets) {
+ return (view.getPaddingLeft() + view.getMeasuredWidth() + insets.left
+ - insets.right - view.getPaddingRight()) / 2;
+ }
+
+ @Override
+ public int getScrollOffsetStart(View view, Rect insets) {
+ return insets.top + view.getPaddingTop();
+ }
+
+ @Override
+ public int getScrollOffsetEnd(View view, Rect insets) {
+ return view.getHeight() - view.getPaddingBottom() - insets.bottom;
+ }
+
+ @Override
+ public SingleAxisSwipeDetector.Direction getOppositeSwipeDirection() {
+ return HORIZONTAL;
+ }
+
+ @Override
+ public int getShortEdgeLength(DeviceProfile dp) {
+ return dp.heightPx;
+ }
+
+ @Override
+ public int getTaskDismissDirectionFactor() {
+ return 1;
+ }
+
+ @Override
+ public ChildBounds getChildBounds(View child, int childStart, int pageCenter,
+ boolean layoutChild) {
+ final int childHeight = child.getMeasuredHeight();
+ final int childBottom = childStart + childHeight;
+ final int childWidth = child.getMeasuredWidth();
+ final int childLeft = pageCenter - childWidth/ 2;
+ if (layoutChild) {
+ child.layout(childLeft, childStart, childLeft + childWidth, childBottom);
+ }
+ return new ChildBounds(childHeight, childWidth, childBottom, childLeft);
+ }
+}
diff --git a/src/com/android/launcher3/touch/PagedOrientationHandler.java b/src/com/android/launcher3/touch/PagedOrientationHandler.java
new file mode 100644
index 0000000..b4802cd
--- /dev/null
+++ b/src/com/android/launcher3/touch/PagedOrientationHandler.java
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2020 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.launcher3.touch;
+
+import android.content.res.Resources;
+import android.graphics.Canvas;
+import android.graphics.PointF;
+import android.graphics.Rect;
+import android.graphics.RectF;
+import android.util.FloatProperty;
+import android.view.MotionEvent;
+import android.view.VelocityTracker;
+import android.view.View;
+import android.view.accessibility.AccessibilityEvent;
+
+import com.android.launcher3.DeviceProfile;
+import com.android.launcher3.LauncherState;
+import com.android.launcher3.PagedView;
+import com.android.launcher3.util.OverScroller;
+
+/**
+ * Abstraction layer to separate horizontal and vertical specific implementations
+ * for {@link com.android.launcher3.PagedView}. Majority of these implementations are (should be) as
+ * simple as choosing the correct X and Y analogous methods.
+ */
+public interface PagedOrientationHandler {
+
+ interface Int2DAction<T> {
+ void call(T target, int x, int y);
+ }
+ interface Float2DAction<T> {
+ void call(T target, float x, float y);
+ }
+ Int2DAction<View> VIEW_SCROLL_BY = View::scrollBy;
+ Int2DAction<View> VIEW_SCROLL_TO = View::scrollTo;
+ Float2DAction<Canvas> CANVAS_TRANSLATE = Canvas::translate;
+ <T> void set(T target, Int2DAction<T> action, int param);
+ <T> void set(T target, Float2DAction<T> action, float param);
+ float getPrimaryDirection(MotionEvent event, int pointerIndex);
+ float getPrimaryVelocity(VelocityTracker velocityTracker, int pointerId);
+ int getMeasuredSize(View view);
+ int getPrimarySize(Rect rect);
+ float getPrimarySize(RectF rect);
+ int getSecondaryDimension(View view);
+ LauncherState.ScaleAndTranslation getScaleAndTranslation(DeviceProfile dp, View view);
+ float getTranslationValue(LauncherState.ScaleAndTranslation scaleAndTranslation);
+ FloatProperty<View> getPrimaryViewTranslate();
+ FloatProperty<View> getSecondaryViewTranslate();
+ void setPrimaryAndResetSecondaryTranslate(View view, float translation);
+ float getViewCenterPosition(View view);
+ int getPrimaryScroll(View view);
+ float getPrimaryScale(View view);
+ int getChildStart(View view);
+ int getCenterForPage(View view, Rect insets);
+ int getScrollOffsetStart(View view, Rect insets);
+ int getScrollOffsetEnd(View view, Rect insets);
+ SingleAxisSwipeDetector.Direction getOppositeSwipeDirection();
+ int getShortEdgeLength(DeviceProfile dp);
+ int getTaskDismissDirectionFactor();
+ ChildBounds getChildBounds(View child, int childStart, int pageCenter, boolean layoutChild);
+ void setMaxScroll(AccessibilityEvent event, int maxScroll);
+ boolean getRecentsRtlSetting(Resources resources);
+ float getDegreesRotated();
+ void offsetTaskRect(RectF rect, float value, int delta);
+ int getPrimaryValue(int x, int y);
+ int getSecondaryValue(int x, int y);
+ void delegateScrollTo(PagedView pagedView, int secondaryScroll, int primaryScroll);
+ /** Uses {@params pagedView}.getScroll[X|Y]() method for the secondary amount*/
+ void delegateScrollTo(PagedView pagedView, int primaryScroll);
+ void delegateScrollBy(PagedView pagedView, int unboundedScroll, int x, int y);
+ void scrollerStartScroll(OverScroller scroller, int newPosition);
+ CurveProperties getCurveProperties(PagedView pagedView, Rect insets);
+ boolean isGoingUp(float displacement);
+
+ /**
+ * Maps the velocity from the coordinate plane of the foreground app to that
+ * of Launcher's (which now will always be portrait)
+ */
+ void adjustFloatingIconStartVelocity(PointF velocity);
+
+ class CurveProperties {
+ public final int scroll;
+ public final int halfPageSize;
+ public final int screenCenter;
+ public final int halfScreenSize;
+
+ public CurveProperties(int scroll, int halfPageSize, int screenCenter, int halfScreenSize) {
+ this.scroll = scroll;
+ this.halfPageSize = halfPageSize;
+ this.screenCenter = screenCenter;
+ this.halfScreenSize = halfScreenSize;
+ }
+ }
+
+ class ChildBounds {
+
+ public final int primaryDimension;
+ public final int secondaryDimension;
+ public final int childPrimaryEnd;
+ public final int childSecondaryEnd;
+
+ ChildBounds(int primaryDimension, int secondaryDimension, int childPrimaryEnd,
+ int childSecondaryEnd) {
+ this.primaryDimension = primaryDimension;
+ this.secondaryDimension = secondaryDimension;
+ this.childPrimaryEnd = childPrimaryEnd;
+ this.childSecondaryEnd = childSecondaryEnd;
+ }
+ }
+}
diff --git a/src/com/android/launcher3/touch/PortraitPagedViewHandler.java b/src/com/android/launcher3/touch/PortraitPagedViewHandler.java
new file mode 100644
index 0000000..22eee49
--- /dev/null
+++ b/src/com/android/launcher3/touch/PortraitPagedViewHandler.java
@@ -0,0 +1,251 @@
+/*
+ * Copyright (C) 2019 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.launcher3.touch;
+
+import android.content.res.Resources;
+import android.graphics.Matrix;
+import android.graphics.PointF;
+import android.graphics.Rect;
+import android.graphics.RectF;
+import android.util.FloatProperty;
+import android.view.MotionEvent;
+import android.view.Surface;
+import android.view.VelocityTracker;
+import android.view.View;
+import android.view.accessibility.AccessibilityEvent;
+
+import com.android.launcher3.DeviceProfile;
+import com.android.launcher3.LauncherState.ScaleAndTranslation;
+import com.android.launcher3.PagedView;
+import com.android.launcher3.Utilities;
+import com.android.launcher3.states.RotationHelper;
+import com.android.launcher3.util.OverScroller;
+
+import static com.android.launcher3.LauncherAnimUtils.VIEW_TRANSLATE_X;
+import static com.android.launcher3.LauncherAnimUtils.VIEW_TRANSLATE_Y;
+import static com.android.launcher3.touch.SingleAxisSwipeDetector.VERTICAL;
+
+public class PortraitPagedViewHandler implements PagedOrientationHandler {
+
+ @Override
+ public int getPrimaryValue(int x, int y) {
+ return x;
+ }
+
+ @Override
+ public int getSecondaryValue(int x, int y) {
+ return y;
+ }
+
+ @Override
+ public void delegateScrollTo(PagedView pagedView, int secondaryScroll, int primaryScroll) {
+ pagedView.superScrollTo(primaryScroll, secondaryScroll);
+ }
+
+ @Override
+ public void delegateScrollBy(PagedView pagedView, int unboundedScroll, int x, int y) {
+ pagedView.scrollTo(unboundedScroll + x, pagedView.getScrollY() + y);
+ }
+
+ @Override
+ public void scrollerStartScroll(OverScroller scroller, int newPosition) {
+ scroller.startScroll(newPosition - scroller.getCurrPos(), scroller.getCurrPos());
+ }
+
+ @Override
+ public CurveProperties getCurveProperties(PagedView pagedView, Rect mInsets) {
+ int scroll = pagedView.getScrollX();
+ final int halfPageSize = pagedView.getNormalChildWidth() / 2;
+ final int screenCenter = mInsets.left + pagedView.getPaddingLeft() + scroll + halfPageSize;
+ final int halfScreenSize = pagedView.getMeasuredWidth() / 2;
+ return new CurveProperties(scroll, halfPageSize, screenCenter, halfScreenSize);
+ }
+
+ @Override
+ public boolean isGoingUp(float displacement) {
+ return displacement < 0;
+ }
+
+ @Override
+ public void adjustFloatingIconStartVelocity(PointF velocity) {
+ //no-op
+ }
+
+ @Override
+ public void delegateScrollTo(PagedView pagedView, int primaryScroll) {
+ pagedView.superScrollTo(primaryScroll, pagedView.getScrollY());
+ }
+
+ @Override
+ public <T> void set(T target, Int2DAction<T> action, int param) {
+ action.call(target, param, 0);
+ }
+
+ @Override
+ public <T> void set(T target, Float2DAction<T> action, float param) {
+ action.call(target, param, 0);
+ }
+
+ @Override
+ public float getPrimaryDirection(MotionEvent event, int pointerIndex) {
+ return event.getX(pointerIndex);
+ }
+
+ @Override
+ public float getPrimaryVelocity(VelocityTracker velocityTracker, int pointerId) {
+ return velocityTracker.getXVelocity(pointerId);
+ }
+
+ @Override
+ public int getMeasuredSize(View view) {
+ return view.getMeasuredWidth();
+ }
+
+ @Override
+ public int getPrimarySize(Rect rect) {
+ return rect.width();
+ }
+
+ @Override
+ public float getPrimarySize(RectF rect) {
+ return rect.width();
+ }
+
+ @Override
+ public int getSecondaryDimension(View view) {
+ return view.getHeight();
+ }
+
+ @Override
+ public ScaleAndTranslation getScaleAndTranslation(DeviceProfile dp, View view) {
+ float offscreenTranslationX = dp.widthPx - view.getPaddingStart();
+ return new ScaleAndTranslation(1f, offscreenTranslationX, 0f);
+ }
+
+ @Override
+ public float getTranslationValue(ScaleAndTranslation scaleAndTranslation) {
+ return scaleAndTranslation.translationX;
+ }
+
+ @Override
+ public FloatProperty<View> getPrimaryViewTranslate() {
+ return VIEW_TRANSLATE_X;
+ }
+
+ @Override
+ public FloatProperty<View> getSecondaryViewTranslate() {
+ return VIEW_TRANSLATE_Y;
+ }
+
+ @Override
+ public void setPrimaryAndResetSecondaryTranslate(View view, float translation) {
+ view.setTranslationX(translation);
+ view.setTranslationY(0);
+ }
+
+ @Override
+ public float getViewCenterPosition(View view) {
+ return view.getLeft() + view.getTranslationX();
+ }
+
+ @Override
+ public int getPrimaryScroll(View view) {
+ return view.getScrollX();
+ }
+
+ @Override
+ public float getPrimaryScale(View view) {
+ return view.getScaleX();
+ }
+
+ @Override
+ public void setMaxScroll(AccessibilityEvent event, int maxScroll) {
+ event.setMaxScrollX(maxScroll);
+ }
+
+ @Override
+ public boolean getRecentsRtlSetting(Resources resources) {
+ return !Utilities.isRtl(resources);
+ }
+
+ @Override
+ public float getDegreesRotated() {
+ return 0;
+ }
+
+ @Override
+ public void offsetTaskRect(RectF rect, float value, int displayRotation) {
+ if (displayRotation == Surface.ROTATION_0) {
+ rect.offset(value, 0);
+ } else if (displayRotation == Surface.ROTATION_90) {
+ rect.offset(0, -value);
+ } else if (displayRotation == Surface.ROTATION_180) {
+ rect.offset(-value, 0);
+ } else {
+ rect.offset(0, value);
+ }
+ }
+
+ @Override
+ public int getChildStart(View view) {
+ return view.getLeft();
+ }
+
+ @Override
+ public int getCenterForPage(View view, Rect insets) {
+ return (view.getPaddingTop() + view.getMeasuredHeight() + insets.top
+ - insets.bottom - view.getPaddingBottom()) / 2;
+ }
+
+ @Override
+ public int getScrollOffsetStart(View view, Rect insets) {
+ return insets.left + view.getPaddingLeft();
+ }
+
+ @Override
+ public int getScrollOffsetEnd(View view, Rect insets) {
+ return view.getWidth() - view.getPaddingRight() - insets.right;
+ }
+
+ @Override
+ public SingleAxisSwipeDetector.Direction getOppositeSwipeDirection() {
+ return VERTICAL;
+ }
+
+ @Override
+ public int getShortEdgeLength(DeviceProfile dp) {
+ return dp.widthPx;
+ }
+
+ @Override
+ public int getTaskDismissDirectionFactor() {
+ return -1;
+ }
+
+ @Override
+ public ChildBounds getChildBounds(View child, int childStart, int pageCenter,
+ boolean layoutChild) {
+ final int childWidth = child.getMeasuredWidth();
+ final int childRight = childStart + childWidth;
+ final int childHeight = child.getMeasuredHeight();
+ final int childTop = pageCenter - childHeight / 2;
+ if (layoutChild) {
+ child.layout(childStart, childTop, childRight, childTop + childHeight);
+ }
+ return new ChildBounds(childWidth, childHeight, childRight, childTop);
+ }
+}
diff --git a/src/com/android/launcher3/touch/SeascapePagedViewHandler.java b/src/com/android/launcher3/touch/SeascapePagedViewHandler.java
new file mode 100644
index 0000000..eebd87f
--- /dev/null
+++ b/src/com/android/launcher3/touch/SeascapePagedViewHandler.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2019 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.launcher3.touch;
+
+import android.content.res.Resources;
+import android.graphics.PointF;
+import android.graphics.RectF;
+import android.view.Surface;
+
+import com.android.launcher3.Utilities;
+
+public class SeascapePagedViewHandler extends LandscapePagedViewHandler {
+
+ @Override
+ public int getTaskDismissDirectionFactor() {
+ return -1;
+ }
+
+ @Override
+ public boolean getRecentsRtlSetting(Resources resources) {
+ return Utilities.isRtl(resources);
+ }
+
+ @Override
+ public void offsetTaskRect(RectF rect, float value, int displayRotation) {
+ if (displayRotation == Surface.ROTATION_0) {
+ rect.offset(0, value);
+ } else if (displayRotation == Surface.ROTATION_90) {
+ rect.offset(value, 0);
+ } else if (displayRotation == Surface.ROTATION_180) {
+ rect.offset(0, -value);
+ } else {
+ rect.offset(-value, 0);
+ }
+ }
+
+ @Override
+ public float getDegreesRotated() {
+ return 270;
+ }
+
+ @Override
+ public boolean isGoingUp(float displacement) {
+ return displacement < 0;
+ }
+
+ @Override
+ public void adjustFloatingIconStartVelocity(PointF velocity) {
+ float oldX = velocity.x;
+ float oldY = velocity.y;
+ velocity.set(oldY, -oldX);
+ }
+}
diff --git a/src/com/android/launcher3/touch/SingleAxisSwipeDetector.java b/src/com/android/launcher3/touch/SingleAxisSwipeDetector.java
index 9d406f3..d725486 100644
--- a/src/com/android/launcher3/touch/SingleAxisSwipeDetector.java
+++ b/src/com/android/launcher3/touch/SingleAxisSwipeDetector.java
@@ -148,7 +148,8 @@
@Override
protected void reportDragStartInternal(boolean recatch) {
- mListener.onDragStart(!recatch);
+ float startDisplacement = mDir.extractDirection(mSubtractDisplacement);
+ mListener.onDragStart(!recatch, startDisplacement);
}
@Override
@@ -165,8 +166,13 @@
/** Listener to receive updates on the swipe. */
public interface Listener {
- /** @param start whether this was the original drag start, as opposed to a recatch. */
- void onDragStart(boolean start);
+ /**
+ * TODO(b/150256055) consolidate all the different onDrag() methods into one
+ * @param start whether this was the original drag start, as opposed to a recatch.
+ * @param startDisplacement the initial touch displacement for the primary direction as
+ * given by by {@link Direction#extractDirection(PointF)}
+ */
+ void onDragStart(boolean start, float startDisplacement);
boolean onDrag(float displacement);
diff --git a/src/com/android/launcher3/util/DefaultDisplay.java b/src/com/android/launcher3/util/DefaultDisplay.java
index d3dac04..f18e411 100644
--- a/src/com/android/launcher3/util/DefaultDisplay.java
+++ b/src/com/android/launcher3/util/DefaultDisplay.java
@@ -28,6 +28,8 @@
import android.view.Display;
import android.view.WindowManager;
+import androidx.annotation.VisibleForTesting;
+
import java.util.ArrayList;
/**
@@ -127,6 +129,18 @@
public final DisplayMetrics metrics;
+ @VisibleForTesting
+ public Info(int id, int rotation, int singleFrameMs, Point realSize, Point smallestSize,
+ Point largestSize, DisplayMetrics metrics) {
+ this.id = id;
+ this.rotation = rotation;
+ this.singleFrameMs = singleFrameMs;
+ this.realSize = realSize;
+ this.smallestSize = smallestSize;
+ this.largestSize = largestSize;
+ this.metrics = metrics;
+ }
+
private Info(Context context) {
this(context.getSystemService(WindowManager.class).getDefaultDisplay());
}
diff --git a/src/com/android/launcher3/util/DynamicResource.java b/src/com/android/launcher3/util/DynamicResource.java
index 8a75767..e6ee186 100644
--- a/src/com/android/launcher3/util/DynamicResource.java
+++ b/src/com/android/launcher3/util/DynamicResource.java
@@ -69,6 +69,11 @@
}
@Override
+ public float getFloat(@DimenRes int resId) {
+ return mContext.getResources().getFloat(resId);
+ }
+
+ @Override
public void onPluginConnected(ResourceProvider plugin, Context context) {
mPlugin = plugin;
}
diff --git a/src/com/android/launcher3/util/OverScroller.java b/src/com/android/launcher3/util/OverScroller.java
index fc8a138..3c398b8 100644
--- a/src/com/android/launcher3/util/OverScroller.java
+++ b/src/com/android/launcher3/util/OverScroller.java
@@ -26,11 +26,13 @@
import android.view.animation.AnimationUtils;
import android.view.animation.Interpolator;
-import androidx.dynamicanimation.animation.DynamicAnimation;
import androidx.dynamicanimation.animation.FloatPropertyCompat;
import androidx.dynamicanimation.animation.SpringAnimation;
import androidx.dynamicanimation.animation.SpringForce;
+import com.android.launcher3.R;
+import com.android.systemui.plugins.ResourceProvider;
+
/**
* Based on {@link android.widget.OverScroller} supporting only 1-d scrolling and with more
* customization options.
@@ -425,6 +427,7 @@
// Current state of the animation.
private int mState = SPLINE;
+ private Context mContext;
private SpringAnimation mSpring;
// Constant gravity value, used in the deceleration phase.
@@ -500,6 +503,7 @@
}
SplineOverScroller(Context context) {
+ mContext = context;
mFinished = true;
final float ppi = context.getResources().getDisplayMetrics().density * 160.0f;
mPhysicalCoeff = SensorManager.GRAVITY_EARTH // g (m/s^2)
@@ -560,9 +564,12 @@
}
mSpring = new SpringAnimation(this, SPRING_PROPERTY);
+ ResourceProvider rp = DynamicResource.provider(mContext);
+ float stiffness = rp.getFloat(R.dimen.horizontal_spring_stiffness);
+ float damping = rp.getFloat(R.dimen.horizontal_spring_damping_ratio);
mSpring.setSpring(new SpringForce(mFinal)
- .setStiffness(SpringForce.STIFFNESS_LOW)
- .setDampingRatio(SpringForce.DAMPING_RATIO_LOW_BOUNCY));
+ .setStiffness(stiffness)
+ .setDampingRatio(damping));
mSpring.setStartVelocity(velocity);
mSpring.animateToFinalPosition(mFinal);
mSpring.addEndListener((animation, canceled, value, velocity1) -> {
diff --git a/src/com/android/launcher3/views/AbstractSlideInView.java b/src/com/android/launcher3/views/AbstractSlideInView.java
index bdba39c..11c1029 100644
--- a/src/com/android/launcher3/views/AbstractSlideInView.java
+++ b/src/com/android/launcher3/views/AbstractSlideInView.java
@@ -149,8 +149,7 @@
/* SingleAxisSwipeDetector.Listener */
@Override
- public void onDragStart(boolean start) {
- }
+ public void onDragStart(boolean start, float startDisplacement) { }
@Override
public boolean onDrag(float displacement) {
diff --git a/src_plugins/com/android/systemui/plugins/ResourceProvider.java b/src_plugins/com/android/systemui/plugins/ResourceProvider.java
index eaed9e7..d1767a0 100644
--- a/src_plugins/com/android/systemui/plugins/ResourceProvider.java
+++ b/src_plugins/com/android/systemui/plugins/ResourceProvider.java
@@ -44,4 +44,9 @@
* @see android.content.res.Resources#getColor(int)
*/
int getColor(int resId);
+
+ /**
+ * @see android.content.res.Resources#getFloat(int)
+ */
+ float getFloat(int resId);
}
diff --git a/tests/src/com/android/launcher3/touch/SingleAxisSwipeDetectorTest.java b/tests/src/com/android/launcher3/touch/SingleAxisSwipeDetectorTest.java
index b0ece77..472e1a1 100644
--- a/tests/src/com/android/launcher3/touch/SingleAxisSwipeDetectorTest.java
+++ b/tests/src/com/android/launcher3/touch/SingleAxisSwipeDetectorTest.java
@@ -89,7 +89,7 @@
mGenerator.put(0, 100, 100);
mGenerator.move(0, 100, 100 - mTouchSlop);
// TODO: actually calculate the following parameters and do exact value checks.
- verify(mMockListener).onDragStart(anyBoolean());
+ verify(mMockListener).onDragStart(anyBoolean(), anyFloat());
}
@Test
@@ -99,7 +99,7 @@
mGenerator.put(0, 100, 100);
mGenerator.move(0, 100, 100 + mTouchSlop);
// TODO: actually calculate the following parameters and do exact value checks.
- verify(mMockListener).onDragStart(anyBoolean());
+ verify(mMockListener).onDragStart(anyBoolean(), anyFloat());
}
@Test
@@ -107,7 +107,7 @@
mGenerator.put(0, 100, 100);
mGenerator.move(0, 100 + mTouchSlop, 100);
// TODO: actually calculate the following parameters and do exact value checks.
- verify(mMockListener, never()).onDragStart(anyBoolean());
+ verify(mMockListener, never()).onDragStart(anyBoolean(), anyFloat());
}
@Test
@@ -118,7 +118,7 @@
mGenerator.put(0, 100, 100);
mGenerator.move(0, 100 + mTouchSlop, 100);
// TODO: actually calculate the following parameters and do exact value checks.
- verify(mMockListener).onDragStart(anyBoolean());
+ verify(mMockListener).onDragStart(anyBoolean(), anyFloat());
}
@Test
@@ -129,7 +129,7 @@
mGenerator.put(0, 100, 100);
mGenerator.move(0, 100 - mTouchSlop, 100);
// TODO: actually calculate the following parameters and do exact value checks.
- verify(mMockListener).onDragStart(anyBoolean());
+ verify(mMockListener).onDragStart(anyBoolean(), anyFloat());
}
@Test
@@ -140,7 +140,7 @@
mGenerator.put(0, 100, 100);
mGenerator.move(0, 100 - mTouchSlop, 100);
// TODO: actually calculate the following parameters and do exact value checks.
- verify(mMockListener).onDragStart(anyBoolean());
+ verify(mMockListener).onDragStart(anyBoolean(), anyFloat());
}
@Test
@@ -151,7 +151,7 @@
mGenerator.put(0, 100, 100);
mGenerator.move(0, 100 + mTouchSlop, 100);
// TODO: actually calculate the following parameters and do exact value checks.
- verify(mMockListener).onDragStart(anyBoolean());
+ verify(mMockListener).onDragStart(anyBoolean(), anyFloat());
}
@Test
diff --git a/tests/src/com/android/launcher3/util/rule/SimpleActivityRule.java b/tests/src/com/android/launcher3/util/rule/SimpleActivityRule.java
index 33a6cf9..1dbba6a 100644
--- a/tests/src/com/android/launcher3/util/rule/SimpleActivityRule.java
+++ b/tests/src/com/android/launcher3/util/rule/SimpleActivityRule.java
@@ -64,6 +64,7 @@
mBase.evaluate();
} finally {
app.unregisterActivityLifecycleCallbacks(this);
+ mActivity = null;
}
}