Creating a separate state for launcehr as background app

This makes is simpler to control the swipe to overview UI, and ties the
transition with the state machine

Bug: 113287120
Bug: 79755195
Bug: 112203163
Change-Id: I3041dbb659b46ccea6284855addc91e370815be6
This commit is contained in:
Sunny Goyal
2018-09-05 17:32:50 -07:00
parent 6b597b823d
commit cf300fc980
9 changed files with 171 additions and 63 deletions
@@ -0,0 +1,46 @@
/*
* Copyright (C) 2018 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.uioverrides;
import com.android.launcher3.Launcher;
import com.android.launcher3.allapps.AllAppsTransitionController;
import com.android.quickstep.QuickScrubController;
import com.android.quickstep.util.LayoutUtils;
/**
* State indicating that the Launcher is behind an app
*/
public class BackgroundAppState extends OverviewState {
private static final int STATE_FLAGS =
FLAG_DISABLE_RESTORE | FLAG_OVERVIEW_UI | FLAG_DISABLE_ACCESSIBILITY;
public BackgroundAppState(int id) {
super(id, QuickScrubController.QUICK_SCRUB_FROM_HOME_START_DURATION, STATE_FLAGS);
}
@Override
public float getVerticalProgress(Launcher launcher) {
if (launcher.getDeviceProfile().isVerticalBarLayout()) {
return super.getVerticalProgress(launcher);
}
int transitionLength = LayoutUtils.getShelfTrackingDistance(launcher.getDeviceProfile());
AllAppsTransitionController controller = launcher.getAllAppsController();
float scrollRange = Math.max(controller.getShiftRange(), 1);
float progressDelta = (transitionLength / scrollRange);
return super.getVerticalProgress(launcher) + progressDelta;
}
}
@@ -19,6 +19,7 @@ import static com.android.launcher3.LauncherAnimUtils.OVERVIEW_TRANSITION_MS;
import static com.android.launcher3.anim.Interpolators.DEACCEL_2;
import static com.android.launcher3.states.RotationHelper.REQUEST_ROTATE;
import android.graphics.Rect;
import android.view.View;
import com.android.launcher3.AbstractFloatingView;
@@ -38,6 +39,8 @@ import com.android.quickstep.views.TaskView;
*/
public class OverviewState extends LauncherState {
protected static final Rect sTempRect = new Rect();
private static final int STATE_FLAGS = FLAG_WORKSPACE_ICONS_CAN_BE_DRAGGED
| FLAG_DISABLE_RESTORE | FLAG_OVERVIEW_UI | FLAG_DISABLE_ACCESSIBILITY;
@@ -16,8 +16,10 @@
package com.android.quickstep;
import static android.view.View.TRANSLATION_Y;
import static com.android.launcher3.LauncherAnimUtils.OVERVIEW_TRANSITION_MS;
import static com.android.launcher3.LauncherAnimUtils.SCALE_PROPERTY;
import static com.android.launcher3.LauncherState.BACKGROUND_APP;
import static com.android.launcher3.LauncherState.FAST_OVERVIEW;
import static com.android.launcher3.LauncherState.OVERVIEW;
import static com.android.launcher3.allapps.AllAppsTransitionController.ALL_APPS_PROGRESS;
@@ -37,7 +39,6 @@ import android.app.ActivityManager.RunningTaskInfo;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.graphics.PointF;
import android.graphics.Rect;
import android.os.Build;
import android.os.Handler;
@@ -54,7 +55,6 @@ import com.android.launcher3.R;
import com.android.launcher3.TestProtocol;
import com.android.launcher3.allapps.AllAppsTransitionController;
import com.android.launcher3.allapps.DiscoveryBounce;
import com.android.launcher3.anim.AnimationSuccessListener;
import com.android.launcher3.anim.AnimatorPlaybackController;
import com.android.launcher3.compat.AccessibilityManagerCompat;
import com.android.launcher3.dragndrop.DragLayer;
@@ -100,13 +100,8 @@ public interface ActivityControlHelper<T extends BaseDraggingActivity> {
void onTransitionCancelled(T activity, boolean activityVisible);
default int getSwipeUpDestinationAndLength(DeviceProfile dp, Context context,
@InteractionType int interactionType, TransformedRect outRect) {
return getSwipeUpDestinationAndLength(dp, context, interactionType, outRect, null);
}
int getSwipeUpDestinationAndLength(DeviceProfile dp, Context context,
@InteractionType int interactionType, TransformedRect outRect, PointF touchTown);
@InteractionType int interactionType, TransformedRect outRect);
void onSwipeUpComplete(T activity);
@@ -190,7 +185,7 @@ public interface ActivityControlHelper<T extends BaseDraggingActivity> {
@Override
public int getSwipeUpDestinationAndLength(DeviceProfile dp, Context context,
@InteractionType int interactionType, TransformedRect outRect, PointF touchDown) {
@InteractionType int interactionType, TransformedRect outRect) {
LayoutUtils.calculateLauncherTaskSize(context, dp, outRect.rect);
if (interactionType == INTERACTION_QUICK_SCRUB) {
outRect.scale = FastOverviewState.getOverviewScale(dp, outRect.rect, context);
@@ -200,12 +195,7 @@ public interface ActivityControlHelper<T extends BaseDraggingActivity> {
int hotseatInset = dp.isSeascape() ? targetInsets.left : targetInsets.right;
return dp.hotseatBarSizePx + hotseatInset;
} else {
int swipeLength = LayoutUtils.getShelfTrackingDistance(dp);
if (touchDown != null) {
// We are already partway through based on where we touched the nav bar.
swipeLength -= dp.heightPx - touchDown.y;
}
return swipeLength;
return LayoutUtils.getShelfTrackingDistance(dp);
}
}
@@ -233,24 +223,28 @@ public interface ActivityControlHelper<T extends BaseDraggingActivity> {
}
activity.getStateManager().setRestState(resetState);
final LauncherState fromState;
if (!activityVisible) {
// Since the launcher is not visible, we can safely reset the scroll position.
// This ensures then the next swipe up to all-apps starts from scroll 0.
activity.getAppsView().reset(false /* animate */);
activity.getStateManager().goToState(OVERVIEW, false);
fromState = BACKGROUND_APP;
activity.getStateManager().goToState(BACKGROUND_APP, false);
// Optimization, hide the all apps view to prevent layout while initializing
activity.getAppsView().getContentView().setVisibility(View.GONE);
AccessibilityManagerCompat.sendEventToTest(
activity, TestProtocol.SWITCHED_TO_STATE_MESSAGE);
} else {
fromState = startState;
}
return new AnimationFactory() {
@Override
public void createActivityController(long transitionLength,
@InteractionType int interactionType) {
createActivityControllerInternal(activity, activityVisible, startState,
createActivityControllerInternal(activity, activityVisible, fromState,
transitionLength, interactionType, callback);
}
@@ -262,7 +256,7 @@ public interface ActivityControlHelper<T extends BaseDraggingActivity> {
}
private void createActivityControllerInternal(Launcher activity, boolean wasVisible,
LauncherState startState, long transitionLength,
LauncherState fromState, long transitionLength,
@InteractionType int interactionType,
Consumer<AnimatorPlaybackController> callback) {
LauncherState endState = interactionType == INTERACTION_QUICK_SCRUB
@@ -271,31 +265,18 @@ public interface ActivityControlHelper<T extends BaseDraggingActivity> {
DeviceProfile dp = activity.getDeviceProfile();
long accuracy = 2 * Math.max(dp.widthPx, dp.heightPx);
callback.accept(activity.getStateManager()
.createAnimationToNewWorkspace(startState, endState, accuracy));
.createAnimationToNewWorkspace(fromState, endState, accuracy));
return;
}
AnimatorSet anim = new AnimatorSet();
if (!activity.getDeviceProfile().isVerticalBarLayout()) {
AllAppsTransitionController controller = activity.getAllAppsController();
float scrollRange = Math.max(controller.getShiftRange(), 1);
float progressDelta = (transitionLength / scrollRange);
float endProgress = endState.getVerticalProgress(activity);
float startProgress = endProgress + progressDelta;
ObjectAnimator shiftAnim = ObjectAnimator.ofFloat(
controller, ALL_APPS_PROGRESS, startProgress, endProgress);
ObjectAnimator shiftAnim = ObjectAnimator.ofFloat(controller, ALL_APPS_PROGRESS,
fromState.getVerticalProgress(activity),
endState.getVerticalProgress(activity));
shiftAnim.setInterpolator(LINEAR);
anim.play(shiftAnim);
// Since we are changing the start position of the UI, reapply the state, at the end
anim.addListener(new AnimationSuccessListener() {
@Override
public void onAnimationSuccess(Animator animator) {
activity.getStateManager().reapplyState();
}
});
}
if (interactionType == INTERACTION_NORMAL) {
@@ -304,7 +285,14 @@ public interface ActivityControlHelper<T extends BaseDraggingActivity> {
anim.setDuration(transitionLength * 2);
activity.getStateManager().setCurrentAnimation(anim);
callback.accept(AnimatorPlaybackController.wrap(anim, transitionLength * 2));
AnimatorPlaybackController controller =
AnimatorPlaybackController.wrap(anim, transitionLength * 2);
// Since we are changing the start position of the UI, reapply the state, at the end
controller.setEndAction(() ->
activity.getStateManager().goToState(
controller.getProgressFraction() > 0.5 ? endState : fromState, false));
callback.accept(controller);
}
/**
@@ -464,7 +452,7 @@ public interface ActivityControlHelper<T extends BaseDraggingActivity> {
@Override
public int getSwipeUpDestinationAndLength(DeviceProfile dp, Context context,
@InteractionType int interactionType, TransformedRect outRect, PointF touchDown) {
@InteractionType int interactionType, TransformedRect outRect) {
LayoutUtils.calculateFallbackTaskSize(context, dp, outRect.rect);
if (dp.isVerticalBarLayout()) {
Rect targetInsets = dp.getInsets();
@@ -17,20 +17,23 @@ package com.android.quickstep;
import android.util.SparseArray;
import com.android.launcher3.Utilities.Consumer;
/**
* Utility class to help manage multiple callbacks based on different states.
*/
public class MultiStateCallback {
private final SparseArray<Runnable> mCallbacks = new SparseArray<>();
private final SparseArray<Consumer<Boolean>> mStateChangeHandlers = new SparseArray<>();
private int mState = 0;
/**
* Adds the provided state flags to the global state and executes any callbacks as a result.
* @param stateFlag
*/
public void setState(int stateFlag) {
int oldState = mState;
mState = mState | stateFlag;
int count = mCallbacks.size();
@@ -46,6 +49,30 @@ public class MultiStateCallback {
}
}
}
notifyStateChangeHandlers(oldState);
}
/**
* Adds the provided state flags to the global state and executes any change handlers
* as a result.
*/
public void clearState(int stateFlag) {
int oldState = mState;
mState = mState & ~stateFlag;
notifyStateChangeHandlers(oldState);
}
private void notifyStateChangeHandlers(int oldState) {
int count = mStateChangeHandlers.size();
for (int i = 0; i < count; i++) {
int state = mStateChangeHandlers.keyAt(i);
boolean wasOn = (state & oldState) == state;
boolean isOn = (state & mState) == state;
if (wasOn != isOn) {
mStateChangeHandlers.valueAt(i).accept(isOn);
}
}
}
/**
@@ -56,6 +83,13 @@ public class MultiStateCallback {
mCallbacks.put(stateMask, callback);
}
/**
* Sets the handler to be called when the provided states are enabled or disabled.
*/
public void addChangeHandler(int stateMask, Consumer<Boolean> handler) {
mStateChangeHandlers.put(stateMask, handler);
}
public int getState() {
return mState;
}
@@ -444,7 +444,7 @@ public class OtherActivityTouchConsumer extends ContextWrapper implements TouchC
} else {
TraceHelper.partitionSection("RecentsController", "Received");
mInteractionHandler.onRecentsAnimationStart(mController, mTargets,
mHomeContentInsets, mMinimizedHomeBounds, mDownPos);
mHomeContentInsets, mMinimizedHomeBounds);
}
}
}
@@ -36,7 +36,6 @@ import android.content.Context;
import android.content.res.Resources;
import android.graphics.Canvas;
import android.graphics.Point;
import android.graphics.PointF;
import android.graphics.Rect;
import android.os.Build;
import android.os.Bundle;
@@ -123,9 +122,11 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity> {
private static final int STATE_CAPTURE_SCREENSHOT = 1 << 15;
private static final int STATE_SCREENSHOT_CAPTURED = 1 << 16;
private static final int STATE_SCREENSHOT_VIEW_SHOWN = 1 << 17;
private static final int STATE_RESUME_LAST_TASK = 1 << 18;
private static final int STATE_ASSIST_DATA_RECEIVED = 1 << 19;
private static final int STATE_RESUME_LAST_TASK = 1 << 17;
private static final int STATE_ASSIST_DATA_RECEIVED = 1 << 18;
private static final int LAUNCHER_UI_STATES =
STATE_LAUNCHER_PRESENT | STATE_LAUNCHER_DRAWN | STATE_ACTIVITY_MULTIPLIER_COMPLETE
@@ -158,6 +159,7 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity> {
"STATE_QUICK_SCRUB_END",
"STATE_CAPTURE_SCREENSHOT",
"STATE_SCREENSHOT_CAPTURED",
"STATE_SCREENSHOT_VIEW_SHOWN",
"STATE_RESUME_LAST_TASK",
"STATE_ASSIST_DATA_RECEIVED",
};
@@ -176,13 +178,14 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity> {
protected boolean mIsGoingToHome;
private DeviceProfile mDp;
private int mTransitionDragLength;
private PointF mTouchDown;
// Shift in the range of [0, 1].
// 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.
private final AnimatedFloat mCurrentShift = new AnimatedFloat(this::updateFinalShift);
// To avoid UI jump when gesture is started, we offset the animation by the threshold.
private float mShiftAtGestureStart = 0;
private final Handler mMainThreadHandler = new Handler(Looper.getMainLooper());
@@ -324,6 +327,10 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity> {
mStateCallback.addCallback(LONG_SWIPE_ENTER_STATE, this::checkLongSwipeCanEnter);
mStateCallback.addCallback(LONG_SWIPE_START_STATE, this::checkLongSwipeCanStart);
mStateCallback.addChangeHandler(STATE_APP_CONTROLLER_RECEIVED | STATE_LAUNCHER_PRESENT
| STATE_SCREENSHOT_VIEW_SHOWN | STATE_CAPTURE_SCREENSHOT,
(b) -> mRecentsView.setRunningTaskHidden(!b));
}
private void executeOnUiThread(Runnable action) {
@@ -342,12 +349,12 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity> {
}
}
private void initTransitionEndpoints(DeviceProfile dp, PointF touchDown) {
private void initTransitionEndpoints(DeviceProfile dp) {
mDp = dp;
TransformedRect tempRect = new TransformedRect();
mTransitionDragLength = mActivityControlHelper.getSwipeUpDestinationAndLength(
dp, mContext, mInteractionType, tempRect, touchDown);
dp, mContext, mInteractionType, tempRect);
mClipAnimationHelper.updateTargetRect(tempRect);
}
@@ -571,14 +578,14 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity> {
* Called by {@link #mLayoutListener} when launcher layout changes
*/
public void buildAnimationController() {
initTransitionEndpoints(mActivity.getDeviceProfile(), mTouchDown);
initTransitionEndpoints(mActivity.getDeviceProfile());
mAnimationFactory.createActivityController(mTransitionDragLength, mInteractionType);
}
private void onAnimatorPlaybackControllerCreated(AnimatorPlaybackController anim) {
mLauncherTransitionController = anim;
mLauncherTransitionController.dispatchOnStart();
mLauncherTransitionController.setPlayFraction(mCurrentShift.value);
updateLauncherTransitionProgress();
}
@WorkerThread
@@ -617,12 +624,18 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity> {
.getAnimationPlayer().isStarted()) {
return;
}
mLauncherTransitionController.setPlayFraction(mCurrentShift.value);
updateLauncherTransitionProgress();
}
private void updateLauncherTransitionProgress() {
float progress = mCurrentShift.value;
mLauncherTransitionController.setPlayFraction(
progress <= mShiftAtGestureStart || mShiftAtGestureStart >= 1
? 0 : (progress - mShiftAtGestureStart) / (1 - mShiftAtGestureStart));
}
public void onRecentsAnimationStart(RecentsAnimationControllerCompat controller,
RemoteAnimationTargetSet targets, Rect homeContentInsets, Rect minimizedHomeBounds,
PointF touchDown) {
RemoteAnimationTargetSet targets, Rect homeContentInsets, Rect minimizedHomeBounds) {
DeviceProfile dp = InvariantDeviceProfile.INSTANCE.get(mContext).getDeviceProfile(mContext);
final Rect overviewStackBounds;
RemoteAnimationTargetCompat runningTaskTarget = targets.findTask(mRunningTaskId);
@@ -653,8 +666,7 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity> {
mClipAnimationHelper.updateSource(overviewStackBounds, runningTaskTarget);
}
mClipAnimationHelper.prepareAnimation(false /* isOpening */);
mTouchDown = touchDown;
initTransitionEndpoints(dp, mTouchDown);
initTransitionEndpoints(dp);
mRecentsAnimationWrapper.setController(controller, targets);
setStateOnUiThread(STATE_APP_CONTROLLER_RECEIVED);
@@ -670,6 +682,7 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity> {
public void onGestureStarted() {
notifyGestureStartedAsync();
mShiftAtGestureStart = mCurrentShift.value;
setStateOnUiThread(mInteractionType == INTERACTION_NORMAL
? STATE_GESTURE_STARTED_QUICKSTEP : STATE_GESTURE_STARTED_QUICKSCRUB);
mGestureStarted = true;
@@ -805,8 +818,8 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity> {
@Override
public void onAnimationSuccess(Animator animator) {
setStateOnUiThread(mIsGoingToHome
? (STATE_SCALED_CONTROLLER_RECENTS | STATE_CAPTURE_SCREENSHOT)
: STATE_SCALED_CONTROLLER_APP);
? (STATE_SCALED_CONTROLLER_RECENTS | STATE_CAPTURE_SCREENSHOT
| STATE_SCREENSHOT_VIEW_SHOWN) : STATE_SCALED_CONTROLLER_APP);
}
});
anim.start();
@@ -900,7 +913,6 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity> {
mTaskSnapshot = controller.screenshotTask(mRunningTaskId);
}
TaskView taskView = mRecentsView.updateThumbnail(mRunningTaskId, mTaskSnapshot);
mRecentsView.setRunningTaskHidden(false);
if (taskView != null) {
// Defer finishing the animation until the next launcher frame with the
// new thumbnail
@@ -1042,6 +1054,7 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity> {
private void onLongSwipeDisabledUi() {
mUiLongSwipeMode = false;
mStateCallback.clearState(STATE_SCREENSHOT_VIEW_SHOWN);
if (mLongSwipeController != null) {
mLongSwipeController.destroy();
@@ -1067,7 +1080,7 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity> {
}
// We are entering long swipe mode, make sure the screen shot is captured.
mStateCallback.setState(STATE_CAPTURE_SCREENSHOT);
mStateCallback.setState(STATE_CAPTURE_SCREENSHOT | STATE_SCREENSHOT_VIEW_SHOWN);
}
@@ -113,8 +113,7 @@ public class LayoutUtils {
}
public static int getShelfTrackingDistance(DeviceProfile dp) {
int shelfHeight = dp.hotseatBarSizePx + dp.getInsets().bottom;
// Track slightly below the top of the shelf (between top and content).
return shelfHeight - dp.edgeMarginPx * 2;
// Start from a third of bottom inset to provide some shelf overlap.
return dp.hotseatBarSizePx + dp.getInsets().bottom / 3 - dp.edgeMarginPx * 2;
}
}