diff --git a/protos/launcher_atom.proto b/protos/launcher_atom.proto index 5f5fab0f8c..d552daff43 100644 --- a/protos/launcher_atom.proto +++ b/protos/launcher_atom.proto @@ -51,6 +51,7 @@ message ContainerInfo { WidgetsContainer widgets_container = 5; PredictionContainer prediction_container = 6; SearchResultContainer search_result_container = 7; + ShortcutsContainer shortcuts_container = 8; } } @@ -69,6 +70,11 @@ message PredictionContainer { message SearchResultContainer { } +// Container for package specific shortcuts to deep links and notifications. +// Typically shown as popup window by longpressing on an icon. +message ShortcutsContainer { +} + enum Origin { UNKNOWN = 0; DEFAULT_LAYOUT = 1; // icon automatically placed in workspace, folder, hotseat diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/hybridhotseat/HotseatEduController.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/hybridhotseat/HotseatEduController.java index e4d0adf0c0..7c4f3ecd01 100644 --- a/quickstep/recents_ui_overrides/src/com/android/launcher3/hybridhotseat/HotseatEduController.java +++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/hybridhotseat/HotseatEduController.java @@ -15,17 +15,9 @@ */ package com.android.launcher3.hybridhotseat; -import android.app.Notification; -import android.app.NotificationChannel; -import android.app.NotificationManager; -import android.app.PendingIntent; import android.content.Intent; -import android.content.res.Configuration; -import android.os.Build; import android.view.View; -import androidx.core.app.NotificationCompat; - import com.android.launcher3.CellLayout; import com.android.launcher3.Hotseat; import com.android.launcher3.InvariantDeviceProfile; @@ -37,11 +29,8 @@ import com.android.launcher3.config.FeatureFlags; import com.android.launcher3.model.data.FolderInfo; import com.android.launcher3.model.data.ItemInfo; import com.android.launcher3.model.data.WorkspaceItemInfo; -import com.android.launcher3.uioverrides.QuickstepLauncher; -import com.android.launcher3.util.ActivityTracker; import com.android.launcher3.util.GridOccupancy; import com.android.launcher3.util.IntArray; -import com.android.launcher3.util.Themes; import com.android.launcher3.views.ArrowTipView; import com.android.launcher3.views.Snackbar; @@ -54,18 +43,15 @@ import java.util.stream.IntStream; * Controller class for managing user onboaridng flow for hybrid hotseat */ public class HotseatEduController { + public static final String KEY_HOTSEAT_EDU_SEEN = "hotseat_edu_seen"; - - private static final String NOTIFICATION_CHANNEL_ID = "launcher_onboarding"; - private static final int ONBOARDING_NOTIFICATION_ID = 7641; - + public static final String HOTSEAT_EDU_ACTION = + "com.android.launcher3.action.SHOW_HYBRID_HOTSEAT_EDU"; private static final String SETTINGS_ACTION = "android.settings.ACTION_CONTENT_SUGGESTIONS_SETTINGS"; private final Launcher mLauncher; private final Hotseat mHotseat; - private final NotificationManager mNotificationManager; - private final Notification mNotification; private List mPredictedApps; private HotseatEduDialog mActiveDialog; @@ -77,9 +63,6 @@ public class HotseatEduController { mLauncher = launcher; mHotseat = launcher.getHotseat(); mOnOnboardingComplete = runnable; - mNotificationManager = mLauncher.getSystemService(NotificationManager.class); - createNotificationChannel(); - mNotification = createNotification(); } /** @@ -216,11 +199,6 @@ public class HotseatEduController { return pageId; } - - void removeNotification() { - mNotificationManager.cancel(ONBOARDING_NOTIFICATION_ID); - } - void moveHotseatItems() { mHotseat.removeAllViewsInLayout(); if (!mNewItems.isEmpty()) { @@ -258,45 +236,9 @@ public class HotseatEduController { void setPredictedApps(List predictedApps) { mPredictedApps = predictedApps; - if (!mPredictedApps.isEmpty() - && mLauncher.getOrientation() == Configuration.ORIENTATION_PORTRAIT) { - mNotificationManager.notify(ONBOARDING_NOTIFICATION_ID, mNotification); - } - else { - removeNotification(); - } - } - - private void createNotificationChannel() { - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) return; - CharSequence name = mLauncher.getString(R.string.hotseat_edu_prompt_title); - int importance = NotificationManager.IMPORTANCE_LOW; - NotificationChannel channel = new NotificationChannel(NOTIFICATION_CHANNEL_ID, name, - importance); - mNotificationManager.createNotificationChannel(channel); - } - - private Notification createNotification() { - Intent intent = new Intent(mLauncher.getApplicationContext(), mLauncher.getClass()); - intent = new NotificationHandler().addToIntent(intent); - - CharSequence name = mLauncher.getString(R.string.hotseat_edu_prompt_title); - String description = mLauncher.getString(R.string.hotseat_edu_prompt_content); - NotificationCompat.Builder builder = new NotificationCompat.Builder(mLauncher, - NOTIFICATION_CHANNEL_ID) - .setContentTitle(name) - .setOngoing(true) - .setColor(Themes.getColorAccent(mLauncher)) - .setContentIntent(PendingIntent.getActivity(mLauncher, 0, intent, - PendingIntent.FLAG_CANCEL_CURRENT)) - .setSmallIcon(R.drawable.hotseat_edu_notification_icon) - .setContentText(description); - return builder.build(); - } void destroy() { - removeNotification(); if (mActiveDialog != null) { mActiveDialog.setHotseatEduController(null); } @@ -334,14 +276,5 @@ public class HotseatEduController { mActiveDialog.setHotseatEduController(this); mActiveDialog.show(mPredictedApps); } - - static class NotificationHandler implements - ActivityTracker.SchedulerCallback { - @Override - public boolean init(QuickstepLauncher activity, boolean alreadyOnHome) { - activity.getHotseatPredictionController().showEdu(); - return true; - } - } } diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/hybridhotseat/HotseatPredictionController.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/hybridhotseat/HotseatPredictionController.java index e2acf9358d..05bcb57adc 100644 --- a/quickstep/recents_ui_overrides/src/com/android/launcher3/hybridhotseat/HotseatPredictionController.java +++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/hybridhotseat/HotseatPredictionController.java @@ -41,7 +41,6 @@ import com.android.launcher3.InvariantDeviceProfile; import com.android.launcher3.Launcher; import com.android.launcher3.LauncherAppState; import com.android.launcher3.LauncherSettings; -import com.android.launcher3.LauncherState; import com.android.launcher3.R; import com.android.launcher3.Utilities; import com.android.launcher3.allapps.AllAppsStore; @@ -148,8 +147,7 @@ public class HotseatPredictionController implements DragController.DragListener, */ public void showEdu() { if (mHotseatEduController == null) return; - mLauncher.getStateManager().goToState(LauncherState.NORMAL, true, - () -> mHotseatEduController.showEdu()); + mHotseatEduController.showEdu(); } @Override diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/QuickstepLauncher.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/QuickstepLauncher.java index 1dc5be6141..39e0f88c40 100644 --- a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/QuickstepLauncher.java +++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/QuickstepLauncher.java @@ -44,6 +44,7 @@ import com.android.launcher3.allapps.DiscoveryBounce; import com.android.launcher3.anim.AnimatorPlaybackController; import com.android.launcher3.config.FeatureFlags; import com.android.launcher3.folder.Folder; +import com.android.launcher3.hybridhotseat.HotseatEduController; import com.android.launcher3.hybridhotseat.HotseatPredictionController; import com.android.launcher3.model.data.AppInfo; import com.android.launcher3.model.data.ItemInfo; @@ -98,6 +99,20 @@ public class QuickstepLauncher extends BaseQuickstepLauncher { } } + @Override + protected void onNewIntent(Intent intent) { + super.onNewIntent(intent); + if (HotseatEduController.HOTSEAT_EDU_ACTION.equals(intent.getAction()) + && mHotseatPredictionController != null) { + boolean alreadyOnHome = hasWindowFocus() && ((intent.getFlags() + & Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT) + != Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT); + getStateManager().goToState(NORMAL, alreadyOnHome, () -> { + mHotseatPredictionController.showEdu(); + }); + } + } + @Override public void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/QuickstepAtomicAnimationFactory.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/QuickstepAtomicAnimationFactory.java index 94c7771513..a487869316 100644 --- a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/QuickstepAtomicAnimationFactory.java +++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/QuickstepAtomicAnimationFactory.java @@ -29,6 +29,7 @@ import static com.android.launcher3.anim.Interpolators.DEACCEL; import static com.android.launcher3.anim.Interpolators.DEACCEL_1_7; import static com.android.launcher3.anim.Interpolators.DEACCEL_3; import static com.android.launcher3.anim.Interpolators.FAST_OUT_SLOW_IN; +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.OVERSHOOT_1_2; @@ -188,7 +189,7 @@ public class QuickstepAtomicAnimationFactory extends } } else if (toState == NORMAL && fromState == OVERVIEW_PEEK) { // Keep fully visible until the very end (when overview is offscreen) to make invisible. - config.setInterpolator(ANIM_OVERVIEW_FADE, t -> t < 1 ? 0 : 1); + config.setInterpolator(ANIM_OVERVIEW_FADE, FINAL_FRAME); } else if (toState == OVERVIEW_PEEK && fromState == NORMAL) { config.setInterpolator(ANIM_OVERVIEW_FADE, INSTANT); config.setInterpolator(ANIM_OVERVIEW_TRANSLATE_X, OVERSHOOT_1_7); 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 bf0690c77d..39bbfb93bc 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 @@ -116,8 +116,7 @@ public class NavBarToHomeTouchController implements TouchController, if (TestProtocol.sDebugTracing) { Log.d(TestProtocol.PAUSE_NOT_DETECTED, "NavBarToHomeTouchController.canInterceptTouch true 2 " - + AbstractFloatingView.getTopOpenView(mLauncher).getClass() - .getSimpleName()); + + AbstractFloatingView.getTopOpenView(mLauncher), new Exception()); } return true; } diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/BaseSwipeUpHandler.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/BaseSwipeUpHandler.java index 5b396dd547..737d837ac7 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/BaseSwipeUpHandler.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/BaseSwipeUpHandler.java @@ -15,57 +15,38 @@ */ package com.android.quickstep; -import static com.android.launcher3.anim.Interpolators.ACCEL_1_5; -import static com.android.launcher3.anim.Interpolators.DEACCEL; import static com.android.launcher3.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TILE; import static com.android.launcher3.util.Executors.MAIN_EXECUTOR; import static com.android.launcher3.util.VibratorWrapper.OVERVIEW_HAPTIC; -import static com.android.launcher3.views.FloatingIconView.SHAPE_PROGRESS_DURATION; -import android.animation.Animator; import android.annotation.TargetApi; import android.content.Context; import android.content.Intent; -import android.graphics.Matrix; -import android.graphics.Matrix.ScaleToFit; import android.graphics.PointF; import android.graphics.Rect; -import android.graphics.RectF; import android.os.Build; import android.util.Log; import android.view.MotionEvent; -import android.view.animation.Interpolator; import androidx.annotation.CallSuper; -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; import androidx.annotation.UiThread; import com.android.launcher3.DeviceProfile; import com.android.launcher3.InvariantDeviceProfile; -import com.android.launcher3.Utilities; -import com.android.launcher3.anim.AnimationSuccessListener; -import com.android.launcher3.anim.AnimatorPlaybackController; -import com.android.launcher3.anim.PendingAnimation; import com.android.launcher3.statemanager.StatefulActivity; import com.android.launcher3.testing.TestProtocol; -import com.android.launcher3.touch.PagedOrientationHandler; import com.android.launcher3.util.VibratorWrapper; -import com.android.launcher3.views.FloatingIconView; +import com.android.launcher3.util.WindowBounds; import com.android.quickstep.RecentsAnimationCallbacks.RecentsAnimationListener; import com.android.quickstep.util.ActiveGestureLog; import com.android.quickstep.util.ActivityInitListener; -import com.android.quickstep.util.RectFSpringAnim; -import com.android.quickstep.util.TaskViewSimulator; import com.android.quickstep.util.TransformParams; -import com.android.quickstep.util.TransformParams.BuilderProxy; import com.android.quickstep.views.RecentsView; import com.android.quickstep.views.TaskView; import com.android.systemui.shared.recents.model.ThumbnailData; import com.android.systemui.shared.system.InputConsumerController; import com.android.systemui.shared.system.RemoteAnimationTargetCompat; import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplierCompat; -import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplierCompat.SurfaceParams.Builder; import java.util.ArrayList; import java.util.function.Consumer; @@ -75,40 +56,13 @@ import java.util.function.Consumer; */ @TargetApi(Build.VERSION_CODES.Q) public abstract class BaseSwipeUpHandler, Q extends RecentsView> - implements RecentsAnimationListener { + extends SwipeUpAnimationLogic implements RecentsAnimationListener { private static final String TAG = "BaseSwipeUpHandler"; - protected static final Rect TEMP_RECT = new Rect(); - public static final float MIN_PROGRESS_FOR_OVERVIEW = 0.7f; - 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; - // Start resisting when swiping past this factor of mTransitionDragLength. - private float mDragLengthFactorStartPullback = 1f; - // This is how far down we can scale down, where 0f is full screen and 1f is recents. - private float mDragLengthFactorMaxPullback = 1f; - - protected final Context mContext; - protected final RecentsAnimationDeviceState mDeviceState; - protected final GestureState mGestureState; protected final BaseActivityInterface mActivityInterface; protected final InputConsumerController mInputConsumer; - protected final TaskViewSimulator mTaskViewSimulator; - private AnimatorPlaybackController mWindowTransitionController; - - protected final TransformParams mTransformParams = new TransformParams(); - - // 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. - protected final AnimatedFloat mCurrentShift = new AnimatedFloat(this::updateFinalShift); - protected final ActivityInitListener mActivityInitListener; protected RecentsAnimationController mRecentsAnimationController; @@ -119,7 +73,6 @@ public abstract class BaseSwipeUpHandler, Q extend protected T mActivity; protected Q mRecentsView; - protected DeviceProfile mDp; protected Runnable mGestureEndCallback; @@ -131,13 +84,10 @@ public abstract class BaseSwipeUpHandler, Q extend protected BaseSwipeUpHandler(Context context, RecentsAnimationDeviceState deviceState, GestureState gestureState, InputConsumerController inputConsumer) { - mContext = context; - mDeviceState = deviceState; - mGestureState = gestureState; + super(context, deviceState, gestureState, new TransformParams()); mActivityInterface = gestureState.getActivityInterface(); mActivityInitListener = mActivityInterface.createActivityInitListener(this::onActivityInit); mInputConsumer = inputConsumer; - mTaskViewSimulator = new TaskViewSimulator(context, gestureState.getActivityInterface()); } /** @@ -157,28 +107,6 @@ public abstract class BaseSwipeUpHandler, Q extend return mRecentsView != null ? mRecentsView.getEventDispatcher(navbarRotation) : null; } - @UiThread - public void updateDisplacement(float displacement) { - // We are moving in the negative x/y direction - displacement = -displacement; - float shift; - if (displacement > mTransitionDragLength * mDragLengthFactor && mTransitionDragLength > 0) { - shift = mDragLengthFactor; - } else { - float translation = Math.max(displacement, 0); - shift = mTransitionDragLength == 0 ? 0 : translation / mTransitionDragLength; - if (shift > mDragLengthFactorStartPullback) { - float pullbackProgress = Utilities.getProgress(shift, - mDragLengthFactorStartPullback, mDragLengthFactor); - pullbackProgress = PULLBACK_INTERPOLATOR.getInterpolation(pullbackProgress); - shift = mDragLengthFactorStartPullback + pullbackProgress - * (mDragLengthFactorMaxPullback - mDragLengthFactorStartPullback); - } - } - - mCurrentShift.updateValue(shift); - } - public void setGestureEndCallback(Runnable gestureEndCallback) { mGestureEndCallback = gestureEndCallback; } @@ -275,6 +203,7 @@ public abstract class BaseSwipeUpHandler, Q extend RecentsAnimationTargets targets) { mRecentsAnimationController = recentsAnimationController; mRecentsAnimationTargets = targets; + mTransformParams.setTargetSet(mRecentsAnimationTargets); DeviceProfile dp = InvariantDeviceProfile.INSTANCE.get(mContext).getDeviceProfile(mContext); RemoteAnimationTargetCompat runningTaskTarget = targets.findTask( mGestureState.getRunningTaskId()); @@ -282,7 +211,8 @@ public abstract class BaseSwipeUpHandler, Q extend if (targets.minimizedHomeBounds != null && runningTaskTarget != null) { Rect overviewStackBounds = mActivityInterface .getOverviewWindowBounds(targets.minimizedHomeBounds, runningTaskTarget); - dp = dp.getMultiWindowProfile(mContext, overviewStackBounds); + dp = dp.getMultiWindowProfile(mContext, + new WindowBounds(overviewStackBounds, targets.homeContentInsets)); } else { // If we are not in multi-window mode, home insets should be same as system insets. dp = dp.copy(mContext); @@ -355,35 +285,6 @@ public abstract class BaseSwipeUpHandler, Q extend return mGestureState.getLastStartedTaskId() != -1; } - protected void initTransitionEndpoints(DeviceProfile dp) { - mDp = dp; - - mTaskViewSimulator.setDp(dp); - mTaskViewSimulator.setLayoutRotation( - mDeviceState.getCurrentActiveRotation(), - mDeviceState.getDisplayRotation()); - mTransitionDragLength = mActivityInterface.getSwipeUpDestinationAndLength( - dp, mContext, TEMP_RECT, - mTaskViewSimulator.getOrientationState().getOrientationHandler()); - - if (mDeviceState.isFullyGesturalNavMode()) { - // We can drag all the way to the top of the screen. - mDragLengthFactor = (float) dp.heightPx / mTransitionDragLength; - - float startScale = mTaskViewSimulator.getFullScreenScale(); - // Start pulling back when RecentsView scale is 0.75f, and let it go down to 0.5f. - mDragLengthFactorStartPullback = (0.75f - startScale) / (1 - startScale); - mDragLengthFactorMaxPullback = (0.5f - startScale) / (1 - startScale); - } else { - mDragLengthFactor = 1; - mDragLengthFactorStartPullback = mDragLengthFactorMaxPullback = 1; - } - - PendingAnimation pa = new PendingAnimation(mTransitionDragLength * 2); - mTaskViewSimulator.addAppToOverviewAnim(pa, t -> t * mDragLengthFactor); - mWindowTransitionController = pa.createPlaybackController(); - } - /** * Return true if the window should be translated horizontally if the recents view scrolls */ @@ -455,7 +356,6 @@ public abstract class BaseSwipeUpHandler, Q extend if (mWindowTransitionController != null) { float progress = mCurrentShift.value / mDragLengthFactor; mWindowTransitionController.setPlayFraction(progress); - mTransformParams.setTargetSet(mRecentsAnimationTargets); if (mRecentsViewScrollLinked) { mTaskViewSimulator.setScroll(mRecentsView.getScrollOffset()); @@ -464,217 +364,9 @@ public abstract class BaseSwipeUpHandler, Q extend } } - protected PagedOrientationHandler getOrientationHandler() { - return mTaskViewSimulator.getOrientationState().getOrientationHandler(); - } - - /** - * Creates an animation that transforms the current app window into the home app. - * @param startProgress The progress of {@link #mCurrentShift} to start the window from. - * @param homeAnimationFactory The home animation factory. - */ - protected RectFSpringAnim createWindowAnimationToHome(float startProgress, - HomeAnimationFactory homeAnimationFactory) { - final RectF targetRect = homeAnimationFactory.getWindowTargetRect(); - final FloatingIconView fiv = homeAnimationFactory.mIconView; - final boolean isFloatingIconView = fiv != null; - - mWindowTransitionController.setPlayFraction(startProgress / mDragLengthFactor); - mTaskViewSimulator.apply(mTransformParams - .setProgress(startProgress) - .setTargetSet(mRecentsAnimationTargets)); - RectF cropRectF = new RectF(mTaskViewSimulator.getCurrentCropRect()); - - // Matrix to map a rect in Launcher space to window space - Matrix homeToWindowPositionMap = new Matrix(); - mTaskViewSimulator.applyWindowToHomeRotation(homeToWindowPositionMap); - - final RectF startRect = new RectF(cropRectF); - mTaskViewSimulator.getCurrentMatrix().mapRect(startRect); - // Move the startRect to Launcher space as floatingIconView runs in Launcher - Matrix windowToHomePositionMap = new Matrix(); - homeToWindowPositionMap.invert(windowToHomePositionMap); - windowToHomePositionMap.mapRect(startRect); - - RectFSpringAnim anim = new RectFSpringAnim(startRect, targetRect, mContext); - if (isFloatingIconView) { - anim.addAnimatorListener(fiv); - fiv.setOnTargetChangeListener(anim::onTargetPositionChanged); - fiv.setFastFinishRunnable(anim::end); - } - - SpringAnimationRunner runner = new SpringAnimationRunner( - homeAnimationFactory, cropRectF, homeToWindowPositionMap); - anim.addOnUpdateListener(runner); - anim.addAnimatorListener(runner); - return anim; - } - public interface Factory { BaseSwipeUpHandler newHandler( GestureState gestureState, long touchTimeMs, boolean continuingLastGesture); } - - protected interface RunningWindowAnim { - void end(); - - void cancel(); - - static RunningWindowAnim wrap(Animator animator) { - return new RunningWindowAnim() { - @Override - public void end() { - animator.end(); - } - - @Override - public void cancel() { - animator.cancel(); - } - }; - } - - static RunningWindowAnim wrap(RectFSpringAnim rectFSpringAnim) { - return new RunningWindowAnim() { - @Override - public void end() { - rectFSpringAnim.end(); - } - - @Override - public void cancel() { - rectFSpringAnim.cancel(); - } - }; - } - } - - /** - * @param progress The progress of the animation to the home screen. - * @return The current alpha to set on the animating app window. - */ - protected float getWindowAlpha(float progress) { - // Alpha interpolates between [1, 0] between progress values [start, end] - final float start = 0f; - final float end = 0.85f; - - if (progress <= start) { - return 1f; - } - if (progress >= end) { - return 0f; - } - return Utilities.mapToRange(progress, start, end, 1, 0, ACCEL_1_5); - } - - protected abstract class HomeAnimationFactory { - - private FloatingIconView mIconView; - - public HomeAnimationFactory(@Nullable FloatingIconView iconView) { - mIconView = iconView; - } - - public @NonNull RectF getWindowTargetRect() { - PagedOrientationHandler orientationHandler = getOrientationHandler(); - DeviceProfile dp = mDp; - final int halfIconSize = dp.iconSizePx / 2; - float primaryDimension = orientationHandler - .getPrimaryValue(dp.availableWidthPx, dp.availableHeightPx); - float secondaryDimension = orientationHandler - .getSecondaryValue(dp.availableWidthPx, dp.availableHeightPx); - final float targetX = primaryDimension / 2f; - final float targetY = secondaryDimension - dp.hotseatBarSizePx; - // Fallback to animate to center of screen. - return new RectF(targetX - halfIconSize, targetY - halfIconSize, - targetX + halfIconSize, targetY + halfIconSize); - } - - public abstract @NonNull AnimatorPlaybackController createActivityAnimationToHome(); - - public void playAtomicAnimation(float velocity) { - // No-op - } - } - - private class SpringAnimationRunner extends AnimationSuccessListener - implements RectFSpringAnim.OnUpdateListener, BuilderProxy { - - final Rect mCropRect = new Rect(); - final Matrix mMatrix = new Matrix(); - - final RectF mWindowCurrentRect = new RectF(); - final Matrix mHomeToWindowPositionMap; - - final FloatingIconView mFIV; - final AnimatorPlaybackController mHomeAnim; - final RectF mCropRectF; - - final float mStartRadius; - final float mEndRadius; - final float mWindowAlphaThreshold; - - SpringAnimationRunner(HomeAnimationFactory factory, RectF cropRectF, - Matrix homeToWindowPositionMap) { - mHomeAnim = factory.createActivityAnimationToHome(); - mCropRectF = cropRectF; - mHomeToWindowPositionMap = homeToWindowPositionMap; - - cropRectF.roundOut(mCropRect); - mFIV = factory.mIconView; - - // End on a "round-enough" radius so that the shape reveal doesn't have to do too much - // rounding at the end of the animation. - mStartRadius = mTaskViewSimulator.getCurrentCornerRadius(); - mEndRadius = cropRectF.width() / 2f; - - // We want the window alpha to be 0 once this threshold is met, so that the - // FolderIconView can be seen morphing into the icon shape. - mWindowAlphaThreshold = mFIV != null ? 1f - SHAPE_PROGRESS_DURATION : 1f; - } - - @Override - public void onUpdate(RectF currentRect, float progress) { - mHomeAnim.setPlayFraction(progress); - mHomeToWindowPositionMap.mapRect(mWindowCurrentRect, currentRect); - - mMatrix.setRectToRect(mCropRectF, mWindowCurrentRect, ScaleToFit.FILL); - float cornerRadius = Utilities.mapRange(progress, mStartRadius, mEndRadius); - mTransformParams - .setTargetAlpha(getWindowAlpha(progress)) - .setCornerRadius(cornerRadius); - - mTransformParams.applySurfaceParams(mTransformParams.createSurfaceParams(this)); - if (mFIV != null) { - mFIV.update(currentRect, 1f, progress, - mWindowAlphaThreshold, mMatrix.mapRadius(cornerRadius), false); - } - } - - @Override - public void onBuildTargetParams( - Builder builder, RemoteAnimationTargetCompat app, TransformParams params) { - builder.withMatrix(mMatrix) - .withWindowCrop(mCropRect) - .withCornerRadius(params.getCornerRadius()); - } - - @Override - public void onCancel() { - if (mFIV != null) { - mFIV.fastFinish(); - } - } - - @Override - public void onAnimationStart(Animator animation) { - mHomeAnim.dispatchOnStart(); - } - - @Override - public void onAnimationSuccess(Animator animator) { - mHomeAnim.getAnimationPlayer().end(); - } - } } diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/BaseSwipeUpHandlerV2.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/BaseSwipeUpHandlerV2.java index 46799ff272..92e10b14f9 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/BaseSwipeUpHandlerV2.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/BaseSwipeUpHandlerV2.java @@ -29,6 +29,7 @@ import static com.android.quickstep.GestureState.GestureEndTarget.LAST_TASK; import static com.android.quickstep.GestureState.GestureEndTarget.NEW_TASK; import static com.android.quickstep.GestureState.GestureEndTarget.RECENTS; import static com.android.quickstep.GestureState.STATE_END_TARGET_ANIMATION_FINISHED; +import static com.android.quickstep.GestureState.STATE_END_TARGET_SET; import static com.android.quickstep.GestureState.STATE_RECENTS_SCROLLING_FINISHED; import static com.android.quickstep.MultiStateCallback.DEBUG_STATES; import static com.android.quickstep.SysUINavigationMode.Mode.TWO_BUTTONS; @@ -253,6 +254,10 @@ public abstract class BaseSwipeUpHandlerV2, Q exte mStateCallback.runOnceAtState(STATE_HANDLER_INVALIDATED | STATE_RESUME_LAST_TASK, this::notifyTransitionCancelled); + mGestureState.runOnceAtState(STATE_END_TARGET_SET, + () -> mDeviceState.onEndTargetCalculated(mGestureState.getEndTarget(), + mActivityInterface)); + if (!ENABLE_QUICKSTEP_LIVE_TILE.get()) { mStateCallback.addChangeListener(STATE_APP_CONTROLLER_RECEIVED | STATE_LAUNCHER_PRESENT | STATE_SCREENSHOT_VIEW_SHOWN | STATE_CAPTURE_SCREENSHOT, @@ -1035,7 +1040,7 @@ public abstract class BaseSwipeUpHandlerV2, Q exte } // Make sure recents is in its final state maybeUpdateRecentsAttachedState(false); - mActivityInterface.onSwipeUpToHomeComplete(); + mActivityInterface.onSwipeUpToHomeComplete(mDeviceState); } }); return anim; @@ -1232,7 +1237,6 @@ public abstract class BaseSwipeUpHandlerV2, Q exte } ActiveGestureLog.INSTANCE.addLog("finishRecentsAnimation", true); doLogGesture(HOME); - mDeviceState.enableMultipleRegions(false); } protected abstract void finishRecentsControllerToHome(Runnable callback); @@ -1248,7 +1252,6 @@ public abstract class BaseSwipeUpHandlerV2, Q exte SystemUiProxy.INSTANCE.get(mContext).onOverviewShown(false, TAG); doLogGesture(RECENTS); - mDeviceState.onSwipeUpToOverview(mActivityInterface); reset(); } diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/FallbackActivityInterface.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/FallbackActivityInterface.java index c9ff88409a..70be3ab8af 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/FallbackActivityInterface.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/FallbackActivityInterface.java @@ -69,7 +69,7 @@ public final class FallbackActivityInterface extends /** 4 */ @Override - public void onSwipeUpToHomeComplete() { + public void onSwipeUpToHomeComplete(RecentsAnimationDeviceState deviceState) { onSwipeUpToRecentsComplete(); } diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityInterface.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityInterface.java index 13b84e036e..62eb235251 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityInterface.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityInterface.java @@ -96,7 +96,7 @@ public final class LauncherActivityInterface extends } @Override - public void onSwipeUpToHomeComplete() { + public void onSwipeUpToHomeComplete(RecentsAnimationDeviceState deviceState) { Launcher launcher = getCreatedActivity(); if (launcher == null) { return; @@ -105,6 +105,7 @@ public final class LauncherActivityInterface extends // recents, we assume the first task is invisible, making translation off by one task. launcher.getStateManager().reapplyState(); launcher.getRootView().setForceHideBackArrow(false); + notifyRecentsOfOrientation(deviceState); } @Override @@ -235,17 +236,20 @@ public final class LauncherActivityInterface extends // Are we going from Recents to Workspace? if (toState == LauncherState.NORMAL) { exitRunnable.run(); - - // reset layout on swipe to home - RecentsView recentsView = getCreatedActivity().getOverviewPanel(); - recentsView.setLayoutRotation(deviceState.getCurrentActiveRotation(), - deviceState.getDisplayRotation()); + notifyRecentsOfOrientation(deviceState); stateManager.removeStateListener(this); } } }); } + private void notifyRecentsOfOrientation(RecentsAnimationDeviceState deviceState) { + // reset layout on swipe to home + RecentsView recentsView = getCreatedActivity().getOverviewPanel(); + recentsView.setLayoutRotation(deviceState.getCurrentActiveRotation(), + deviceState.getDisplayRotation()); + } + @Override public Rect getOverviewWindowBounds(Rect homeBounds, RemoteAnimationTargetCompat target) { return homeBounds; diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/QuickstepTestInformationHandler.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/QuickstepTestInformationHandler.java index 0d49b2b500..a28dabc6a3 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/QuickstepTestInformationHandler.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/QuickstepTestInformationHandler.java @@ -79,12 +79,13 @@ public class QuickstepTestInformationHandler extends TestInformationHandler { @Override protected Activity getCurrentActivity() { - OverviewComponentObserver observer = new OverviewComponentObserver(mContext, - new RecentsAnimationDeviceState(mContext)); + RecentsAnimationDeviceState rads = new RecentsAnimationDeviceState(mContext); + OverviewComponentObserver observer = new OverviewComponentObserver(mContext, rads); try { return observer.getActivityInterface().getCreatedActivity(); } finally { observer.onDestroy(); + rads.destroy(); } } diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/SwipeUpAnimationLogic.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/SwipeUpAnimationLogic.java new file mode 100644 index 0000000000..b17730ba6d --- /dev/null +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/SwipeUpAnimationLogic.java @@ -0,0 +1,350 @@ +/* + * Copyright (C) 2020 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 com.android.launcher3.anim.Interpolators.ACCEL_1_5; +import static com.android.launcher3.anim.Interpolators.DEACCEL; +import static com.android.launcher3.views.FloatingIconView.SHAPE_PROGRESS_DURATION; + +import android.animation.Animator; +import android.content.Context; +import android.graphics.Matrix; +import android.graphics.Matrix.ScaleToFit; +import android.graphics.Rect; +import android.graphics.RectF; +import android.view.animation.Interpolator; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.annotation.UiThread; + +import com.android.launcher3.DeviceProfile; +import com.android.launcher3.Utilities; +import com.android.launcher3.anim.AnimationSuccessListener; +import com.android.launcher3.anim.AnimatorPlaybackController; +import com.android.launcher3.anim.PendingAnimation; +import com.android.launcher3.touch.PagedOrientationHandler; +import com.android.launcher3.views.FloatingIconView; +import com.android.quickstep.util.RectFSpringAnim; +import com.android.quickstep.util.TaskViewSimulator; +import com.android.quickstep.util.TransformParams; +import com.android.quickstep.util.TransformParams.BuilderProxy; +import com.android.systemui.shared.system.RemoteAnimationTargetCompat; +import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplierCompat.SurfaceParams.Builder; + +public abstract class SwipeUpAnimationLogic { + + protected static final Rect TEMP_RECT = new Rect(); + private static final Interpolator PULLBACK_INTERPOLATOR = DEACCEL; + + protected DeviceProfile mDp; + + protected final Context mContext; + protected final RecentsAnimationDeviceState mDeviceState; + protected final GestureState mGestureState; + protected final TaskViewSimulator mTaskViewSimulator; + + protected final TransformParams mTransformParams; + + // 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. + protected final AnimatedFloat mCurrentShift = new AnimatedFloat(this::updateFinalShift); + + // 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; + // Start resisting when swiping past this factor of mTransitionDragLength. + private float mDragLengthFactorStartPullback = 1f; + // This is how far down we can scale down, where 0f is full screen and 1f is recents. + private float mDragLengthFactorMaxPullback = 1f; + + protected AnimatorPlaybackController mWindowTransitionController; + + public SwipeUpAnimationLogic(Context context, RecentsAnimationDeviceState deviceState, + GestureState gestureState, TransformParams transformParams) { + mContext = context; + mDeviceState = deviceState; + mGestureState = gestureState; + mTaskViewSimulator = new TaskViewSimulator(context, gestureState.getActivityInterface()); + mTransformParams = transformParams; + } + + protected void initTransitionEndpoints(DeviceProfile dp) { + mDp = dp; + + mTaskViewSimulator.setDp(dp); + mTaskViewSimulator.setLayoutRotation( + mDeviceState.getCurrentActiveRotation(), + mDeviceState.getDisplayRotation()); + mTransitionDragLength = mGestureState.getActivityInterface().getSwipeUpDestinationAndLength( + dp, mContext, TEMP_RECT, + mTaskViewSimulator.getOrientationState().getOrientationHandler()); + + if (mDeviceState.isFullyGesturalNavMode()) { + // We can drag all the way to the top of the screen. + mDragLengthFactor = (float) dp.heightPx / mTransitionDragLength; + + float startScale = mTaskViewSimulator.getFullScreenScale(); + // Start pulling back when RecentsView scale is 0.75f, and let it go down to 0.5f. + mDragLengthFactorStartPullback = (0.75f - startScale) / (1 - startScale); + mDragLengthFactorMaxPullback = (0.5f - startScale) / (1 - startScale); + } else { + mDragLengthFactor = 1; + mDragLengthFactorStartPullback = mDragLengthFactorMaxPullback = 1; + } + + PendingAnimation pa = new PendingAnimation(mTransitionDragLength * 2); + mTaskViewSimulator.addAppToOverviewAnim(pa, t -> t * mDragLengthFactor); + mWindowTransitionController = pa.createPlaybackController(); + } + + @UiThread + public void updateDisplacement(float displacement) { + // We are moving in the negative x/y direction + displacement = -displacement; + float shift; + if (displacement > mTransitionDragLength * mDragLengthFactor && mTransitionDragLength > 0) { + shift = mDragLengthFactor; + } else { + float translation = Math.max(displacement, 0); + shift = mTransitionDragLength == 0 ? 0 : translation / mTransitionDragLength; + if (shift > mDragLengthFactorStartPullback) { + float pullbackProgress = Utilities.getProgress(shift, + mDragLengthFactorStartPullback, mDragLengthFactor); + pullbackProgress = PULLBACK_INTERPOLATOR.getInterpolation(pullbackProgress); + shift = mDragLengthFactorStartPullback + pullbackProgress + * (mDragLengthFactorMaxPullback - mDragLengthFactorStartPullback); + } + } + + mCurrentShift.updateValue(shift); + } + + /** + * Called when the value of {@link #mCurrentShift} changes + */ + @UiThread + public abstract void updateFinalShift(); + + protected PagedOrientationHandler getOrientationHandler() { + return mTaskViewSimulator.getOrientationState().getOrientationHandler(); + } + + protected abstract class HomeAnimationFactory { + + public FloatingIconView mIconView; + + public HomeAnimationFactory(@Nullable FloatingIconView iconView) { + mIconView = iconView; + } + + public @NonNull RectF getWindowTargetRect() { + PagedOrientationHandler orientationHandler = getOrientationHandler(); + DeviceProfile dp = mDp; + final int halfIconSize = dp.iconSizePx / 2; + float primaryDimension = orientationHandler + .getPrimaryValue(dp.availableWidthPx, dp.availableHeightPx); + float secondaryDimension = orientationHandler + .getSecondaryValue(dp.availableWidthPx, dp.availableHeightPx); + final float targetX = primaryDimension / 2f; + final float targetY = secondaryDimension - dp.hotseatBarSizePx; + // Fallback to animate to center of screen. + return new RectF(targetX - halfIconSize, targetY - halfIconSize, + targetX + halfIconSize, targetY + halfIconSize); + } + + public abstract @NonNull AnimatorPlaybackController createActivityAnimationToHome(); + + public void playAtomicAnimation(float velocity) { + // No-op + } + } + + /** + * Creates an animation that transforms the current app window into the home app. + * @param startProgress The progress of {@link #mCurrentShift} to start the window from. + * @param homeAnimationFactory The home animation factory. + */ + protected RectFSpringAnim createWindowAnimationToHome(float startProgress, + HomeAnimationFactory homeAnimationFactory) { + final RectF targetRect = homeAnimationFactory.getWindowTargetRect(); + final FloatingIconView fiv = homeAnimationFactory.mIconView; + final boolean isFloatingIconView = fiv != null; + + mWindowTransitionController.setPlayFraction(startProgress / mDragLengthFactor); + mTaskViewSimulator.apply(mTransformParams.setProgress(startProgress)); + RectF cropRectF = new RectF(mTaskViewSimulator.getCurrentCropRect()); + + // Matrix to map a rect in Launcher space to window space + Matrix homeToWindowPositionMap = new Matrix(); + mTaskViewSimulator.applyWindowToHomeRotation(homeToWindowPositionMap); + + final RectF startRect = new RectF(cropRectF); + mTaskViewSimulator.getCurrentMatrix().mapRect(startRect); + // Move the startRect to Launcher space as floatingIconView runs in Launcher + Matrix windowToHomePositionMap = new Matrix(); + homeToWindowPositionMap.invert(windowToHomePositionMap); + windowToHomePositionMap.mapRect(startRect); + + RectFSpringAnim anim = new RectFSpringAnim(startRect, targetRect, mContext); + if (isFloatingIconView) { + anim.addAnimatorListener(fiv); + fiv.setOnTargetChangeListener(anim::onTargetPositionChanged); + fiv.setFastFinishRunnable(anim::end); + } + + SpringAnimationRunner runner = new SpringAnimationRunner( + homeAnimationFactory, cropRectF, homeToWindowPositionMap); + anim.addOnUpdateListener(runner); + anim.addAnimatorListener(runner); + return anim; + } + + /** + * @param progress The progress of the animation to the home screen. + * @return The current alpha to set on the animating app window. + */ + protected float getWindowAlpha(float progress) { + // Alpha interpolates between [1, 0] between progress values [start, end] + final float start = 0f; + final float end = 0.85f; + + if (progress <= start) { + return 1f; + } + if (progress >= end) { + return 0f; + } + return Utilities.mapToRange(progress, start, end, 1, 0, ACCEL_1_5); + } + + protected class SpringAnimationRunner extends AnimationSuccessListener + implements RectFSpringAnim.OnUpdateListener, BuilderProxy { + + final Rect mCropRect = new Rect(); + final Matrix mMatrix = new Matrix(); + + final RectF mWindowCurrentRect = new RectF(); + final Matrix mHomeToWindowPositionMap; + + final FloatingIconView mFIV; + final AnimatorPlaybackController mHomeAnim; + final RectF mCropRectF; + + final float mStartRadius; + final float mEndRadius; + final float mWindowAlphaThreshold; + + SpringAnimationRunner(HomeAnimationFactory factory, RectF cropRectF, + Matrix homeToWindowPositionMap) { + mHomeAnim = factory.createActivityAnimationToHome(); + mCropRectF = cropRectF; + mHomeToWindowPositionMap = homeToWindowPositionMap; + + cropRectF.roundOut(mCropRect); + mFIV = factory.mIconView; + + // End on a "round-enough" radius so that the shape reveal doesn't have to do too much + // rounding at the end of the animation. + mStartRadius = mTaskViewSimulator.getCurrentCornerRadius(); + mEndRadius = cropRectF.width() / 2f; + + // We want the window alpha to be 0 once this threshold is met, so that the + // FolderIconView can be seen morphing into the icon shape. + mWindowAlphaThreshold = mFIV != null ? 1f - SHAPE_PROGRESS_DURATION : 1f; + } + + @Override + public void onUpdate(RectF currentRect, float progress) { + mHomeAnim.setPlayFraction(progress); + mHomeToWindowPositionMap.mapRect(mWindowCurrentRect, currentRect); + + mMatrix.setRectToRect(mCropRectF, mWindowCurrentRect, ScaleToFit.FILL); + float cornerRadius = Utilities.mapRange(progress, mStartRadius, mEndRadius); + mTransformParams + .setTargetAlpha(getWindowAlpha(progress)) + .setCornerRadius(cornerRadius); + + mTransformParams.applySurfaceParams(mTransformParams.createSurfaceParams(this)); + if (mFIV != null) { + mFIV.update(currentRect, 1f, progress, + mWindowAlphaThreshold, mMatrix.mapRadius(cornerRadius), false); + } + } + + @Override + public void onBuildTargetParams( + Builder builder, RemoteAnimationTargetCompat app, TransformParams params) { + builder.withMatrix(mMatrix) + .withWindowCrop(mCropRect) + .withCornerRadius(params.getCornerRadius()); + } + + @Override + public void onCancel() { + if (mFIV != null) { + mFIV.fastFinish(); + } + } + + @Override + public void onAnimationStart(Animator animation) { + mHomeAnim.dispatchOnStart(); + } + + @Override + public void onAnimationSuccess(Animator animator) { + mHomeAnim.getAnimationPlayer().end(); + } + } + + public interface RunningWindowAnim { + void end(); + + void cancel(); + + static RunningWindowAnim wrap(Animator animator) { + return new RunningWindowAnim() { + @Override + public void end() { + animator.end(); + } + + @Override + public void cancel() { + animator.cancel(); + } + }; + } + + static RunningWindowAnim wrap(RectFSpringAnim rectFSpringAnim) { + return new RunningWindowAnim() { + @Override + public void end() { + rectFSpringAnim.end(); + } + + @Override + public void cancel() { + rectFSpringAnim.cancel(); + } + }; + } + } +} diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java index c4d4ab850a..c8619bdd12 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java @@ -82,6 +82,7 @@ import com.android.quickstep.inputconsumers.OverviewInputConsumer; import com.android.quickstep.inputconsumers.OverviewWithoutFocusInputConsumer; import com.android.quickstep.inputconsumers.ResetGestureInputConsumer; import com.android.quickstep.inputconsumers.ScreenPinnedInputConsumer; +import com.android.quickstep.inputconsumers.SysUiOverlayInputConsumer; import com.android.quickstep.util.ActiveGestureLog; import com.android.quickstep.util.AssistantUtilities; import com.android.quickstep.util.ProtoTracer; @@ -595,6 +596,13 @@ public class TouchInteractionService extends Service implements PluginListenergetOverviewPanel().startHome(); } + + @Override + public void onSwipeUpCancelled() {} } diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java index 8b08ea76fe..14215a1f67 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java @@ -403,6 +403,11 @@ public class OtherActivityInputConsumer extends ContextWrapper implements InputC TraceHelper.INSTANCE.endSection(traceToken); } + @Override + public void notifyOrientationSetup() { + mDeviceState.onStartGesture(); + } + @Override public void onConsumerAboutToBeSwitched() { Preconditions.assertUIThread(); diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OverviewWithoutFocusInputConsumer.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OverviewWithoutFocusInputConsumer.java index ac1c3a8742..4440a04bea 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OverviewWithoutFocusInputConsumer.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OverviewWithoutFocusInputConsumer.java @@ -17,6 +17,7 @@ package com.android.quickstep.inputconsumers; import android.content.Context; import android.content.Intent; +import android.graphics.PointF; import android.view.MotionEvent; import com.android.launcher3.BaseActivity; @@ -33,7 +34,8 @@ import com.android.quickstep.util.ActiveGestureLog; import com.android.quickstep.util.TriggerSwipeUpTouchTracker; import com.android.systemui.shared.system.InputMonitorCompat; -public class OverviewWithoutFocusInputConsumer implements InputConsumer { +public class OverviewWithoutFocusInputConsumer implements InputConsumer, + TriggerSwipeUpTouchTracker.OnSwipeUpListener { private final Context mContext; private final InputMonitorCompat mInputMonitor; @@ -45,7 +47,7 @@ public class OverviewWithoutFocusInputConsumer implements InputConsumer { mContext = context; mInputMonitor = inputMonitor; mTriggerSwipeUpTracker = new TriggerSwipeUpTouchTracker(context, disableHorizontalSwipe, - deviceState.getNavBarPosition(), this::onInterceptTouch, this::onSwipeUp); + deviceState.getNavBarPosition(), this::onInterceptTouch, this); } @Override @@ -70,7 +72,8 @@ public class OverviewWithoutFocusInputConsumer implements InputConsumer { } } - private void onSwipeUp(boolean wasFling) { + @Override + public void onSwipeUp(boolean wasFling, PointF finalVelocity) { mContext.startActivity(new Intent(Intent.ACTION_MAIN) .addCategory(Intent.CATEGORY_HOME) .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK)); @@ -83,4 +86,7 @@ public class OverviewWithoutFocusInputConsumer implements InputConsumer { wasFling ? Touch.FLING : Touch.SWIPE, Direction.UP, containerType, pageIndex); activity.getUserEventDispatcher().setPreviousHomeGesture(true); } + + @Override + public void onSwipeUpCancelled() {} } diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/SysUiOverlayInputConsumer.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/SysUiOverlayInputConsumer.java new file mode 100644 index 0000000000..3f833c0a6d --- /dev/null +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/SysUiOverlayInputConsumer.java @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2020 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.inputconsumers; + +import android.content.Context; +import android.content.Intent; +import android.graphics.PointF; +import android.view.MotionEvent; + +import com.android.launcher3.testing.TestLogging; +import com.android.launcher3.testing.TestProtocol; +import com.android.quickstep.InputConsumer; +import com.android.quickstep.RecentsAnimationDeviceState; +import com.android.quickstep.util.TriggerSwipeUpTouchTracker; +import com.android.systemui.shared.system.InputMonitorCompat; + +/** + * Input consumer used when a fullscreen System UI overlay is showing (such as the expanded Bubbles + * UI). + * + * This responds to swipes up by sending a closeSystemDialogs broadcast (causing overlays to close) + * rather than closing the app behind the overlay and sending the user all the way home. + */ +public class SysUiOverlayInputConsumer implements InputConsumer, + TriggerSwipeUpTouchTracker.OnSwipeUpListener { + + private final Context mContext; + private final InputMonitorCompat mInputMonitor; + private final TriggerSwipeUpTouchTracker mTriggerSwipeUpTracker; + + public SysUiOverlayInputConsumer( + Context context, + RecentsAnimationDeviceState deviceState, + InputMonitorCompat inputMonitor) { + mContext = context; + mInputMonitor = inputMonitor; + mTriggerSwipeUpTracker = new TriggerSwipeUpTouchTracker(context, true, + deviceState.getNavBarPosition(), this::onInterceptTouch, this); + } + + @Override + public int getType() { + return TYPE_SYSUI_OVERLAY; + } + + @Override + public boolean allowInterceptByParent() { + return !mTriggerSwipeUpTracker.interceptedTouch(); + } + + @Override + public void onMotionEvent(MotionEvent ev) { + mTriggerSwipeUpTracker.onMotionEvent(ev); + } + + private void onInterceptTouch() { + if (mInputMonitor != null) { + TestLogging.recordEvent(TestProtocol.SEQUENCE_PILFER, "pilferPointers"); + mInputMonitor.pilferPointers(); + } + } + + @Override + public void onSwipeUp(boolean wasFling, PointF finalVelocity) { + // Close system dialogs when a swipe up is detected. + mContext.sendBroadcast(new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS)); + } + + @Override + public void onSwipeUpCancelled() { + + } +} diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/util/TaskViewSimulator.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/util/TaskViewSimulator.java index 3b08675885..3c9762be6d 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/util/TaskViewSimulator.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/util/TaskViewSimulator.java @@ -23,6 +23,7 @@ import static com.android.systemui.shared.system.WindowManagerWrapper.WINDOWING_ import android.animation.TimeInterpolator; import android.content.Context; import android.graphics.Matrix; +import android.graphics.Point; import android.graphics.PointF; import android.graphics.Rect; import android.graphics.RectF; @@ -74,7 +75,7 @@ public class TaskViewSimulator implements TransformParams.BuilderProxy { private DeviceProfile mDp; private final Matrix mMatrix = new Matrix(); - private RemoteAnimationTargetCompat mRunningTarget; + private final Point mRunningTargetWindowPosition = new Point(); // Thumbnail view properties private final Rect mThumbnailPosition = new Rect(); @@ -139,13 +140,19 @@ public class TaskViewSimulator implements TransformParams.BuilderProxy { * Sets the targets which the simulator will control */ public void setPreview(RemoteAnimationTargetCompat runningTarget) { - mRunningTarget = runningTarget; + setPreviewBounds(runningTarget.screenSpaceBounds, runningTarget.contentInsets); + mRunningTargetWindowPosition.set(runningTarget.position.x, runningTarget.position.y); + } - mThumbnailData.insets.set(mRunningTarget.contentInsets); + /** + * Sets the targets which the simulator will control + */ + public void setPreviewBounds(Rect bounds, Rect insets) { + mThumbnailData.insets.set(insets); // TODO: What is this? mThumbnailData.windowingMode = WINDOWING_MODE_FULLSCREEN; - mThumbnailPosition.set(runningTarget.screenSpaceBounds); + mThumbnailPosition.set(bounds); mLayoutValid = false; } @@ -199,16 +206,14 @@ public class TaskViewSimulator implements TransformParams.BuilderProxy { postDisplayRotation(deltaRotation( mOrientationState.getLauncherRotation(), mOrientationState.getDisplayRotation()), mDp.widthPx, mDp.heightPx, matrix); - if (mRunningTarget != null) { - matrix.postTranslate(-mRunningTarget.position.x, -mRunningTarget.position.y); - } + matrix.postTranslate(-mRunningTargetWindowPosition.x, -mRunningTargetWindowPosition.y); } /** * Applies the target to the previously set parameters */ public void apply(TransformParams params) { - if (mDp == null || mRunningTarget == null) { + if (mDp == null || mThumbnailPosition.isEmpty()) { return; } if (!mLayoutValid) { diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/util/TriggerSwipeUpTouchTracker.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/util/TriggerSwipeUpTouchTracker.java index c71258b87b..29b95589f3 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/util/TriggerSwipeUpTouchTracker.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/util/TriggerSwipeUpTouchTracker.java @@ -149,8 +149,12 @@ public class TriggerSwipeUpTouchTracker { isSwipeUp = squaredHypot(displacementX, displacementY) >= mSquaredTouchSlop; } - if (isSwipeUp && mOnSwipeUp != null) { - mOnSwipeUp.onSwipeUp(wasFling); + if (mOnSwipeUp != null) { + if (isSwipeUp) { + mOnSwipeUp.onSwipeUp(wasFling, new PointF(velocityX, velocityY)); + } else { + mOnSwipeUp.onSwipeUpCancelled(); + } } } @@ -161,7 +165,11 @@ public class TriggerSwipeUpTouchTracker { /** * Called on touch up if a swipe up was detected. * @param wasFling Whether the swipe was a fling, or just passed touch slop at low velocity. + * @param finalVelocity The final velocity of the swipe. */ - void onSwipeUp(boolean wasFling); + void onSwipeUp(boolean wasFling, PointF finalVelocity); + + /** Called on touch up if a swipe up was not detected. */ + void onSwipeUpCancelled(); } } diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/OverviewActionsView.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/OverviewActionsView.java index ea33d007f4..83287c463a 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/OverviewActionsView.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/OverviewActionsView.java @@ -45,8 +45,6 @@ import java.lang.annotation.RetentionPolicy; public class OverviewActionsView extends FrameLayout implements OnClickListener { - public static final long VISIBILITY_TRANSITION_DURATION_MS = 80; - @IntDef(flag = true, value = { HIDDEN_UNSUPPORTED_NAVIGATION, HIDDEN_DISABLED_FEATURE, diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsView.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsView.java index a506b7eb0c..324aaecf0e 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsView.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsView.java @@ -1039,6 +1039,11 @@ public abstract class RecentsView extends PagedView impl } private void animateRecentsRotationInPlace(int newRotation) { + if (mOrientationState.canLauncherRotate()) { + // Update the rotation but let system take care of the rotation animation + setLayoutRotation(newRotation, mOrientationState.getDisplayRotation()); + return; + } AnimatorSet pa = setRecentsChangedOrientation(true); pa.addListener(AnimationSuccessListener.forRunnable(() -> { setLayoutRotation(newRotation, mOrientationState.getDisplayRotation()); diff --git a/quickstep/res/layout/gesture_tutorial_fragment.xml b/quickstep/res/layout/gesture_tutorial_fragment.xml index 190290ebb4..74197bef40 100644 --- a/quickstep/res/layout/gesture_tutorial_fragment.xml +++ b/quickstep/res/layout/gesture_tutorial_fragment.xml @@ -24,6 +24,13 @@ android:layout_height="match_parent" android:background="@drawable/gesture_tutorial_ripple"/> + + Close - - - Easily access your most-used apps - - Pixel predicts apps you\’ll need next, right on your Home screen. Tap to set up. - Get app suggestions on the bottom row of your Home screen diff --git a/quickstep/src/com/android/launcher3/statehandlers/DepthController.java b/quickstep/src/com/android/launcher3/statehandlers/DepthController.java index 8292a92af6..fcffaedfd8 100644 --- a/quickstep/src/com/android/launcher3/statehandlers/DepthController.java +++ b/quickstep/src/com/android/launcher3/statehandlers/DepthController.java @@ -102,11 +102,30 @@ public class DepthController implements StateHandler { */ private float mDepth; + private View.OnAttachStateChangeListener mOnAttachListener; + public DepthController(Launcher l) { mLauncher = l; } private void ensureDependencies() { + if (mLauncher.getRootView() != null && mOnAttachListener == null) { + mOnAttachListener = new View.OnAttachStateChangeListener() { + @Override + public void onViewAttachedToWindow(View view) { + // To handle the case where window token is invalid during last setDepth call. + IBinder windowToken = mLauncher.getRootView().getWindowToken(); + if (windowToken != null) { + mWallpaperManager.setWallpaperZoomOut(windowToken, mDepth); + } + } + + @Override + public void onViewDetachedFromWindow(View view) { + } + }; + mLauncher.getRootView().addOnAttachStateChangeListener(mOnAttachListener); + } if (mWallpaperManager != null) { return; } @@ -184,10 +203,10 @@ public class DepthController implements StateHandler { return; } - mDepth = depthF; if (mSurface == null || !mSurface.isValid()) { return; } + mDepth = depthF; ensureDependencies(); IBinder windowToken = mLauncher.getRootView().getWindowToken(); if (windowToken != null) { diff --git a/quickstep/src/com/android/quickstep/BaseActivityInterface.java b/quickstep/src/com/android/quickstep/BaseActivityInterface.java index 91249250f5..7122647e6f 100644 --- a/quickstep/src/com/android/quickstep/BaseActivityInterface.java +++ b/quickstep/src/com/android/quickstep/BaseActivityInterface.java @@ -101,7 +101,7 @@ public abstract class BaseActivityInterface TYPE_NO_OP; @@ -71,6 +73,11 @@ public interface InputConsumer { return false; } + /** + * Handle and specific setup necessary based on the orientation of the device + */ + default void notifyOrientationSetup() {} + /** * Returns the active input consumer is in the hierarchy of this input consumer. */ diff --git a/quickstep/src/com/android/quickstep/OrientationTouchTransformer.java b/quickstep/src/com/android/quickstep/OrientationTouchTransformer.java index 6b94a79000..b59f0118af 100644 --- a/quickstep/src/com/android/quickstep/OrientationTouchTransformer.java +++ b/quickstep/src/com/android/quickstep/OrientationTouchTransformer.java @@ -67,6 +67,14 @@ class OrientationTouchTransformer { private boolean mEnableMultipleRegions; private Resources mResources; private OrientationRectF mLastRectTouched; + /** + * The rotation of the last touched nav bar. Derived from {@link #mLastRectTouched}, but has a + * longer lifetime than the rect. Note this is different than {@link #mQuickStepStartingRotation} + * as it always updates its value on every touch whereas mQuickstepStartingRotation only + * updates when device rotation matches touch rotation. Maybe this will be only one necessary + * after TODO(b/154580671) is in. TBD. + */ + private int mLastRectRotation; private SysUINavigationMode.Mode mMode; private QuickStepContractInfo mContractInfo; @@ -143,15 +151,18 @@ class OrientationTouchTransformer { * ALSO, you BETTER call this with {@param enableMultipleRegions} set to false once you're done. * * @param enableMultipleRegions Set to true to start tracking multiple nav bar regions - * @param info The current displayInfo + * @param info The current displayInfo which will be the start of the quickswitch gesture */ void enableMultipleRegions(boolean enableMultipleRegions, DefaultDisplay.Info info) { mEnableMultipleRegions = enableMultipleRegions && mMode != SysUINavigationMode.Mode.TWO_BUTTONS; - if (!enableMultipleRegions) { + if (mEnableMultipleRegions) { + mQuickStepStartingRotation = info.rotation; + } else { + mLastRectRotation = 0; mQuickStepStartingRotation = QUICKSTEP_ROTATION_UNINITIALIZED; - resetSwipeRegions(info); } + resetSwipeRegions(info); } /** @@ -248,11 +259,7 @@ class OrientationTouchTransformer { } int getCurrentActiveRotation() { - if (mLastRectTouched == null) { - return 0; - } else { - return mLastRectTouched.mRotation; - } + return mLastRectRotation; } int getQuickStepStartingRotation() { @@ -291,7 +298,9 @@ class OrientationTouchTransformer { } if (rect.applyTransform(event, false)) { mLastRectTouched = rect; - if (mCurrentDisplayRotation == mLastRectTouched.mRotation) { + mLastRectRotation = rect.mRotation; + if (mEnableMultipleRegions && mCurrentDisplayRotation == mLastRectRotation) { + // TODO(b/154580671) might make this block unnecessary // Start a touch session for the default nav region for the display mQuickStepStartingRotation = mLastRectTouched.mRotation; resetSwipeRegions(); diff --git a/quickstep/src/com/android/quickstep/RecentTasksList.java b/quickstep/src/com/android/quickstep/RecentTasksList.java index 2d9c56f673..70b4f20c2b 100644 --- a/quickstep/src/com/android/quickstep/RecentTasksList.java +++ b/quickstep/src/com/android/quickstep/RecentTasksList.java @@ -40,21 +40,20 @@ import java.util.function.Consumer; /** * Manages the recent task list from the system, caching it as necessary. */ -@TargetApi(Build.VERSION_CODES.P) +@TargetApi(Build.VERSION_CODES.R) public class RecentTasksList extends TaskStackChangeListener { + private static final TaskLoadResult INVALID_RESULT = new TaskLoadResult(-1, false, 0); + private final KeyguardManagerCompat mKeyguardManager; private final LooperExecutor mMainThreadExecutor; private final ActivityManagerWrapper mActivityManagerWrapper; // The list change id, increments as the task list changes in the system private int mChangeId; - // The last change id when the list was last loaded completely, must be <= the list change id - private int mLastLoadedId; - // The last change id was loaded with keysOnly = true - private boolean mLastLoadHadKeysOnly; - ArrayList mTasks = new ArrayList<>(); + private TaskLoadResult mResultsBg = INVALID_RESULT; + private TaskLoadResult mResultsUi = INVALID_RESULT; public RecentTasksList(LooperExecutor mainThreadExecutor, KeyguardManagerCompat keyguardManager, ActivityManagerWrapper activityManagerWrapper) { @@ -71,7 +70,7 @@ public class RecentTasksList extends TaskStackChangeListener { public void getTaskKeys(int numTasks, Consumer> callback) { // Kick off task loading in the background UI_HELPER_EXECUTOR.execute(() -> { - ArrayList tasks = loadTasksInBackground(numTasks, true /* loadKeysOnly */); + ArrayList tasks = loadTasksInBackground(numTasks, -1, true /* loadKeysOnly */); mMainThreadExecutor.execute(() -> callback.accept(tasks)); }); } @@ -85,26 +84,30 @@ public class RecentTasksList extends TaskStackChangeListener { */ public synchronized int getTasks(boolean loadKeysOnly, Consumer> callback) { final int requestLoadId = mChangeId; - Runnable resultCallback = callback == null - ? () -> { } - : () -> callback.accept(copyOf(mTasks)); - - if (mLastLoadedId == mChangeId && (!mLastLoadHadKeysOnly || loadKeysOnly)) { + if (mResultsUi.isValidForRequest(requestLoadId, loadKeysOnly)) { // The list is up to date, send the callback on the next frame, // so that requestID can be returned first. - mMainThreadExecutor.post(resultCallback); + if (callback != null) { + // Copy synchronously as the changeId might change by next frame + ArrayList result = copyOf(mResultsUi); + mMainThreadExecutor.post(() -> callback.accept(result)); + } + return requestLoadId; } // Kick off task loading in the background UI_HELPER_EXECUTOR.execute(() -> { - ArrayList tasks = loadTasksInBackground(Integer.MAX_VALUE, loadKeysOnly); - + if (!mResultsBg.isValidForRequest(requestLoadId, loadKeysOnly)) { + mResultsBg = loadTasksInBackground(Integer.MAX_VALUE, requestLoadId, loadKeysOnly); + } + TaskLoadResult loadResult = mResultsBg; mMainThreadExecutor.execute(() -> { - mTasks = tasks; - mLastLoadedId = requestLoadId; - mLastLoadHadKeysOnly = loadKeysOnly; - resultCallback.run(); + mResultsUi = loadResult; + if (callback != null) { + ArrayList result = copyOf(mResultsUi); + callback.accept(result); + } }); }); @@ -119,8 +122,8 @@ public class RecentTasksList extends TaskStackChangeListener { } @Override - public synchronized void onTaskStackChanged() { - mChangeId++; + public void onTaskStackChanged() { + invalidateLoadedTasks(); } @Override @@ -131,22 +134,28 @@ public class RecentTasksList extends TaskStackChangeListener { // callback (those are for changes to the active tasks), but the task list is still updated, // so we should also invalidate the change id to ensure we load a new list instead of // reusing a stale list. - mChangeId++; + invalidateLoadedTasks(); } @Override public void onTaskRemoved(int taskId) { - mTasks = loadTasksInBackground(Integer.MAX_VALUE, false); + invalidateLoadedTasks(); } + @Override - public synchronized void onActivityPinned(String packageName, int userId, int taskId, - int stackId) { - mChangeId++; + public void onActivityPinned(String packageName, int userId, int taskId, int stackId) { + invalidateLoadedTasks(); } @Override public synchronized void onActivityUnpinned() { + invalidateLoadedTasks(); + } + + private synchronized void invalidateLoadedTasks() { + UI_HELPER_EXECUTOR.execute(() -> mResultsBg = INVALID_RESULT); + mResultsUi = INVALID_RESULT; mChangeId++; } @@ -154,9 +163,8 @@ public class RecentTasksList extends TaskStackChangeListener { * Loads and creates a list of all the recent tasks. */ @VisibleForTesting - ArrayList loadTasksInBackground(int numTasks, boolean loadKeysOnly) { + TaskLoadResult loadTasksInBackground(int numTasks, int requestId, boolean loadKeysOnly) { int currentUserId = Process.myUserHandle().getIdentifier(); - ArrayList allTasks = new ArrayList<>(); List rawTasks = mActivityManagerWrapper.getRecentTasks(numTasks, currentUserId); // The raw tasks are given in most-recent to least-recent order, we need to reverse it @@ -173,6 +181,7 @@ public class RecentTasksList extends TaskStackChangeListener { } }; + TaskLoadResult allTasks = new TaskLoadResult(requestId, loadKeysOnly, rawTasks.size()); for (ActivityManager.RecentTaskInfo rawTask : rawTasks) { Task.TaskKey taskKey = new Task.TaskKey(rawTask); Task task; @@ -197,4 +206,22 @@ public class RecentTasksList extends TaskStackChangeListener { } return newTasks; } + + private static class TaskLoadResult extends ArrayList { + + final int mId; + + // If the result was loaded with keysOnly = true + final boolean mKeysOnly; + + TaskLoadResult(int id, boolean keysOnly, int size) { + super(size); + mId = id; + mKeysOnly = keysOnly; + } + + boolean isValidForRequest(int requestId, boolean loadKeysOnly) { + return mId == requestId && (!mKeysOnly || loadKeysOnly); + } + } } \ No newline at end of file diff --git a/quickstep/src/com/android/quickstep/RecentsAnimationController.java b/quickstep/src/com/android/quickstep/RecentsAnimationController.java index b0a3cd2a1e..4e9aa6135e 100644 --- a/quickstep/src/com/android/quickstep/RecentsAnimationController.java +++ b/quickstep/src/com/android/quickstep/RecentsAnimationController.java @@ -29,7 +29,6 @@ import android.view.KeyEvent; import android.view.MotionEvent; import androidx.annotation.NonNull; -import androidx.annotation.Nullable; import androidx.annotation.UiThread; import com.android.launcher3.util.Preconditions; @@ -58,8 +57,7 @@ public class RecentsAnimationController { private boolean mUseLauncherSysBarFlags = false; private boolean mSplitScreenMinimized = false; private boolean mTouchInProgress; - private boolean mFinishPending; - private @Nullable Runnable mFinishPendingCallback; + private boolean mDisableInputProxyPending; public RecentsAnimationController(RecentsAnimationControllerCompat controller, boolean allowMinimizeSplitScreen, @@ -138,12 +136,12 @@ public class RecentsAnimationController { @UiThread public void finishAnimationToHome() { - finishAndClear(true /* toRecents */, null, false /* sendUserLeaveHint */); + finishAndDisableInputProxy(true /* toRecents */, null, false /* sendUserLeaveHint */); } @UiThread public void finishAnimationToApp() { - finishAndClear(false /* toRecents */, null, false /* sendUserLeaveHint */); + finishAndDisableInputProxy(false /* toRecents */, null, false /* sendUserLeaveHint */); } /** See {@link #finish(boolean, Runnable, boolean)} */ @@ -162,19 +160,16 @@ public class RecentsAnimationController { @UiThread public void finish(boolean toRecents, Runnable onFinishComplete, boolean sendUserLeaveHint) { Preconditions.assertUIThread(); - if (!toRecents) { - finishAndClear(false, onFinishComplete, sendUserLeaveHint); + if (toRecents && mTouchInProgress) { + // Finish the controller as requested, but don't disable input proxy yet. + mDisableInputProxyPending = true; + finishController(toRecents, onFinishComplete, sendUserLeaveHint); } else { - if (mTouchInProgress) { - mFinishPending = true; - mFinishPendingCallback = onFinishComplete; - } else { - finishAndClear(true, onFinishComplete, sendUserLeaveHint); - } + finishAndDisableInputProxy(toRecents, onFinishComplete, sendUserLeaveHint); } } - private void finishAndClear(boolean toRecents, Runnable onFinishComplete, + private void finishAndDisableInputProxy(boolean toRecents, Runnable onFinishComplete, boolean sendUserLeaveHint) { disableInputProxy(); finishController(toRecents, onFinishComplete, sendUserLeaveHint); @@ -262,11 +257,9 @@ public class RecentsAnimationController { } else if (action == ACTION_CANCEL || action == ACTION_UP) { // Finish any pending actions mTouchInProgress = false; - if (mFinishPending) { - mFinishPending = false; - finishAndClear(true /* toRecents */, mFinishPendingCallback, - false /* sendUserLeaveHint */); - mFinishPendingCallback = null; + if (mDisableInputProxyPending) { + mDisableInputProxyPending = false; + disableInputProxy(); } } if (mInputConsumer != null) { diff --git a/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java b/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java index f7c29851af..c83de13618 100644 --- a/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java +++ b/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java @@ -18,6 +18,7 @@ package com.android.quickstep; import static android.content.Intent.ACTION_USER_UNLOCKED; import static com.android.launcher3.util.DefaultDisplay.CHANGE_ALL; +import static com.android.launcher3.util.DefaultDisplay.CHANGE_FRAME_DELAY; import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR; import static com.android.quickstep.SysUINavigationMode.Mode.NO_BUTTON; import static com.android.quickstep.SysUINavigationMode.Mode.THREE_BUTTONS; @@ -46,6 +47,7 @@ import android.graphics.Region; import android.os.Process; import android.os.SystemProperties; import android.os.UserManager; +import android.provider.Settings; import android.text.TextUtils; import android.util.DisplayMetrics; import android.view.MotionEvent; @@ -111,7 +113,8 @@ public class RecentsAnimationDeviceState implements private TaskStackChangeListener mFrozenTaskListener = new TaskStackChangeListener() { @Override public void onRecentTaskListFrozenChanged(boolean frozen) { - if (frozen) { + mTaskListFrozen = frozen; + if (frozen || mInOverview) { return; } enableMultipleRegions(false); @@ -132,6 +135,9 @@ public class RecentsAnimationDeviceState implements * TODO: (b/156984037) For when user rotates after entering overview */ private boolean mInOverview; + private boolean mTaskListFrozen; + + private boolean mIsUserSetupComplete; public RecentsAnimationDeviceState(Context context) { mContext = context; @@ -190,6 +196,17 @@ public class RecentsAnimationDeviceState implements mOneHandedEnabledObserver.register(); mOneHandedEnabledObserver.dispatchOnChange(); } + + SecureSettingsObserver userSetupObserver = new SecureSettingsObserver( + context.getContentResolver(), + e -> mIsUserSetupComplete = e, + Settings.Secure.USER_SETUP_COMPLETE, + 0); + mIsUserSetupComplete = userSetupObserver.getValue(); + if (!mIsUserSetupComplete) { + userSetupObserver.register(); + runOnDestroy(userSetupObserver::unregister); + } } private void setupOrientationSwipeHandler() { @@ -258,7 +275,8 @@ public class RecentsAnimationDeviceState implements @Override public void onDisplayInfoChanged(DefaultDisplay.Info info, int flags) { - if (info.id != getDisplayId()) { + if (info.id != getDisplayId() || (flags & CHANGE_FRAME_DELAY) == CHANGE_FRAME_DELAY) { + // ignore displays that aren't running launcher and frame refresh rate changes return; } @@ -329,6 +347,13 @@ public class RecentsAnimationDeviceState implements return mIsUserUnlocked; } + /** + * @return whether the user has completed setup wizard + */ + public boolean isUserSetupComplete() { + return mIsUserSetupComplete; + } + private void notifyUserUnlocked() { for (Runnable action : mUserUnlockedActions) { action.run(); @@ -375,7 +400,6 @@ public class RecentsAnimationDeviceState implements return (mSystemUiStateFlags & SYSUI_STATE_NAV_BAR_HIDDEN) == 0 && (mSystemUiStateFlags & SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED) == 0 && (mSystemUiStateFlags & SYSUI_STATE_QUICK_SETTINGS_EXPANDED) == 0 - && (mSystemUiStateFlags & SYSUI_STATE_BUBBLES_EXPANDED) == 0 && ((mSystemUiStateFlags & SYSUI_STATE_HOME_DISABLED) == 0 || (mSystemUiStateFlags & SYSUI_STATE_OVERVIEW_DISABLED) == 0); } @@ -395,6 +419,13 @@ public class RecentsAnimationDeviceState implements return (mSystemUiStateFlags & SYSUI_STATE_SCREEN_PINNING) != 0; } + /** + * @return whether the bubble stack is expanded + */ + public boolean isBubblesExpanded() { + return (mSystemUiStateFlags & SYSUI_STATE_BUBBLES_EXPANDED) != 0; + } + /** * @return whether lock-task mode is active */ @@ -550,7 +581,7 @@ public class RecentsAnimationDeviceState implements * *May* apply a transform on the motion event if it lies in the nav bar region for another * orientation that is currently being tracked as a part of quickstep */ - public void setOrientationTransformIfNeeded(MotionEvent event) { + void setOrientationTransformIfNeeded(MotionEvent event) { // negative coordinates bug b/143901881 if (event.getX() < 0 || event.getY() < 0) { event.setLocation(Math.max(0, event.getX()), Math.max(0, event.getY())); @@ -558,25 +589,54 @@ public class RecentsAnimationDeviceState implements mOrientationTouchTransformer.transform(event); } - void onSwipeUpToOverview(BaseActivityInterface activityInterface) { - mInOverview = true; - activityInterface.onExitOverview(this, () -> { - mInOverview = false; - enableMultipleRegions(false); - }); + void enableMultipleRegions(boolean enable) { + mOrientationTouchTransformer.enableMultipleRegions(enable, mDefaultDisplay.getInfo()); + notifySysuiForRotation(mOrientationTouchTransformer.getQuickStepStartingRotation()); } - void enableMultipleRegions(boolean enable) { - if (mInOverview) { - return; + private void notifySysuiForRotation(int rotation) { + UI_HELPER_EXECUTOR.execute(() -> + SystemUiProxy.INSTANCE.get(mContext).onQuickSwitchToNewTask(rotation)); + } + + public void onStartGesture() { + if (mTaskListFrozen) { + // Prioritize whatever nav bar user touches once in quickstep + // This case is specifically when user changes what nav bar they are using mid + // quickswitch session before tasks list is unfrozen + notifySysuiForRotation(mOrientationTouchTransformer.getCurrentActiveRotation()); + } + } + + + void onEndTargetCalculated(GestureState.GestureEndTarget endTarget, + BaseActivityInterface activityInterface) { + if (endTarget == GestureState.GestureEndTarget.RECENTS) { + mInOverview = true; + if (!mTaskListFrozen) { + // If we're in landscape w/o ever quickswitching, show the navbar in landscape + enableMultipleRegions(true); + } + activityInterface.onExitOverview(this, () -> { + mInOverview = false; + enableMultipleRegions(false); + }); + } else if (endTarget == GestureState.GestureEndTarget.HOME) { + enableMultipleRegions(false); + } else if (endTarget == GestureState.GestureEndTarget.NEW_TASK) { + if (mOrientationTouchTransformer.getQuickStepStartingRotation() == -1) { + // First gesture to start quickswitch + enableMultipleRegions(true); + } else { + notifySysuiForRotation(mOrientationTouchTransformer.getCurrentActiveRotation()); + } + } else if (endTarget == GestureState.GestureEndTarget.LAST_TASK) { + if (!mTaskListFrozen) { + // touched nav bar but didn't go anywhere and not quickswitching, do nothing + return; + } + notifySysuiForRotation(mOrientationTouchTransformer.getCurrentActiveRotation()); } - mOrientationTouchTransformer.enableMultipleRegions(enable, mDefaultDisplay.getInfo()); - UI_HELPER_EXECUTOR.execute(() -> { - int quickStepStartingRotation = - mOrientationTouchTransformer.getQuickStepStartingRotation(); - SystemUiProxy.INSTANCE.get(mContext) - .onQuickSwitchToNewTask(quickStepStartingRotation); - }); } public int getCurrentActiveRotation() { diff --git a/quickstep/src/com/android/quickstep/interaction/BackGestureTutorialController.java b/quickstep/src/com/android/quickstep/interaction/BackGestureTutorialController.java index 58870edece..41e86e00b6 100644 --- a/quickstep/src/com/android/quickstep/interaction/BackGestureTutorialController.java +++ b/quickstep/src/com/android/quickstep/interaction/BackGestureTutorialController.java @@ -18,8 +18,11 @@ package com.android.quickstep.interaction; import static com.android.quickstep.interaction.TutorialController.TutorialType.BACK_NAVIGATION_COMPLETE; import static com.android.quickstep.interaction.TutorialController.TutorialType.LEFT_EDGE_BACK_NAVIGATION; +import android.graphics.PointF; import android.view.View; +import androidx.annotation.Nullable; + import com.android.launcher3.R; import com.android.quickstep.interaction.EdgeBackGestureHandler.BackGestureResult; import com.android.quickstep.interaction.NavBarGestureHandler.NavBarGestureResult; @@ -154,11 +157,14 @@ final class BackGestureTutorialController extends TutorialController { } @Override - public void onNavBarGestureAttempted(NavBarGestureResult result) { + public void onNavBarGestureAttempted(NavBarGestureResult result, PointF finalVelocity) { if (mTutorialType == BACK_NAVIGATION_COMPLETE) { if (result == NavBarGestureResult.HOME_GESTURE_COMPLETED) { mTutorialFragment.closeTutorial(); } } } + + @Override + public void setNavBarGestureProgress(@Nullable Float displacement) {} } diff --git a/quickstep/src/com/android/quickstep/interaction/HomeGestureTutorialController.java b/quickstep/src/com/android/quickstep/interaction/HomeGestureTutorialController.java index 524cbaf06f..65f41a4a6c 100644 --- a/quickstep/src/com/android/quickstep/interaction/HomeGestureTutorialController.java +++ b/quickstep/src/com/android/quickstep/interaction/HomeGestureTutorialController.java @@ -15,19 +15,135 @@ */ package com.android.quickstep.interaction; +import static com.android.launcher3.anim.Interpolators.ACCEL; +import static com.android.launcher3.util.DefaultDisplay.getSingleFrameMs; +import static com.android.quickstep.BaseSwipeUpHandlerV2.MAX_SWIPE_DURATION; import static com.android.quickstep.interaction.TutorialController.TutorialType.HOME_NAVIGATION_COMPLETE; +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; +import android.animation.AnimatorSet; +import android.annotation.TargetApi; +import android.content.Context; +import android.graphics.Insets; +import android.graphics.Outline; +import android.graphics.PointF; +import android.graphics.Rect; +import android.graphics.RectF; +import android.os.Build; +import android.view.SurfaceControl; import android.view.View; +import android.view.ViewOutlineProvider; +import android.view.WindowInsets.Type; +import android.view.WindowManager; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import com.android.launcher3.DeviceProfile; +import com.android.launcher3.InvariantDeviceProfile; import com.android.launcher3.R; +import com.android.launcher3.Utilities; +import com.android.launcher3.anim.AnimationSuccessListener; +import com.android.launcher3.anim.AnimatorPlaybackController; +import com.android.launcher3.anim.PendingAnimation; +import com.android.quickstep.AnimatedFloat; +import com.android.quickstep.GestureState; +import com.android.quickstep.OverviewComponentObserver; +import com.android.quickstep.RecentsAnimationDeviceState; +import com.android.quickstep.SwipeUpAnimationLogic; +import com.android.quickstep.SwipeUpAnimationLogic.RunningWindowAnim; import com.android.quickstep.interaction.EdgeBackGestureHandler.BackGestureResult; import com.android.quickstep.interaction.NavBarGestureHandler.NavBarGestureResult; +import com.android.quickstep.util.RectFSpringAnim; +import com.android.quickstep.util.TransformParams; +import com.android.systemui.shared.system.QuickStepContract; +import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplierCompat.SurfaceParams; /** A {@link TutorialController} for the Home tutorial. */ +@TargetApi(Build.VERSION_CODES.R) final class HomeGestureTutorialController extends TutorialController { + private float mFakeTaskViewRadius; + private Rect mFakeTaskViewRect = new Rect(); + + private final ViewSwipeUpAnimation mViewSwipeUpAnimation; + private RunningWindowAnim mRunningWindowAnim; + HomeGestureTutorialController(HomeGestureTutorialFragment fragment, TutorialType tutorialType) { super(fragment, tutorialType); + + RecentsAnimationDeviceState deviceState = new RecentsAnimationDeviceState(mContext); + OverviewComponentObserver observer = new OverviewComponentObserver(mContext, deviceState); + mViewSwipeUpAnimation = new ViewSwipeUpAnimation(mContext, deviceState, + new GestureState(observer, -1)); + observer.onDestroy(); + deviceState.destroy(); + + DeviceProfile dp = InvariantDeviceProfile.INSTANCE.get(mContext) + .getDeviceProfile(mContext) + .copy(mContext); + Insets insets = mContext.getSystemService(WindowManager.class) + .getCurrentWindowMetrics() + .getWindowInsets() + .getInsets(Type.systemBars()); + dp.updateInsets(new Rect(insets.left, insets.top, insets.right, insets.bottom)); + mViewSwipeUpAnimation.initDp(dp); + + mFakeTaskViewRadius = QuickStepContract.getWindowCornerRadius(mContext.getResources()); + + mFakeTaskView.setClipToOutline(true); + mFakeTaskView.setOutlineProvider(new ViewOutlineProvider() { + @Override + public void getOutline(View view, Outline outline) { + outline.setRoundRect(mFakeTaskViewRect, mFakeTaskViewRadius); + } + }); + } + + private void cancelRunningAnimation() { + if (mRunningWindowAnim != null) { + mRunningWindowAnim.cancel(); + } + mRunningWindowAnim = null; + } + + /** Fades the task view, optionally after animating to a fake Overview. */ + private void fadeOutFakeTaskView(boolean toOverviewFirst, @Nullable Runnable onEndRunnable) { + cancelRunningAnimation(); + PendingAnimation anim = new PendingAnimation(300); + AnimatorListenerAdapter resetTaskView = new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation, boolean isReverse) { + mFakeTaskView.setVisibility(View.INVISIBLE); + mFakeTaskView.setAlpha(1); + mRunningWindowAnim = null; + } + }; + if (toOverviewFirst) { + anim.setFloat(mViewSwipeUpAnimation.getCurrentShift(), AnimatedFloat.VALUE, 1, ACCEL); + anim.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation, boolean isReverse) { + PendingAnimation fadeAnim = new PendingAnimation(300); + fadeAnim.setViewAlpha(mFakeTaskView, 0, ACCEL); + fadeAnim.addListener(resetTaskView); + AnimatorSet animset = fadeAnim.buildAnim(); + animset.setStartDelay(100); + animset.start(); + mRunningWindowAnim = RunningWindowAnim.wrap(animset); + } + }); + } else { + anim.setViewAlpha(mFakeTaskView, 0, ACCEL); + anim.addListener(resetTaskView); + } + if (onEndRunnable != null) { + anim.addListener(AnimationSuccessListener.forRunnable(onEndRunnable)); + } + AnimatorSet animset = anim.buildAnim(); + animset.start(); + mRunningWindowAnim = RunningWindowAnim.wrap(animset); } @Override @@ -85,22 +201,35 @@ final class HomeGestureTutorialController extends TutorialController { } @Override - public void onNavBarGestureAttempted(NavBarGestureResult result) { + public void onNavBarGestureAttempted(NavBarGestureResult result, PointF finalVelocity) { switch (mTutorialType) { case HOME_NAVIGATION: switch (result) { - case HOME_GESTURE_COMPLETED: + case HOME_GESTURE_COMPLETED: { + hideFeedback(); + cancelRunningAnimation(); hideHandCoachingAnimation(); - mTutorialFragment.changeController(HOME_NAVIGATION_COMPLETE); + RectFSpringAnim rectAnim = + mViewSwipeUpAnimation.handleSwipeUpToHome(finalVelocity); + // After home animation finishes, fade out and then move to the next screen. + rectAnim.addAnimatorListener(AnimationSuccessListener.forRunnable( + () -> fadeOutFakeTaskView(false, + () -> mTutorialFragment.changeController( + HOME_NAVIGATION_COMPLETE)))); + mRunningWindowAnim = RunningWindowAnim.wrap(rectAnim); break; + } case HOME_NOT_STARTED_TOO_FAR_FROM_EDGE: case OVERVIEW_NOT_STARTED_TOO_FAR_FROM_EDGE: showFeedback(R.string.home_gesture_feedback_swipe_too_far_from_edge); break; case OVERVIEW_GESTURE_COMPLETED: - showFeedback(R.string.home_gesture_feedback_overview_detected); + fadeOutFakeTaskView(true, () -> + showFeedback(R.string.home_gesture_feedback_overview_detected)); break; case HOME_OR_OVERVIEW_NOT_STARTED_WRONG_SWIPE_DIRECTION: + case HOME_OR_OVERVIEW_CANCELLED: + fadeOutFakeTaskView(false, null); showFeedback(R.string.home_gesture_feedback_wrong_swipe_direction); break; } @@ -112,4 +241,94 @@ final class HomeGestureTutorialController extends TutorialController { break; } } + + @Override + public void setNavBarGestureProgress(@Nullable Float displacement) { + if (displacement == null || mTutorialType == HOME_NAVIGATION_COMPLETE) { + mFakeTaskView.setVisibility(View.INVISIBLE); + } else { + mFakeTaskView.setVisibility(View.VISIBLE); + if (mRunningWindowAnim == null) { + mViewSwipeUpAnimation.updateDisplacement(displacement); + } + } + } + + private class ViewSwipeUpAnimation extends SwipeUpAnimationLogic { + + ViewSwipeUpAnimation(Context context, RecentsAnimationDeviceState deviceState, + GestureState gestureState) { + super(context, deviceState, gestureState, new FakeTransformParams()); + } + + void initDp(DeviceProfile dp) { + initTransitionEndpoints(dp); + mTaskViewSimulator.setPreviewBounds( + new Rect(0, 0, dp.widthPx, dp.heightPx), dp.getInsets()); + } + + @Override + public void updateFinalShift() { + float progress = mCurrentShift.value / mDragLengthFactor; + mWindowTransitionController.setPlayFraction(progress); + mTaskViewSimulator.apply(mTransformParams); + } + + AnimatedFloat getCurrentShift() { + return mCurrentShift; + } + + RectFSpringAnim handleSwipeUpToHome(PointF velocity) { + PointF velocityPxPerMs = new PointF(velocity.x, velocity.y); + float currentShift = mCurrentShift.value; + final float startShift = Utilities.boundToRange(currentShift - velocityPxPerMs.y + * getSingleFrameMs(mContext) / mTransitionDragLength, 0, mDragLengthFactor); + float distanceToTravel = (1 - currentShift) * mTransitionDragLength; + + // we want the page's snap velocity to approximately match the velocity at + // which the user flings, so we scale the duration by a value near to the + // derivative of the scroll interpolator at zero, ie. 2. + long baseDuration = Math.round(Math.abs(distanceToTravel / velocityPxPerMs.y)); + long duration = Math.min(MAX_SWIPE_DURATION, 2 * baseDuration); + HomeAnimationFactory homeAnimFactory = new HomeAnimationFactory(null) { + @Override + public AnimatorPlaybackController createActivityAnimationToHome() { + return AnimatorPlaybackController.wrap(new AnimatorSet(), duration); + } + + @NonNull + @Override + public RectF getWindowTargetRect() { + int fakeHomeIconSizePx = mDp.allAppsIconSizePx; + int fakeHomeIconLeft = (mDp.widthPx - fakeHomeIconSizePx) / 2; + int fakeHomeIconTop = mDp.heightPx - (mDp.allAppsCellHeightPx * 3); + return new RectF(fakeHomeIconLeft, fakeHomeIconTop, + fakeHomeIconLeft + fakeHomeIconSizePx, + fakeHomeIconTop + fakeHomeIconSizePx); + } + }; + RectFSpringAnim windowAnim = createWindowAnimationToHome(startShift, homeAnimFactory); + windowAnim.start(mContext, velocityPxPerMs); + return windowAnim; + } + } + + private class FakeTransformParams extends TransformParams { + + @Override + public SurfaceParams[] createSurfaceParams(BuilderProxy proxy) { + SurfaceParams.Builder builder = new SurfaceParams.Builder((SurfaceControl) null); + proxy.onBuildTargetParams(builder, null, this); + return new SurfaceParams[] {builder.build()}; + } + + @Override + public void applySurfaceParams(SurfaceParams[] params) { + SurfaceParams p = params[0]; + mFakeTaskView.setAnimationMatrix(p.matrix); + mFakeTaskViewRect.set(p.windowCrop); + mFakeTaskViewRadius = p.cornerRadius; + mFakeTaskView.invalidateOutline(); + } + } } diff --git a/quickstep/src/com/android/quickstep/interaction/NavBarGestureHandler.java b/quickstep/src/com/android/quickstep/interaction/NavBarGestureHandler.java index 6d8caa2ec5..4069c09a28 100644 --- a/quickstep/src/com/android/quickstep/interaction/NavBarGestureHandler.java +++ b/quickstep/src/com/android/quickstep/interaction/NavBarGestureHandler.java @@ -17,6 +17,7 @@ package com.android.quickstep.interaction; import static com.android.quickstep.interaction.NavBarGestureHandler.NavBarGestureResult.HOME_GESTURE_COMPLETED; import static com.android.quickstep.interaction.NavBarGestureHandler.NavBarGestureResult.HOME_NOT_STARTED_TOO_FAR_FROM_EDGE; +import static com.android.quickstep.interaction.NavBarGestureHandler.NavBarGestureResult.HOME_OR_OVERVIEW_CANCELLED; import static com.android.quickstep.interaction.NavBarGestureHandler.NavBarGestureResult.HOME_OR_OVERVIEW_NOT_STARTED_WRONG_SWIPE_DIRECTION; import static com.android.quickstep.interaction.NavBarGestureHandler.NavBarGestureResult.OVERVIEW_GESTURE_COMPLETED; import static com.android.quickstep.interaction.NavBarGestureHandler.NavBarGestureResult.OVERVIEW_NOT_STARTED_TOO_FAR_FROM_EDGE; @@ -24,19 +25,23 @@ import static com.android.quickstep.interaction.NavBarGestureHandler.NavBarGestu import android.content.Context; import android.content.res.Resources; import android.graphics.Point; +import android.graphics.PointF; import android.view.Display; import android.view.MotionEvent; import android.view.Surface; import android.view.View; import android.view.View.OnTouchListener; +import androidx.annotation.Nullable; + import com.android.launcher3.ResourceUtils; import com.android.quickstep.SysUINavigationMode.Mode; import com.android.quickstep.util.NavBarPosition; import com.android.quickstep.util.TriggerSwipeUpTouchTracker; /** Utility class to handle home gestures. */ -public class NavBarGestureHandler implements OnTouchListener { +public class NavBarGestureHandler implements OnTouchListener, + TriggerSwipeUpTouchTracker.OnSwipeUpListener { private static final String LOG_TAG = "NavBarGestureHandler"; @@ -44,6 +49,7 @@ public class NavBarGestureHandler implements OnTouchListener { private final TriggerSwipeUpTouchTracker mSwipeUpTouchTracker; private int mBottomGestureHeight; private boolean mTouchCameFromNavBar; + private float mDownY; private NavBarGestureAttemptCallback mGestureCallback; NavBarGestureHandler(Context context) { @@ -55,10 +61,11 @@ public class NavBarGestureHandler implements OnTouchListener { displayRotation = display.getRotation(); display.getRealSize(mDisplaySize); } + mDownY = mDisplaySize.y; mSwipeUpTouchTracker = new TriggerSwipeUpTouchTracker(context, true /*disableHorizontalSwipe*/, new NavBarPosition(Mode.NO_BUTTON, displayRotation), - null /*onInterceptTouch*/, this::onSwipeUp); + null /*onInterceptTouch*/, this); final Resources resources = context.getResources(); mBottomGestureHeight = @@ -73,16 +80,26 @@ public class NavBarGestureHandler implements OnTouchListener { mGestureCallback = null; } - private void onSwipeUp(boolean wasFling) { + @Override + public void onSwipeUp(boolean wasFling, PointF finalVelocity) { if (mGestureCallback == null) { return; } + finalVelocity.set(finalVelocity.x / 1000, finalVelocity.y / 1000); if (mTouchCameFromNavBar) { mGestureCallback.onNavBarGestureAttempted(wasFling - ? HOME_GESTURE_COMPLETED : OVERVIEW_GESTURE_COMPLETED); + ? HOME_GESTURE_COMPLETED : OVERVIEW_GESTURE_COMPLETED, finalVelocity); } else { mGestureCallback.onNavBarGestureAttempted(wasFling - ? HOME_NOT_STARTED_TOO_FAR_FROM_EDGE : OVERVIEW_NOT_STARTED_TOO_FAR_FROM_EDGE); + ? HOME_NOT_STARTED_TOO_FAR_FROM_EDGE : OVERVIEW_NOT_STARTED_TOO_FAR_FROM_EDGE, + finalVelocity); + } + } + + @Override + public void onSwipeUpCancelled() { + if (mGestureCallback != null) { + mGestureCallback.onNavBarGestureAttempted(HOME_OR_OVERVIEW_CANCELLED, new PointF()); } } @@ -91,15 +108,22 @@ public class NavBarGestureHandler implements OnTouchListener { int action = motionEvent.getAction(); boolean intercepted = mSwipeUpTouchTracker.interceptedTouch(); if (action == MotionEvent.ACTION_DOWN) { - mTouchCameFromNavBar = motionEvent.getRawY() >= mDisplaySize.y - mBottomGestureHeight; + mDownY = motionEvent.getY(); + mTouchCameFromNavBar = mDownY >= mDisplaySize.y - mBottomGestureHeight; + if (!mTouchCameFromNavBar) { + mGestureCallback.setNavBarGestureProgress(null); + } mSwipeUpTouchTracker.init(); } else if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) { if (mGestureCallback != null && !intercepted && mTouchCameFromNavBar) { mGestureCallback.onNavBarGestureAttempted( - HOME_OR_OVERVIEW_NOT_STARTED_WRONG_SWIPE_DIRECTION); + HOME_OR_OVERVIEW_NOT_STARTED_WRONG_SWIPE_DIRECTION, new PointF()); intercepted = true; } } + if (mTouchCameFromNavBar && mGestureCallback != null) { + mGestureCallback.setNavBarGestureProgress(motionEvent.getY() - mDownY); + } mSwipeUpTouchTracker.onMotionEvent(motionEvent); return intercepted; } @@ -110,12 +134,16 @@ public class NavBarGestureHandler implements OnTouchListener { OVERVIEW_GESTURE_COMPLETED, HOME_NOT_STARTED_TOO_FAR_FROM_EDGE, OVERVIEW_NOT_STARTED_TOO_FAR_FROM_EDGE, - HOME_OR_OVERVIEW_NOT_STARTED_WRONG_SWIPE_DIRECTION // Side swipe on nav bar. + HOME_OR_OVERVIEW_NOT_STARTED_WRONG_SWIPE_DIRECTION, // Side swipe on nav bar. + HOME_OR_OVERVIEW_CANCELLED } /** Callback to let the UI react to attempted nav bar gestures. */ interface NavBarGestureAttemptCallback { /** Called whenever any touch is completed. */ - void onNavBarGestureAttempted(NavBarGestureResult result); + void onNavBarGestureAttempted(NavBarGestureResult result, PointF finalVelocity); + + /** Indicates how far a touch originating in the nav bar has moved from the nav bar. */ + void setNavBarGestureProgress(@Nullable Float displacement); } } diff --git a/quickstep/src/com/android/quickstep/interaction/TutorialController.java b/quickstep/src/com/android/quickstep/interaction/TutorialController.java index 1e29f44704..f27d500eff 100644 --- a/quickstep/src/com/android/quickstep/interaction/TutorialController.java +++ b/quickstep/src/com/android/quickstep/interaction/TutorialController.java @@ -15,6 +15,7 @@ */ package com.android.quickstep.interaction; +import android.content.Context; import android.graphics.drawable.RippleDrawable; import android.view.View; import android.view.View.OnClickListener; @@ -39,11 +40,13 @@ abstract class TutorialController implements BackGestureAttemptCallback, final TutorialFragment mTutorialFragment; TutorialType mTutorialType; + final Context mContext; final ImageButton mCloseButton; final TextView mTitleTextView; final TextView mSubtitleTextView; final TextView mFeedbackView; + final View mFakeTaskView; final View mRippleView; final RippleDrawable mRippleDrawable; final TutorialHandAnimation mHandCoachingAnimation; @@ -55,6 +58,7 @@ abstract class TutorialController implements BackGestureAttemptCallback, TutorialController(TutorialFragment tutorialFragment, TutorialType tutorialType) { mTutorialFragment = tutorialFragment; mTutorialType = tutorialType; + mContext = mTutorialFragment.getContext(); View rootView = tutorialFragment.getRootView(); mCloseButton = rootView.findViewById(R.id.gesture_tutorial_fragment_close_button); @@ -62,6 +66,7 @@ abstract class TutorialController implements BackGestureAttemptCallback, mTitleTextView = rootView.findViewById(R.id.gesture_tutorial_fragment_title_view); mSubtitleTextView = rootView.findViewById(R.id.gesture_tutorial_fragment_subtitle_view); mFeedbackView = rootView.findViewById(R.id.gesture_tutorial_fragment_feedback_view); + mFakeTaskView = rootView.findViewById(R.id.gesture_tutorial_fake_task_view); mRippleView = rootView.findViewById(R.id.gesture_tutorial_ripple_view); mRippleDrawable = (RippleDrawable) mRippleView.getBackground(); mHandCoachingAnimation = tutorialFragment.getHandAnimation(); diff --git a/quickstep/src/com/android/quickstep/interaction/TutorialFragment.java b/quickstep/src/com/android/quickstep/interaction/TutorialFragment.java index 44c1a5da04..a3881cffb0 100644 --- a/quickstep/src/com/android/quickstep/interaction/TutorialFragment.java +++ b/quickstep/src/com/android/quickstep/interaction/TutorialFragment.java @@ -37,11 +37,6 @@ import com.android.quickstep.interaction.TutorialController.TutorialType; abstract class TutorialFragment extends Fragment implements OnTouchListener { private static final String LOG_TAG = "TutorialFragment"; - private static final String SYSTEM_NAVIGATION_SETTING_INTENT = - "#Intent;action=com.android.settings.SEARCH_RESULT_TRAMPOLINE;S" - + ".:settings:fragment_args_key=gesture_system_navigation_input_summary;S" - + ".:settings:show_fragment=com.android.settings.gestures" - + ".SystemNavigationGestureSettings;end"; static final String KEY_TUTORIAL_TYPE = "tutorial_type"; TutorialType mTutorialType; diff --git a/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java b/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java index 69812b6154..d4d46fbb2c 100644 --- a/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java +++ b/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java @@ -65,10 +65,10 @@ public class StatsLogCompatManager extends StatsLogManager { } /** - * Logs a {@link LauncherEvent}. + * Logs a {@link EventEnum}. */ @Override - public void log(LauncherEvent event) { + public void log(EventEnum event) { log(event, DEFAULT_INSTANCE_ID, LauncherAtom.ItemInfo.getDefaultInstance()); } @@ -76,7 +76,7 @@ public class StatsLogCompatManager extends StatsLogManager { * Logs an event and accompanying {@link InstanceId}. */ @Override - public void log(LauncherEvent event, InstanceId instanceId) { + public void log(EventEnum event, InstanceId instanceId) { log(event, instanceId, LauncherAtom.ItemInfo.getDefaultInstance()); } @@ -84,7 +84,7 @@ public class StatsLogCompatManager extends StatsLogManager { * Logs an event and accompanying {@link ItemInfo}. */ @Override - public void log(LauncherEvent event, @Nullable LauncherAtom.ItemInfo info) { + public void log(EventEnum event, @Nullable LauncherAtom.ItemInfo info) { log(event, DEFAULT_INSTANCE_ID, info); } @@ -92,7 +92,7 @@ public class StatsLogCompatManager extends StatsLogManager { * Logs an event and accompanying {@link InstanceId} and {@link LauncherAtom.ItemInfo}. */ @Override - public void log(LauncherEvent event, InstanceId instanceId, + public void log(EventEnum event, InstanceId instanceId, @Nullable LauncherAtom.ItemInfo info) { logInternal(event, instanceId, info, LAUNCHER_UICHANGED__DST_STATE__HOME, @@ -102,14 +102,17 @@ public class StatsLogCompatManager extends StatsLogManager { /** * Logs an event and accompanying {@link InstanceId} and {@link LauncherAtom.ItemInfo}. */ - private void logInternal(LauncherEvent event, InstanceId instanceId, + private void logInternal(EventEnum event, InstanceId instanceId, @Nullable LauncherAtom.ItemInfo info, int startState, int endState) { info = info == null ? LauncherAtom.ItemInfo.getDefaultInstance() : info; if (IS_VERBOSE) { + String name = (event instanceof LauncherEvent) ? ((LauncherEvent) event).name() : + event.getId() + ""; + Log.d(TAG, instanceId == DEFAULT_INSTANCE_ID - ? String.format("\n%s\n%s", event.name(), info) - : String.format("%s(InstanceId:%s)\n%s", event.name(), instanceId, info)); + ? String.format("\n%s\n%s", name, info) + : String.format("%s(InstanceId:%s)\n%s", name, instanceId, info)); } if (!Utilities.ATLEAST_R) { diff --git a/quickstep/src/com/android/quickstep/util/RecentsOrientedState.java b/quickstep/src/com/android/quickstep/util/RecentsOrientedState.java index 5745990614..498c232ec3 100644 --- a/quickstep/src/com/android/quickstep/util/RecentsOrientedState.java +++ b/quickstep/src/com/android/quickstep/util/RecentsOrientedState.java @@ -208,7 +208,7 @@ public final class RecentsOrientedState implements SharedPreferences.OnSharedPre mDisplayRotation = displayRotation; mTouchRotation = touchRotation; - if (mLauncherRotation == mTouchRotation) { + if (mLauncherRotation == mTouchRotation || canLauncherRotate()) { mOrientationHandler = PagedOrientationHandler.HOME_ROTATED; if (DEBUG) { Log.d(TAG, "current RecentsOrientedState: " + this); @@ -240,7 +240,7 @@ public final class RecentsOrientedState implements SharedPreferences.OnSharedPre private void setFlag(int mask, boolean enabled) { boolean wasRotationEnabled = !TestProtocol.sDisableSensorRotation - && mFlags == VALUE_ROTATION_WATCHER_ENABLED; + && (mFlags & VALUE_ROTATION_WATCHER_ENABLED) == VALUE_ROTATION_WATCHER_ENABLED; if (enabled) { mFlags |= mask; } else { @@ -248,7 +248,7 @@ public final class RecentsOrientedState implements SharedPreferences.OnSharedPre } boolean isRotationEnabled = !TestProtocol.sDisableSensorRotation - && mFlags == VALUE_ROTATION_WATCHER_ENABLED; + && (mFlags & VALUE_ROTATION_WATCHER_ENABLED) == VALUE_ROTATION_WATCHER_ENABLED; if (wasRotationEnabled != isRotationEnabled) { UI_HELPER_EXECUTOR.execute(() -> { if (isRotationEnabled) { diff --git a/quickstep/tests/src/com/android/quickstep/RecentTasksListTest.java b/quickstep/tests/src/com/android/quickstep/RecentTasksListTest.java index 34eb7f8177..79ddf7a399 100644 --- a/quickstep/tests/src/com/android/quickstep/RecentTasksListTest.java +++ b/quickstep/tests/src/com/android/quickstep/RecentTasksListTest.java @@ -58,9 +58,9 @@ public class RecentTasksListTest { } @Test - public void onTaskRemoved_reloadsAllTasks() { + public void onTaskRemoved_doesNotFetchTasks() { mRecentTasksList.onTaskRemoved(0); - verify(mockActivityManagerWrapper, times(1)) + verify(mockActivityManagerWrapper, times(0)) .getRecentTasks(anyInt(), anyInt()); } @@ -77,7 +77,7 @@ public class RecentTasksListTest { when(mockActivityManagerWrapper.getRecentTasks(anyInt(), anyInt())) .thenReturn(Collections.singletonList(recentTaskInfo)); - List taskList = mRecentTasksList.loadTasksInBackground(Integer.MAX_VALUE, true); + List taskList = mRecentTasksList.loadTasksInBackground(Integer.MAX_VALUE, -1, true); assertEquals(1, taskList.size()); assertNull(taskList.get(0).taskDescription.getLabel()); @@ -91,7 +91,7 @@ public class RecentTasksListTest { when(mockActivityManagerWrapper.getRecentTasks(anyInt(), anyInt())) .thenReturn(Collections.singletonList(recentTaskInfo)); - List taskList = mRecentTasksList.loadTasksInBackground(Integer.MAX_VALUE, false); + List taskList = mRecentTasksList.loadTasksInBackground(Integer.MAX_VALUE, -1, false); assertEquals(1, taskList.size()); assertEquals(taskDescription, taskList.get(0).taskDescription.getLabel()); diff --git a/res/values/colors.xml b/res/values/colors.xml index c9c893e511..c4ec7dd7f0 100644 --- a/res/values/colors.xml +++ b/res/values/colors.xml @@ -43,6 +43,7 @@ #99000000 #FF000000 #A0C2F9 + #6DA1FF #FFFFFFFF #1A73E8 diff --git a/src/com/android/launcher3/BaseDraggingActivity.java b/src/com/android/launcher3/BaseDraggingActivity.java index 0ac278457a..d1d5e2624d 100644 --- a/src/com/android/launcher3/BaseDraggingActivity.java +++ b/src/com/android/launcher3/BaseDraggingActivity.java @@ -24,6 +24,7 @@ import android.content.ActivityNotFoundException; import android.content.Intent; import android.content.pm.LauncherApps; import android.content.res.Configuration; +import android.graphics.Insets; import android.graphics.Point; import android.graphics.Rect; import android.os.Bundle; @@ -35,6 +36,8 @@ import android.view.ActionMode; import android.view.Display; import android.view.View; import android.view.View.OnClickListener; +import android.view.WindowInsets.Type; +import android.view.WindowMetrics; import android.widget.Toast; import androidx.annotation.Nullable; @@ -51,6 +54,7 @@ import com.android.launcher3.util.DefaultDisplay.Info; import com.android.launcher3.util.PackageManagerHelper; import com.android.launcher3.util.Themes; import com.android.launcher3.util.TraceHelper; +import com.android.launcher3.util.WindowBounds; /** * Extension of BaseActivity allowing support for drag-n-drop @@ -272,15 +276,19 @@ public abstract class BaseDraggingActivity extends BaseActivity protected abstract void reapplyUi(); - protected Rect getMultiWindowDisplaySize() { + protected WindowBounds getMultiWindowDisplaySize() { if (Utilities.ATLEAST_R) { - return new Rect(getWindowManager().getCurrentWindowMetrics().getBounds()); + WindowMetrics wm = getWindowManager().getCurrentWindowMetrics(); + + Insets insets = wm.getWindowInsets().getInsets(Type.systemBars()); + return new WindowBounds(wm.getBounds(), + new Rect(insets.left, insets.top, insets.right, insets.bottom)); } // Note: Calls to getSize() can't rely on our cached DefaultDisplay since it can return // the app window size Display display = getWindowManager().getDefaultDisplay(); Point mwSize = new Point(); display.getSize(mwSize); - return new Rect(0, 0, mwSize.x, mwSize.y); + return new WindowBounds(new Rect(0, 0, mwSize.x, mwSize.y), new Rect()); } } diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java index 51b21aa795..72831f4d09 100644 --- a/src/com/android/launcher3/DeviceProfile.java +++ b/src/com/android/launcher3/DeviceProfile.java @@ -29,6 +29,7 @@ import com.android.launcher3.graphics.IconShape; import com.android.launcher3.icons.DotRenderer; import com.android.launcher3.icons.IconNormalizer; import com.android.launcher3.util.DefaultDisplay; +import com.android.launcher3.util.WindowBounds; public class DeviceProfile { @@ -265,19 +266,16 @@ public class DeviceProfile { /** * TODO: Move this to the builder as part of setMultiWindowMode */ - public DeviceProfile getMultiWindowProfile(Context context, Rect windowPosition) { + public DeviceProfile getMultiWindowProfile(Context context, WindowBounds windowBounds) { // We take the minimum sizes of this profile and it's multi-window variant to ensure that // the system decor is always excluded. - Point mwSize = new Point(Math.min(availableWidthPx, windowPosition.width()), - Math.min(availableHeightPx, windowPosition.height())); + Point mwSize = new Point(Math.min(availableWidthPx, windowBounds.availableSize.x), + Math.min(availableHeightPx, windowBounds.availableSize.y)); - // In multi-window mode, we can have widthPx = availableWidthPx - // and heightPx = availableHeightPx because Launcher uses the InvariantDeviceProfiles' - // widthPx and heightPx values where it's needed. DeviceProfile profile = toBuilder(context) .setSizeRange(mwSize, mwSize) - .setSize(mwSize.x, mwSize.y) - .setWindowPosition(windowPosition.left, windowPosition.top) + .setSize(windowBounds.bounds.width(), windowBounds.bounds.height()) + .setWindowPosition(windowBounds.bounds.left, windowBounds.bounds.top) .setMultiWindowMode(true) .build(); @@ -299,7 +297,7 @@ public class DeviceProfile { } /** - * Inverse of {@link #getMultiWindowProfile(Context, Rect)} + * Inverse of {@link #getMultiWindowProfile(Context, WindowBounds)} * @return device profile corresponding to the current orientation in non multi-window mode. */ public DeviceProfile getFullScreenProfile() { diff --git a/src/com/android/launcher3/InvariantDeviceProfile.java b/src/com/android/launcher3/InvariantDeviceProfile.java index 8951674879..60abc66b2b 100644 --- a/src/com/android/launcher3/InvariantDeviceProfile.java +++ b/src/com/android/launcher3/InvariantDeviceProfile.java @@ -200,7 +200,7 @@ public class InvariantDeviceProfile { DefaultDisplay.INSTANCE.get(context).getInfo(), getPredefinedDeviceProfiles(context, gridName)); - Info myInfo = new Info(display); + Info myInfo = new Info(context, display); DisplayOption myDisplayOption = invDistWeightedInterpolate( myInfo, getPredefinedDeviceProfiles(context, gridName)); diff --git a/src/com/android/launcher3/LauncherSettings.java b/src/com/android/launcher3/LauncherSettings.java index 67890726b1..2cb3910793 100644 --- a/src/com/android/launcher3/LauncherSettings.java +++ b/src/com/android/launcher3/LauncherSettings.java @@ -154,9 +154,9 @@ public class LauncherSettings { public static final int CONTAINER_HOTSEAT_PREDICTION = -103; public static final int CONTAINER_ALL_APPS = -104; public static final int CONTAINER_WIDGETS_TRAY = -105; - // Represents search results view. public static final int CONTAINER_SEARCH_RESULTS = -106; + public static final int CONTAINER_SHORTCUTS = -107; public static final String containerToString(int container) { switch (container) { @@ -166,6 +166,7 @@ public class LauncherSettings { case CONTAINER_ALL_APPS: return "all_apps"; case CONTAINER_WIDGETS_TRAY: return "widgets_tray"; case CONTAINER_SEARCH_RESULTS: return "search_result"; + case CONTAINER_SHORTCUTS: return "shortcuts"; default: return String.valueOf(container); } } diff --git a/src/com/android/launcher3/allapps/AllAppsTransitionController.java b/src/com/android/launcher3/allapps/AllAppsTransitionController.java index aa9edda582..99ed0ad52b 100644 --- a/src/com/android/launcher3/allapps/AllAppsTransitionController.java +++ b/src/com/android/launcher3/allapps/AllAppsTransitionController.java @@ -6,6 +6,8 @@ import static com.android.launcher3.LauncherState.APPS_VIEW_ITEM_MASK; import static com.android.launcher3.LauncherState.OVERVIEW; import static com.android.launcher3.LauncherState.VERTICAL_SWIPE_INDICATOR; import static com.android.launcher3.anim.Interpolators.FAST_OUT_SLOW_IN; +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.PropertySetter.NO_ANIM_PROPERTY_SETTER; import static com.android.launcher3.states.StateAnimationConfig.ANIM_ALL_APPS_FADE; @@ -227,7 +229,9 @@ public class AllAppsTransitionController implements StateHandler, setter.setInt(mScrimView, ScrimView.DRAG_HANDLE_ALPHA, (visibleElements & VERTICAL_SWIPE_INDICATOR) != 0 ? 255 : 0, allAppsFade); - setter.setViewAlpha(mAppsView, hasAnyVisibleItem ? 1 : 0, allAppsFade); + // Set visibility of the container at the very beginning or end of the transition. + setter.setViewAlpha(mAppsView, hasAnyVisibleItem ? 1 : 0, + hasAnyVisibleItem ? INSTANT : FINAL_FRAME); } public AnimatorListenerAdapter getProgressAnimatorListener() { diff --git a/src/com/android/launcher3/anim/Interpolators.java b/src/com/android/launcher3/anim/Interpolators.java index fccc120900..860ccebef4 100644 --- a/src/com/android/launcher3/anim/Interpolators.java +++ b/src/com/android/launcher3/anim/Interpolators.java @@ -61,6 +61,11 @@ public class Interpolators { public static final Interpolator EXAGGERATED_EASE; public static final Interpolator INSTANT = t -> 1; + /** + * All values of t map to 0 until t == 1. This is primarily useful for setting view visibility, + * which should only happen at the very end of the animation (when it's already hidden). + */ + public static final Interpolator FINAL_FRAME = t -> t < 1 ? 0 : 1; private static final int MIN_SETTLE_DURATION = 200; private static final float OVERSHOOT_FACTOR = 0.9f; diff --git a/src/com/android/launcher3/folder/Folder.java b/src/com/android/launcher3/folder/Folder.java index f7fe535a48..fdf0ea46f2 100644 --- a/src/com/android/launcher3/folder/Folder.java +++ b/src/com/android/launcher3/folder/Folder.java @@ -466,6 +466,7 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo if (!isEmpty(firstLabel)) { mFolderName.setHint(""); mFolderName.setText(firstLabel); + mFolderName.selectAll(); } } mFolderName.showKeyboard(); diff --git a/src/com/android/launcher3/logging/StatsLogManager.java b/src/com/android/launcher3/logging/StatsLogManager.java index 4c2c79d6dd..dda39e8a51 100644 --- a/src/com/android/launcher3/logging/StatsLogManager.java +++ b/src/com/android/launcher3/logging/StatsLogManager.java @@ -32,7 +32,7 @@ import com.android.launcher3.util.ResourceBasedOverride; */ public class StatsLogManager implements ResourceBasedOverride { - interface EventEnum { + public interface EventEnum { int getId(); } @@ -63,6 +63,18 @@ public class StatsLogManager implements ResourceBasedOverride { + "new/same value.") LAUNCHER_FOLDER_LABEL_UPDATED(460), + @UiEvent(doc = "User long pressed on the workspace empty space.") + LAUNCHER_WORKSPACE_LONGPRESS(461), + + @UiEvent(doc = "User tapped or long pressed on a wallpaper icon inside launcher settings.") + LAUNCHER_WALLPAPER_BUTTON_TAP_OR_LONGPRESS(462), + + @UiEvent(doc = "User tapped or long pressed on settings icon inside launcher settings.") + LAUNCHER_SETTINGS_BUTTON_TAP_OR_LONGPRESS(463), + + @UiEvent(doc = "User tapped or long pressed on widget tray icon inside launcher settings.") + LAUNCHER_WIDGETSTRAY_BUTTON_TAP_OR_LONGPRESS(464), + @UiEvent(doc = "A dragged item is dropped on 'Remove' button in the target bar") LAUNCHER_ITEM_DROPPED_ON_REMOVE(465), @@ -82,7 +94,15 @@ public class StatsLogManager implements ResourceBasedOverride { @UiEvent(doc = "User cancelled uninstalling the package after dropping on " + "the icon onto 'Uninstall' button in the target bar") - LAUNCHER_ITEM_UNINSTALL_CANCELLED(470); + LAUNCHER_ITEM_UNINSTALL_CANCELLED(470), + + @UiEvent(doc = "User opened package specific widgets list by tapping on widgets system " + + "shortcut within longpress popup window.") + LAUNCHER_SYSTEM_SHORTCUT_WIDGETS_TAP(514), + + @UiEvent(doc = "User opened app info of the package by tapping on appinfo system shortcut " + + "within longpress popup window.") + LAUNCHER_SYSTEM_SHORTCUT_APP_INFO_TAP(515); // ADD MORE private final int mId; @@ -113,27 +133,27 @@ public class StatsLogManager implements ResourceBasedOverride { } /** - * Logs a {@link LauncherEvent}. + * Logs a {@link EventEnum}. */ - public void log(LauncherEvent event) { + public void log(EventEnum event) { } /** * Logs an event and accompanying {@link InstanceId}. */ - public void log(LauncherEvent event, InstanceId instanceId) { + public void log(EventEnum event, InstanceId instanceId) { } /** * Logs an event and accompanying {@link ItemInfo}. */ - public void log(LauncherEvent event, @Nullable ItemInfo info) { + public void log(EventEnum event, @Nullable ItemInfo itemInfo) { } /** * Logs an event and accompanying {@link InstanceId} and {@link ItemInfo}. */ - public void log(LauncherEvent event, InstanceId instanceId, @Nullable ItemInfo info) { + public void log(EventEnum event, InstanceId instanceId, @Nullable ItemInfo itemInfo) { } /** diff --git a/src/com/android/launcher3/model/data/ItemInfo.java b/src/com/android/launcher3/model/data/ItemInfo.java index 3a89236138..0c815d145a 100644 --- a/src/com/android/launcher3/model/data/ItemInfo.java +++ b/src/com/android/launcher3/model/data/ItemInfo.java @@ -22,6 +22,7 @@ import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_HOTSEAT import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_HOTSEAT_PREDICTION; import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_PREDICTION; import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_SEARCH_RESULTS; +import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_SHORTCUTS; import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_WIDGETS_TRAY; import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_APPLICATION; import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET; @@ -45,6 +46,7 @@ import com.android.launcher3.logger.LauncherAtom.AllAppsContainer; import com.android.launcher3.logger.LauncherAtom.ContainerInfo; import com.android.launcher3.logger.LauncherAtom.PredictionContainer; import com.android.launcher3.logger.LauncherAtom.SearchResultContainer; +import com.android.launcher3.logger.LauncherAtom.ShortcutsContainer; import com.android.launcher3.util.ContentWriter; import java.util.Optional; @@ -363,6 +365,10 @@ public class ItemInfo { return ContainerInfo.newBuilder() .setSearchResultContainer(SearchResultContainer.getDefaultInstance()) .build(); + case CONTAINER_SHORTCUTS: + return ContainerInfo.newBuilder() + .setShortcutsContainer(ShortcutsContainer.getDefaultInstance()) + .build(); } return ContainerInfo.getDefaultInstance(); } diff --git a/src/com/android/launcher3/popup/PopupContainerWithArrow.java b/src/com/android/launcher3/popup/PopupContainerWithArrow.java index 331298f414..614cf1401d 100644 --- a/src/com/android/launcher3/popup/PopupContainerWithArrow.java +++ b/src/com/android/launcher3/popup/PopupContainerWithArrow.java @@ -16,6 +16,7 @@ package com.android.launcher3.popup; +import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_SHORTCUTS; import static com.android.launcher3.Utilities.squaredHypot; import static com.android.launcher3.Utilities.squaredTouchSlop; import static com.android.launcher3.logging.LoggerUtils.newContainerTarget; @@ -61,6 +62,7 @@ import com.android.launcher3.dragndrop.DragView; import com.android.launcher3.dragndrop.DraggableView; import com.android.launcher3.model.data.ItemInfo; import com.android.launcher3.model.data.ItemInfoWithIcon; +import com.android.launcher3.model.data.WorkspaceItemInfo; import com.android.launcher3.notification.NotificationInfo; import com.android.launcher3.notification.NotificationItemView; import com.android.launcher3.notification.NotificationKeyData; @@ -675,8 +677,10 @@ public class PopupContainerWithArrow extends Arr iconShift.y = mIconLastTouchPos.y - mLauncher.getDeviceProfile().iconSizePx; DraggableView draggableView = DraggableView.ofType(DraggableView.DRAGGABLE_ICON); + WorkspaceItemInfo itemInfo = sv.getFinalInfo(); + itemInfo.container = CONTAINER_SHORTCUTS; DragView dv = mLauncher.getWorkspace().beginDragShared(sv.getIconView(), draggableView, - mContainer, sv.getFinalInfo(), + mContainer, itemInfo, new ShortcutDragPreviewProvider(sv.getIconView(), iconShift), new DragOptions()); dv.animateShift(-iconShift.x, -iconShift.y); diff --git a/src/com/android/launcher3/popup/PopupPopulator.java b/src/com/android/launcher3/popup/PopupPopulator.java index 7da86cc0af..6d3bc1451a 100644 --- a/src/com/android/launcher3/popup/PopupPopulator.java +++ b/src/com/android/launcher3/popup/PopupPopulator.java @@ -16,6 +16,8 @@ package com.android.launcher3.popup; +import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_SHORTCUTS; + import android.content.ComponentName; import android.content.pm.ShortcutInfo; import android.os.Handler; @@ -160,6 +162,7 @@ public class PopupPopulator { final WorkspaceItemInfo si = new WorkspaceItemInfo(shortcut, launcher); cache.getUnbadgedShortcutIcon(si, shortcut); si.rank = i; + si.container = CONTAINER_SHORTCUTS; final DeepShortcutView view = shortcutViews.get(i); uiHandler.post(() -> view.applyShortcutInfo(si, shortcut, container)); diff --git a/src/com/android/launcher3/popup/SystemShortcut.java b/src/com/android/launcher3/popup/SystemShortcut.java index ae35d4c594..58ed5e8132 100644 --- a/src/com/android/launcher3/popup/SystemShortcut.java +++ b/src/com/android/launcher3/popup/SystemShortcut.java @@ -1,5 +1,7 @@ package com.android.launcher3.popup; +import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_SYSTEM_SHORTCUT_APP_INFO_TAP; +import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_SYSTEM_SHORTCUT_WIDGETS_TAP; import android.app.ActivityOptions; import android.content.Context; @@ -103,7 +105,6 @@ public abstract class SystemShortcut extends Ite }; public static class Widgets extends SystemShortcut { - public Widgets(Launcher target, ItemInfo itemInfo) { super(R.drawable.ic_widget, R.string.widget_button_text, target, itemInfo); } @@ -117,6 +118,9 @@ public abstract class SystemShortcut extends Ite widgetsBottomSheet.populateAndShow(mItemInfo); mTarget.getUserEventDispatcher().logActionOnControl(Action.Touch.TAP, ControlType.WIDGETS_BUTTON, view); + // TODO(thiruram): Fix missing container info when item is inside folder. + mTarget.getStatsLogManager().log(LAUNCHER_SYSTEM_SHORTCUT_WIDGETS_TAP, + mItemInfo.buildProto()); } } @@ -137,6 +141,9 @@ public abstract class SystemShortcut extends Ite mItemInfo, sourceBounds, ActivityOptions.makeBasic().toBundle()); mTarget.getUserEventDispatcher().logActionOnControl(Action.Touch.TAP, ControlType.APPINFO_TARGET, view); + // TODO(thiruram): Fix missing container info when item is inside folder. + mTarget.getStatsLogManager().log(LAUNCHER_SYSTEM_SHORTCUT_APP_INFO_TAP, + mItemInfo.buildProto()); } } diff --git a/src/com/android/launcher3/touch/WorkspaceTouchListener.java b/src/com/android/launcher3/touch/WorkspaceTouchListener.java index e6de06d6f0..7270ce28fb 100644 --- a/src/com/android/launcher3/touch/WorkspaceTouchListener.java +++ b/src/com/android/launcher3/touch/WorkspaceTouchListener.java @@ -22,6 +22,7 @@ import static android.view.MotionEvent.ACTION_POINTER_UP; import static android.view.MotionEvent.ACTION_UP; import static com.android.launcher3.LauncherState.NORMAL; +import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_WORKSPACE_LONGPRESS; import android.graphics.PointF; import android.graphics.Rect; @@ -41,8 +42,6 @@ import com.android.launcher3.dragndrop.DragLayer; import com.android.launcher3.testing.TestLogging; import com.android.launcher3.testing.TestProtocol; import com.android.launcher3.views.OptionsPopupView; -import com.android.launcher3.userevent.nano.LauncherLogProto.Action; -import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType; /** * Helper class to handle touch on empty space in workspace and show options popup on long press @@ -175,9 +174,7 @@ public class WorkspaceTouchListener extends GestureDetector.SimpleOnGestureListe mWorkspace.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS, HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING); - mLauncher.getUserEventDispatcher().logActionOnContainer(Action.Touch.LONGPRESS, - Action.Direction.NONE, ContainerType.WORKSPACE, - mWorkspace.getCurrentPage()); + mLauncher.getStatsLogManager().log(LAUNCHER_WORKSPACE_LONGPRESS); OptionsPopupView.showDefaultOptions(mLauncher, mTouchDownPoint.x, mTouchDownPoint.y); } else { cancelLongPress(); diff --git a/src/com/android/launcher3/util/DefaultDisplay.java b/src/com/android/launcher3/util/DefaultDisplay.java index fabdb4e86c..150fb5b043 100644 --- a/src/com/android/launcher3/util/DefaultDisplay.java +++ b/src/com/android/launcher3/util/DefaultDisplay.java @@ -145,10 +145,11 @@ public class DefaultDisplay implements DisplayListener { } private Info(Context context) { - this(context.getSystemService(DisplayManager.class).getDisplay(DEFAULT_DISPLAY)); + this(context, context.getSystemService(DisplayManager.class) + .getDisplay(DEFAULT_DISPLAY)); } - public Info(Display display) { + public Info(Context context, Display display) { id = display.getDisplayId(); rotation = display.getRotation(); @@ -161,8 +162,8 @@ public class DefaultDisplay implements DisplayListener { display.getRealSize(realSize); display.getCurrentSizeRange(smallestSize, largestSize); - metrics = new DisplayMetrics(); - display.getMetrics(metrics); + Context defaultDisplayContext = context.createDisplayContext(display); + metrics = defaultDisplayContext.getResources().getDisplayMetrics(); } private boolean hasDifferentSize(Info info) { diff --git a/src/com/android/launcher3/views/BaseDragLayer.java b/src/com/android/launcher3/views/BaseDragLayer.java index 6915953068..c37c47c0a0 100644 --- a/src/com/android/launcher3/views/BaseDragLayer.java +++ b/src/com/android/launcher3/views/BaseDragLayer.java @@ -181,6 +181,11 @@ public abstract class BaseDragLayer } private TouchController findControllerToHandleTouch(MotionEvent ev) { + if (TestProtocol.sDebugTracing) { + Log.d(TestProtocol.PAUSE_NOT_DETECTED, "findControllerToHandleTouch ev=" + ev + + ", isEventInLauncher=" + isEventInLauncher(ev) + + ", topOpenView=" + AbstractFloatingView.getTopOpenView(mActivity)); + } if (isEventInLauncher(ev)) { AbstractFloatingView topView = AbstractFloatingView.getTopOpenView(mActivity); if (topView != null && topView.onControllerInterceptTouchEvent(ev)) { diff --git a/src/com/android/launcher3/views/FloatingIconView.java b/src/com/android/launcher3/views/FloatingIconView.java index bd12e06b60..177aff4a89 100644 --- a/src/com/android/launcher3/views/FloatingIconView.java +++ b/src/com/android/launcher3/views/FloatingIconView.java @@ -59,6 +59,7 @@ import com.android.launcher3.icons.LauncherIcons; import com.android.launcher3.model.data.ItemInfo; import com.android.launcher3.popup.SystemShortcut; import com.android.launcher3.shortcuts.DeepShortcutView; +import com.android.launcher3.testing.TestProtocol; /** * A view that is created to look like another view with the purpose of creating fluid animations. @@ -560,6 +561,11 @@ public class FloatingIconView extends FrameLayout implements view.setVisibility(INVISIBLE); parent.addView(view); dragLayer.addView(view.mListenerView); + if (TestProtocol.sDebugTracing) { + Log.d(TestProtocol.PAUSE_NOT_DETECTED, "getFloatingIconView. listenerView " + + "added to dragLayer. listenerView=" + view.mListenerView + ", fiv=" + view, + new Exception()); + } view.mListenerView.setListener(view::fastFinish); view.mEndRunnable = () -> { @@ -639,6 +645,10 @@ public class FloatingIconView extends FrameLayout implements private void finish(DragLayer dragLayer) { ((ViewGroup) dragLayer.getParent()).removeView(this); dragLayer.removeView(mListenerView); + if (TestProtocol.sDebugTracing) { + Log.d(TestProtocol.PAUSE_NOT_DETECTED, "listenerView removed from dragLayer. " + + "listenerView=" + mListenerView + ", fiv=" + this, new Exception()); + } recycle(); mLauncher.getViewCache().recycleView(R.layout.floating_icon_view, this); } diff --git a/src/com/android/launcher3/views/ListenerView.java b/src/com/android/launcher3/views/ListenerView.java index 263f7c4c32..575f86454c 100644 --- a/src/com/android/launcher3/views/ListenerView.java +++ b/src/com/android/launcher3/views/ListenerView.java @@ -17,18 +17,20 @@ package com.android.launcher3.views; import android.content.Context; import android.util.AttributeSet; +import android.util.Log; import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; import com.android.launcher3.AbstractFloatingView; +import com.android.launcher3.testing.TestProtocol; /** * An invisible AbstractFloatingView that can run a callback when it is being closed. */ public class ListenerView extends AbstractFloatingView { - public Runnable mCloseListener; + private Runnable mCloseListener; public ListenerView(Context context, AttributeSet attrs) { super(context, attrs); @@ -36,12 +38,20 @@ public class ListenerView extends AbstractFloatingView { } public void setListener(Runnable listener) { + if (TestProtocol.sDebugTracing) { + Log.d(TestProtocol.PAUSE_NOT_DETECTED, "ListenerView setListener lv=" + this + + ", listener=" + listener, new Exception()); + } mCloseListener = listener; } @Override protected void onAttachedToWindow() { super.onAttachedToWindow(); + if (TestProtocol.sDebugTracing) { + Log.d(TestProtocol.PAUSE_NOT_DETECTED, "ListenerView onAttachedToWindow lv=" + this, + new Exception()); + } mIsOpen = true; } @@ -49,10 +59,19 @@ public class ListenerView extends AbstractFloatingView { protected void onDetachedFromWindow() { super.onDetachedFromWindow(); mIsOpen = false; + if (TestProtocol.sDebugTracing) { + Log.d(TestProtocol.PAUSE_NOT_DETECTED, "ListenerView onDetachedFromView lv=" + this, + new Exception()); + } } @Override protected void handleClose(boolean animate) { + if (TestProtocol.sDebugTracing) { + Log.d(TestProtocol.PAUSE_NOT_DETECTED, "ListenerView handeClose lv=" + this + + ", mIsOpen=" + mIsOpen + ", mCloseListener=" + mCloseListener + + ", getParent()=" + getParent(), new Exception()); + } if (mIsOpen) { if (mCloseListener != null) { mCloseListener.run(); @@ -77,6 +96,10 @@ public class ListenerView extends AbstractFloatingView { @Override public boolean onControllerInterceptTouchEvent(MotionEvent ev) { + if (TestProtocol.sDebugTracing) { + Log.d(TestProtocol.PAUSE_NOT_DETECTED, "ListenerView touchEvent lv=" + this + + ", ev=" + ev, new Exception()); + } if (ev.getAction() == MotionEvent.ACTION_DOWN) { handleClose(false); } diff --git a/src/com/android/launcher3/views/OptionsPopupView.java b/src/com/android/launcher3/views/OptionsPopupView.java index d5c3c1d30e..7467186721 100644 --- a/src/com/android/launcher3/views/OptionsPopupView.java +++ b/src/com/android/launcher3/views/OptionsPopupView.java @@ -17,6 +17,9 @@ package com.android.launcher3.views; import static com.android.launcher3.Utilities.EXTRA_WALLPAPER_FLAVOR; import static com.android.launcher3.Utilities.EXTRA_WALLPAPER_OFFSET; +import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_SETTINGS_BUTTON_TAP_OR_LONGPRESS; +import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_WALLPAPER_BUTTON_TAP_OR_LONGPRESS; +import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_WIDGETSTRAY_BUTTON_TAP_OR_LONGPRESS; import android.content.Context; import android.content.Intent; @@ -37,13 +40,12 @@ import androidx.annotation.VisibleForTesting; import com.android.launcher3.Launcher; import com.android.launcher3.R; import com.android.launcher3.Utilities; +import com.android.launcher3.logging.StatsLogManager.EventEnum; import com.android.launcher3.model.WidgetsModel; import com.android.launcher3.popup.ArrowPopup; import com.android.launcher3.shortcuts.DeepShortcutView; import com.android.launcher3.testing.TestLogging; import com.android.launcher3.testing.TestProtocol; -import com.android.launcher3.userevent.nano.LauncherLogProto.Action; -import com.android.launcher3.userevent.nano.LauncherLogProto.ControlType; import com.android.launcher3.widget.WidgetsFullSheet; import java.util.ArrayList; @@ -68,21 +70,21 @@ public class OptionsPopupView extends ArrowPopup @Override public void onClick(View view) { - handleViewClick(view, Action.Touch.TAP); + handleViewClick(view); } @Override public boolean onLongClick(View view) { - return handleViewClick(view, Action.Touch.LONGPRESS); + return handleViewClick(view); } - private boolean handleViewClick(View view, int action) { + private boolean handleViewClick(View view) { OptionItem item = mItemMap.get(view); if (item == null) { return false; } - if (item.mControlTypeForLog > 0) { - logTap(action, item.mControlTypeForLog); + if (item.mEventId.getId() > 0) { + mLauncher.getStatsLogManager().log(item.mEventId); } if (item.mClickListener.onLongClick(view)) { close(true); @@ -91,10 +93,6 @@ public class OptionsPopupView extends ArrowPopup return false; } - private void logTap(int action, int controlType) { - mLauncher.getUserEventDispatcher().logActionOnControl(action, controlType); - } - @Override public boolean onControllerInterceptTouchEvent(MotionEvent ev) { if (ev.getAction() != MotionEvent.ACTION_DOWN) { @@ -159,13 +157,16 @@ public class OptionsPopupView extends ArrowPopup int resDrawable = Utilities.existsStyleWallpapers(launcher) ? R.drawable.ic_palette : R.drawable.ic_wallpaper; options.add(new OptionItem(resString, resDrawable, - ControlType.WALLPAPER_BUTTON, OptionsPopupView::startWallpaperPicker)); + LAUNCHER_WALLPAPER_BUTTON_TAP_OR_LONGPRESS, + OptionsPopupView::startWallpaperPicker)); if (!WidgetsModel.GO_DISABLE_WIDGETS) { options.add(new OptionItem(R.string.widget_button_text, R.drawable.ic_widget, - ControlType.WIDGETS_BUTTON, OptionsPopupView::onWidgetsClicked)); + LAUNCHER_WIDGETSTRAY_BUTTON_TAP_OR_LONGPRESS, + OptionsPopupView::onWidgetsClicked)); } options.add(new OptionItem(R.string.settings_button_text, R.drawable.ic_setting, - ControlType.SETTINGS_BUTTON, OptionsPopupView::startSettings)); + LAUNCHER_SETTINGS_BUTTON_TAP_OR_LONGPRESS, + OptionsPopupView::startSettings)); show(launcher, target, options); } @@ -224,14 +225,14 @@ public class OptionsPopupView extends ArrowPopup private final int mLabelRes; private final int mIconRes; - private final int mControlTypeForLog; + private final EventEnum mEventId; private final OnLongClickListener mClickListener; - public OptionItem(int labelRes, int iconRes, int controlTypeForLog, + public OptionItem(int labelRes, int iconRes, EventEnum eventId, OnLongClickListener clickListener) { mLabelRes = labelRes; mIconRes = iconRes; - mControlTypeForLog = controlTypeForLog; + mEventId = eventId; mClickListener = clickListener; } } diff --git a/src_ui_overrides/com/android/launcher3/uioverrides/PreviewSurfaceRenderer.java b/src_ui_overrides/com/android/launcher3/uioverrides/PreviewSurfaceRenderer.java deleted file mode 100644 index 4913cadb5a..0000000000 --- a/src_ui_overrides/com/android/launcher3/uioverrides/PreviewSurfaceRenderer.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright (C) 2020 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 android.content.Context; -import android.os.Bundle; - -/** Render preview using surface view. */ -public class PreviewSurfaceRenderer { - - /** Handle a received surface view request. */ - public static void render(Context context, Bundle bundle) { } -}