Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 6b0eb384 authored by Sunny Goyal's avatar Sunny Goyal
Browse files

Swipe-up support for 3P Launcher

On swipe up, we start a rencets transition to the current launcher app. At the
end of the transition, if the user is going to recents, we start overview activity.

Bug: 137197916
Change-Id: Ie5ed848879ad965dcab2780a05d649e3be066568
parent f11dd8e1
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -23,6 +23,7 @@
    package="com.android.launcher3" >

    <uses-permission android:name="android.permission.CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS" />
    <uses-permission android:name="android.permission.VIBRATE" />

    <application
        android:backupAgent="com.android.launcher3.LauncherBackupAgent"
+101 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2019 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.android.quickstep;

import static android.os.VibrationEffect.EFFECT_CLICK;
import static android.os.VibrationEffect.createPredefined;

import static com.android.launcher3.anim.Interpolators.DEACCEL;
import static com.android.quickstep.TouchInteractionService.BACKGROUND_EXECUTOR;

import android.annotation.TargetApi;
import android.content.Context;
import android.os.Build;
import android.os.VibrationEffect;
import android.os.Vibrator;
import android.provider.Settings;
import android.view.animation.Interpolator;

import com.android.launcher3.Utilities;
import com.android.quickstep.util.ClipAnimationHelper;
import com.android.quickstep.util.ClipAnimationHelper.TransformParams;

/**
 * Base class for swipe up handler with some utility methods
 */
@TargetApi(Build.VERSION_CODES.Q)
public abstract class BaseSwipeUpHandler {

    // Start resisting when swiping past this factor of mTransitionDragLength.
    private static final float DRAG_LENGTH_FACTOR_START_PULLBACK = 1.4f;
    // This is how far down we can scale down, where 0f is full screen and 1f is recents.
    private static final float DRAG_LENGTH_FACTOR_MAX_PULLBACK = 1.8f;
    private static final Interpolator PULLBACK_INTERPOLATOR = DEACCEL;

    // The distance needed to drag to reach the task size in recents.
    protected int mTransitionDragLength;
    // How much further we can drag past recents, as a factor of mTransitionDragLength.
    protected float mDragLengthFactor = 1;

    protected final Context mContext;

    protected final ClipAnimationHelper mClipAnimationHelper;
    protected final TransformParams mTransformParams = new TransformParams();

    private final Vibrator mVibrator;

    protected BaseSwipeUpHandler(Context context) {
        mContext = context;
        mClipAnimationHelper = new ClipAnimationHelper(context);

        mVibrator = context.getSystemService(Vibrator.class);
    }

    public void performHapticFeedback() {
        if (!mVibrator.hasVibrator()) {
            return;
        }
        if (Settings.System.getInt(
                mContext.getContentResolver(), Settings.System.HAPTIC_FEEDBACK_ENABLED, 0) == 0) {
            return;
        }

        VibrationEffect effect = createPredefined(EFFECT_CLICK);
        if (effect == null) {
            return;
        }
        BACKGROUND_EXECUTOR.execute(() -> mVibrator.vibrate(effect));
    }

    protected float getShiftForDisplacement(float displacement) {
        // We are moving in the negative x/y direction
        displacement = -displacement;
        if (displacement > mTransitionDragLength * mDragLengthFactor && mTransitionDragLength > 0) {
            return mDragLengthFactor;
        } else {
            float translation = Math.max(displacement, 0);
            float shift = mTransitionDragLength == 0 ? 0 : translation / mTransitionDragLength;
            if (shift > DRAG_LENGTH_FACTOR_START_PULLBACK) {
                float pullbackProgress = Utilities.getProgress(shift,
                        DRAG_LENGTH_FACTOR_START_PULLBACK, mDragLengthFactor);
                pullbackProgress = PULLBACK_INTERPOLATOR.getInterpolation(pullbackProgress);
                shift = DRAG_LENGTH_FACTOR_START_PULLBACK + pullbackProgress
                        * (DRAG_LENGTH_FACTOR_MAX_PULLBACK - DRAG_LENGTH_FACTOR_START_PULLBACK);
            }
            return shift;
        }
    }
}
+21 −0
Original line number Diff line number Diff line
@@ -28,8 +28,10 @@ import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.app.ActivityOptions;
import android.content.Intent;
import android.content.res.Configuration;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.view.View;

@@ -42,7 +44,9 @@ import com.android.launcher3.views.BaseDragLayer;
import com.android.quickstep.fallback.FallbackRecentsView;
import com.android.quickstep.fallback.RecentsRootView;
import com.android.quickstep.util.ClipAnimationHelper;
import com.android.quickstep.util.ObjectWrapper;
import com.android.quickstep.views.TaskView;
import com.android.systemui.shared.recents.model.ThumbnailData;
import com.android.systemui.shared.system.ActivityOptionsCompat;
import com.android.systemui.shared.system.RemoteAnimationAdapterCompat;
import com.android.systemui.shared.system.RemoteAnimationRunnerCompat;
@@ -54,6 +58,9 @@ import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
 */
public final class RecentsActivity extends BaseRecentsActivity {

    public static final String EXTRA_THUMBNAIL = "thumbnailData";
    public static final String EXTRA_TASK_ID = "taskID";

    private Handler mUiHandler = new Handler(Looper.getMainLooper());
    private RecentsRootView mRecentsRootView;
    private FallbackRecentsView mFallbackRecentsView;
@@ -78,6 +85,20 @@ public final class RecentsActivity extends BaseRecentsActivity {
        }
    }

    @Override
    protected void onNewIntent(Intent intent) {
        int taskID = intent.getIntExtra(EXTRA_TASK_ID, 0);
        IBinder thumbnail = intent.getExtras().getBinder(EXTRA_THUMBNAIL);
        if (taskID != 0 && thumbnail instanceof ObjectWrapper) {
            ThumbnailData thumbnailData = ((ObjectWrapper<ThumbnailData>) thumbnail).get();
            mFallbackRecentsView.showCurrentTask(taskID);
            mFallbackRecentsView.updateThumbnail(taskID, thumbnailData);
        }
        intent.removeExtra(EXTRA_TASK_ID);
        intent.removeExtra(EXTRA_THUMBNAIL);
        super.onNewIntent(intent);
    }

    @Override
    protected void onHandleConfigChanged() {
        super.onHandleConfigChanged();
+10 −59
Original line number Diff line number Diff line
@@ -43,7 +43,6 @@ import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_O

import android.animation.Animator;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.animation.TimeInterpolator;
import android.animation.ValueAnimator;
import android.annotation.TargetApi;
@@ -59,7 +58,6 @@ import android.os.Handler;
import android.os.Looper;
import android.os.SystemClock;
import android.util.Log;
import android.view.HapticFeedbackConstants;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnApplyWindowInsetsListener;
@@ -97,7 +95,7 @@ import com.android.quickstep.ActivityControlHelper.HomeAnimationFactory;
import com.android.quickstep.SysUINavigationMode.Mode;
import com.android.quickstep.inputconsumers.InputConsumer;
import com.android.quickstep.inputconsumers.OverviewInputConsumer;
import com.android.quickstep.util.ClipAnimationHelper;
import com.android.quickstep.util.ClipAnimationHelper.TargetAlphaProvider;
import com.android.quickstep.util.RectFSpringAnim;
import com.android.quickstep.util.RemoteAnimationTargetSet;
import com.android.quickstep.util.SwipeAnimationTargetSet;
@@ -112,11 +110,10 @@ import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplierCompat;
import com.android.systemui.shared.system.WindowCallbacksCompat;

import java.util.function.BiFunction;
import java.util.function.Consumer;

@TargetApi(Build.VERSION_CODES.O)
public class WindowTransformSwipeHandler<T extends BaseDraggingActivity>
public class WindowTransformSwipeHandler<T extends BaseDraggingActivity> extends BaseSwipeUpHandler
        implements SwipeAnimationListener, OnApplyWindowInsetsListener {
    private static final String TAG = WindowTransformSwipeHandler.class.getSimpleName();

@@ -220,30 +217,17 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity>
    private static final long SHELF_ANIM_DURATION = 240;
    public static final long RECENTS_ATTACH_DURATION = 300;

    // Start resisting when swiping past this factor of mTransitionDragLength.
    private static final float DRAG_LENGTH_FACTOR_START_PULLBACK = 1.4f;
    // This is how far down we can scale down, where 0f is full screen and 1f is recents.
    private static final float DRAG_LENGTH_FACTOR_MAX_PULLBACK = 1.8f;
    private static final Interpolator PULLBACK_INTERPOLATOR = DEACCEL;

    /**
     * Used as the page index for logging when we return to the last task at the end of the gesture.
     */
    private static final int LOG_NO_OP_PAGE_INDEX = -1;

    private final ClipAnimationHelper mClipAnimationHelper;
    private final ClipAnimationHelper.TransformParams mTransformParams;

    private Runnable mGestureEndCallback;
    private GestureEndTarget mGestureEndTarget;
    // Either RectFSpringAnim (if animating home) or ObjectAnimator (from mCurrentShift) otherwise
    private RunningWindowAnim mRunningWindowAnim;
    private boolean mIsShelfPeeking;
    private DeviceProfile mDp;
    // The distance needed to drag to reach the task size in recents.
    private int mTransitionDragLength;
    // How much further we can drag past recents, as a factor of mTransitionDragLength.
    private float mDragLengthFactor = 1;

    // Shift in the range of [0, 1].
    // 0 => preview snapShot is completely visible, and hotseat is completely translated down
@@ -256,7 +240,6 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity>

    private final Handler mMainThreadHandler = MAIN_THREAD_EXECUTOR.getHandler();

    private final Context mContext;
    private final ActivityControlHelper<T> mActivityControlHelper;
    private final ActivityInitListener mActivityInitListener;

@@ -294,7 +277,7 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity>
    public WindowTransformSwipeHandler(RunningTaskInfo runningTaskInfo, Context context,
            long touchTimeMs, ActivityControlHelper<T> controller, boolean continuingLastGesture,
            InputConsumerController inputConsumer) {
        mContext = context;
        super(context);
        mRunningTaskId = runningTaskInfo.id;
        mTouchTimeMs = touchTimeMs;
        mActivityControlHelper = controller;
@@ -303,8 +286,6 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity>
        mContinuingLastGesture = continuingLastGesture;
        mRecentsAnimationWrapper = new RecentsAnimationWrapper(inputConsumer,
                this::createNewInputProxyHandler);
        mClipAnimationHelper = new ClipAnimationHelper(context);
        mTransformParams = new ClipAnimationHelper.TransformParams();

        mMode = SysUINavigationMode.getMode(context);
        initStateCallbacks();
@@ -394,18 +375,6 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity>
        }
    }

    private long getFadeInDuration() {
        if (mCurrentShift.getCurrentAnimation() != null) {
            ObjectAnimator anim = mCurrentShift.getCurrentAnimation();
            long theirDuration = anim.getDuration() - anim.getCurrentPlayTime();

            // TODO: Find a better heuristic
            return Math.min(MAX_SWIPE_DURATION, Math.max(theirDuration, MIN_SWIPE_DURATION));
        } else {
            return MAX_SWIPE_DURATION;
        }
    }

    public void initWhenReady() {
        mActivityInitListener.register();
    }
@@ -583,22 +552,7 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity>

    @UiThread
    public void updateDisplacement(float displacement) {
        // We are moving in the negative x/y direction
        displacement = -displacement;
        if (displacement > mTransitionDragLength * mDragLengthFactor && mTransitionDragLength > 0) {
            mCurrentShift.updateValue(mDragLengthFactor);
        } else {
            float translation = Math.max(displacement, 0);
            float shift = mTransitionDragLength == 0 ? 0 : translation / mTransitionDragLength;
            if (shift > DRAG_LENGTH_FACTOR_START_PULLBACK) {
                float pullbackProgress = Utilities.getProgress(shift,
                        DRAG_LENGTH_FACTOR_START_PULLBACK, mDragLengthFactor);
                pullbackProgress = PULLBACK_INTERPOLATOR.getInterpolation(pullbackProgress);
                shift = DRAG_LENGTH_FACTOR_START_PULLBACK + pullbackProgress
                        * (DRAG_LENGTH_FACTOR_MAX_PULLBACK - DRAG_LENGTH_FACTOR_START_PULLBACK);
            }
            mCurrentShift.updateValue(shift);
        }
        mCurrentShift.updateValue(getShiftForDisplacement(displacement));
    }

    public void onMotionPauseChanged(boolean isPaused) {
@@ -666,9 +620,8 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity>
        if (mIsShelfPeeking != wasShelfPeeking) {
            maybeUpdateRecentsAttachedState();
        }
        if (mRecentsView != null && shelfState.shouldPreformHaptic) {
            mRecentsView.performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY,
                    HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING);
        if (shelfState.shouldPreformHaptic) {
            performHapticFeedback();
        }
    }

@@ -722,9 +675,8 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity>
        final boolean passed = mCurrentShift.value >= MIN_PROGRESS_FOR_OVERVIEW;
        if (passed != mPassedOverviewThreshold) {
            mPassedOverviewThreshold = passed;
            if (mRecentsView != null && mMode != Mode.NO_BUTTON) {
                mRecentsView.performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY,
                    HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING);
            if (mMode != Mode.NO_BUTTON) {
                performHapticFeedback();
            }
        }

@@ -1450,13 +1402,12 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity>
        mGestureEndCallback = gestureEndCallback;
    }

    private void setTargetAlphaProvider(
            BiFunction<RemoteAnimationTargetCompat, Float, Float> provider) {
    private void setTargetAlphaProvider(TargetAlphaProvider provider) {
        mClipAnimationHelper.setTaskAlphaCallback(provider);
        updateFinalShift();
    }

    public static float getHiddenTargetAlpha(RemoteAnimationTargetCompat app, Float expectedAlpha) {
    public static float getHiddenTargetAlpha(RemoteAnimationTargetCompat app, float expectedAlpha) {
        if (!isNotInRecents(app)) {
            return 0;
        }
+134 −69

File changed.

Preview size limit exceeded, changes collapsed.

Loading