Merge "Add long swipe from app to overview gesture (with flag)." into udc-dev

This commit is contained in:
Andy Wickham
2023-04-26 21:30:53 +00:00
committed by Android (Google) Code Review
20 changed files with 278 additions and 46 deletions
+1
View File
@@ -63,5 +63,6 @@ message GestureStateProto {
RECENTS = 2;
NEW_TASK = 3;
LAST_TASK = 4;
ALL_APPS = 5;
}
}
@@ -39,6 +39,7 @@ import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
import static com.android.launcher3.util.SystemUiController.UI_STATE_FULLSCREEN_TASK;
import static com.android.launcher3.util.VibratorWrapper.OVERVIEW_HAPTIC;
import static com.android.launcher3.util.window.RefreshRateTracker.getSingleFrameMs;
import static com.android.quickstep.GestureState.GestureEndTarget.ALL_APPS;
import static com.android.quickstep.GestureState.GestureEndTarget.HOME;
import static com.android.quickstep.GestureState.GestureEndTarget.LAST_TASK;
import static com.android.quickstep.GestureState.GestureEndTarget.NEW_TASK;
@@ -161,6 +162,9 @@ public abstract class AbsSwipeUpHandler<T extends StatefulActivity<S>,
private static final ArrayList<String> STATE_NAMES = new ArrayList<>();
/** Shift distance to transition to All Apps if ENABLE_ALL_APPS_FROM_OVERVIEW. */
public static final float ALL_APPS_SHIFT_THRESHOLD = 2f;
protected final BaseActivityInterface<S, T> mActivityInterface;
protected final InputConsumerProxy mInputConsumerProxy;
protected final ActivityInitListener mActivityInitListener;
@@ -247,6 +251,8 @@ public abstract class AbsSwipeUpHandler<T extends StatefulActivity<S>,
getNextStateFlag("STATE_CURRENT_TASK_FINISHED");
private static final int STATE_FINISH_WITH_NO_END =
getNextStateFlag("STATE_FINISH_WITH_NO_END");
private static final int STATE_SETTLED_ON_ALL_APPS =
getNextStateFlag("STATE_SETTLED_ON_ALL_APPS");
private static final int LAUNCHER_UI_STATES =
STATE_LAUNCHER_PRESENT | STATE_LAUNCHER_DRAWN | STATE_LAUNCHER_STARTED |
@@ -299,6 +305,7 @@ public abstract class AbsSwipeUpHandler<T extends StatefulActivity<S>,
private boolean mGestureStarted;
private boolean mLogDirectionUpOrLeft = true;
private boolean mIsLikelyToStartNewTask;
private boolean mIsInAllAppsRegion;
private final long mTouchTimeMs;
private long mLauncherFrameDrawnTime;
@@ -432,6 +439,9 @@ public abstract class AbsSwipeUpHandler<T extends StatefulActivity<S>,
this::finishCurrentTransitionToHome);
mStateCallback.runOnceAtState(STATE_SCALED_CONTROLLER_HOME | STATE_CURRENT_TASK_FINISHED,
this::reset);
mStateCallback.runOnceAtState(STATE_SETTLED_ON_ALL_APPS | STATE_SCREENSHOT_CAPTURED
| STATE_GESTURE_COMPLETED,
this::finishCurrentTransitionToAllApps);
mStateCallback.runOnceAtState(STATE_LAUNCHER_PRESENT | STATE_APP_CONTROLLER_RECEIVED
| STATE_LAUNCHER_DRAWN | STATE_SCALED_CONTROLLER_RECENTS
@@ -681,7 +691,9 @@ public abstract class AbsSwipeUpHandler<T extends StatefulActivity<S>,
maybeUpdateRecentsAttachedState(true/* animate */, true/* moveRunningTask */);
Optional.ofNullable(mActivityInterface.getTaskbarController())
.ifPresent(TaskbarUIController::startTranslationSpring);
performHapticFeedback();
if (!mIsInAllAppsRegion) {
performHapticFeedback();
}
}
@Override
@@ -695,7 +707,7 @@ public abstract class AbsSwipeUpHandler<T extends StatefulActivity<S>,
maybeUpdateRecentsAttachedState(true /* animate */);
}
private void maybeUpdateRecentsAttachedState(boolean animate) {
protected void maybeUpdateRecentsAttachedState(boolean animate) {
maybeUpdateRecentsAttachedState(animate, false /* moveRunningTask */);
}
@@ -716,7 +728,9 @@ public abstract class AbsSwipeUpHandler<T extends StatefulActivity<S>,
? mRecentsAnimationTargets.findTask(mGestureState.getRunningTaskId())
: null;
final boolean recentsAttachedToAppWindow;
if (mGestureState.getEndTarget() != null) {
if (mIsInAllAppsRegion) {
recentsAttachedToAppWindow = false;
} else if (mGestureState.getEndTarget() != null) {
recentsAttachedToAppWindow = mGestureState.getEndTarget().recentsAttachedToAppWindow;
} else if (mContinuingLastGesture
&& mRecentsView.getRunningTaskIndex() != mRecentsView.getNextPage()) {
@@ -772,6 +786,26 @@ public abstract class AbsSwipeUpHandler<T extends StatefulActivity<S>,
}
}
/**
* Update whether user is currently dragging in a region that will trigger all apps.
*/
private void setIsInAllAppsRegion(boolean isInAllAppsRegion) {
if (mIsInAllAppsRegion == isInAllAppsRegion
|| !mActivityInterface.allowAllAppsFromOverview()) {
return;
}
mIsInAllAppsRegion = isInAllAppsRegion;
// Newly entering or exiting the zone - do haptic and animate recent tasks.
VibratorWrapper.INSTANCE.get(mContext).vibrate(OVERVIEW_HAPTIC);
maybeUpdateRecentsAttachedState(true);
// Draw active task below Launcher so that All Apps can appear over it.
runActionOnRemoteHandles(remoteTargetHandle ->
remoteTargetHandle.getTaskViewSimulator().setDrawsBelowRecents(isInAllAppsRegion));
}
private void buildAnimationController() {
if (!canCreateNewOrUpdateExistingLauncherTransitionController()) {
return;
@@ -792,10 +826,15 @@ public abstract class AbsSwipeUpHandler<T extends StatefulActivity<S>,
@Override
public WindowInsets onApplyWindowInsets(View view, WindowInsets windowInsets) {
WindowInsets result = view.onApplyWindowInsets(windowInsets);
// Don't rebuild animation when we are animating the IME, because it will cause a loop
// where the insets change -> animation changes (updating ime) -> insets change -> ...
if (windowInsets.isVisible(WindowInsets.Type.ime())) {
return result;
}
buildAnimationController();
// Reapply the current shift to ensure it takes new insets into account, e.g. when long
// pressing to stash taskbar without moving the finger.
updateFinalShift();
onCurrentShiftUpdated();
return result;
}
@@ -822,7 +861,8 @@ public abstract class AbsSwipeUpHandler<T extends StatefulActivity<S>,
*/
@UiThread
@Override
public void updateFinalShift() {
public void onCurrentShiftUpdated() {
setIsInAllAppsRegion(mCurrentShift.value >= ALL_APPS_SHIFT_THRESHOLD);
updateSysUiFlags(mCurrentShift.value);
applyScrollAndTransform();
@@ -1085,6 +1125,9 @@ public abstract class AbsSwipeUpHandler<T extends StatefulActivity<S>,
}
switch (endTarget) {
case ALL_APPS:
mStateCallback.setState(STATE_SETTLED_ON_ALL_APPS | STATE_CAPTURE_SCREENSHOT);
break;
case HOME:
mStateCallback.setState(STATE_SCALED_CONTROLLER_HOME | STATE_CAPTURE_SCREENSHOT);
// Notify the SysUI to use fade-in animation when entering PiP
@@ -1173,6 +1216,9 @@ public abstract class AbsSwipeUpHandler<T extends StatefulActivity<S>,
final boolean willGoToNewTask =
isScrollingToNewTask() && Math.abs(velocity.x) > Math.abs(endVelocity);
final boolean isSwipeUp = endVelocity < 0;
if (mIsInAllAppsRegion) {
return isSwipeUp ? ALL_APPS : LAST_TASK;
}
if (!isSwipeUp) {
final boolean isCenteredOnNewTask =
mRecentsView.getDestinationPage() != mRecentsView.getRunningTaskIndex();
@@ -1188,7 +1234,9 @@ public abstract class AbsSwipeUpHandler<T extends StatefulActivity<S>,
// Fully gestural mode.
final boolean isFlingX = Math.abs(velocity.x) > mContext.getResources()
.getDimension(R.dimen.quickstep_fling_threshold_speed);
if (isScrollingToNewTask && isFlingX) {
if (mIsInAllAppsRegion) {
return ALL_APPS;
} else if (isScrollingToNewTask && isFlingX) {
// Flinging towards new task takes precedence over mIsMotionPaused (which only
// checks y-velocity).
return NEW_TASK;
@@ -1236,7 +1284,8 @@ public abstract class AbsSwipeUpHandler<T extends StatefulActivity<S>,
mGestureState.setEndTarget(endTarget, false /* isAtomic */);
mAnimationFactory.setEndTarget(endTarget);
float endShift = endTarget.isLauncher ? 1 : 0;
float endShift = endTarget == ALL_APPS ? mDragLengthFactor
: endTarget.isLauncher ? 1 : 0;
final float startShift;
if (!isFling) {
long expectedDuration = Math.abs(Math.round((endShift - currentShift)
@@ -1793,6 +1842,12 @@ public abstract class AbsSwipeUpHandler<T extends StatefulActivity<S>,
reset();
}
@UiThread
private void finishCurrentTransitionToAllApps() {
finishCurrentTransitionToHome();
reset();
}
private void reset() {
mStateCallback.setStateOnUiThread(STATE_HANDLER_INVALIDATED);
if (mActivity != null) {
@@ -1926,7 +1981,8 @@ public abstract class AbsSwipeUpHandler<T extends StatefulActivity<S>,
private boolean updateThumbnail(int runningTaskId, boolean refreshView) {
boolean finishTransitionPosted = false;
final TaskView taskView;
if (mGestureState.getEndTarget() == HOME || mGestureState.getEndTarget() == NEW_TASK) {
if (mGestureState.getEndTarget() == HOME || mGestureState.getEndTarget() == NEW_TASK
|| mGestureState.getEndTarget() == ALL_APPS) {
// Capture the screenshot before finishing the transition to home or quickswitching to
// ensure it's taken in the correct orientation, but no need to update the thumbnail.
taskView = null;
@@ -2072,7 +2128,7 @@ public abstract class AbsSwipeUpHandler<T extends StatefulActivity<S>,
private void onRecentsViewScroll() {
if (moveWindowWithRecentsScroll()) {
updateFinalShift();
onCurrentShiftUpdated();
}
}
@@ -187,6 +187,9 @@ public abstract class BaseActivityInterface<STATE_TYPE extends BaseState<STATE_T
public abstract boolean allowMinimizeSplitScreen();
/** @return whether to allow going to All Apps from Overview. */
public abstract boolean allowAllAppsFromOverview();
public boolean deferStartingActivity(RecentsAnimationDeviceState deviceState, MotionEvent ev) {
return deviceState.isInDeferredGestureRegion(ev) || deviceState.isImeRenderingNavButtons()
|| isTrackpadMultiFingerSwipe(ev);
@@ -138,6 +138,11 @@ public final class FallbackActivityInterface extends
return false;
}
@Override
public boolean allowAllAppsFromOverview() {
return false;
}
@Override
public boolean deferStartingActivity(RecentsAnimationDeviceState deviceState, MotionEvent ev) {
// In non-gesture mode, user might be clicking on the home button which would directly
@@ -196,6 +201,7 @@ public final class FallbackActivityInterface extends
case LAST_TASK:
return BACKGROUND_APP;
case HOME:
case ALL_APPS:
default:
return HOME;
}
@@ -18,11 +18,13 @@ package com.android.quickstep;
import static com.android.launcher3.MotionEventsUtils.isTrackpadFourFingerSwipe;
import static com.android.launcher3.MotionEventsUtils.isTrackpadMultiFingerSwipe;
import static com.android.launcher3.MotionEventsUtils.isTrackpadThreeFingerSwipe;
import static com.android.launcher3.logging.StatsLogManager.LAUNCHER_STATE_ALLAPPS;
import static com.android.launcher3.logging.StatsLogManager.LAUNCHER_STATE_BACKGROUND;
import static com.android.launcher3.logging.StatsLogManager.LAUNCHER_STATE_HOME;
import static com.android.launcher3.logging.StatsLogManager.LAUNCHER_STATE_OVERVIEW;
import static com.android.quickstep.MultiStateCallback.DEBUG_STATES;
import static com.android.quickstep.util.ActiveGestureErrorDetector.GestureEvent.SET_END_TARGET;
import static com.android.quickstep.util.ActiveGestureErrorDetector.GestureEvent.SET_END_TARGET_ALL_APPS;
import static com.android.quickstep.util.ActiveGestureErrorDetector.GestureEvent.SET_END_TARGET_HOME;
import static com.android.quickstep.util.ActiveGestureErrorDetector.GestureEvent.SET_END_TARGET_NEW_TASK;
@@ -68,7 +70,9 @@ public class GestureState implements RecentsAnimationCallbacks.RecentsAnimationL
GestureStateProto.GestureEndTarget.NEW_TASK),
LAST_TASK(false, LAUNCHER_STATE_BACKGROUND, true,
GestureStateProto.GestureEndTarget.LAST_TASK);
GestureStateProto.GestureEndTarget.LAST_TASK),
ALL_APPS(true, LAUNCHER_STATE_ALLAPPS, false, GestureStateProto.GestureEndTarget.ALL_APPS);
GestureEndTarget(boolean isLauncher, int containerType, boolean recentsAttachedToAppWindow,
GestureStateProto.GestureEndTarget protoEndTarget) {
@@ -385,6 +389,9 @@ public class GestureState implements RecentsAnimationCallbacks.RecentsAnimationL
case NEW_TASK:
ActiveGestureLog.INSTANCE.trackEvent(SET_END_TARGET_NEW_TASK);
break;
case ALL_APPS:
ActiveGestureLog.INSTANCE.trackEvent(SET_END_TARGET_ALL_APPS);
break;
case LAST_TASK:
case RECENTS:
default:
@@ -15,6 +15,7 @@
*/
package com.android.quickstep;
import static com.android.launcher3.LauncherState.ALL_APPS;
import static com.android.launcher3.LauncherState.BACKGROUND_APP;
import static com.android.launcher3.LauncherState.NORMAL;
import static com.android.launcher3.LauncherState.OVERVIEW;
@@ -39,6 +40,7 @@ import com.android.launcher3.LauncherAnimUtils;
import com.android.launcher3.LauncherInitListener;
import com.android.launcher3.LauncherState;
import com.android.launcher3.anim.PendingAnimation;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.statehandlers.DepthController;
import com.android.launcher3.statehandlers.DesktopVisibilityController;
import com.android.launcher3.statemanager.StateManager;
@@ -263,6 +265,11 @@ public final class LauncherActivityInterface extends
return true;
}
@Override
public boolean allowAllAppsFromOverview() {
return FeatureFlags.ENABLE_ALL_APPS_FROM_OVERVIEW.get();
}
@Override
public boolean isInLiveTileMode() {
Launcher launcher = getCreatedActivity();
@@ -347,6 +354,8 @@ public final class LauncherActivityInterface extends
case NEW_TASK:
case LAST_TASK:
return BACKGROUND_APP;
case ALL_APPS:
return ALL_APPS;
case HOME:
default:
return NORMAL;
@@ -350,7 +350,8 @@ public class RotationTouchHelper implements DisplayInfoChangeListener {
enableMultipleRegions(true);
}
activityInterface.onExitOverview(this, mExitOverviewRunnable);
} else if (endTarget == GestureState.GestureEndTarget.HOME) {
} else if (endTarget == GestureState.GestureEndTarget.HOME
|| endTarget == GestureState.GestureEndTarget.ALL_APPS) {
enableMultipleRegions(false);
} else if (endTarget == GestureState.GestureEndTarget.NEW_TASK) {
if (mOrientationTouchTransformer.getQuickStepStartingRotation() == -1) {
@@ -67,7 +67,7 @@ public abstract class SwipeUpAnimationLogic implements
// 0 => preview snapShot is completely visible, and hotseat is completely translated down
// 1 => preview snapShot is completely aligned with the recents view and hotseat is completely
// visible.
protected final AnimatedFloat mCurrentShift = new AnimatedFloat(this::updateFinalShift);
protected final AnimatedFloat mCurrentShift = new AnimatedFloat(this::onCurrentShiftUpdated);
protected float mCurrentDisplacement;
// The distance needed to drag to reach the task size in recents.
@@ -148,7 +148,7 @@ public abstract class SwipeUpAnimationLogic implements
* Called when the value of {@link #mCurrentShift} changes
*/
@UiThread
public abstract void updateFinalShift();
public abstract void onCurrentShiftUpdated();
protected PagedOrientationHandler getOrientationHandler() {
// OrientationHandler should be independent of remote target, can directly take one
@@ -309,7 +309,7 @@ abstract class SwipeUpGestureTutorialController extends TutorialController {
}
@Override
public void updateFinalShift() {
public void onCurrentShiftUpdated() {
mRemoteTargetHandles[0].getPlaybackController()
.setProgress(mCurrentShift.value, mDragLengthFactor);
mRemoteTargetHandles[0].getTaskViewSimulator().apply(
@@ -33,10 +33,11 @@ public class ActiveGestureErrorDetector {
*/
public enum GestureEvent {
MOTION_DOWN, MOTION_UP, MOTION_MOVE, SET_END_TARGET, SET_END_TARGET_HOME,
SET_END_TARGET_NEW_TASK, ON_SETTLED_ON_END_TARGET, START_RECENTS_ANIMATION,
FINISH_RECENTS_ANIMATION, CANCEL_RECENTS_ANIMATION, SET_ON_PAGE_TRANSITION_END_CALLBACK,
CANCEL_CURRENT_ANIMATION, CLEANUP_SCREENSHOT, SCROLLER_ANIMATION_ABORTED, TASK_APPEARED,
EXPECTING_TASK_APPEARED, FLAG_USING_OTHER_ACTIVITY_INPUT_CONSUMER, LAUNCHER_DESTROYED,
SET_END_TARGET_NEW_TASK, SET_END_TARGET_ALL_APPS, ON_SETTLED_ON_END_TARGET,
START_RECENTS_ANIMATION, FINISH_RECENTS_ANIMATION, CANCEL_RECENTS_ANIMATION,
SET_ON_PAGE_TRANSITION_END_CALLBACK, CANCEL_CURRENT_ANIMATION, CLEANUP_SCREENSHOT,
SCROLLER_ANIMATION_ABORTED, TASK_APPEARED, EXPECTING_TASK_APPEARED,
FLAG_USING_OTHER_ACTIVITY_INPUT_CONSUMER, LAUNCHER_DESTROYED,
/**
* These GestureEvents are specifically associated to state flags that get set in
@@ -220,6 +221,7 @@ public class ActiveGestureErrorDetector {
case MOTION_DOWN:
case SET_END_TARGET:
case SET_END_TARGET_HOME:
case SET_END_TARGET_ALL_APPS:
case SET_END_TARGET_NEW_TASK:
case START_RECENTS_ANIMATION:
case SET_ON_PAGE_TRANSITION_END_CALLBACK:
@@ -17,9 +17,11 @@ package com.android.quickstep.util;
import static com.android.launcher3.anim.Interpolators.DEACCEL;
import static com.android.launcher3.anim.Interpolators.LINEAR;
import static com.android.quickstep.AbsSwipeUpHandler.ALL_APPS_SHIFT_THRESHOLD;
import static com.android.quickstep.views.RecentsView.RECENTS_SCALE_PROPERTY;
import static com.android.quickstep.views.RecentsView.TASK_SECONDARY_TRANSLATION;
import android.animation.AnimatorSet;
import android.animation.TimeInterpolator;
import android.content.Context;
import android.graphics.Matrix;
@@ -32,11 +34,15 @@ import androidx.annotation.Nullable;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherState;
import com.android.launcher3.Utilities;
import com.android.launcher3.anim.AnimatorPlaybackController;
import com.android.launcher3.anim.PendingAnimation;
import com.android.launcher3.statemanager.StateManager;
import com.android.launcher3.statemanager.StatefulActivity;
import com.android.launcher3.states.StateAnimationConfig;
import com.android.launcher3.touch.AllAppsSwipeController;
import com.android.launcher3.touch.PagedOrientationHandler;
import com.android.quickstep.LauncherActivityInterface;
import com.android.quickstep.views.RecentsView;
/**
@@ -49,7 +55,9 @@ public class AnimatorControllerWithResistance {
private enum RecentsResistanceParams {
FROM_APP(0.75f, 0.5f, 1f, false),
FROM_APP_TO_ALL_APPS(0.75f, 0.5f, 0.8f, false),
FROM_APP_TABLET(1f, 0.7f, 1f, true),
FROM_APP_TO_ALL_APPS_TABLET(1f, 0.5f, 0.5f, false),
FROM_OVERVIEW(1f, 0.75f, 0.5f, false);
RecentsResistanceParams(float scaleStartResist, float scaleMaxResist,
@@ -86,6 +94,8 @@ public class AnimatorControllerWithResistance {
private static final TimeInterpolator RECENTS_SCALE_RESIST_INTERPOLATOR = DEACCEL;
private static final TimeInterpolator RECENTS_TRANSLATE_RESIST_INTERPOLATOR = LINEAR;
private static final Rect TEMP_RECT = new Rect();
private final AnimatorPlaybackController mNormalController;
private final AnimatorPlaybackController mResistanceController;
@@ -145,10 +155,42 @@ public class AnimatorControllerWithResistance {
scaleProperty, translationTarget, translationProperty);
PendingAnimation resistAnim = createRecentsResistanceAnim(params);
// Apply All Apps animation during the resistance animation.
if (recentsOrientedState.getActivityInterface().allowAllAppsFromOverview()) {
StatefulActivity activity =
recentsOrientedState.getActivityInterface().getCreatedActivity();
if (activity != null) {
StateManager<LauncherState> stateManager = activity.getStateManager();
if (stateManager.isInStableState(LauncherState.BACKGROUND_APP)
&& stateManager.isInTransition()) {
// Calculate the resistance progress threshold where All Apps will trigger.
float threshold = getAllAppsThreshold(context, recentsOrientedState, dp);
StateAnimationConfig config = new StateAnimationConfig();
AllAppsSwipeController.applyOverviewToAllAppsAnimConfig(dp, config, threshold);
AnimatorSet allAppsAnimator = stateManager.createAnimationToNewWorkspace(
LauncherState.ALL_APPS, config).getTarget();
resistAnim.add(allAppsAnimator);
}
}
}
AnimatorPlaybackController resistanceController = resistAnim.createPlaybackController();
return new AnimatorControllerWithResistance(normalController, resistanceController);
}
private static float getAllAppsThreshold(Context context,
RecentsOrientedState recentsOrientedState, DeviceProfile dp) {
int transitionDragLength =
recentsOrientedState.getActivityInterface().getSwipeUpDestinationAndLength(
dp, context, TEMP_RECT,
recentsOrientedState.getOrientationHandler());
float dragLengthFactor = (float) dp.heightPx / transitionDragLength;
// -1s are because 0-1 is reserved for the normal transition.
return (ALL_APPS_SHIFT_THRESHOLD - 1) / (dragLengthFactor - 1);
}
/**
* Creates the resistance animation for {@link #createForRecents}, or can be used separately
* when starting from recents, i.e. {@link #createRecentsResistanceFromOverviewAnim}.
@@ -158,8 +200,8 @@ public class AnimatorControllerWithResistance {
Rect startRect = new Rect();
PagedOrientationHandler orientationHandler = params.recentsOrientedState
.getOrientationHandler();
LauncherActivityInterface.INSTANCE.calculateTaskSize(params.context, params.dp, startRect,
orientationHandler);
params.recentsOrientedState.getActivityInterface()
.calculateTaskSize(params.context, params.dp, startRect, orientationHandler);
long distanceToCover = startRect.bottom;
PendingAnimation resistAnim = params.resistAnim != null
? params.resistAnim
@@ -257,9 +299,15 @@ public class AnimatorControllerWithResistance {
this.translationTarget = translationTarget;
this.translationProperty = translationProperty;
if (dp.isTablet) {
resistanceParams = RecentsResistanceParams.FROM_APP_TABLET;
resistanceParams =
recentsOrientedState.getActivityInterface().allowAllAppsFromOverview()
? RecentsResistanceParams.FROM_APP_TO_ALL_APPS_TABLET
: RecentsResistanceParams.FROM_APP_TABLET;
} else {
resistanceParams = RecentsResistanceParams.FROM_APP;
resistanceParams =
recentsOrientedState.getActivityInterface().allowAllAppsFromOverview()
? RecentsResistanceParams.FROM_APP_TO_ALL_APPS
: RecentsResistanceParams.FROM_APP;
}
}
@@ -116,6 +116,7 @@ public class RecentsOrientedState implements
| FLAG_SWIPE_UP_NOT_RUNNING;
private final Context mContext;
private final BaseActivityInterface mActivityInterface;
private final OrientationEventListener mOrientationListener;
private final SettingsCache mSettingsCache;
private final SettingsCache.OnChangeListener mRotationChangeListener =
@@ -135,9 +136,10 @@ public class RecentsOrientedState implements
* is enabled
* @see #setRotationWatcherEnabled(boolean)
*/
public RecentsOrientedState(Context context, BaseActivityInterface sizeStrategy,
public RecentsOrientedState(Context context, BaseActivityInterface activityInterface,
IntConsumer rotationChangeListener) {
mContext = context;
mActivityInterface = activityInterface;
mOrientationListener = new OrientationEventListener(context) {
@Override
public void onOrientationChanged(int degrees) {
@@ -149,7 +151,7 @@ public class RecentsOrientedState implements
}
};
mFlags = sizeStrategy.rotationSupportedByActivity
mFlags = mActivityInterface.rotationSupportedByActivity
? FLAG_MULTIPLE_ORIENTATION_SUPPORTED_BY_ACTIVITY : 0;
mFlags |= FLAG_SWIPE_UP_NOT_RUNNING;
@@ -157,6 +159,10 @@ public class RecentsOrientedState implements
initFlags();
}
public BaseActivityInterface getActivityInterface() {
return mActivityInterface;
}
/**
* Sets the device profile for the current state.
*/
@@ -17,6 +17,7 @@ package com.android.quickstep.views;
import static android.app.ActivityTaskManager.INVALID_TASK_ID;
import static com.android.launcher3.LauncherState.ALL_APPS;
import static com.android.launcher3.LauncherState.CLEAR_ALL_BUTTON;
import static com.android.launcher3.LauncherState.NORMAL;
import static com.android.launcher3.LauncherState.OVERVIEW;
@@ -129,7 +130,7 @@ public class LauncherRecentsView extends RecentsView<QuickstepLauncher, Launcher
@Override
public void onStateTransitionComplete(LauncherState finalState) {
if (finalState == NORMAL || finalState == SPRING_LOADED) {
if (finalState == NORMAL || finalState == SPRING_LOADED || finalState == ALL_APPS) {
// Clean-up logic that occurs when recents is no longer in use/visible.
reset();
}
+4 -4
View File
@@ -68,16 +68,16 @@
android:id="@+id/scrim_view"
android:background="@android:color/transparent" />
<include
android:id="@+id/overview_panel"
layout="@layout/overview_panel" />
<include
android:id="@+id/apps_view"
layout="@layout/all_apps"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<include
android:id="@+id/overview_panel"
layout="@layout/overview_panel" />
</com.android.launcher3.dragndrop.DragLayer>
</com.android.launcher3.LauncherRootView>
@@ -40,6 +40,7 @@ import android.os.Parcelable;
import android.os.Process;
import android.os.UserManager;
import android.util.AttributeSet;
import android.util.FloatProperty;
import android.util.Log;
import android.util.SparseArray;
import android.util.TypedValue;
@@ -101,6 +102,20 @@ public class ActivityAllAppsContainerView<T extends Context & ActivityContext>
OnDeviceProfileChangeListener, PersonalWorkSlidingTabStrip.OnActivePageChangedListener,
ScrimView.ScrimDrawingController {
public static final FloatProperty<ActivityAllAppsContainerView<?>> BOTTOM_SHEET_ALPHA =
new FloatProperty<>("bottomSheetAlpha") {
@Override
public Float get(ActivityAllAppsContainerView<?> containerView) {
return containerView.mBottomSheetAlpha;
}
@Override
public void setValue(ActivityAllAppsContainerView<?> containerView, float v) {
containerView.setBottomSheetAlpha(v);
}
};
public static final float PULL_MULTIPLIER = .02f;
public static final float FLING_VELOCITY_MULTIPLIER = 1200f;
protected static final String BUNDLE_KEY_CURRENT_PAGE = "launcher.allapps.current_page";
@@ -159,6 +174,8 @@ public class ActivityAllAppsContainerView<T extends Context & ActivityContext>
private ScrimView mScrimView;
private int mHeaderColor;
private int mBottomSheetBackgroundColor;
private float mBottomSheetAlpha = 1f;
private boolean mForceBottomSheetVisible;
private int mTabsProtectionAlpha;
@Nullable private AllAppsTransitionController mAllAppsTransitionController;
@@ -258,7 +275,7 @@ public class ActivityAllAppsContainerView<T extends Context & ActivityContext>
final TypedValue value = new TypedValue();
getContext().getTheme().resolveAttribute(android.R.attr.colorBackground, value, true);
mBottomSheetBackgroundColor = value.data;
updateBackground(mActivityContext.getDeviceProfile());
updateBackgroundVisibility(mActivityContext.getDeviceProfile());
mSearchUiManager.initializeSearch(this);
}
@@ -282,6 +299,16 @@ public class ActivityAllAppsContainerView<T extends Context & ActivityContext>
return mBottomSheetBackground;
}
/**
* Temporarily force the bottom sheet to be visible on non-tablets.
*
* @param force {@code true} means bottom sheet will be visible on phones until {@code reset()}.
**/
public void forceBottomSheetVisible(boolean force) {
mForceBottomSheetVisible = force;
updateBackgroundVisibility(mActivityContext.getDeviceProfile());
}
public View getSearchView() {
return mSearchContainer;
}
@@ -408,6 +435,7 @@ public class ActivityAllAppsContainerView<T extends Context & ActivityContext>
if (mHeader != null && mHeader.getVisibility() == VISIBLE) {
mHeader.reset(animate);
}
forceBottomSheetVisible(false);
// Reset the base recycler view after transitioning home.
updateHeaderScroll(0);
if (exitSearch) {
@@ -830,7 +858,7 @@ public class ActivityAllAppsContainerView<T extends Context & ActivityContext>
holder.mRecyclerView.getRecycledViewPool().clear();
}
}
updateBackground(dp);
updateBackgroundVisibility(dp);
int navBarScrimColor = Themes.getNavBarScrimColor(mActivityContext);
if (mNavBarScrimPaint.getColor() != navBarScrimColor) {
@@ -839,13 +867,19 @@ public class ActivityAllAppsContainerView<T extends Context & ActivityContext>
}
}
protected void updateBackground(DeviceProfile deviceProfile) {
mBottomSheetBackground.setVisibility(deviceProfile.isTablet ? View.VISIBLE : View.GONE);
protected void updateBackgroundVisibility(DeviceProfile deviceProfile) {
boolean visible = deviceProfile.isTablet || mForceBottomSheetVisible;
mBottomSheetBackground.setVisibility(visible ? View.VISIBLE : View.GONE);
// Note: For tablets, the opaque background and header protection are added in drawOnScrim.
// For the taskbar entrypoint, the scrim is drawn differently, so a static background is
// added in TaskbarAllAppsContainerView and header protection is not yet supported.
}
private void setBottomSheetAlpha(float alpha) {
// Bottom sheet alpha is always 1 for tablets.
mBottomSheetAlpha = mActivityContext.getDeviceProfile().isTablet ? 1f : alpha;
}
private void onAppsUpdated() {
mHasWorkApps = Stream.of(mAllAppsStore.getApps()).anyMatch(mWorkManager.getMatcher());
if (TestProtocol.sDebugTracing) {
@@ -1148,8 +1182,8 @@ public class ActivityAllAppsContainerView<T extends Context & ActivityContext>
@Override
public void drawOnScrimWithScale(Canvas canvas, float scale) {
final boolean isTablet = mActivityContext.getDeviceProfile().isTablet;
final View panel = mBottomSheetBackground;
final boolean hasBottomSheet = panel.getVisibility() == VISIBLE;
final float translationY = ((View) panel.getParent()).getTranslationY();
final float horizontalScaleOffset = (1 - scale) * panel.getWidth() / 2;
@@ -1160,8 +1194,9 @@ public class ActivityAllAppsContainerView<T extends Context & ActivityContext>
final float leftWithScale = panel.getLeft() + horizontalScaleOffset;
final float rightWithScale = panel.getRight() - horizontalScaleOffset;
// Draw full background panel for tablets.
if (isTablet) {
if (hasBottomSheet) {
mHeaderPaint.setColor(mBottomSheetBackgroundColor);
mHeaderPaint.setAlpha((int) (255 * mBottomSheetAlpha));
mTmpRectF.set(
leftWithScale,
@@ -1192,7 +1227,7 @@ public class ActivityAllAppsContainerView<T extends Context & ActivityContext>
final float headerBottomOffset = (getVisibleContainerView().getHeight() * (1 - scale) / 2);
final float headerBottomWithScaleOnPhone = headerBottomNoScale * scale + headerBottomOffset;
final FloatingHeaderView headerView = getFloatingHeaderView();
if (isTablet) {
if (hasBottomSheet) {
// Start adding header protection if search bar or tabs will attach to the top.
if (!FeatureFlags.ENABLE_FLOATING_SEARCH_BAR.get() || mUsingTabs) {
mTmpRectF.set(
@@ -1219,12 +1254,12 @@ public class ActivityAllAppsContainerView<T extends Context & ActivityContext>
}
float left = 0f;
float right = canvas.getWidth();
if (isTablet) {
if (hasBottomSheet) {
left = mBottomSheetBackground.getLeft() + horizontalScaleOffset;
right = mBottomSheetBackground.getRight() - horizontalScaleOffset;
}
final float tabTopWithScale = isTablet
final float tabTopWithScale = hasBottomSheet
? headerBottomWithScaleOnTablet
: headerBottomWithScaleOnPhone;
final float tabBottomWithScale = tabTopWithScale + tabsHeight * scale;
@@ -1263,7 +1298,7 @@ public class ActivityAllAppsContainerView<T extends Context & ActivityContext>
* Returns a view that denotes the visible part of all apps container view.
*/
public View getVisibleContainerView() {
return mActivityContext.getDeviceProfile().isTablet ? mBottomSheetBackground : this;
return mBottomSheetBackground.getVisibility() == VISIBLE ? mBottomSheetBackground : this;
}
protected void onInitializeRecyclerView(RecyclerView rv) {
@@ -21,8 +21,10 @@ import static com.android.launcher3.LauncherState.ALL_APPS;
import static com.android.launcher3.LauncherState.ALL_APPS_CONTENT;
import static com.android.launcher3.LauncherState.NORMAL;
import static com.android.launcher3.anim.Interpolators.DEACCEL_1_7;
import static com.android.launcher3.anim.Interpolators.INSTANT;
import static com.android.launcher3.anim.Interpolators.LINEAR;
import static com.android.launcher3.anim.PropertySetter.NO_ANIM_PROPERTY_SETTER;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_ALL_APPS_BOTTOM_SHEET_FADE;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_ALL_APPS_FADE;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_VERTICAL_PROGRESS;
import static com.android.launcher3.util.SystemUiController.FLAG_DARK_NAV;
@@ -410,8 +412,12 @@ public class AllAppsTransitionController
setter.setFloat(getAppsViewPullbackAlpha(), MultiPropertyFactory.MULTI_PROPERTY_VALUE,
hasAllAppsContent ? 1 : 0, allAppsFade);
boolean shouldProtectHeader =
ALL_APPS == state || mLauncher.getStateManager().getState() == ALL_APPS;
setter.setFloat(mLauncher.getAppsView(),
ActivityAllAppsContainerView.BOTTOM_SHEET_ALPHA, hasAllAppsContent ? 1 : 0,
config.getInterpolator(ANIM_ALL_APPS_BOTTOM_SHEET_FADE, INSTANT));
boolean shouldProtectHeader = !config.hasAnimationFlag(StateAnimationConfig.SKIP_SCRIM)
&& (ALL_APPS == state || mLauncher.getStateManager().getState() == ALL_APPS);
mScrimView.setDrawingController(shouldProtectHeader ? mAppsView : null);
}
@@ -41,7 +41,7 @@ public class SecondaryLauncherAllAppsContainerView extends
}
@Override
protected void updateBackground(DeviceProfile deviceProfile) {}
protected void updateBackgroundVisibility(DeviceProfile deviceProfile) {}
@Override
public boolean isInAllApps() {
@@ -118,9 +118,13 @@ public final class FeatureFlags {
// TODO(Block 4): Cleanup flags
public static final BooleanFlag ENABLE_FLOATING_SEARCH_BAR =
getReleaseFlag(270390286, "ENABLE_FLOATING_SEARCH_BAR", DISABLED,
getReleaseFlag(268388460, "ENABLE_FLOATING_SEARCH_BAR", DISABLED,
"Keep All Apps search bar at the bottom (but above keyboard if open)");
public static final BooleanFlag ENABLE_ALL_APPS_FROM_OVERVIEW =
getDebugFlag(275132633, "ENABLE_ALL_APPS_FROM_OVERVIEW", DISABLED,
"Allow entering All Apps from Overview (e.g. long swipe up from app)");
public static final BooleanFlag ENABLE_SHOW_KEYBOARD_OPTION_IN_ALL_APPS = getReleaseFlag(
270394468, "ENABLE_SHOW_KEYBOARD_OPTION_IN_ALL_APPS", ENABLED,
"Enable option to show keyboard when going to all-apps");
@@ -65,7 +65,8 @@ public class StateAnimationConfig {
ANIM_OVERVIEW_ACTIONS_FADE,
ANIM_WORKSPACE_PAGE_TRANSLATE_X,
ANIM_OVERVIEW_SPLIT_SELECT_FLOATING_TASK_TRANSLATE_OFFSCREEN,
ANIM_OVERVIEW_SPLIT_SELECT_INSTRUCTIONS_FADE
ANIM_OVERVIEW_SPLIT_SELECT_INSTRUCTIONS_FADE,
ANIM_ALL_APPS_BOTTOM_SHEET_FADE
})
@Retention(RetentionPolicy.SOURCE)
public @interface AnimType {}
@@ -88,8 +89,9 @@ public class StateAnimationConfig {
public static final int ANIM_WORKSPACE_PAGE_TRANSLATE_X = 15;
public static final int ANIM_OVERVIEW_SPLIT_SELECT_FLOATING_TASK_TRANSLATE_OFFSCREEN = 17;
public static final int ANIM_OVERVIEW_SPLIT_SELECT_INSTRUCTIONS_FADE = 18;
public static final int ANIM_ALL_APPS_BOTTOM_SHEET_FADE = 19;
private static final int ANIM_TYPES_COUNT = 19;
private static final int ANIM_TYPES_COUNT = 20;
protected final Interpolator[] mInterpolators = new Interpolator[ANIM_TYPES_COUNT];
@@ -23,6 +23,8 @@ import static com.android.launcher3.anim.Interpolators.EMPHASIZED_DECELERATE;
import static com.android.launcher3.anim.Interpolators.FINAL_FRAME;
import static com.android.launcher3.anim.Interpolators.INSTANT;
import static com.android.launcher3.anim.Interpolators.LINEAR;
import static com.android.launcher3.anim.Interpolators.clampToProgress;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_ALL_APPS_BOTTOM_SHEET_FADE;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_ALL_APPS_FADE;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_DEPTH;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_HOTSEAT_FADE;
@@ -32,11 +34,14 @@ import static com.android.launcher3.states.StateAnimationConfig.ANIM_SCRIM_FADE;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_VERTICAL_PROGRESS;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_WORKSPACE_FADE;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_WORKSPACE_SCALE;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_WORKSPACE_TRANSLATE;
import static com.android.launcher3.states.StateAnimationConfig.SKIP_OVERVIEW;
import android.view.MotionEvent;
import android.view.animation.Interpolator;
import com.android.launcher3.AbstractFloatingView;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherState;
import com.android.launcher3.anim.Interpolators;
@@ -269,4 +274,44 @@ public class AllAppsSwipeController extends AbstractStateChangeTouchController {
: ALL_APPS_VERTICAL_PROGRESS_ATOMIC);
}
}
/**
* Applies Animation config values for transition from overview to all apps.
*
* @param threshold progress at which all apps will open upon release
*/
public static void applyOverviewToAllAppsAnimConfig(
DeviceProfile deviceProfile, StateAnimationConfig config, float threshold) {
config.userControlled = true;
config.animFlags = SKIP_OVERVIEW;
if (deviceProfile.isTablet) {
config.setInterpolator(ANIM_ALL_APPS_FADE, INSTANT);
config.setInterpolator(ANIM_SCRIM_FADE, ALL_APPS_SCRIM_RESPONDER);
// The fact that we end on Workspace is not very ideal, but since we do, fade it in at
// the end of the transition. Don't scale/translate it.
config.setInterpolator(ANIM_WORKSPACE_FADE, clampToProgress(LINEAR, 0.8f, 1));
config.setInterpolator(ANIM_WORKSPACE_SCALE, INSTANT);
config.setInterpolator(ANIM_WORKSPACE_TRANSLATE, INSTANT);
} else {
// Remove scrim for this transition.
config.setInterpolator(ANIM_SCRIM_FADE, progress -> 0);
// For now, pop the background panel in at full opacity at the threshold.
config.setInterpolator(ANIM_ALL_APPS_BOTTOM_SHEET_FADE,
thresholdInterpolator(threshold, INSTANT));
// Fade the apps in when the scrim normally does, so it's apparent sooner what is
// happening (in this case we are fading them on top of the background panel).
config.setInterpolator(ANIM_ALL_APPS_FADE,
thresholdInterpolator(threshold, SCRIM_FADE_MANUAL));
config.setInterpolator(ANIM_VERTICAL_PROGRESS,
thresholdInterpolator(threshold, ALL_APPS_VERTICAL_PROGRESS_MANUAL));
}
}
/** Creates an interpolator that is 0 until the threshold, then follows given interpolator. */
private static Interpolator thresholdInterpolator(float threshold, Interpolator interpolator) {
return progress -> progress <= threshold ? 0 : interpolator.getInterpolation(progress);
}
}