diff options
9 files changed, 220 insertions, 60 deletions
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 673beff85..21ddfc015 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 @@ -15,74 +15,131 @@ */ package com.android.launcher3.uioverrides.touchcontrollers; +import static android.view.View.TRANSLATION_X; + +import static com.android.launcher3.AbstractFloatingView.TYPE_ALL; +import static com.android.launcher3.AbstractFloatingView.TYPE_HIDE_BACK_BUTTON; import static com.android.launcher3.LauncherState.ALL_APPS; import static com.android.launcher3.LauncherState.NORMAL; import static com.android.launcher3.LauncherState.OVERVIEW; import static com.android.launcher3.allapps.AllAppsTransitionController.ALL_APPS_PROGRESS; import static com.android.launcher3.anim.Interpolators.DEACCEL_3; +import static com.android.launcher3.touch.AbstractStateChangeTouchController.SUCCESS_TRANSITION_PROGRESS; import android.animation.Animator; import android.animation.AnimatorSet; import android.animation.ObjectAnimator; +import android.animation.ValueAnimator; import android.view.MotionEvent; -import android.view.View; import android.view.animation.Interpolator; +import com.android.launcher3.AbstractFloatingView; import com.android.launcher3.Launcher; import com.android.launcher3.LauncherState; import com.android.launcher3.LauncherStateManager.AnimationConfig; +import com.android.launcher3.R; import com.android.launcher3.Utilities; import com.android.launcher3.allapps.AllAppsTransitionController; +import com.android.launcher3.anim.AnimationSuccessListener; import com.android.launcher3.anim.AnimatorPlaybackController; import com.android.launcher3.anim.AnimatorSetBuilder; import com.android.launcher3.anim.Interpolators; -import com.android.launcher3.touch.AbstractStateChangeTouchController; import com.android.launcher3.touch.SwipeDetector; import com.android.launcher3.userevent.nano.LauncherLogProto; +import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Command; import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch; +import com.android.launcher3.util.TouchController; import com.android.quickstep.views.RecentsView; /** - * Handles swiping up on the nav bar to go home from overview or all apps. + * Handles swiping up on the nav bar to go home from launcher, e.g. overview or all apps. */ -public class NavBarToHomeTouchController extends AbstractStateChangeTouchController { +public class NavBarToHomeTouchController implements TouchController, SwipeDetector.Listener { private static final Interpolator PULLBACK_INTERPOLATOR = DEACCEL_3; + private final Launcher mLauncher; + private final SwipeDetector mSwipeDetector; + private final float mPullbackDistance; + + private boolean mNoIntercept; + private LauncherState mStartState; + private LauncherState mEndState = NORMAL; + private AnimatorPlaybackController mCurrentAnimation; + public NavBarToHomeTouchController(Launcher launcher) { - super(launcher, SwipeDetector.VERTICAL); + mLauncher = launcher; + mSwipeDetector = new SwipeDetector(mLauncher, this, SwipeDetector.VERTICAL); + mPullbackDistance = mLauncher.getResources().getDimension(R.dimen.home_pullback_distance); } @Override - protected boolean canInterceptTouch(MotionEvent ev) { + public final boolean onControllerInterceptTouchEvent(MotionEvent ev) { + if (ev.getAction() == MotionEvent.ACTION_DOWN) { + mStartState = mLauncher.getStateManager().getState(); + mNoIntercept = !canInterceptTouch(ev); + if (mNoIntercept) { + return false; + } + mSwipeDetector.setDetectableScrollConditions(SwipeDetector.DIRECTION_POSITIVE, false); + } + + if (mNoIntercept) { + return false; + } + + onControllerTouchEvent(ev); + return mSwipeDetector.isDraggingOrSettling(); + } + + private boolean canInterceptTouch(MotionEvent ev) { boolean cameFromNavBar = (ev.getEdgeFlags() & Utilities.EDGE_NAV_BAR) != 0; - return cameFromNavBar && (mLauncher.isInState(OVERVIEW) || mLauncher.isInState(ALL_APPS)); + if (!cameFromNavBar) { + return false; + } + if (mStartState == OVERVIEW || mStartState == ALL_APPS) { + return true; + } + if (!mLauncher.hasWindowFocus()) { + return true; + } + if (AbstractFloatingView.getTopOpenView(mLauncher) != null) { + return true; + } + return false; } @Override - protected LauncherState getTargetState(LauncherState fromState, boolean isDragTowardPositive) { - return isDragTowardPositive ? NORMAL : fromState; + public final boolean onControllerTouchEvent(MotionEvent ev) { + return mSwipeDetector.onTouchEvent(ev); + } + + private float getShiftRange() { + return mLauncher.getDeviceProfile().heightPx; } @Override - protected float initCurrentAnimation(int animComponents) { + public void onDragStart(boolean start) { + initCurrentAnimation(); + } + + private void initCurrentAnimation() { long accuracy = (long) (getShiftRange() * 2); - final AnimatorSet anim; - if (mFromState == OVERVIEW) { - anim = new AnimatorSet(); + final AnimatorSet anim = new AnimatorSet(); + if (mStartState == OVERVIEW) { RecentsView recentsView = mLauncher.getOverviewPanel(); - float pullbackDistance = recentsView.getPaddingStart() / 2; + float pullbackDist = mPullbackDistance; if (!recentsView.isRtl()) { - pullbackDistance = -pullbackDistance; + pullbackDist = -pullbackDist; } - anim.play(ObjectAnimator.ofFloat(recentsView, View.TRANSLATION_X, pullbackDistance)); - anim.setInterpolator(PULLBACK_INTERPOLATOR); - } else { // if (mFromState == ALL_APPS) + Animator pullback = ObjectAnimator.ofFloat(recentsView, TRANSLATION_X, pullbackDist); + pullback.setInterpolator(PULLBACK_INTERPOLATOR); + anim.play(pullback); + } else if (mStartState == ALL_APPS) { AnimatorSetBuilder builder = new AnimatorSetBuilder(); AllAppsTransitionController allAppsController = mLauncher.getAllAppsController(); - final float pullbackDistance = mLauncher.getDeviceProfile().allAppsIconSizePx / 2; Animator allAppsProgress = ObjectAnimator.ofFloat(allAppsController, ALL_APPS_PROGRESS, - -pullbackDistance / allAppsController.getShiftRange()); + -mPullbackDistance / allAppsController.getShiftRange()); allAppsProgress.setInterpolator(PULLBACK_INTERPOLATOR); builder.play(allAppsProgress); // Slightly fade out all apps content to further distinguish from scrolling. @@ -90,52 +147,79 @@ public class NavBarToHomeTouchController extends AbstractStateChangeTouchControl .mapToProgress(PULLBACK_INTERPOLATOR, 0, 0.5f)); AnimationConfig config = new AnimationConfig(); config.duration = accuracy; - allAppsController.setAlphas(mToState.getVisibleElements(mLauncher), config, builder); - anim = builder.build(); + allAppsController.setAlphas(mEndState.getVisibleElements(mLauncher), config, builder); + anim.play(builder.build()); + } + AbstractFloatingView topView = AbstractFloatingView.getTopOpenView(mLauncher); + if (topView != null) { + Animator hintCloseAnim = topView.createHintCloseAnim(mPullbackDistance); + if (hintCloseAnim != null) { + hintCloseAnim.setInterpolator(PULLBACK_INTERPOLATOR); + anim.play(hintCloseAnim); + } } anim.setDuration(accuracy); mCurrentAnimation = AnimatorPlaybackController.wrap(anim, accuracy, this::clearState); - return -1 / getShiftRange(); + } + + private void clearState() { + mCurrentAnimation = null; + mSwipeDetector.finishedScrolling(); + mSwipeDetector.setDetectableScrollConditions(0, false); } @Override - public void onDragStart(boolean start) { - super.onDragStart(start); - mStartContainerType = LauncherLogProto.ContainerType.NAVBAR; + public boolean onDrag(float displacement) { + // Only allow swipe up. + displacement = Math.min(0, displacement); + float progress = Utilities.getProgress(displacement, 0, getShiftRange()); + mCurrentAnimation.setPlayFraction(progress); + return true; } @Override public void onDragEnd(float velocity, boolean fling) { final int logAction = fling ? Touch.FLING : Touch.SWIPE; - float interpolatedProgress = PULLBACK_INTERPOLATOR.getInterpolation( - mCurrentAnimation.getProgressFraction()); - if (interpolatedProgress >= SUCCESS_TRANSITION_PROGRESS || velocity < 0 && fling) { - mLauncher.getStateManager().goToState(mToState, true, - () -> onSwipeInteractionCompleted(mToState, logAction)); + float progress = mCurrentAnimation.getProgressFraction(); + float interpolatedProgress = PULLBACK_INTERPOLATOR.getInterpolation(progress); + boolean success = interpolatedProgress >= SUCCESS_TRANSITION_PROGRESS + || (velocity < 0 && fling); + if (success) { + mLauncher.getStateManager().goToState(mEndState, true, + () -> onSwipeInteractionCompleted(mEndState)); + if (mStartState != mEndState) { + logStateChange(mStartState.containerType, logAction); + } + AbstractFloatingView topOpenView = AbstractFloatingView.getTopOpenView(mLauncher); + if (topOpenView != null) { + AbstractFloatingView.closeAllOpenViews(mLauncher); + logStateChange(topOpenView.getLogContainerType(), logAction); + } } else { // Quickly return to the state we came from (we didn't move far). - AnimatorPlaybackController anim = mLauncher.getStateManager() - .createAnimationToNewWorkspace(mFromState, 80); - anim.setEndAction(() -> onSwipeInteractionCompleted(mFromState, logAction)); - anim.start(); + ValueAnimator anim = mCurrentAnimation.getAnimationPlayer(); + anim.setFloatValues(progress, 0); + anim.addListener(new AnimationSuccessListener() { + @Override + public void onAnimationSuccess(Animator animator) { + onSwipeInteractionCompleted(mStartState); + } + }); + anim.setDuration(80).start(); } - mCurrentAnimation.dispatchOnCancel(); - } - - @Override - protected int getDirectionForLog() { - return LauncherLogProto.Action.Direction.UP; } - @Override - protected boolean goingBetweenNormalAndOverview(LauncherState fromState, - LauncherState toState) { - // We don't want to create an atomic animation to/from overview. - return false; + private void onSwipeInteractionCompleted(LauncherState targetState) { + clearState(); + mLauncher.getStateManager().goToState(targetState, false /* animated */); } - @Override - protected int getLogContainerTypeForNormalState() { - return LauncherLogProto.ContainerType.NAVBAR; + private void logStateChange(int startContainerType, int logAction) { + mLauncher.getUserEventDispatcher().logStateChangeAction(logAction, + LauncherLogProto.Action.Direction.UP, + LauncherLogProto.ContainerType.NAVBAR, + startContainerType, + mEndState.containerType, + mLauncher.getWorkspace().getCurrentPage()); } } diff --git a/quickstep/res/values/dimens.xml b/quickstep/res/values/dimens.xml index 97f2de762..9e1833c75 100644 --- a/quickstep/res/values/dimens.xml +++ b/quickstep/res/values/dimens.xml @@ -68,4 +68,7 @@ <!-- Assistant Gestures --> <dimen name="gestures_assistant_size">28dp</dimen> <dimen name="gestures_assistant_drag_threshold">70dp</dimen> + + <!-- Distance to move elements when swiping up to go home from launcher --> + <dimen name="home_pullback_distance">28dp</dimen> </resources> diff --git a/src/com/android/launcher3/AbstractFloatingView.java b/src/com/android/launcher3/AbstractFloatingView.java index 599a3533d..e7d7a69fd 100644 --- a/src/com/android/launcher3/AbstractFloatingView.java +++ b/src/com/android/launcher3/AbstractFloatingView.java @@ -19,9 +19,11 @@ package com.android.launcher3; import static android.view.accessibility.AccessibilityEvent.TYPE_VIEW_FOCUSED; import static android.view.accessibility.AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED; import static android.view.accessibility.AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED; + import static com.android.launcher3.compat.AccessibilityManagerCompat.isAccessibilityEnabled; import static com.android.launcher3.compat.AccessibilityManagerCompat.sendCustomAccessibilityEvent; +import android.animation.Animator; import android.annotation.SuppressLint; import android.content.Context; import android.util.AttributeSet; @@ -30,7 +32,11 @@ import android.view.MotionEvent; import android.view.View; import android.widget.LinearLayout; +import androidx.annotation.IntDef; +import androidx.annotation.Nullable; + import com.android.launcher3.userevent.nano.LauncherLogProto.Action; +import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType; import com.android.launcher3.util.TouchController; import com.android.launcher3.views.ActivityContext; import com.android.launcher3.views.BaseDragLayer; @@ -38,8 +44,6 @@ import com.android.launcher3.views.BaseDragLayer; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; -import androidx.annotation.IntDef; - /** * Base class for a View which shows a floating UI on top of the launcher UI. */ @@ -124,8 +128,20 @@ public abstract class AbstractFloatingView extends LinearLayout implements Touch protected abstract void handleClose(boolean animate); + /** + * Creates a user-controlled animation to hint that the view will be closed if completed. + * @param distanceToMove The max distance that elements should move from their starting point. + */ + public @Nullable Animator createHintCloseAnim(float distanceToMove) { + return null; + } + public abstract void logActionCommand(int command); + public int getLogContainerType() { + return ContainerType.DEFAULT_CONTAINERTYPE; + } + public final boolean isOpen() { return mIsOpen; } diff --git a/src/com/android/launcher3/folder/Folder.java b/src/com/android/launcher3/folder/Folder.java index bcddd037e..2ce663433 100644 --- a/src/com/android/launcher3/folder/Folder.java +++ b/src/com/android/launcher3/folder/Folder.java @@ -1406,7 +1406,12 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo @Override public void logActionCommand(int command) { mLauncher.getUserEventDispatcher().logActionCommand( - command, getFolderIcon(), ContainerType.FOLDER); + command, getFolderIcon(), getLogContainerType()); + } + + @Override + public int getLogContainerType() { + return ContainerType.FOLDER; } @Override diff --git a/src/com/android/launcher3/popup/PopupContainerWithArrow.java b/src/com/android/launcher3/popup/PopupContainerWithArrow.java index 080a0cb69..593dbd46c 100644 --- a/src/com/android/launcher3/popup/PopupContainerWithArrow.java +++ b/src/com/android/launcher3/popup/PopupContainerWithArrow.java @@ -157,7 +157,12 @@ public class PopupContainerWithArrow extends ArrowPopup implements DragSource, @Override public void logActionCommand(int command) { mLauncher.getUserEventDispatcher().logActionCommand( - command, mOriginalIcon, ContainerType.DEEPSHORTCUTS); + command, mOriginalIcon, getLogContainerType()); + } + + @Override + public int getLogContainerType() { + return ContainerType.DEEPSHORTCUTS; } public OnClickListener getItemClickListener() { diff --git a/src/com/android/launcher3/views/BottomUserEducationView.java b/src/com/android/launcher3/views/BottomUserEducationView.java index a291fc605..bdc69af69 100644 --- a/src/com/android/launcher3/views/BottomUserEducationView.java +++ b/src/com/android/launcher3/views/BottomUserEducationView.java @@ -15,6 +15,8 @@ */ package com.android.launcher3.views; +import static com.android.launcher3.compat.AccessibilityManagerCompat.sendCustomAccessibilityEvent; + import android.animation.PropertyValuesHolder; import android.content.Context; import android.graphics.Rect; @@ -28,8 +30,7 @@ import com.android.launcher3.Insettable; import com.android.launcher3.Launcher; import com.android.launcher3.R; import com.android.launcher3.anim.Interpolators; - -import static com.android.launcher3.compat.AccessibilityManagerCompat.sendCustomAccessibilityEvent; +import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType; public class BottomUserEducationView extends AbstractSlideInView implements Insettable { @@ -71,6 +72,11 @@ public class BottomUserEducationView extends AbstractSlideInView implements Inse } @Override + public int getLogContainerType() { + return ContainerType.TIP; + } + + @Override protected boolean isOfType(int type) { return (type & TYPE_ON_BOARD_POPUP) != 0; } diff --git a/src/com/android/launcher3/widget/BaseWidgetSheet.java b/src/com/android/launcher3/widget/BaseWidgetSheet.java index df8266119..72cddc780 100644 --- a/src/com/android/launcher3/widget/BaseWidgetSheet.java +++ b/src/com/android/launcher3/widget/BaseWidgetSheet.java @@ -162,11 +162,16 @@ abstract class BaseWidgetSheet extends AbstractSlideInView @Override public final void logActionCommand(int command) { - Target target = newContainerTarget(ContainerType.WIDGETS); + Target target = newContainerTarget(getLogContainerType()); target.cardinality = getElementsRowCount(); mLauncher.getUserEventDispatcher().logActionCommand(command, target); } + @Override + public int getLogContainerType() { + return ContainerType.WIDGETS; + } + protected abstract int getElementsRowCount(); protected SystemUiController getSystemUiController() { diff --git a/src/com/android/launcher3/widget/WidgetsBottomSheet.java b/src/com/android/launcher3/widget/WidgetsBottomSheet.java index 05368faa6..3e2c0aef4 100644 --- a/src/com/android/launcher3/widget/WidgetsBottomSheet.java +++ b/src/com/android/launcher3/widget/WidgetsBottomSheet.java @@ -16,10 +16,13 @@ package com.android.launcher3.widget; +import android.animation.Animator; +import android.animation.ObjectAnimator; import android.animation.PropertyValuesHolder; import android.content.Context; import android.graphics.Rect; import android.util.AttributeSet; +import android.util.IntProperty; import android.util.Pair; import android.view.Gravity; import android.view.LayoutInflater; @@ -27,6 +30,8 @@ import android.view.View; import android.view.ViewGroup; import android.widget.TextView; +import androidx.annotation.Nullable; + import com.android.launcher3.Insettable; import com.android.launcher3.ItemInfo; import com.android.launcher3.LauncherAppState; @@ -43,6 +48,20 @@ import java.util.List; */ public class WidgetsBottomSheet extends BaseWidgetSheet implements Insettable { + private static final IntProperty<View> PADDING_BOTTOM = + new IntProperty<View>("paddingBottom") { + @Override + public void setValue(View view, int paddingBottom) { + view.setPadding(view.getPaddingLeft(), view.getPaddingTop(), + view.getPaddingRight(), paddingBottom); + } + + @Override + public Integer get(View view) { + return view.getPaddingBottom(); + } + }; + private static final int DEFAULT_CLOSE_DURATION = 200; private ItemInfo mOriginalItemInfo; private Rect mInsets; @@ -158,8 +177,7 @@ public class WidgetsBottomSheet extends BaseWidgetSheet implements Insettable { int rightInset = insets.right - mInsets.right; int bottomInset = insets.bottom - mInsets.bottom; mInsets.set(insets); - setPadding(getPaddingLeft() + leftInset, getPaddingTop(), - getPaddingRight() + rightInset, getPaddingBottom() + bottomInset); + setPadding(leftInset, getPaddingTop(), rightInset, bottomInset); } @Override @@ -172,4 +190,10 @@ public class WidgetsBottomSheet extends BaseWidgetSheet implements Insettable { return Pair.create(findViewById(R.id.title), getContext().getString( mIsOpen ? R.string.widgets_list : R.string.widgets_list_closed)); } + + @Nullable + @Override + public Animator createHintCloseAnim(float distanceToMove) { + return ObjectAnimator.ofInt(this, PADDING_BOTTOM, (int) (distanceToMove + mInsets.bottom)); + } } diff --git a/src/com/android/launcher3/widget/WidgetsFullSheet.java b/src/com/android/launcher3/widget/WidgetsFullSheet.java index ec06d1e6d..521f5117a 100644 --- a/src/com/android/launcher3/widget/WidgetsFullSheet.java +++ b/src/com/android/launcher3/widget/WidgetsFullSheet.java @@ -17,6 +17,8 @@ package com.android.launcher3.widget; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; +import android.animation.AnimatorSet; +import android.animation.ObjectAnimator; import android.animation.PropertyValuesHolder; import android.content.Context; import android.graphics.Rect; @@ -27,6 +29,9 @@ import android.view.MotionEvent; import android.view.View; import android.view.animation.AnimationUtils; +import androidx.annotation.Nullable; +import androidx.annotation.VisibleForTesting; + import com.android.launcher3.Insettable; import com.android.launcher3.Launcher; import com.android.launcher3.LauncherAppState; @@ -35,8 +40,6 @@ import com.android.launcher3.R; import com.android.launcher3.views.RecyclerViewFastScroller; import com.android.launcher3.views.TopRoundedCornerView; -import androidx.annotation.VisibleForTesting; - /** * Popup for showing the full list of available widgets */ @@ -235,4 +238,13 @@ public class WidgetsFullSheet extends BaseWidgetSheet protected int getElementsRowCount() { return mAdapter.getItemCount(); } + + @Nullable + @Override + public Animator createHintCloseAnim(float distanceToMove) { + AnimatorSet anim = new AnimatorSet(); + anim.play(ObjectAnimator.ofFloat(mRecyclerView, TRANSLATION_Y, -distanceToMove)); + anim.play(ObjectAnimator.ofFloat(mRecyclerView, ALPHA, 0.5f)); + return anim; + } } |