From 5d835bcdaa99a688f6e4dc5f3097b52acd1f4da4 Mon Sep 17 00:00:00 2001 From: Vinit Nayak Date: Thu, 21 May 2020 16:13:27 -0700 Subject: [PATCH 01/24] Enable RotationWatcher when home rotation is on Update the PagedOrientationHandler when launcher is allowed to rotate to ensure the correct one gets set. Fixes: 157173248 Change-Id: Iffb9df479fcccfb0fe2bd462167242b592949f69 --- .../src/com/android/quickstep/views/RecentsView.java | 5 +++++ .../com/android/quickstep/util/RecentsOrientedState.java | 6 +++--- 2 files changed, 8 insertions(+), 3 deletions(-) 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 3273e85c8f..78c114e231 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 @@ -1047,6 +1047,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/src/com/android/quickstep/util/RecentsOrientedState.java b/quickstep/src/com/android/quickstep/util/RecentsOrientedState.java index 4c47d7fe6f..7888828bdd 100644 --- a/quickstep/src/com/android/quickstep/util/RecentsOrientedState.java +++ b/quickstep/src/com/android/quickstep/util/RecentsOrientedState.java @@ -203,7 +203,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); @@ -235,7 +235,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 { @@ -243,7 +243,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) { From b46703d538f488d58626c4f812530cd032723e90 Mon Sep 17 00:00:00 2001 From: Sunny Goyal Date: Wed, 27 May 2020 17:52:03 -0700 Subject: [PATCH 02/24] Fixing incorrect taskView size in multiwindow-landscape RecentsView uses deviceProfile to calculate the padding. Device profile had incorrect sizes in multiwindow mode as it was not considering the insets. Bug: 155816922 Change-Id: Iaa5b939624b4128ed634e6de1abf8453e2ae852b --- .../android/quickstep/BaseSwipeUpHandler.java | 4 +++- .../android/launcher3/BaseDraggingActivity.java | 14 +++++++++++--- src/com/android/launcher3/DeviceProfile.java | 16 +++++++--------- 3 files changed, 21 insertions(+), 13 deletions(-) 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..91714227e5 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/BaseSwipeUpHandler.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/BaseSwipeUpHandler.java @@ -51,6 +51,7 @@ 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.util.WindowBounds; import com.android.launcher3.views.FloatingIconView; import com.android.quickstep.RecentsAnimationCallbacks.RecentsAnimationListener; import com.android.quickstep.util.ActiveGestureLog; @@ -282,7 +283,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); diff --git a/src/com/android/launcher3/BaseDraggingActivity.java b/src/com/android/launcher3/BaseDraggingActivity.java index 239d8a314c..dcab127f11 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() { From f0dc0b6ae031b382802115ff6b5fe323ec510f98 Mon Sep 17 00:00:00 2001 From: Samuel Fufa Date: Thu, 28 May 2020 14:49:01 -0700 Subject: [PATCH 03/24] Remove dependency on Launcher notification for hotseat edu Doc: go/hybrid-hotseat-tips Allow launcher to show hotseat education with intent action "launcher.show_hotseat_edu" Bug: 157683315 Test: Manual Change-Id: I62c79b821b79cf1adb831e2f79f6f0f02166ca42 --- .../hybridhotseat/HotseatEduController.java | 73 +------------------ .../HotseatPredictionController.java | 4 +- .../uioverrides/QuickstepLauncher.java | 15 ++++ quickstep/res/values/strings.xml | 6 -- 4 files changed, 19 insertions(+), 79 deletions(-) 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 9ae6080830..494a98dcf5 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/res/values/strings.xml b/quickstep/res/values/strings.xml index c841170c4c..be1d47b9f2 100644 --- a/quickstep/res/values/strings.xml +++ b/quickstep/res/values/strings.xml @@ -63,12 +63,6 @@ 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 From 244e173a68639cccbf9f2bb156999eb09190e160 Mon Sep 17 00:00:00 2001 From: Tony Wickham Date: Fri, 29 May 2020 11:10:10 -0500 Subject: [PATCH 04/24] Fix all apps alpha applying twice Test: quick switch from home, ensure QSB fades out at the same rate as the workspace/hotsea Change-Id: I59ecd0c65a6abf3e24ea1c2bfba3c84f6a88e653 --- .../uioverrides/states/QuickstepAtomicAnimationFactory.java | 3 ++- .../launcher3/allapps/AllAppsTransitionController.java | 6 +++++- src/com/android/launcher3/anim/Interpolators.java | 5 +++++ 3 files changed, 12 insertions(+), 2 deletions(-) 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/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; From 0a0255812ba9953789b5888f7b346d8bc87b5a98 Mon Sep 17 00:00:00 2001 From: Tracy Zhou Date: Fri, 29 May 2020 12:08:18 -0700 Subject: [PATCH 05/24] Delete PreviewSurfaceRendered (launcher3 fork) We had this class when we used SysUI to pipe through surface rendering, but this is no longer used after we swtiched to public API. Bug: 152003916 Test: N/A Change-Id: I21459c254c1e200ad1a193536e826dae9be2561d --- .../uioverrides/PreviewSurfaceRenderer.java | 27 ------------------- 1 file changed, 27 deletions(-) delete mode 100644 src_ui_overrides/com/android/launcher3/uioverrides/PreviewSurfaceRenderer.java 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) { } -} From 84f6e0182e8768329c744d63345d4201892933a2 Mon Sep 17 00:00:00 2001 From: Jon Miranda Date: Fri, 29 May 2020 12:00:56 -0700 Subject: [PATCH 06/24] Fix depth jumping around during transitions. This is caused because we use mDepth for depth comparisons, but there are cases where we set mDepth but we do not pass that value to WallpaperManager (ie. surface is null or not valid) and that leads us into inconsistent states. Bug: 155780358 Change-Id: I3faf14416d5783ad472892425eb0bd37dd469a46 --- .../statehandlers/DepthController.java | 21 ++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) 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) { From 7e78e63d503cff9e63e6b3c33051505c7aa1888d Mon Sep 17 00:00:00 2001 From: Andy Wickham Date: Fri, 29 May 2020 13:49:09 -0700 Subject: [PATCH 07/24] Removes unused constant Change-Id: Ic3d96ae3791ba75c5ce6c1c00203bf9d21469fe5 --- .../com/android/quickstep/interaction/TutorialFragment.java | 5 ----- 1 file changed, 5 deletions(-) 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; From f8a8117676e89c64f626fabb092f467b17041f72 Mon Sep 17 00:00:00 2001 From: Andy Wickham Date: Thu, 21 May 2020 18:04:18 -0700 Subject: [PATCH 08/24] Animates a fake TaskView in Home gesture tutorial. The "TaskView" morphs as you drag up from the nav bar, and transforms into a "home icon" or final "TaskView" when you release your finger. If you cancel the gesture (e.g. drag back down), the view simply fades out and provides a hint to swipe straight up. Demo: https://drive.google.com/open?id=1NXlO1W6IhLoX0k2K6b-QZ5IXp0o7OYqO Bug: 148542211 Change-Id: I3d5e9a45fcadc6a498941ea17813b9487720a504 --- .../android/quickstep/BaseSwipeUpHandler.java | 316 +--------------- .../quickstep/SwipeUpAnimationLogic.java | 350 ++++++++++++++++++ .../FallbackNavBarTouchController.java | 12 +- .../OverviewWithoutFocusInputConsumer.java | 12 +- .../quickstep/util/TaskViewSimulator.java | 21 +- .../util/TriggerSwipeUpTouchTracker.java | 14 +- .../res/layout/gesture_tutorial_fragment.xml | 7 + .../BackGestureTutorialController.java | 8 +- .../HomeGestureTutorialController.java | 226 ++++++++++- .../interaction/NavBarGestureHandler.java | 46 ++- .../interaction/TutorialController.java | 5 + res/values/colors.xml | 1 + 12 files changed, 674 insertions(+), 344 deletions(-) create mode 100644 quickstep/recents_ui_overrides/src/com/android/quickstep/SwipeUpAnimationLogic.java 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 91714227e5..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,58 +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.util.WindowBounds; -import com.android.launcher3.views.FloatingIconView; 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; @@ -76,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; @@ -120,7 +73,6 @@ public abstract class BaseSwipeUpHandler, Q extend protected T mActivity; protected Q mRecentsView; - protected DeviceProfile mDp; protected Runnable mGestureEndCallback; @@ -132,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()); } /** @@ -158,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; } @@ -276,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()); @@ -357,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 */ @@ -457,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()); @@ -466,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/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/fallback/FallbackNavBarTouchController.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/fallback/FallbackNavBarTouchController.java index 6f919c10c8..be3fddecf0 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/fallback/FallbackNavBarTouchController.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/fallback/FallbackNavBarTouchController.java @@ -15,6 +15,7 @@ */ package com.android.quickstep.fallback; +import android.graphics.PointF; import android.view.MotionEvent; import androidx.annotation.Nullable; @@ -30,7 +31,8 @@ import com.android.quickstep.util.TriggerSwipeUpTouchTracker; /** * In 0-button mode, intercepts swipe up from the nav bar on FallbackRecentsView to go home. */ -public class FallbackNavBarTouchController implements TouchController { +public class FallbackNavBarTouchController implements TouchController, + TriggerSwipeUpTouchTracker.OnSwipeUpListener { private final RecentsActivity mActivity; @Nullable @@ -44,7 +46,7 @@ public class FallbackNavBarTouchController implements TouchController { DefaultDisplay.INSTANCE.get(mActivity).getInfo()); mTriggerSwipeUpTracker = new TriggerSwipeUpTouchTracker(mActivity, true /* disableHorizontalSwipe */, navBarPosition, - null /* onInterceptTouch */, this::onSwipeUp); + null /* onInterceptTouch */, this); } else { mTriggerSwipeUpTracker = null; } @@ -72,7 +74,11 @@ public class FallbackNavBarTouchController implements TouchController { return false; } - private void onSwipeUp(boolean wasFling) { + @Override + public void onSwipeUp(boolean wasFling, PointF finalVelocity) { mActivity.getOverviewPanel().startHome(); } + + @Override + public void onSwipeUpCancelled() {} } 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/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/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"/> + + 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 +240,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/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 From 0c8e20eea7af24894a700eed1e5bb16924491da3 Mon Sep 17 00:00:00 2001 From: Zak Cohen Date: Fri, 29 May 2020 14:15:09 -0700 Subject: [PATCH 09/24] [Overview actions] Remove unused duration variable. Test: local build Change-Id: I2f18e77273753f491c6d802aa3b4406fefce6ad7 --- .../src/com/android/quickstep/views/OverviewActionsView.java | 2 -- 1 file changed, 2 deletions(-) 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, From b117a9221c1abf81e2e43441a8d8d53f9ccc6d0d Mon Sep 17 00:00:00 2001 From: Hyunyoung Song Date: Thu, 28 May 2020 23:36:14 -0700 Subject: [PATCH 10/24] Migrate launcher home settings button tap/longpress logging to WW Bug: 157777128 Change-Id: Ic88811efc9aef8f38a0e7e5ae79e3b35236c6663 --- .../logging/StatsLogCompatManager.java | 19 +++++----- .../launcher3/logging/StatsLogManager.java | 24 +++++++++---- .../touch/WorkspaceTouchListener.java | 7 ++-- .../launcher3/views/OptionsPopupView.java | 35 ++++++++++--------- 4 files changed, 49 insertions(+), 36 deletions(-) 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/src/com/android/launcher3/logging/StatsLogManager.java b/src/com/android/launcher3/logging/StatsLogManager.java index 4c2c79d6dd..e11d21f34e 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), @@ -113,27 +125,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/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/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; } } From cc558e86fbc852099c343eb34034e07116190cbf Mon Sep 17 00:00:00 2001 From: Tony Wickham Date: Fri, 29 May 2020 17:33:24 -0500 Subject: [PATCH 11/24] Don't defer finish, only defer disableInputProxy We should always finish the controller when requested, to ensure everything is cleaned up immediately. But if touch is in progress, we should keep input proxy enabled until touch up/cancel. Test: swipe up to launcher and interact with it during the transition - Swipe to recents and scroll it or dismiss the current task - Swipe to home and open another app or swipe again on the nav bar Bug: 157771305 Change-Id: Ida53289e4ecbd5e5d16933fcc79bbebdf1f8d898 --- .../quickstep/RecentsAnimationController.java | 31 +++++++------------ 1 file changed, 12 insertions(+), 19 deletions(-) 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) { From 75dedacfc4eb0e1139bb7e099df207358abd3cec Mon Sep 17 00:00:00 2001 From: Hyunyoung Song Date: Fri, 29 May 2020 17:36:40 -0700 Subject: [PATCH 12/24] When tap on empty string edittext, and suggestion is made, select all the string Bug: 157771174 Change-Id: I4a274333d897693bc214d50edcea30cf012ce859 --- src/com/android/launcher3/folder/Folder.java | 1 + 1 file changed, 1 insertion(+) 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(); From 77d8903f4a567bc91b0938b009d33316ea3fa4c1 Mon Sep 17 00:00:00 2001 From: Jon Miranda Date: Fri, 29 May 2020 19:41:11 -0700 Subject: [PATCH 13/24] More logging for pause non-detection Bug: 156044202 Change-Id: I0831735aa743360c16e1f940c30875f32432fec5 --- .../NavBarToHomeTouchController.java | 3 +-- .../launcher3/views/FloatingIconView.java | 10 ++++++++ .../android/launcher3/views/ListenerView.java | 25 ++++++++++++++++++- 3 files changed, 35 insertions(+), 3 deletions(-) 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..2ae90a5c57 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)); } return true; } 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); } From 10a6ed86eb002fce565ce27fc85447e65f42cada Mon Sep 17 00:00:00 2001 From: Jon Miranda Date: Mon, 1 Jun 2020 09:34:50 -0700 Subject: [PATCH 14/24] More logging for pause non-detection Bug: 156044202 Change-Id: I68d6febf4c201c2fea41c7e24600dcc2c54a680a --- .../touchcontrollers/NavBarToHomeTouchController.java | 2 +- src/com/android/launcher3/views/BaseDragLayer.java | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) 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 2ae90a5c57..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,7 +116,7 @@ public class NavBarToHomeTouchController implements TouchController, if (TestProtocol.sDebugTracing) { Log.d(TestProtocol.PAUSE_NOT_DETECTED, "NavBarToHomeTouchController.canInterceptTouch true 2 " - + AbstractFloatingView.getTopOpenView(mLauncher)); + + AbstractFloatingView.getTopOpenView(mLauncher), new Exception()); } return true; } 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)) { From 90b006dbe5a826156e6d6ef69a3d353e3968a9e4 Mon Sep 17 00:00:00 2001 From: Vinit Nayak Date: Fri, 22 May 2020 21:48:19 -0700 Subject: [PATCH 15/24] Reset Overview layout after swiping to home Reset overview when user does a swipe to home gesture. Preivously we only rest when user first when to over, and then swiped to home. Fixes: 156053957 Change-Id: I5a157f9e2229aba4b36851bd46d704a39d647110 --- .../android/quickstep/BaseSwipeUpHandlerV2.java | 2 +- .../quickstep/FallbackActivityInterface.java | 2 +- .../quickstep/LauncherActivityInterface.java | 16 ++++++++++------ .../android/quickstep/BaseActivityInterface.java | 2 +- 4 files changed, 13 insertions(+), 9 deletions(-) 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..c92dd5068b 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/BaseSwipeUpHandlerV2.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/BaseSwipeUpHandlerV2.java @@ -1035,7 +1035,7 @@ public abstract class BaseSwipeUpHandlerV2, Q exte } // Make sure recents is in its final state maybeUpdateRecentsAttachedState(false); - mActivityInterface.onSwipeUpToHomeComplete(); + mActivityInterface.onSwipeUpToHomeComplete(mDeviceState); } }); return anim; 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/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 Date: Thu, 28 May 2020 17:58:40 -0700 Subject: [PATCH 16/24] Start quickswitch on task switch instead of touch down Previously we would enter a quickswitch session state whenever user tapped on navbar and sent flags to sysui to only enable edge gesture for the current rotation. Now we only do that on a new task resulting from the gesture or when going into recents to show nav bar in the orientation user would expect it (only if they never quickswitched). Fixes: 155844780 Test: Tested swiping back from quickswitching into apps of different orientations. Note that back is still broken when you quickswitch and then rotate the foreground app. Change-Id: I935e7c66489d46e59156414d64653c846ae4c5d8 --- .../quickstep/BaseSwipeUpHandlerV2.java | 7 +- .../quickstep/TouchInteractionService.java | 2 +- .../OtherActivityInputConsumer.java | 5 ++ .../com/android/quickstep/InputConsumer.java | 5 ++ .../OrientationTouchTransformer.java | 28 +++++--- .../RecentsAnimationDeviceState.java | 71 ++++++++++++++----- 6 files changed, 85 insertions(+), 33 deletions(-) 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..1be0bac417 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, @@ -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/TouchInteractionService.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java index 4954588790..8c772408a8 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java @@ -613,7 +613,7 @@ public class TouchInteractionService extends Service implements PluginListener { - 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() { From eeb675683ba25912f5cc09221c074d62c74a1664 Mon Sep 17 00:00:00 2001 From: Joshua Tsuji Date: Mon, 1 Jun 2020 14:21:33 -0400 Subject: [PATCH 17/24] Add SysUiOverlayInputConsumer. This consumer is used when Bubbles is expanded, and causes swipes up to hide bubbles via closeSystemDialogs rather than going all the way home. Test: install launcher and swipe up (after including the other CL in this topic) Fixes: 156390484 Change-Id: I36b71dd95dc45a5a547eddfe0faddf61630b6f25 --- .../quickstep/TouchInteractionService.java | 8 ++ .../SysUiOverlayInputConsumer.java | 86 +++++++++++++++++++ .../com/android/quickstep/InputConsumer.java | 2 + .../RecentsAnimationDeviceState.java | 8 +- 4 files changed, 103 insertions(+), 1 deletion(-) create mode 100644 quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/SysUiOverlayInputConsumer.java 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 4954588790..0ea735dcba 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java @@ -81,6 +81,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; @@ -588,6 +589,13 @@ public class TouchInteractionService extends Service implements PluginListener TYPE_NO_OP; diff --git a/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java b/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java index 6e7c423821..bd667fc102 100644 --- a/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java +++ b/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java @@ -360,7 +360,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); } @@ -380,6 +379,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 */ From 7772fcde4792d623acbfd8222e8881d01e7db953 Mon Sep 17 00:00:00 2001 From: Jon Miranda Date: Mon, 1 Jun 2020 14:08:16 -0700 Subject: [PATCH 18/24] Fix bug where font size (etc.) doesn't change after changing display settings. The metrics we get from Display#getMetrics does not change regardless of what the new configuration is (we would expect the scaledDensity to change). Documentation shows that Display#getMetrics is deprecated in R. Using guidance from b/154665987#comment14 we get the metrics from the derived context. Bug: 156141463 Change-Id: I25e5f2c13f94e0471111f6c895694947998e3222 --- src/com/android/launcher3/InvariantDeviceProfile.java | 2 +- src/com/android/launcher3/util/DefaultDisplay.java | 9 +++++---- 2 files changed, 6 insertions(+), 5 deletions(-) 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/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) { From 63bf8eedf958d995050c5ef8d20b525679d23511 Mon Sep 17 00:00:00 2001 From: thiruram Date: Mon, 1 Jun 2020 12:03:19 -0700 Subject: [PATCH 19/24] Add WW log for drag events from longpress popup window. Bug: 157765763 Sample Log: https://docs.google.com/document/d/1CBP2yTcXdFhPdNG5ZmWFKSgd8mDbMevY-akVlUXPLDo/edit#bookmark=id.368csp9y1pwc Change-Id: I73024f2c8010e77b6f89829fda64130f54ff81f1 --- protos/launcher_atom.proto | 6 ++++++ src/com/android/launcher3/LauncherSettings.java | 3 ++- src/com/android/launcher3/model/data/ItemInfo.java | 6 ++++++ .../android/launcher3/popup/PopupContainerWithArrow.java | 6 +++++- 4 files changed, 19 insertions(+), 2 deletions(-) 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/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/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); From 5f1274c863fd0723f3661eb739b7ebc404a71e73 Mon Sep 17 00:00:00 2001 From: thiruram Date: Mon, 1 Jun 2020 14:05:13 -0700 Subject: [PATCH 20/24] Log tap on widget and appinfo system icons within ShortcutContainer. Bug: 157765763 Change-Id: Id417728d27678cce073ff36d24b129c4435dcbe5 --- src/com/android/launcher3/logging/StatsLogManager.java | 10 +++++++++- src/com/android/launcher3/popup/SystemShortcut.java | 9 ++++++++- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/src/com/android/launcher3/logging/StatsLogManager.java b/src/com/android/launcher3/logging/StatsLogManager.java index e11d21f34e..dda39e8a51 100644 --- a/src/com/android/launcher3/logging/StatsLogManager.java +++ b/src/com/android/launcher3/logging/StatsLogManager.java @@ -94,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; 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()); } } From b396864072f671f181b8add71e83d075f6608658 Mon Sep 17 00:00:00 2001 From: Sunny Goyal Date: Fri, 29 May 2020 14:07:54 -0700 Subject: [PATCH 21/24] Fixing loadTasksInBackground called twice on swipe up Bug: 157644889 Change-Id: Ia4413ea878f8ba731fbb7a8f61b7c0c0050f3811 --- .../android/quickstep/RecentTasksList.java | 83 ++++++++++++------- .../quickstep/RecentTasksListTest.java | 8 +- 2 files changed, 59 insertions(+), 32 deletions(-) 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/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()); From 518d54e3f27d9132c67a0ec3c153fe33663b0571 Mon Sep 17 00:00:00 2001 From: Sunny Goyal Date: Mon, 1 Jun 2020 16:18:36 -0700 Subject: [PATCH 22/24] Preventing launcher preload if user setup is not complete Also fixing some leaks due to not destroying RecentsAnimationDeviceState Bug: 155350432 Change-Id: I70f510c3db03515d5889f0bcde6a15a9456e9791 --- .../QuickstepTestInformationHandler.java | 5 +++-- .../quickstep/TouchInteractionService.java | 3 ++- .../RecentsAnimationDeviceState.java | 22 +++++++++++++++++++ .../HomeGestureTutorialController.java | 1 + 4 files changed, 28 insertions(+), 3 deletions(-) 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/TouchInteractionService.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java index 8c772408a8..a2ce36eab8 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java @@ -725,12 +725,13 @@ public class TouchInteractionService extends Service implements PluginListener mIsUserSetupComplete = e, + Settings.Secure.USER_SETUP_COMPLETE, + 0); + mIsUserSetupComplete = userSetupObserver.getValue(); + if (!mIsUserSetupComplete) { + userSetupObserver.register(); + runOnDestroy(userSetupObserver::unregister); + } } private void setupOrientationSwipeHandler() { @@ -318,6 +333,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(); diff --git a/quickstep/src/com/android/quickstep/interaction/HomeGestureTutorialController.java b/quickstep/src/com/android/quickstep/interaction/HomeGestureTutorialController.java index 1113bc25ae..65f41a4a6c 100644 --- a/quickstep/src/com/android/quickstep/interaction/HomeGestureTutorialController.java +++ b/quickstep/src/com/android/quickstep/interaction/HomeGestureTutorialController.java @@ -78,6 +78,7 @@ final class HomeGestureTutorialController extends TutorialController { mViewSwipeUpAnimation = new ViewSwipeUpAnimation(mContext, deviceState, new GestureState(observer, -1)); observer.onDestroy(); + deviceState.destroy(); DeviceProfile dp = InvariantDeviceProfile.INSTANCE.get(mContext) .getDeviceProfile(mContext) From b91480e3c781ab0da22e3bc55955f2020bddfb34 Mon Sep 17 00:00:00 2001 From: thiruram Date: Mon, 1 Jun 2020 16:38:36 -0700 Subject: [PATCH 23/24] Add app launch event for tap on shortcut in shortcut container. Bug: 157765763 Change-Id: I769eb81ccabc96ad1c6c4c3d53ff89a8a744c3e0 --- src/com/android/launcher3/popup/PopupPopulator.java | 3 +++ 1 file changed, 3 insertions(+) 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)); From fb442a70f8d1bbaa54054023558892ef01aaf7a1 Mon Sep 17 00:00:00 2001 From: Vinit Nayak Date: Mon, 1 Jun 2020 18:30:15 -0700 Subject: [PATCH 24/24] Set mLastRectRotation to valid rotation mLastRectRotation's value is used after swipe gestures are complete to reset the layout for overview (after swiping to home animation is complete), so we need to set it to a valid value instead of -1. OverviewActions visibility depends on it being rotation 0 for it to be visible, otherwise it won't show up. Bug: 155844780 Test: Swipe up to home from an app, Swipe up to overview, observe overview actions show in portrait. Swipe up and back down from landscape app, hit back. Open portrait app, ensure back gesture still works. Change-Id: Ia923a54e68af567b4470841783328528fffebe6a --- .../com/android/quickstep/OrientationTouchTransformer.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/quickstep/src/com/android/quickstep/OrientationTouchTransformer.java b/quickstep/src/com/android/quickstep/OrientationTouchTransformer.java index d06393ac3c..a976126202 100644 --- a/quickstep/src/com/android/quickstep/OrientationTouchTransformer.java +++ b/quickstep/src/com/android/quickstep/OrientationTouchTransformer.java @@ -157,8 +157,9 @@ class OrientationTouchTransformer { mMode != SysUINavigationMode.Mode.TWO_BUTTONS; if (mEnableMultipleRegions) { mQuickStepStartingRotation = info.rotation; - } else if (!enableMultipleRegions) { - mLastRectRotation = mQuickStepStartingRotation = QUICKSTEP_ROTATION_UNINITIALIZED; + } else { + mLastRectRotation = 0; + mQuickStepStartingRotation = QUICKSTEP_ROTATION_UNINITIALIZED; } resetSwipeRegions(info); } @@ -293,6 +294,7 @@ class OrientationTouchTransformer { mLastRectTouched = rect; 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();