diff --git a/AndroidManifest-common.xml b/AndroidManifest-common.xml index c7a02536d2..d7191b4b40 100644 --- a/AndroidManifest-common.xml +++ b/AndroidManifest-common.xml @@ -137,14 +137,6 @@ - - - + + + + diff --git a/quickstep/recents_ui_overrides/res/values/dimens.xml b/quickstep/recents_ui_overrides/res/values/dimens.xml index 20b148537f..363840a217 100644 --- a/quickstep/recents_ui_overrides/res/values/dimens.xml +++ b/quickstep/recents_ui_overrides/res/values/dimens.xml @@ -31,9 +31,6 @@ 16dp 8dp 14sp - 8dp - - 2dp 80dp diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/appprediction/AllAppsTipView.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/appprediction/AllAppsTipView.java index b3bb850806..079a738036 100644 --- a/quickstep/recents_ui_overrides/src/com/android/launcher3/appprediction/AllAppsTipView.java +++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/appprediction/AllAppsTipView.java @@ -24,13 +24,13 @@ import static com.android.quickstep.logging.UserEventDispatcherExtension.ALL_APP import android.os.UserManager; import com.android.launcher3.AbstractFloatingView; -import com.android.launcher3.ArrowTipView; import com.android.launcher3.Launcher; import com.android.launcher3.LauncherState; import com.android.launcher3.LauncherStateManager; import com.android.launcher3.R; import com.android.launcher3.Utilities; import com.android.launcher3.allapps.FloatingHeaderView; +import com.android.launcher3.views.ArrowTipView; import com.android.systemui.shared.system.LauncherEventUtil; /** 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 5b01185ca3..773c6c8a6a 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 @@ -26,7 +26,6 @@ import android.view.View; import androidx.core.app.NotificationCompat; -import com.android.launcher3.ArrowTipView; import com.android.launcher3.CellLayout; import com.android.launcher3.FolderInfo; import com.android.launcher3.Hotseat; @@ -43,6 +42,7 @@ 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; import java.util.ArrayDeque; diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/RecentsViewStateController.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/RecentsViewStateController.java index 549187f9e9..131b71fc53 100644 --- a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/RecentsViewStateController.java +++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/RecentsViewStateController.java @@ -15,18 +15,22 @@ */ package com.android.launcher3.uioverrides; -import static com.android.launcher3.LauncherState.RECENTS_CLEAR_ALL_BUTTON; +import static com.android.launcher3.LauncherState.OVERVIEW_BUTTONS; +import static com.android.launcher3.anim.Interpolators.AGGRESSIVE_EASE_IN_OUT; import static com.android.launcher3.anim.Interpolators.LINEAR; +import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_FADE; import static com.android.quickstep.views.RecentsView.CONTENT_ALPHA; import static com.android.quickstep.views.RecentsView.FULLSCREEN_PROGRESS; import android.annotation.TargetApi; import android.os.Build; import android.util.FloatProperty; +import android.view.View; +import android.view.animation.Interpolator; import androidx.annotation.NonNull; -import com.android.launcher3.Launcher; +import com.android.launcher3.BaseQuickstepLauncher; import com.android.launcher3.LauncherState; import com.android.launcher3.anim.AnimationSuccessListener; import com.android.launcher3.anim.PendingAnimation; @@ -44,7 +48,7 @@ import com.android.quickstep.views.RecentsView; public final class RecentsViewStateController extends BaseRecentsViewStateController { - public RecentsViewStateController(Launcher launcher) { + public RecentsViewStateController(BaseQuickstepLauncher launcher) { super(launcher); } @@ -55,7 +59,7 @@ public final class RecentsViewStateController extends mRecentsView.updateEmptyMessage(); mRecentsView.resetTaskVisuals(); } - setAlphas(PropertySetter.NO_ANIM_PROPERTY_SETTER, state.getVisibleElements(mLauncher)); + setAlphas(PropertySetter.NO_ANIM_PROPERTY_SETTER, state, LINEAR); mRecentsView.setFullscreenProgress(state.getOverviewFullscreenProgress()); } @@ -73,15 +77,22 @@ public final class RecentsViewStateController extends AnimationSuccessListener.forRunnable(mRecentsView::resetTaskVisuals)); } - setAlphas(builder, toState.getVisibleElements(mLauncher)); + setAlphas(builder, toState, + config.getInterpolator(ANIM_OVERVIEW_FADE, AGGRESSIVE_EASE_IN_OUT)); builder.setFloat(mRecentsView, FULLSCREEN_PROGRESS, toState.getOverviewFullscreenProgress(), LINEAR); } - private void setAlphas(PropertySetter propertySetter, int visibleElements) { - boolean hasClearAllButton = (visibleElements & RECENTS_CLEAR_ALL_BUTTON) != 0; + private void setAlphas(PropertySetter propertySetter, LauncherState state, + Interpolator actionInterpolator) { + float buttonAlpha = (state.getVisibleElements(mLauncher) & OVERVIEW_BUTTONS) != 0 ? 1 : 0; propertySetter.setFloat(mRecentsView.getClearAllButton(), ClearAllButton.VISIBILITY_ALPHA, - hasClearAllButton ? 1f : 0f, LINEAR); + buttonAlpha, LINEAR); + + View actionsView = mLauncher.getActionsView(); + if (actionsView != null) { + propertySetter.setViewAlpha(actionsView, buttonAlpha, actionInterpolator); + } } @Override diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/BackgroundAppState.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/BackgroundAppState.java index de3fce13ce..a87d6d14d6 100644 --- a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/BackgroundAppState.java +++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/BackgroundAppState.java @@ -90,7 +90,7 @@ public class BackgroundAppState extends OverviewState { @Override public int getVisibleElements(Launcher launcher) { return super.getVisibleElements(launcher) - & ~RECENTS_CLEAR_ALL_BUTTON & ~VERTICAL_SWIPE_INDICATOR; + & ~OVERVIEW_BUTTONS & ~VERTICAL_SWIPE_INDICATOR; } @Override diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/OverviewPeekState.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/OverviewPeekState.java index 8087611633..1288e7bf9b 100644 --- a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/OverviewPeekState.java +++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/OverviewPeekState.java @@ -25,6 +25,7 @@ import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_TR import com.android.launcher3.Launcher; import com.android.launcher3.LauncherState; import com.android.launcher3.R; +import com.android.launcher3.Utilities; import com.android.launcher3.states.StateAnimationConfig; public class OverviewPeekState extends OverviewState { @@ -37,6 +38,9 @@ public class OverviewPeekState extends OverviewState { ScaleAndTranslation result = super.getOverviewScaleAndTranslation(launcher); result.translationX = NORMAL.getOverviewScaleAndTranslation(launcher).translationX - launcher.getResources().getDimension(R.dimen.overview_peek_distance); + if (Utilities.isRtl(launcher.getResources())) { + result.translationX = -result.translationX; + } return result; } diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/OverviewState.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/OverviewState.java index 024872fec4..bcfb11c090 100644 --- a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/OverviewState.java +++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/OverviewState.java @@ -164,17 +164,15 @@ public class OverviewState extends LauncherState { @Override public int getVisibleElements(Launcher launcher) { - if (launcher.getDeviceProfile().isVerticalBarLayout()) { - return VERTICAL_SWIPE_INDICATOR | RECENTS_CLEAR_ALL_BUTTON; + if (ENABLE_OVERVIEW_ACTIONS.get() && removeShelfFromOverview(launcher)) { + return OVERVIEW_BUTTONS; + } else if (launcher.getDeviceProfile().isVerticalBarLayout()) { + return VERTICAL_SWIPE_INDICATOR | OVERVIEW_BUTTONS; } else { - if (ENABLE_OVERVIEW_ACTIONS.get() && removeShelfFromOverview(launcher)) { - return VERTICAL_SWIPE_INDICATOR | RECENTS_CLEAR_ALL_BUTTON; - } - boolean hasAllAppsHeaderExtra = launcher.getAppsView() != null && launcher.getAppsView().getFloatingHeaderView().hasVisibleContent(); - return HOTSEAT_SEARCH_BOX | VERTICAL_SWIPE_INDICATOR | RECENTS_CLEAR_ALL_BUTTON | - (hasAllAppsHeaderExtra ? ALL_APPS_HEADER_EXTRA : HOTSEAT_ICONS); + return HOTSEAT_SEARCH_BOX | VERTICAL_SWIPE_INDICATOR | OVERVIEW_BUTTONS + | (hasAllAppsHeaderExtra ? ALL_APPS_HEADER_EXTRA : HOTSEAT_ICONS); } } diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/FlingAndHoldTouchController.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/FlingAndHoldTouchController.java index 6fc03b1bf1..8af2747352 100644 --- a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/FlingAndHoldTouchController.java +++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/FlingAndHoldTouchController.java @@ -73,7 +73,11 @@ public class FlingAndHoldTouchController extends PortraitStatesTouchController { super(l, false /* allowDragToOverview */); mMotionPauseDetector = new MotionPauseDetector(l); mMotionPauseMinDisplacement = ViewConfiguration.get(l).getScaledTouchSlop(); - mMotionPauseMaxDisplacement = getShiftRange() * MAX_DISPLACEMENT_PERCENT; + mMotionPauseMaxDisplacement = getMotionPauseMaxDisplacement(); + } + + protected float getMotionPauseMaxDisplacement() { + return getShiftRange() * MAX_DISPLACEMENT_PERCENT; } @Override diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonNavbarToOverviewTouchController.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonNavbarToOverviewTouchController.java index 064133cfd9..71aa2e8d99 100644 --- a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonNavbarToOverviewTouchController.java +++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonNavbarToOverviewTouchController.java @@ -65,6 +65,13 @@ public class NoButtonNavbarToOverviewTouchController extends FlingAndHoldTouchCo mRecentsView = l.getOverviewPanel(); } + @Override + protected float getMotionPauseMaxDisplacement() { + // No need to disallow pause when swiping up all the way up the screen (unlike + // FlingAndHoldTouchController where user is probably intending to go to all apps). + return Float.MAX_VALUE; + } + @Override protected boolean canInterceptTouch(MotionEvent ev) { mDidTouchStartInNavBar = (ev.getEdgeFlags() & EDGE_NAV_BAR) != 0; diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/AppToOverviewAnimationProvider.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/AppToOverviewAnimationProvider.java index ce7fa0d413..9dce9847c2 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/AppToOverviewAnimationProvider.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/AppToOverviewAnimationProvider.java @@ -19,7 +19,7 @@ import static com.android.launcher3.LauncherState.BACKGROUND_APP; import static com.android.launcher3.LauncherState.OVERVIEW; import static com.android.launcher3.anim.Interpolators.FAST_OUT_SLOW_IN; import static com.android.launcher3.anim.Interpolators.TOUCH_RESPONSE_INTERPOLATOR; -import static com.android.launcher3.uioverrides.DepthController.DEPTH; +import static com.android.launcher3.statehandlers.DepthController.DEPTH; import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.MODE_CLOSING; import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.MODE_OPENING; @@ -34,7 +34,7 @@ import android.view.View; import com.android.launcher3.AbstractFloatingView; import com.android.launcher3.BaseDraggingActivity; import com.android.launcher3.anim.AnimationSuccessListener; -import com.android.launcher3.uioverrides.DepthController; +import com.android.launcher3.statehandlers.DepthController; import com.android.quickstep.util.AppWindowAnimationHelper; import com.android.quickstep.util.AppWindowAnimationHelper.TransformParams; import com.android.quickstep.util.RemoteAnimationProvider; @@ -105,12 +105,6 @@ final class AppToOverviewAnimationProvider exten mRecentsView.setRunningTaskIconScaledDown(true); } - DepthController depthController = mActivityInterface.getDepthController(); - if (depthController != null) { - // Update the surface to be the lowest closing app surface - depthController.setSurfaceToLauncher(mRecentsView); - } - AnimatorSet anim = new AnimatorSet(); anim.addListener(new AnimationSuccessListener() { @Override @@ -123,11 +117,17 @@ final class AppToOverviewAnimationProvider exten }); if (mActivity == null) { Log.e(TAG, "Animation created, before activity"); - anim.play(ValueAnimator.ofInt(0, 1).setDuration(RECENTS_LAUNCH_DURATION)) - .with(createDepthAnimator(depthController)); return anim; } + DepthController depthController = mActivityInterface.getDepthController(); + if (depthController != null) { + anim.play(ObjectAnimator.ofFloat(depthController, DEPTH, + BACKGROUND_APP.getDepth(mActivity), + OVERVIEW.getDepth(mActivity)) + .setDuration(RECENTS_LAUNCH_DURATION)); + } + RemoteAnimationTargets targets = new RemoteAnimationTargets(appTargets, wallpaperTargets, MODE_CLOSING); @@ -135,8 +135,6 @@ final class AppToOverviewAnimationProvider exten RemoteAnimationTargetCompat runningTaskTarget = targets.findTask(mTargetTaskId); if (runningTaskTarget == null) { Log.e(TAG, "No closing app"); - anim.play(ValueAnimator.ofInt(0, 1).setDuration(RECENTS_LAUNCH_DURATION)) - .with(createDepthAnimator(depthController)); return anim; } @@ -183,8 +181,6 @@ final class AppToOverviewAnimationProvider exten transaction.apply(); }); } - anim.play(valueAnimator) - .with(createDepthAnimator(depthController)); return anim; } @@ -196,15 +192,4 @@ final class AppToOverviewAnimationProvider exten long getRecentsLaunchDuration() { return RECENTS_LAUNCH_DURATION; } - - private Animator createDepthAnimator(DepthController depthController) { - if (depthController == null) { - // Dummy animation - return ValueAnimator.ofInt(0); - } - return ObjectAnimator.ofFloat(depthController, DEPTH, - BACKGROUND_APP.getDepth(mActivity), - OVERVIEW.getDepth(mActivity)) - .setDuration(RECENTS_LAUNCH_DURATION); - } } 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 7786a8f55b..113cdec9d0 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/BaseSwipeUpHandler.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/BaseSwipeUpHandler.java @@ -31,6 +31,7 @@ import android.graphics.PointF; import android.graphics.Rect; import android.graphics.RectF; import android.os.Build; +import android.util.Log; import android.util.Pair; import android.view.MotionEvent; import android.view.View; @@ -48,6 +49,7 @@ import com.android.launcher3.anim.AnimatorPlaybackController; import com.android.launcher3.graphics.RotationMode; import com.android.launcher3.model.PagedViewOrientedState; import com.android.launcher3.states.RotationHelper; +import com.android.launcher3.testing.TestProtocol; import com.android.launcher3.touch.PagedOrientationHandler; import com.android.launcher3.touch.PortraitPagedViewHandler; import com.android.launcher3.util.VibratorWrapper; @@ -198,18 +200,33 @@ public abstract class BaseSwipeUpHandler resultCallback) { + if (TestProtocol.sDebugTracing) { + Log.d(TestProtocol.NO_START_FROM_RECENTS, "startNewTask1"); + } // Launch the task user scrolled to (mRecentsView.getNextPage()). if (ENABLE_QUICKSTEP_LIVE_TILE.get()) { // We finish recents animation inside launchTask() when live tile is enabled. mRecentsView.getNextPageTaskView().launchTask(false /* animate */, true /* freezeTaskList */); } else { + if (TestProtocol.sDebugTracing) { + Log.d(TestProtocol.NO_START_FROM_RECENTS, "startNewTask2"); + } int taskId = mRecentsView.getNextPageTaskView().getTask().key.id; mFinishingRecentsAnimationForNewTaskId = taskId; mRecentsAnimationController.finish(true /* toRecents */, () -> { + if (TestProtocol.sDebugTracing) { + Log.d(TestProtocol.NO_START_FROM_RECENTS, "onFinishComplete1"); + } if (!mCanceled) { + if (TestProtocol.sDebugTracing) { + Log.d(TestProtocol.NO_START_FROM_RECENTS, "onFinishComplete2"); + } TaskView nextTask = mRecentsView.getTaskView(taskId); if (nextTask != null) { + if (TestProtocol.sDebugTracing) { + Log.d(TestProtocol.NO_START_FROM_RECENTS, "onFinishComplete3"); + } nextTask.launchTask(false /* animate */, true /* freezeTaskList */, success -> { resultCallback.accept(success); diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/FallbackSwipeHandler.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/FallbackSwipeHandler.java index ea5561b137..da73bc0ee4 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/FallbackSwipeHandler.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/FallbackSwipeHandler.java @@ -166,6 +166,7 @@ public class FallbackSwipeHandler extends BaseSwipeUpHandler mBitmapSupplier; + private final SystemUiProxy mSystemUiProxy; + + public ImageActionsApi(Context context, Supplier bitmapSupplier) { + mContext = context; + mBitmapSupplier = bitmapSupplier; + mSystemUiProxy = SystemUiProxy.INSTANCE.get(context); + } + + /** + * Share the image this api was constructed with using the provided intent. The implementation + * should add an {@link Intent#EXTRA_STREAM} with the URI pointing to the image to the intent. + */ + @UiThread + public void shareWithExplicitIntent(@Nullable Rect crop, Intent intent) { + if (mBitmapSupplier.get() == null) { + Log.e(TAG, "No snapshot available, not starting share."); + return; + } + + UI_HELPER_EXECUTOR.execute(() -> persistBitmapAndStartActivity(mContext, + mBitmapSupplier.get(), crop, intent, (uri, intentForUri) -> { + intentForUri.putExtra(EXTRA_STREAM, uri); + return new Intent[]{intentForUri}; + }, TAG)); + + } + + /** + * Share the image this api was constructed with. + */ + @UiThread + public void startShareActivity() { + ImageActionUtils.startShareActivity(mContext, mBitmapSupplier, null, null, TAG); + } + + /** + * @param screenshot to be saved to the media store. + * @param screenshotBounds the location of where the bitmap was laid out on the screen in + * screen coordinates. + * @param visibleInsets that are used to draw the screenshot within the bounds. + * @param taskId of the task that the screenshot was taken of. + */ + public void saveScreenshot(Bitmap screenshot, Rect screenshotBounds, + Insets visibleInsets, int taskId) { + ImageActionUtils.saveScreenshot(mSystemUiProxy, screenshot, screenshotBounds, visibleInsets, + taskId); + } +} 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 55e6ba2117..455ae764a9 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityInterface.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityInterface.java @@ -55,9 +55,9 @@ import com.android.launcher3.LauncherState; import com.android.launcher3.allapps.DiscoveryBounce; import com.android.launcher3.anim.AnimatorPlaybackController; import com.android.launcher3.appprediction.PredictionUiStateManager; +import com.android.launcher3.statehandlers.DepthController; +import com.android.launcher3.statehandlers.DepthController.ClampedDepthProperty; import com.android.launcher3.touch.PagedOrientationHandler; -import com.android.launcher3.uioverrides.DepthController; -import com.android.launcher3.uioverrides.DepthController.ClampedDepthProperty; import com.android.launcher3.userevent.nano.LauncherLogProto; import com.android.launcher3.views.FloatingIconView; import com.android.quickstep.SysUINavigationMode.Mode; diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherSwipeHandler.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherSwipeHandler.java index cafdb624a5..b3b0b0263a 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherSwipeHandler.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherSwipeHandler.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_RECENTS_SCROLLING_FINISHED; import static com.android.quickstep.MultiStateCallback.DEBUG_STATES; import static com.android.quickstep.SysUINavigationMode.Mode.TWO_BUTTONS; import static com.android.quickstep.util.ShelfPeekAnim.ShelfAnimState.HIDE; @@ -46,6 +47,7 @@ import android.graphics.PointF; import android.graphics.RectF; import android.os.Build; import android.os.SystemClock; +import android.util.Log; import android.view.View; import android.view.View.OnApplyWindowInsetsListener; import android.view.ViewTreeObserver.OnDrawListener; @@ -64,6 +66,7 @@ import com.android.launcher3.anim.AnimationSuccessListener; import com.android.launcher3.anim.AnimatorPlaybackController; import com.android.launcher3.anim.Interpolators; import com.android.launcher3.logging.UserEventDispatcher; +import com.android.launcher3.testing.TestProtocol; import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Direction; import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch; import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType; @@ -244,7 +247,11 @@ public class LauncherSwipeHandler | STATE_GESTURE_STARTED, this::setupLauncherUiAfterSwipeUpToRecentsAnimation); - mGestureState.runOnceAtState(STATE_END_TARGET_ANIMATION_FINISHED, this::onEndTargetSet); + mGestureState.runOnceAtState(STATE_END_TARGET_ANIMATION_FINISHED, + this::continueComputingRecentsScrollIfNecessary); + mGestureState.runOnceAtState(STATE_END_TARGET_ANIMATION_FINISHED + | STATE_RECENTS_SCROLLING_FINISHED, + this::onSettledOnEndTarget); mStateCallback.runOnceAtState(STATE_HANDLER_INVALIDATED, this::invalidateHandler); mStateCallback.runOnceAtState(STATE_LAUNCHER_PRESENT | STATE_HANDLER_INVALIDATED, @@ -283,6 +290,7 @@ public class LauncherSwipeHandler } mRecentsView = activity.getOverviewPanel(); + mRecentsView.setOnPageTransitionEndCallback(null); linkRecentsViewScroll(); addLiveTileOverlay(); @@ -294,7 +302,6 @@ public class LauncherSwipeHandler } setupRecentsViewUi(); - mActivityInterface.getDepthController().setSurfaceToLauncher(mRecentsView); if (mDeviceState.getNavMode() == TWO_BUTTONS) { // If the device is in two button mode, swiping up will show overview with predictions @@ -506,16 +513,22 @@ public class LauncherSwipeHandler } private void buildAnimationController() { - if (mGestureState.getEndTarget() == HOME || mHasLauncherTransitionControllerStarted) { - // We don't want a new mLauncherTransitionController if - // mGestureState.getEndTarget() == HOME (it has its own animation) or if we're already - // animating the current controller. + if (!canCreateNewOrUpdateExistingLauncherTransitionController()) { return; } initTransitionEndpoints(mActivity.getDeviceProfile()); mAnimationFactory.createActivityInterface(mTransitionDragLength); } + /** + * We don't want to change mLauncherTransitionController if mGestureState.getEndTarget() == HOME + * (it has its own animation) or if we're already animating the current controller. + * @return Whether we can create the launcher controller or update its progress. + */ + private boolean canCreateNewOrUpdateExistingLauncherTransitionController() { + return mGestureState.getEndTarget() != HOME && !mHasLauncherTransitionControllerStarted; + } + @Override public WindowInsets onApplyWindowInsets(View view, WindowInsets windowInsets) { WindowInsets result = view.onApplyWindowInsets(windowInsets); @@ -559,15 +572,12 @@ public class LauncherSwipeHandler } } - if (mLauncherTransitionController == null || mLauncherTransitionController - .getAnimationPlayer().isStarted()) { - return; - } updateLauncherTransitionProgress(); } private void updateLauncherTransitionProgress() { - if (mGestureState.getEndTarget() == HOME) { + if (mLauncherTransitionController == null + || !canCreateNewOrUpdateExistingLauncherTransitionController()) { return; } // Normalize the progress to 0 to 1, as the animation controller will clamp it to that @@ -697,7 +707,7 @@ public class LauncherSwipeHandler } } - private void onEndTargetSet() { + private void onSettledOnEndTarget() { switch (mGestureState.getEndTarget()) { case HOME: mStateCallback.setState(STATE_SCALED_CONTROLLER_HOME | STATE_CAPTURE_SCREENSHOT); @@ -860,13 +870,17 @@ public class LauncherSwipeHandler if (mDeviceState.isFullyGesturalNavMode()) { setShelfState(ShelfAnimState.OVERVIEW, interpolator, duration); } - } else if (endTarget == NEW_TASK || endTarget == LAST_TASK) { - // Let RecentsView handle the scrolling to the task, which we launch in startNewTask() - // or resumeLastTask(). - if (mRecentsView != null) { - duration = Math.max(duration, mRecentsView.getScroller().getDuration()); - } } + + // Let RecentsView handle the scrolling to the task, which we launch in startNewTask() + // or resumeLastTask(). + if (mRecentsView != null) { + mRecentsView.setOnPageTransitionEndCallback( + () -> mGestureState.setState(STATE_RECENTS_SCROLLING_FINISHED)); + } else { + mGestureState.setState(STATE_RECENTS_SCROLLING_FINISHED); + } + animateToProgress(startShift, endShift, duration, interpolator, endTarget, velocityPxPerMs); } @@ -950,15 +964,14 @@ public class LauncherSwipeHandler ValueAnimator windowAnim = mCurrentShift.animateToValue(start, end); windowAnim.setDuration(duration).setInterpolator(interpolator); windowAnim.addUpdateListener(valueAnimator -> { - if (mRecentsView != null && mRecentsView.getVisibility() != View.VISIBLE) { - // Views typically don't compute scroll when invisible as an optimization, - // but in our case we need to since the window offset depends on the scroll. - mRecentsView.computeScroll(); - } + computeRecentsScrollIfInvisible(); }); windowAnim.addListener(new AnimationSuccessListener() { @Override public void onAnimationSuccess(Animator animator) { + if (TestProtocol.sDebugTracing) { + Log.d(TestProtocol.NO_START_FROM_RECENTS, "onAnimationSuccess"); + } if (mRecentsAnimationController == null) { // If the recents animation is interrupted, we still end the running // animation (not canceled) so this is still called. In that case, we can @@ -1006,6 +1019,21 @@ public class LauncherSwipeHandler mHasLauncherTransitionControllerStarted = true; } + private void computeRecentsScrollIfInvisible() { + if (mRecentsView != null && mRecentsView.getVisibility() != View.VISIBLE) { + // Views typically don't compute scroll when invisible as an optimization, + // but in our case we need to since the window offset depends on the scroll. + mRecentsView.computeScroll(); + } + } + + private void continueComputingRecentsScrollIfNecessary() { + if (!mGestureState.hasState(STATE_RECENTS_SCROLLING_FINISHED)) { + computeRecentsScrollIfInvisible(); + mRecentsView.post(this::continueComputingRecentsScrollIfNecessary); + } + } + /** * 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. @@ -1167,6 +1195,9 @@ public class LauncherSwipeHandler } private void switchToScreenshot() { + if (TestProtocol.sDebugTracing) { + Log.d(TestProtocol.NO_START_FROM_RECENTS, "switchToScreenshot"); + } final int runningTaskId = mGestureState.getRunningTaskId(); if (ENABLE_QUICKSTEP_LIVE_TILE.get()) { if (mRecentsAnimationController != null) { diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/TaskOverlayFactory.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/TaskOverlayFactory.java index 33d9d9aa55..fbf29af9fb 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/TaskOverlayFactory.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/TaskOverlayFactory.java @@ -16,12 +16,13 @@ package com.android.quickstep; +import static com.android.launcher3.config.FeatureFlags.ENABLE_OVERVIEW_ACTIONS; import static com.android.launcher3.util.MainThreadInitializedObject.forOverride; +import android.content.Context; +import android.graphics.Insets; import android.graphics.Matrix; -import android.view.View; - -import androidx.annotation.Nullable; +import android.graphics.Rect; import com.android.launcher3.BaseActivity; import com.android.launcher3.BaseDraggingActivity; @@ -29,6 +30,7 @@ import com.android.launcher3.R; import com.android.launcher3.popup.SystemShortcut; import com.android.launcher3.util.MainThreadInitializedObject; import com.android.launcher3.util.ResourceBasedOverride; +import com.android.quickstep.views.OverviewActionsView; import com.android.quickstep.views.TaskThumbnailView; import com.android.quickstep.views.TaskView; import com.android.systemui.plugins.OverscrollPlugin; @@ -43,16 +45,6 @@ import java.util.List; */ public class TaskOverlayFactory implements ResourceBasedOverride { - /** Note that these will be shown in order from top to bottom, if available for the task. */ - private static final TaskShortcutFactory[] MENU_OPTIONS = new TaskShortcutFactory[]{ - TaskShortcutFactory.APP_INFO, - TaskShortcutFactory.SPLIT_SCREEN, - TaskShortcutFactory.PIN, - TaskShortcutFactory.INSTALL, - TaskShortcutFactory.FREE_FORM, - TaskShortcutFactory.WELLBEING - }; - public static List getEnabledShortcuts(TaskView taskView) { final ArrayList shortcuts = new ArrayList<>(); final BaseDraggingActivity activity = BaseActivity.fromContext(taskView.getContext()); @@ -76,25 +68,68 @@ public class TaskOverlayFactory implements ResourceBasedOverride { } public TaskOverlay createOverlay(TaskThumbnailView thumbnailView) { - return new TaskOverlay(); + return new TaskOverlay(thumbnailView); } + /** Note that these will be shown in order from top to bottom, if available for the task. */ + private static final TaskShortcutFactory[] MENU_OPTIONS = new TaskShortcutFactory[]{ + TaskShortcutFactory.APP_INFO, + TaskShortcutFactory.SPLIT_SCREEN, + TaskShortcutFactory.PIN, + TaskShortcutFactory.INSTALL, + TaskShortcutFactory.FREE_FORM, + TaskShortcutFactory.WELLBEING + }; + + /** + * Overlay on each task handling Overview Action Buttons. + */ public static class TaskOverlay { + private final Context mApplicationContext; + private OverviewActionsView mActionsView; + private final TaskThumbnailView mThumbnailView; + + + protected TaskOverlay(TaskThumbnailView taskThumbnailView) { + mApplicationContext = taskThumbnailView.getContext().getApplicationContext(); + mThumbnailView = taskThumbnailView; + } + /** * Called when the current task is interactive for the user */ - public void initOverlay(Task task, ThumbnailData thumbnail, Matrix matrix) { } + public void initOverlay(Task task, ThumbnailData thumbnail, Matrix matrix) { + ImageActionsApi imageApi = new ImageActionsApi( + mApplicationContext, mThumbnailView::getThumbnail); + + if (mActionsView == null && ENABLE_OVERVIEW_ACTIONS.get() + && SysUINavigationMode.removeShelfFromOverview(mApplicationContext)) { + mActionsView = BaseActivity.fromContext(mThumbnailView.getContext()).findViewById( + R.id.overview_actions_view); + } + if (mActionsView != null) { + mActionsView.setListener(new OverviewActionsView.Listener() { + @Override + public void onShare() { + imageApi.startShareActivity(); + } + + @Override + public void onScreenshot() { + imageApi.saveScreenshot(mThumbnailView.getThumbnail(), + getTaskSnapshotBounds(), getTaskSnapshotInsets(), task.key.id); + } + }); + } - @Nullable - public View getActionsView() { - return null; } /** * Called when the overlay is no longer used. */ - public void reset() { } + public void reset() { + } /** * Whether the overlay is modal, which means only tapping is enabled, but no swiping. @@ -102,5 +137,28 @@ public class TaskOverlayFactory implements ResourceBasedOverride { public boolean isOverlayModal() { return false; } + + /** + * Gets the task snapshot as it is displayed on the screen. + * + * @return the bounds of the snapshot in screen coordinates. + */ + public Rect getTaskSnapshotBounds() { + int[] location = new int[2]; + mThumbnailView.getLocationOnScreen(location); + + return new Rect(location[0], location[1], mThumbnailView.getWidth() + location[0], + mThumbnailView.getHeight() + location[1]); + } + + /** + * Gets the insets that the snapshot is drawn with. + * + * @return the insets in screen coordinates. + */ + public Insets getTaskSnapshotInsets() { + // TODO: return the real insets + return Insets.of(0, 0, 0, 0); + } } } diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/TaskViewUtils.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/TaskViewUtils.java index 7ec083e5df..6a3e1feddb 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/TaskViewUtils.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/TaskViewUtils.java @@ -19,7 +19,7 @@ import static com.android.launcher3.LauncherState.BACKGROUND_APP; import static com.android.launcher3.anim.Interpolators.LINEAR; import static com.android.launcher3.anim.Interpolators.TOUCH_RESPONSE_INTERPOLATOR; import static com.android.launcher3.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TILE; -import static com.android.launcher3.uioverrides.DepthController.DEPTH; +import static com.android.launcher3.statehandlers.DepthController.DEPTH; import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.MODE_OPENING; import android.animation.Animator; @@ -35,7 +35,7 @@ import com.android.launcher3.BaseActivity; import com.android.launcher3.BaseDraggingActivity; import com.android.launcher3.ItemInfo; import com.android.launcher3.Utilities; -import com.android.launcher3.uioverrides.DepthController; +import com.android.launcher3.statehandlers.DepthController; import com.android.quickstep.util.AppWindowAnimationHelper; import com.android.quickstep.util.MultiValueUpdateListener; import com.android.quickstep.views.RecentsView; 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 4a14d9b990..2d0f978a0d 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java @@ -22,6 +22,7 @@ import static android.view.MotionEvent.ACTION_UP; 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.Executors.UI_HELPER_EXECUTOR; +import static com.android.quickstep.GestureState.DEFAULT_STATE; import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_INPUT_MONITOR; import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SYSUI_PROXY; import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_TRACING_ENABLED; @@ -124,6 +125,7 @@ public class TouchInteractionService extends Service implements PluginListener mAM.getRunningTask(true /* filterOnlyVisibleRecents */))); + mDeviceState.setOrientationTransformIfNeeded(event); + GestureState newGestureState; if (mDeviceState.isInSwipeUpTouchRegion(event)) { + newGestureState = createGestureState(); mConsumer.onConsumerAboutToBeSwitched(); mConsumer = newConsumer(mGestureState, newGestureState, event); @@ -453,6 +453,7 @@ public class TouchInteractionService extends Service implements PluginListener mAM.getRunningTask(true /* filterOnlyVisibleRecents */))); + return gestureState; + } + private InputConsumer newConsumer(GestureState previousGestureState, GestureState newGestureState, MotionEvent event) { boolean canStartSystemGesture = mDeviceState.canStartSystemGesture(); diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/DelegateInputConsumer.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/DelegateInputConsumer.java index a87e7ebf6d..71465eb201 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/DelegateInputConsumer.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/DelegateInputConsumer.java @@ -41,7 +41,7 @@ public abstract class DelegateInputConsumer implements InputConsumer { protected void setActive(MotionEvent ev) { mState = STATE_ACTIVE; - TestLogging.recordEvent(TestProtocol.SEQUENCE_MAIN, "pilferPointers"); + TestLogging.recordEvent(TestProtocol.SEQUENCE_PILFER, "pilferPointers"); mInputMonitor.pilferPointers(); // Send cancel event diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/DeviceLockedInputConsumer.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/DeviceLockedInputConsumer.java index ba1d38cf6a..7b8d40c911 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/DeviceLockedInputConsumer.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/DeviceLockedInputConsumer.java @@ -204,7 +204,7 @@ public class DeviceLockedInputConsumer implements InputConsumer, private void startRecentsTransition() { mThresholdCrossed = true; - TestLogging.recordEvent(TestProtocol.SEQUENCE_MAIN, "pilferPointers"); + TestLogging.recordEvent(TestProtocol.SEQUENCE_PILFER, "pilferPointers"); mInputMonitorCompat.pilferPointers(); Intent intent = new Intent(Intent.ACTION_MAIN) 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 416d7a1bca..a462949738 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 @@ -314,7 +314,7 @@ public class OtherActivityInputConsumer extends ContextWrapper implements InputC if (mInteractionHandler == null) { return; } - TestLogging.recordEvent(TestProtocol.SEQUENCE_MAIN, "pilferPointers"); + TestLogging.recordEvent(TestProtocol.SEQUENCE_PILFER, "pilferPointers"); mInputMonitorCompat.pilferPointers(); mActivityInterface.closeOverlay(); diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OverviewInputConsumer.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OverviewInputConsumer.java index f8abba5f6f..d3160b3961 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OverviewInputConsumer.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OverviewInputConsumer.java @@ -108,7 +108,7 @@ public class OverviewInputConsumer ActiveGestureLog.INSTANCE.addLog("startQuickstep"); } if (mInputMonitor != null) { - TestLogging.recordEvent(TestProtocol.SEQUENCE_MAIN, "pilferPointers"); + TestLogging.recordEvent(TestProtocol.SEQUENCE_PILFER, "pilferPointers"); mInputMonitor.pilferPointers(); } } 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 823b254d80..ac1c3a8742 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 @@ -65,7 +65,7 @@ public class OverviewWithoutFocusInputConsumer implements InputConsumer { private void onInterceptTouch() { if (mInputMonitor != null) { - TestLogging.recordEvent(TestProtocol.SEQUENCE_MAIN, "pilferPointers"); + TestLogging.recordEvent(TestProtocol.SEQUENCE_PILFER, "pilferPointers"); mInputMonitor.pilferPointers(); } } diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/LauncherRecentsView.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/LauncherRecentsView.java index a027feaed5..e62de186f8 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/LauncherRecentsView.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/LauncherRecentsView.java @@ -19,7 +19,7 @@ import static com.android.launcher3.LauncherState.ALL_APPS; import static com.android.launcher3.LauncherState.ALL_APPS_HEADER_EXTRA; import static com.android.launcher3.LauncherState.NORMAL; import static com.android.launcher3.LauncherState.OVERVIEW; -import static com.android.launcher3.LauncherState.RECENTS_CLEAR_ALL_BUTTON; +import static com.android.launcher3.LauncherState.OVERVIEW_BUTTONS; import static com.android.launcher3.LauncherState.SPRING_LOADED; import static com.android.launcher3.QuickstepAppTransitionManagerImpl.ALL_APPS_PROGRESS_OFF_SCREEN; import static com.android.launcher3.allapps.AllAppsTransitionController.ALL_APPS_PROGRESS; @@ -37,9 +37,9 @@ import android.view.MotionEvent; import android.view.View; import android.widget.FrameLayout; +import com.android.launcher3.BaseQuickstepLauncher; import com.android.launcher3.DeviceProfile; import com.android.launcher3.Hotseat; -import com.android.launcher3.Launcher; import com.android.launcher3.LauncherState; import com.android.launcher3.LauncherStateManager.StateListener; import com.android.launcher3.R; @@ -47,8 +47,8 @@ import com.android.launcher3.anim.Interpolators; import com.android.launcher3.appprediction.PredictionUiStateManager; import com.android.launcher3.appprediction.PredictionUiStateManager.Client; import com.android.launcher3.config.FeatureFlags; +import com.android.launcher3.statehandlers.DepthController; import com.android.launcher3.states.RotationHelper; -import com.android.launcher3.uioverrides.DepthController; import com.android.launcher3.uioverrides.plugins.PluginManagerWrapper; import com.android.launcher3.util.TraceHelper; import com.android.launcher3.views.ScrimView; @@ -63,7 +63,8 @@ import com.android.systemui.plugins.RecentsExtraCard; * {@link RecentsView} used in Launcher activity */ @TargetApi(Build.VERSION_CODES.O) -public class LauncherRecentsView extends RecentsView implements StateListener { +public class LauncherRecentsView extends RecentsView + implements StateListener { private static final Rect sTempRect = new Rect(); @@ -322,7 +323,7 @@ public class LauncherRecentsView extends RecentsView implements StateL if (enabled) { LauncherState state = mActivity.getStateManager().getState(); boolean hasClearAllButton = (state.getVisibleElements(mActivity) - & RECENTS_CLEAR_ALL_BUTTON) != 0; + & OVERVIEW_BUTTONS) != 0; setDisallowScrollToClearAll(!hasClearAllButton); } } 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 new file mode 100644 index 0000000000..6a37e2b7de --- /dev/null +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/OverviewActionsView.java @@ -0,0 +1,79 @@ +/* + * 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.views; + +import android.content.Context; +import android.util.AttributeSet; +import android.view.LayoutInflater; +import android.view.View; +import android.widget.FrameLayout; + +import androidx.annotation.Nullable; + +import com.android.launcher3.R; + +/** + * View for showing action buttons in Overview + */ +public class OverviewActionsView extends FrameLayout { + + private final View mScreenshotButton; + private final View mShareButton; + + /** + * Listener for taps on the various actions. + */ + public interface Listener { + /** User has initiated the share actions. */ + void onShare(); + + /** User has initiated the screenshot action. */ + void onScreenshot(); + } + + public OverviewActionsView(Context context) { + this(context, null); + } + + public OverviewActionsView(Context context, @Nullable AttributeSet attrs) { + this(context, attrs, 0); + } + + public OverviewActionsView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { + this(context, attrs, defStyleAttr, 0); + } + + public OverviewActionsView(Context context, AttributeSet attrs, int defStyleAttr, + int defStyleRes) { + super(context, attrs, defStyleAttr, defStyleRes); + LayoutInflater.from(context).inflate(R.layout.overview_actions, this, true); + mShareButton = findViewById(R.id.action_share); + mScreenshotButton = findViewById(R.id.action_screenshot); + } + + /** + * Set listener for callbacks on action button taps. + * + * @param listener for callbacks, or {@code null} to clear the listener. + */ + public void setListener(@Nullable OverviewActionsView.Listener listener) { + mShareButton.setOnClickListener( + listener == null ? null : view -> listener.onShare()); + mScreenshotButton.setOnClickListener( + listener == null ? null : view -> listener.onScreenshot()); + } +} 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 68c51a0b34..1c95a9ef77 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 @@ -30,7 +30,9 @@ import static com.android.launcher3.anim.Interpolators.FAST_OUT_SLOW_IN; import static com.android.launcher3.anim.Interpolators.LINEAR; import static com.android.launcher3.config.FeatureFlags.ENABLE_OVERVIEW_ACTIONS; import static com.android.launcher3.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TILE; -import static com.android.launcher3.uioverrides.DepthController.DEPTH; +import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.TASK_DISMISS_SWIPE_UP; +import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.TASK_LAUNCH_SWIPE_DOWN; +import static com.android.launcher3.statehandlers.DepthController.DEPTH; import static com.android.launcher3.uioverrides.touchcontrollers.TaskViewTouchController.SUCCESS_TRANSITION_PROGRESS; import static com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch.TAP; import static com.android.launcher3.userevent.nano.LauncherLogProto.ControlType.CLEAR_ALL_BUTTON; @@ -96,9 +98,9 @@ import com.android.launcher3.anim.SpringProperty; import com.android.launcher3.compat.AccessibilityManagerCompat; import com.android.launcher3.config.FeatureFlags; import com.android.launcher3.graphics.RotationMode; +import com.android.launcher3.statehandlers.DepthController; import com.android.launcher3.states.RotationHelper; import com.android.launcher3.touch.PagedOrientationHandler.CurveProperties; -import com.android.launcher3.uioverrides.DepthController; import com.android.launcher3.userevent.nano.LauncherLogProto; import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Direction; import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch; @@ -1183,13 +1185,13 @@ public abstract class RecentsView extends PagedView impl verticalFactor * secondaryTaskDimension).setDuration(duration), LINEAR, sp); } - private void removeTask(Task task, int index, EndState endState) { - if (task != null) { - ActivityManagerWrapper.getInstance().removeTask(task.key.id); - ComponentKey componentKey = TaskUtils.getLaunchComponentKeyForTask(task.key); + private void removeTask(TaskView taskView, int index, EndState endState) { + if (taskView.getTask() != null) { + ActivityManagerWrapper.getInstance().removeTask(taskView.getTask().key.id); + ComponentKey compKey = TaskUtils.getLaunchComponentKeyForTask(taskView.getTask().key); mActivity.getUserEventDispatcher().logTaskLaunchOrDismiss( - endState.logAction, Direction.UP, index, componentKey); - mActivity.getStatsLogManager().logTaskDismiss(this, componentKey); + endState.logAction, Direction.UP, index, compKey); + mActivity.getStatsLogManager().log(TASK_DISMISS_SWIPE_UP, taskView.buildProto()); } } @@ -1284,7 +1286,7 @@ public abstract class RecentsView extends PagedView impl private void onEnd(EndState endState) { if (endState.isSuccess) { if (shouldRemoveTask) { - removeTask(taskView.getTask(), draggedIndex, endState); + removeTask(taskView, draggedIndex, endState); } int pageToSnapTo = mCurrentPage; @@ -1733,6 +1735,8 @@ public abstract class RecentsView extends PagedView impl mActivity.getUserEventDispatcher().logTaskLaunchOrDismiss( endState.logAction, Direction.DOWN, indexOfChild(tv), TaskUtils.getLaunchComponentKeyForTask(task.key)); + mActivity.getStatsLogManager().log(TASK_LAUNCH_SWIPE_DOWN, tv.buildProto() + ); } } else { onTaskLaunched(false); diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskView.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskView.java index 56e3632dcd..7010f9ab8a 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskView.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskView.java @@ -29,6 +29,7 @@ import static com.android.launcher3.anim.Interpolators.FAST_OUT_SLOW_IN; import static com.android.launcher3.anim.Interpolators.LINEAR; import static com.android.launcher3.anim.Interpolators.TOUCH_RESPONSE_INTERPOLATOR; import static com.android.launcher3.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TILE; +import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.TASK_LAUNCH_TAP; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; @@ -43,6 +44,7 @@ import android.graphics.RectF; import android.graphics.drawable.Drawable; import android.os.Bundle; import android.os.Handler; +import android.os.Process; import android.util.AttributeSet; import android.util.FloatProperty; import android.util.Log; @@ -59,6 +61,7 @@ import com.android.launcher3.Utilities; import com.android.launcher3.anim.AnimatorPlaybackController; import com.android.launcher3.anim.Interpolators; import com.android.launcher3.anim.PendingAnimation; +import com.android.launcher3.logger.LauncherAtom; import com.android.launcher3.logging.UserEventDispatcher; import com.android.launcher3.popup.SystemShortcut; import com.android.launcher3.states.RotationHelper; @@ -68,6 +71,7 @@ import com.android.launcher3.touch.PagedOrientationHandler; import com.android.launcher3.userevent.nano.LauncherLogProto; import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Direction; import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch; +import com.android.launcher3.util.ComponentKey; import com.android.launcher3.util.ViewPool.Reusable; import com.android.quickstep.RecentsModel; import com.android.quickstep.TaskIconCache; @@ -217,8 +221,7 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable { mActivity.getUserEventDispatcher().logTaskLaunchOrDismiss( Touch.TAP, Direction.NONE, getRecentsView().indexOfChild(this), TaskUtils.getLaunchComponentKeyForTask(getTask().key)); - mActivity.getStatsLogManager().logTaskLaunch(getRecentsView(), - TaskUtils.getLaunchComponentKeyForTask(getTask().key)); + mActivity.getStatsLogManager().log(TASK_LAUNCH_TAP, buildProto()); }); mCornerRadius = TaskCornerRadius.get(context); mWindowCornerRadius = QuickStepContract.getWindowCornerRadius(context.getResources()); @@ -229,6 +232,17 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable { setOutlineProvider(mOutlineProvider); } + /* Builds proto for logging */ + protected LauncherAtom.ItemInfo buildProto() { + ComponentKey componentKey = TaskUtils.getLaunchComponentKeyForTask(getTask().key); + LauncherAtom.ItemInfo.Builder itemBuilder = LauncherAtom.ItemInfo.newBuilder(); + itemBuilder.setIsWork(componentKey.user != Process.myUserHandle()); + itemBuilder.setTask(LauncherAtom.Task.newBuilder() + .setComponentName(componentKey.componentName.flattenToShortString()) + .setIndex(getRecentsView().indexOfChild(this))); + return itemBuilder.build(); + } + @Override protected void onFinishInflate() { super.onFinishInflate(); @@ -812,8 +826,8 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable { super.onInitializeAccessibilityNodeInfo(info); info.addAction( - new AccessibilityNodeInfo.AccessibilityAction(R.string.accessibility_close_task, - getContext().getText(R.string.accessibility_close_task))); + new AccessibilityNodeInfo.AccessibilityAction(R.string.accessibility_close, + getContext().getText(R.string.accessibility_close))); final Context context = getContext(); for (SystemShortcut s : TaskOverlayFactory.getEnabledShortcuts(this)) { @@ -837,7 +851,7 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable { @Override public boolean performAccessibilityAction(int action, Bundle arguments) { - if (action == R.string.accessibility_close_task) { + if (action == R.string.accessibility_close) { getRecentsView().dismissTask(this, true /*animateTaskView*/, true /*removeTask*/); return true; diff --git a/quickstep/res/drawable/ic_screenshot.xml b/quickstep/res/drawable/ic_screenshot.xml new file mode 100644 index 0000000000..d97eae1d15 --- /dev/null +++ b/quickstep/res/drawable/ic_screenshot.xml @@ -0,0 +1,23 @@ + + + + diff --git a/quickstep/res/drawable/ic_share.xml b/quickstep/res/drawable/ic_share.xml new file mode 100644 index 0000000000..ff4baec79b --- /dev/null +++ b/quickstep/res/drawable/ic_share.xml @@ -0,0 +1,23 @@ + + + + diff --git a/quickstep/res/layout/overview_actions.xml b/quickstep/res/layout/overview_actions.xml new file mode 100644 index 0000000000..ad5efb6ae0 --- /dev/null +++ b/quickstep/res/layout/overview_actions.xml @@ -0,0 +1,41 @@ + + + + + +