mirror of
https://github.com/LawnchairLauncher/lawnchair.git
synced 2026-02-18 02:08:20 +00:00
Merge "Support predictive back from all apps to home" into tm-qpr-dev am: 944348a522
Original change: https://googleplex-android-review.googlesource.com/c/platform/packages/apps/Launcher3/+/20789107 Change-Id: Ib53aa807f447aeba483f6a4a10f078a5b39bf660 Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
@@ -69,9 +69,13 @@ import android.view.HapticFeedbackConstants;
|
||||
import android.view.RemoteAnimationTarget;
|
||||
import android.view.View;
|
||||
import android.view.WindowManagerGlobal;
|
||||
import android.window.BackEvent;
|
||||
import android.window.OnBackAnimationCallback;
|
||||
import android.window.OnBackInvokedDispatcher;
|
||||
import android.window.SplashScreen;
|
||||
|
||||
import androidx.annotation.BinderThread;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.android.app.viewcapture.ViewCapture;
|
||||
@@ -105,6 +109,8 @@ import com.android.launcher3.statemanager.StateManager.AtomicAnimationFactory;
|
||||
import com.android.launcher3.statemanager.StateManager.StateHandler;
|
||||
import com.android.launcher3.taskbar.LauncherTaskbarUIController;
|
||||
import com.android.launcher3.taskbar.TaskbarManager;
|
||||
import com.android.launcher3.testing.TestLogging;
|
||||
import com.android.launcher3.testing.shared.TestProtocol;
|
||||
import com.android.launcher3.uioverrides.QuickstepWidgetHolder.QuickstepHolderFactory;
|
||||
import com.android.launcher3.uioverrides.states.QuickstepAtomicAnimationFactory;
|
||||
import com.android.launcher3.uioverrides.touchcontrollers.NavBarToHomeTouchController;
|
||||
@@ -623,6 +629,29 @@ public class QuickstepLauncher extends Launcher {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void registerBackDispatcher() {
|
||||
getOnBackInvokedDispatcher().registerOnBackInvokedCallback(
|
||||
OnBackInvokedDispatcher.PRIORITY_DEFAULT,
|
||||
new OnBackAnimationCallback() {
|
||||
@Override
|
||||
public void onBackInvoked() {
|
||||
onBackPressed();
|
||||
TestLogging.recordEvent(TestProtocol.SEQUENCE_MAIN, "onBackInvoked");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBackProgressed(@NonNull BackEvent backEvent) {
|
||||
QuickstepLauncher.this.onBackProgressed(backEvent.getProgress());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBackCancelled() {
|
||||
QuickstepLauncher.this.onBackCancelled();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void onTaskbarInAppDisplayProgressUpdate(float progress, int flag) {
|
||||
if (mTaskbarManager == null
|
||||
|| mTaskbarManager.getCurrentActivityContext() == null
|
||||
|
||||
@@ -176,14 +176,7 @@ public abstract class BaseActivity extends Activity implements ActivityContext {
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
if (Utilities.ATLEAST_T) {
|
||||
getOnBackInvokedDispatcher().registerOnBackInvokedCallback(
|
||||
OnBackInvokedDispatcher.PRIORITY_DEFAULT,
|
||||
() -> {
|
||||
onBackPressed();
|
||||
TestLogging.recordEvent(TestProtocol.SEQUENCE_MAIN, "onBackInvoked");
|
||||
});
|
||||
}
|
||||
registerBackDispatcher();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -246,6 +239,17 @@ public abstract class BaseActivity extends Activity implements ActivityContext {
|
||||
|
||||
}
|
||||
|
||||
protected void registerBackDispatcher() {
|
||||
if (Utilities.ATLEAST_T) {
|
||||
getOnBackInvokedDispatcher().registerOnBackInvokedCallback(
|
||||
OnBackInvokedDispatcher.PRIORITY_DEFAULT,
|
||||
() -> {
|
||||
onBackPressed();
|
||||
TestLogging.recordEvent(TestProtocol.SEQUENCE_MAIN, "onBackInvoked");
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isStarted() {
|
||||
return (mActivityFlags & ACTIVITY_STATE_STARTED) != 0;
|
||||
}
|
||||
|
||||
@@ -120,6 +120,7 @@ import android.widget.ImageView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.annotation.CallSuper;
|
||||
import androidx.annotation.FloatRange;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.StringRes;
|
||||
@@ -2065,6 +2066,14 @@ public class Launcher extends StatefulActivity<LauncherState>
|
||||
mStateManager.getState().onBackPressed(this);
|
||||
}
|
||||
|
||||
protected void onBackProgressed(@FloatRange(from = 0.0, to = 1.0) float backProgress) {
|
||||
mStateManager.getState().onBackProgressed(this, backProgress);
|
||||
}
|
||||
|
||||
protected void onBackCancelled() {
|
||||
mStateManager.getState().onBackCancelled(this);
|
||||
}
|
||||
|
||||
protected void onScreenOff() {
|
||||
// Reset AllApps to its initial state only if we are not in the middle of
|
||||
// processing a multi-step drop
|
||||
|
||||
@@ -34,6 +34,8 @@ import android.content.Context;
|
||||
import android.graphics.Color;
|
||||
import android.view.animation.Interpolator;
|
||||
|
||||
import androidx.annotation.FloatRange;
|
||||
|
||||
import com.android.launcher3.statemanager.BaseState;
|
||||
import com.android.launcher3.statemanager.StateManager;
|
||||
import com.android.launcher3.states.HintState;
|
||||
@@ -342,6 +344,27 @@ public abstract class LauncherState implements BaseState<LauncherState> {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Find {@link StateManager} and target {@link LauncherState} to handle back progress in
|
||||
* predictive back gesture.
|
||||
*/
|
||||
public void onBackProgressed(
|
||||
Launcher launcher, @FloatRange(from = 0.0, to = 1.0) float backProgress) {
|
||||
StateManager<LauncherState> lsm = launcher.getStateManager();
|
||||
LauncherState toState = lsm.getLastState();
|
||||
lsm.onBackProgressed(toState, backProgress);
|
||||
}
|
||||
|
||||
/**
|
||||
* Find {@link StateManager} and target {@link LauncherState} to handle backProgress in
|
||||
* predictive back gesture.
|
||||
*/
|
||||
public void onBackCancelled(Launcher launcher) {
|
||||
StateManager<LauncherState> lsm = launcher.getStateManager();
|
||||
LauncherState toState = lsm.getLastState();
|
||||
lsm.onBackCancelled(toState);
|
||||
}
|
||||
|
||||
public static abstract class PageAlphaProvider {
|
||||
|
||||
public final Interpolator interpolator;
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
*/
|
||||
package com.android.launcher3.allapps;
|
||||
|
||||
import static com.android.launcher3.LauncherAnimUtils.SCALE_PROPERTY;
|
||||
import static com.android.launcher3.LauncherAnimUtils.VIEW_TRANSLATE_Y;
|
||||
import static com.android.launcher3.LauncherState.ALL_APPS;
|
||||
import static com.android.launcher3.LauncherState.ALL_APPS_CONTENT;
|
||||
@@ -33,11 +34,15 @@ import android.view.HapticFeedbackConstants;
|
||||
import android.view.View;
|
||||
import android.view.animation.Interpolator;
|
||||
|
||||
import androidx.annotation.FloatRange;
|
||||
|
||||
import com.android.launcher3.DeviceProfile;
|
||||
import com.android.launcher3.DeviceProfile.OnDeviceProfileChangeListener;
|
||||
import com.android.launcher3.Launcher;
|
||||
import com.android.launcher3.LauncherState;
|
||||
import com.android.launcher3.anim.AnimatedFloat;
|
||||
import com.android.launcher3.anim.AnimatorListeners;
|
||||
import com.android.launcher3.anim.Interpolators;
|
||||
import com.android.launcher3.anim.PendingAnimation;
|
||||
import com.android.launcher3.anim.PropertySetter;
|
||||
import com.android.launcher3.statemanager.StateManager.StateHandler;
|
||||
@@ -61,6 +66,8 @@ public class AllAppsTransitionController
|
||||
implements StateHandler<LauncherState>, OnDeviceProfileChangeListener {
|
||||
// This constant should match the second derivative of the animator interpolator.
|
||||
public static final float INTERP_COEFF = 1.7f;
|
||||
private static final float SWIPE_ALL_APPS_TO_HOME_MIN_SCALE = 0.9f;
|
||||
private static final int REVERT_SWIPE_ALL_APPS_TO_HOME_ANIMATION_DURATION_MS = 200;
|
||||
|
||||
public static final FloatProperty<AllAppsTransitionController> ALL_APPS_PROGRESS =
|
||||
new FloatProperty<AllAppsTransitionController>("allAppsProgress") {
|
||||
@@ -139,6 +146,7 @@ public class AllAppsTransitionController
|
||||
private ActivityAllAppsContainerView<Launcher> mAppsView;
|
||||
|
||||
private final Launcher mLauncher;
|
||||
private final AnimatedFloat mAllAppScale = new AnimatedFloat(this::onScaleProgressChanged);
|
||||
private boolean mIsVerticalLayout;
|
||||
|
||||
// Whether this class should take care of closing the keyboard.
|
||||
@@ -232,6 +240,52 @@ public class AllAppsTransitionController
|
||||
onProgressAnimationEnd();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBackProgressed(
|
||||
LauncherState toState, @FloatRange(from = 0.0, to = 1.0) float backProgress) {
|
||||
if (!mLauncher.isInState(ALL_APPS) || !NORMAL.equals(toState)) {
|
||||
return;
|
||||
}
|
||||
|
||||
float deceleratedProgress =
|
||||
Interpolators.PREDICTIVE_BACK_DECELERATED_EASE.getInterpolation(backProgress);
|
||||
float scaleProgress = SWIPE_ALL_APPS_TO_HOME_MIN_SCALE
|
||||
+ (1 - SWIPE_ALL_APPS_TO_HOME_MIN_SCALE) * (1 - deceleratedProgress);
|
||||
|
||||
mAllAppScale.updateValue(scaleProgress);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBackCancelled(LauncherState toState) {
|
||||
if (!mLauncher.isInState(ALL_APPS) || !NORMAL.equals(toState)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: once ag/20649618 is picked into tm-qpr, we don't need to animate back on cancel
|
||||
// swipe because framework will do that for us in {@link #onBackProgressed}.
|
||||
animateAllAppsToNoScale();
|
||||
}
|
||||
|
||||
private void onScaleProgressChanged() {
|
||||
final float scaleProgress = mAllAppScale.value;
|
||||
SCALE_PROPERTY.set(mLauncher.getAppsView(), scaleProgress);
|
||||
mLauncher.getScrimView().setScrimHeaderScale(scaleProgress);
|
||||
|
||||
AllAppsRecyclerView rv = mLauncher.getAppsView().getActiveRecyclerView();
|
||||
if (rv != null && rv.getScrollbar() != null) {
|
||||
rv.getScrollbar().setVisibility(scaleProgress < 1f ? View.INVISIBLE : View.VISIBLE);
|
||||
}
|
||||
|
||||
// TODO(b/264906511): We need to disable view clipping on all apps' parent views so
|
||||
// that the extra roll of app icons are displayed.
|
||||
}
|
||||
|
||||
private void animateAllAppsToNoScale() {
|
||||
mAllAppScale.animateToValue(1f)
|
||||
.setDuration(REVERT_SWIPE_ALL_APPS_TO_HOME_ANIMATION_DURATION_MS)
|
||||
.start();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an animation which updates the vertical transition progress and updates all the
|
||||
* dependent UI using various animation events
|
||||
@@ -258,6 +312,8 @@ public class AllAppsTransitionController
|
||||
if (config.userControlled && success && mShouldControlKeyboard) {
|
||||
mLauncher.getAppsView().getSearchUiManager().getEditText().hideKeyboard();
|
||||
}
|
||||
|
||||
mAllAppScale.updateValue(1f);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -808,7 +808,7 @@ public abstract class BaseAllAppsContainerView<T extends Context & ActivityConte
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawOnScrim(Canvas canvas) {
|
||||
public void drawOnScrimWithScale(Canvas canvas, float scale) {
|
||||
boolean isTablet = mActivityContext.getDeviceProfile().isTablet;
|
||||
|
||||
// Draw full background panel for tablets.
|
||||
@@ -833,7 +833,9 @@ public abstract class BaseAllAppsContainerView<T extends Context & ActivityConte
|
||||
if (mHeaderPaint.getColor() == mScrimColor || mHeaderPaint.getColor() == 0) {
|
||||
return;
|
||||
}
|
||||
int bottom = getHeaderBottom() + getVisibleContainerView().getPaddingTop();
|
||||
final float offset = (getVisibleContainerView().getHeight() * (1 - scale) / 2);
|
||||
final float bottom =
|
||||
scale * (getHeaderBottom() + getVisibleContainerView().getPaddingTop()) + offset;
|
||||
FloatingHeaderView headerView = getFloatingHeaderView();
|
||||
if (isTablet) {
|
||||
// Start adding header protection if search bar or tabs will attach to the top.
|
||||
|
||||
@@ -56,6 +56,8 @@ public class Interpolators {
|
||||
|
||||
public static final Interpolator DECELERATED_EASE = new PathInterpolator(0, 0, .2f, 1f);
|
||||
public static final Interpolator ACCELERATED_EASE = new PathInterpolator(0.4f, 0, 1f, 1f);
|
||||
public static final Interpolator PREDICTIVE_BACK_DECELERATED_EASE =
|
||||
new PathInterpolator(0, 0, 0, 1f);
|
||||
|
||||
/**
|
||||
* The default emphasized interpolator. Used for hero / emphasized movement of content.
|
||||
|
||||
@@ -28,6 +28,8 @@ import android.animation.AnimatorSet;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
|
||||
import androidx.annotation.FloatRange;
|
||||
|
||||
import com.android.launcher3.anim.AnimationSuccessListener;
|
||||
import com.android.launcher3.anim.AnimatorPlaybackController;
|
||||
import com.android.launcher3.anim.PendingAnimation;
|
||||
@@ -195,6 +197,21 @@ public class StateManager<STATE_TYPE extends BaseState<STATE_TYPE>> {
|
||||
}
|
||||
}
|
||||
|
||||
/** Handles backProgress in predictive back gesture by passing it to state handlers. */
|
||||
public void onBackProgressed(
|
||||
STATE_TYPE toState, @FloatRange(from = 0.0, to = 1.0) float backProgress) {
|
||||
for (StateHandler handler : getStateHandlers()) {
|
||||
handler.onBackProgressed(toState, backProgress);
|
||||
}
|
||||
}
|
||||
|
||||
/** Handles back cancelled event in predictive back gesture by passing it to state handlers. */
|
||||
public void onBackCancelled(STATE_TYPE toState) {
|
||||
for (StateHandler handler : getStateHandlers()) {
|
||||
handler.onBackCancelled(toState);
|
||||
}
|
||||
}
|
||||
|
||||
private void goToState(
|
||||
STATE_TYPE state, boolean animated, long delay, AnimatorListener listener) {
|
||||
animated &= areAnimatorsEnabled();
|
||||
@@ -586,6 +603,13 @@ public class StateManager<STATE_TYPE extends BaseState<STATE_TYPE>> {
|
||||
*/
|
||||
void setStateWithAnimation(
|
||||
STATE_TYPE toState, StateAnimationConfig config, PendingAnimation animation);
|
||||
|
||||
/** Handles backProgress in predictive back gesture for target state. */
|
||||
default void onBackProgressed(
|
||||
STATE_TYPE toState, @FloatRange(from = 0.0, to = 1.0) float backProgress) {};
|
||||
|
||||
/** Handles back cancelled event in predictive back gesture for target state. */
|
||||
default void onBackCancelled(STATE_TYPE toState) {};
|
||||
}
|
||||
|
||||
public interface StateListener<STATE_TYPE> {
|
||||
|
||||
@@ -46,6 +46,7 @@ public class ScrimView extends View implements Insettable {
|
||||
private int mBackgroundColor;
|
||||
private boolean mIsVisible = true;
|
||||
private boolean mLastDispatchedOpaqueness;
|
||||
private float mHeaderScale = 1f;
|
||||
|
||||
public ScrimView(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
@@ -91,7 +92,16 @@ public class ScrimView extends View implements Insettable {
|
||||
protected void onDraw(Canvas canvas) {
|
||||
super.onDraw(canvas);
|
||||
if (mDrawingController != null) {
|
||||
mDrawingController.drawOnScrim(canvas);
|
||||
mDrawingController.drawOnScrimWithScale(canvas, mHeaderScale);
|
||||
}
|
||||
}
|
||||
|
||||
/** Set scrim header's scale and bottom offset. */
|
||||
public void setScrimHeaderScale(float scale) {
|
||||
boolean hasChanged = mHeaderScale != scale;
|
||||
mHeaderScale = scale;
|
||||
if (hasChanged) {
|
||||
invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -176,6 +186,6 @@ public class ScrimView extends View implements Insettable {
|
||||
/**
|
||||
* Called inside ScrimView#OnDraw
|
||||
*/
|
||||
void drawOnScrim(Canvas canvas);
|
||||
void drawOnScrimWithScale(Canvas canvas, float scale);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user