From 71767d1605b196edb8f0a4b9488392de6e53630d Mon Sep 17 00:00:00 2001 From: Catherine Liang Date: Mon, 26 Feb 2024 20:11:22 +0000 Subject: [PATCH 001/985] Fix Launcher preview crash Launcher preview could crash when unfolding a foldable device due to the folded state display id no longer being valid, resulting in getting a null display. This was leading to an empty preview bundle being returned, which is unexpected because null is expected in the case of an exception. Instead of crashing in getDisplayId, it's better to throw an exception earlier on if the display is null and return null. Flag: NA Bug: 326637851 Test: manually verified by testing unfold in WPP in old and new preview Change-Id: Ibc353d9447a71d33092d96029a812017487d0970 --- .../launcher3/graphics/PreviewSurfaceRenderer.java | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/com/android/launcher3/graphics/PreviewSurfaceRenderer.java b/src/com/android/launcher3/graphics/PreviewSurfaceRenderer.java index 051fb6f4fe..db278321dc 100644 --- a/src/com/android/launcher3/graphics/PreviewSurfaceRenderer.java +++ b/src/com/android/launcher3/graphics/PreviewSurfaceRenderer.java @@ -87,6 +87,7 @@ public class PreviewSurfaceRenderer { private final int mHeight; private String mGridName; + private final int mDisplayId; private final Display mDisplay; private final WallpaperColors mWallpaperColors; private final RunnableList mOnDestroyCallbacks = new RunnableList(); @@ -110,8 +111,12 @@ public class PreviewSurfaceRenderer { mHostToken = bundle.getBinder(KEY_HOST_TOKEN); mWidth = bundle.getInt(KEY_VIEW_WIDTH); mHeight = bundle.getInt(KEY_VIEW_HEIGHT); + mDisplayId = bundle.getInt(KEY_DISPLAY_ID); mDisplay = context.getSystemService(DisplayManager.class) - .getDisplay(bundle.getInt(KEY_DISPLAY_ID)); + .getDisplay(mDisplayId); + if (mDisplay == null) { + throw new IllegalArgumentException("Display ID does not match any displays."); + } mSurfaceControlViewHost = MAIN_EXECUTOR.submit(() -> new SurfaceControlViewHost(mContext, context.getSystemService(DisplayManager.class) @@ -121,7 +126,7 @@ public class PreviewSurfaceRenderer { } public int getDisplayId() { - return mDisplay.getDisplayId(); + return mDisplayId; } public IBinder getHostToken() { -- GitLab From b0e96db76c8706fc65a1a69a71305455b9d33ca9 Mon Sep 17 00:00:00 2001 From: Johannes Gallmann Date: Thu, 29 Feb 2024 13:13:14 +0000 Subject: [PATCH 002/985] Play predictive animation when quickly restarting back gesture after cancel Bug: 327579977 Flag: ACONFIG com.android.systemui.predictive_back_system_anims TRUNKFOOD50 Test: atest BackProgressAnimatorTest Test: atest BackAnimationControllerTest Test: Manual, i.e. extensively testing all three system animations with quick swipes in succession Change-Id: Ia8815088240084ce22246baa6d3562812462ab19 --- .../LauncherBackAnimationController.java | 61 +++++-------------- 1 file changed, 15 insertions(+), 46 deletions(-) diff --git a/quickstep/src/com/android/quickstep/LauncherBackAnimationController.java b/quickstep/src/com/android/quickstep/LauncherBackAnimationController.java index cc5a923e5a..2d25295402 100644 --- a/quickstep/src/com/android/quickstep/LauncherBackAnimationController.java +++ b/quickstep/src/com/android/quickstep/LauncherBackAnimationController.java @@ -44,7 +44,6 @@ import android.view.IRemoteAnimationRunner; import android.view.RemoteAnimationTarget; import android.view.SurfaceControl; import android.view.View; -import android.view.animation.AnimationUtils; import android.view.animation.DecelerateInterpolator; import android.view.animation.Interpolator; import android.window.BackEvent; @@ -84,7 +83,6 @@ import java.lang.ref.WeakReference; * */ public class LauncherBackAnimationController { - private static final int CANCEL_TRANSITION_DURATION = 233; private static final int SCRIM_FADE_DURATION = 233; private static final float MIN_WINDOW_SCALE = 0.85f; private static final float MAX_SCRIM_ALPHA_DARK = 0.8f; @@ -95,15 +93,12 @@ public class LauncherBackAnimationController { private final Matrix mTransformMatrix = new Matrix(); /** The window position at the beginning of the back animation. */ private final Rect mStartRect = new Rect(); - /** The window position when the back gesture is cancelled. */ - private final RectF mCancelRect = new RectF(); /** The current window position. */ private final RectF mCurrentRect = new RectF(); private final QuickstepLauncher mLauncher; private final int mWindowScaleMarginX; private float mWindowScaleEndCornerRadius; private float mWindowScaleStartCornerRadius; - private final Interpolator mCancelInterpolator; private final Interpolator mProgressInterpolator = Interpolators.STANDARD_DECELERATE; private final Interpolator mVerticalMoveInterpolator = new DecelerateInterpolator(); private final PointF mInitialTouchPos = new PointF(); @@ -142,8 +137,6 @@ public class LauncherBackAnimationController { loadCornerRadius(); mWindowScaleMarginX = mLauncher.getResources().getDimensionPixelSize( R.dimen.swipe_back_window_scale_x_margin); - mCancelInterpolator = - AnimationUtils.loadInterpolator(mLauncher, R.interpolator.standard_interpolator); } /** @@ -181,8 +174,7 @@ public class LauncherBackAnimationController { mHandler.post(() -> { LauncherBackAnimationController controller = mControllerRef.get(); if (controller != null) { - mProgressAnimator.onBackCancelled( - controller::resetPositionAnimated); + mProgressAnimator.onBackCancelled(controller::onCancelFinished); } }); } @@ -262,24 +254,9 @@ public class LauncherBackAnimationController { public void onAnimationCancelled() {} } - private void resetPositionAnimated() { - ValueAnimator cancelAnimator = ValueAnimator.ofFloat(0, 1); - mCancelRect.set(mCurrentRect); - cancelAnimator.setDuration(CANCEL_TRANSITION_DURATION); - cancelAnimator.setInterpolator(mCancelInterpolator); - cancelAnimator.addUpdateListener( - animation -> { - updateCancelProgress((float) animation.getAnimatedValue()); - }); - cancelAnimator.addListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationEnd(Animator animation) { - // Refresh the status bar appearance to the original one. - customizeStatusBarAppearance(false); - finishAnimation(); - } - }); - cancelAnimator.start(); + private void onCancelFinished() { + customizeStatusBarAppearance(false); + finishAnimation(); } /** Unregisters the back to launcher callback in shell. */ @@ -292,6 +269,14 @@ public class LauncherBackAnimationController { } private void startBack(BackMotionEvent backEvent) { + // in case we're still animating an onBackCancelled event, let's remove the finish- + // callback from the progress animator to prevent calling finishAnimation() before + // restarting a new animation + // Side note: startBack is never called during the post-commit phase if the back gesture + // was committed (not cancelled). BackAnimationController prevents that. Therefore we + // don't have to handle that case. + mProgressAnimator.removeOnBackCancelledFinishCallback(); + mBackInProgress = true; RemoteAnimationTarget appTarget = backEvent.getDepartingAnimationTarget(); @@ -314,7 +299,9 @@ public class LauncherBackAnimationController { new RemoteAnimationTarget[]{ mBackTarget }); setLauncherTargetViewVisible(false); mCurrentRect.set(mStartRect); - addScrimLayer(); + if (mScrimLayer == null) { + addScrimLayer(); + } mTransaction.apply(); } @@ -397,23 +384,6 @@ public class LauncherBackAnimationController { customizeStatusBarAppearance(progress > UPDATE_SYSUI_FLAGS_THRESHOLD); } - private void updateCancelProgress(float progress) { - if (mBackTarget == null) { - return; - } - mCurrentRect.set( - Utilities.mapRange(progress, mCancelRect.left, mStartRect.left), - Utilities.mapRange(progress, mCancelRect.top, mStartRect.top), - Utilities.mapRange(progress, mCancelRect.right, mStartRect.right), - Utilities.mapRange(progress, mCancelRect.bottom, mStartRect.bottom)); - - float endCornerRadius = Utilities.mapRange( - mBackProgress, mWindowScaleStartCornerRadius, mWindowScaleEndCornerRadius); - float cornerRadius = Utilities.mapRange( - progress, endCornerRadius, mWindowScaleStartCornerRadius); - applyTransform(mCurrentRect, cornerRadius); - } - /** Transform the target window to match the target rect. */ private void applyTransform(RectF targetRect, float cornerRadius) { final float scale = targetRect.width() / mStartRect.width(); @@ -484,7 +454,6 @@ public class LauncherBackAnimationController { mBackInProgress = false; mBackProgress = 0; mTransformMatrix.reset(); - mCancelRect.setEmpty(); mCurrentRect.setEmpty(); mStartRect.setEmpty(); mInitialTouchPos.set(0, 0); -- GitLab From b274152194799639febe58c4fa1daa896595fd8c Mon Sep 17 00:00:00 2001 From: Vinit Nayak Date: Wed, 28 Feb 2024 21:36:07 -0800 Subject: [PATCH 003/985] Fix split selection for 3P launcher with animations off * When animations were off, the currentState in FallbackRecentsStateController is incorrect (we didn't need that check at all) * Surfaced a bug in MultiValueUpdateListener that is being fixed in ag/26416537 Test: 1P + 3P launcher all of the following: starting split from overview with animations and without rotation selecting second app before and after rotation Fixes: 327346105 Change-Id: I4f19119c30a8669bba6ced06e30773f085a78047 --- .../quickstep/fallback/FallbackRecentsStateController.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/quickstep/src/com/android/quickstep/fallback/FallbackRecentsStateController.java b/quickstep/src/com/android/quickstep/fallback/FallbackRecentsStateController.java index 41c6f9bfb8..3e731e5f2b 100644 --- a/quickstep/src/com/android/quickstep/fallback/FallbackRecentsStateController.java +++ b/quickstep/src/com/android/quickstep/fallback/FallbackRecentsStateController.java @@ -117,9 +117,7 @@ public class FallbackRecentsStateController implements StateHandler Date: Sun, 25 Feb 2024 14:49:06 +0000 Subject: [PATCH 004/985] Clearing All Apps Search For ALL_APPS Intent Currently, if ALL_APPS intent is executed while All Apps QSB is highlighted, user is left on the search sub-view of the All Apps view. To fix this, we add a runner to check the search view and exit from it after State Transition has happened. Before: https://photos.app.goo.gl/c5WeUnAzowxRWW1m7 After: https://photos.app.goo.gl/dxvb23wzwPfKqi3o6 Bug: 324516950 Flag: NA Test: Manual flash and running intent via cmd Change-Id: Icc291f792545b0c515535857f578bc2e01fef7f7 --- src/com/android/launcher3/Launcher.java | 19 +++- .../search/AllAppsSearchBarController.java | 1 + .../android/launcher3/LauncherIntentTest.java | 106 ++++++++++++++++++ 3 files changed, 120 insertions(+), 6 deletions(-) create mode 100644 tests/src/com/android/launcher3/LauncherIntentTest.java diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java index c1ebbe58a2..e4914aabf5 100644 --- a/src/com/android/launcher3/Launcher.java +++ b/src/com/android/launcher3/Launcher.java @@ -1629,7 +1629,8 @@ public class Launcher extends StatefulActivity } else if (INTENT_ACTION_ALL_APPS_TOGGLE.equals(intent.getAction())) { toggleAllAppsFromIntent(alreadyOnHome); } else if (Intent.ACTION_SHOW_WORK_APPS.equals(intent.getAction())) { - showAllAppsWorkTabFromIntent(alreadyOnHome); + showAllAppsWithSelectedTabFromIntent(alreadyOnHome, + ActivityAllAppsContainerView.AdapterHolder.WORK); } TraceHelper.INSTANCE.endSection(); @@ -1661,13 +1662,19 @@ public class Launcher extends StatefulActivity } protected void showAllAppsFromIntent(boolean alreadyOnHome) { - AbstractFloatingView.closeAllOpenViews(this); - getStateManager().goToState(ALL_APPS, alreadyOnHome); + showAllAppsWithSelectedTabFromIntent(alreadyOnHome, + ActivityAllAppsContainerView.AdapterHolder.MAIN); } - private void showAllAppsWorkTabFromIntent(boolean alreadyOnHome) { - showAllAppsFromIntent(alreadyOnHome); - mAppsView.switchToTab(ActivityAllAppsContainerView.AdapterHolder.WORK); + private void showAllAppsWithSelectedTabFromIntent(boolean alreadyOnHome, int tab) { + AbstractFloatingView.closeAllOpenViews(this); + getStateManager().goToState(ALL_APPS, alreadyOnHome); + if (mAppsView.isSearching()) { + mAppsView.reset(alreadyOnHome); + } + if (mAppsView.getCurrentPage() != tab) { + mAppsView.switchToTab(tab); + } } /** diff --git a/src/com/android/launcher3/allapps/search/AllAppsSearchBarController.java b/src/com/android/launcher3/allapps/search/AllAppsSearchBarController.java index f9d047b980..ec45415afa 100644 --- a/src/com/android/launcher3/allapps/search/AllAppsSearchBarController.java +++ b/src/com/android/launcher3/allapps/search/AllAppsSearchBarController.java @@ -155,6 +155,7 @@ public class AllAppsSearchBarController public void reset() { mCallback.clearSearchResult(); mInput.reset(); + mInput.clearFocus(); mQuery = null; mInput.removeOnFocusChangeListener(this); } diff --git a/tests/src/com/android/launcher3/LauncherIntentTest.java b/tests/src/com/android/launcher3/LauncherIntentTest.java new file mode 100644 index 0000000000..e2971e8731 --- /dev/null +++ b/tests/src/com/android/launcher3/LauncherIntentTest.java @@ -0,0 +1,106 @@ +/* + * Copyright (C) 2024 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; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import android.content.Intent; +import android.platform.test.annotations.LargeTest; +import android.view.KeyEvent; + +import androidx.test.runner.AndroidJUnit4; + +import com.android.launcher3.allapps.ActivityAllAppsContainerView; +import com.android.launcher3.allapps.SearchRecyclerView; +import com.android.launcher3.ui.AbstractLauncherUiTest; + +import org.junit.Test; +import org.junit.runner.RunWith; + +@LargeTest +@RunWith(AndroidJUnit4.class) +public class LauncherIntentTest extends AbstractLauncherUiTest { + + public final Intent allAppsIntent = new Intent(Intent.ACTION_ALL_APPS); + + @Test + public void testAllAppsIntent() { + // setup by moving to home + mLauncher.goHome(); + assertTrue("Launcher internal state is not Home", isInState(() -> LauncherState.NORMAL)); + + // Try executing ALL_APPS intent + executeOnLauncher(launcher -> launcher.onNewIntent(allAppsIntent)); + // A-Z view with Main adapter should be loaded + assertOnMainAdapterAToZView(); + + + // Try Moving to search view now + moveToSearchView(); + // Try executing ALL_APPS intent + executeOnLauncher(launcher -> launcher.onNewIntent(allAppsIntent)); + // A-Z view with Main adapter should be loaded + assertOnMainAdapterAToZView(); + + // finish + mLauncher.goHome(); + assertTrue("Launcher internal state is not Home", isInState(() -> LauncherState.NORMAL)); + } + + // Highlights the search bar, then fills text to display the SearchView. + private void moveToSearchView() { + mLauncher.goHome().switchToAllApps(); + + // All Apps view should be loaded + assertTrue("Launcher internal state is not All Apps", + isInState(() -> LauncherState.ALL_APPS)); + executeOnLauncher(launcher -> launcher.getAppsView().getSearchView().requestFocus()); + // Search view should be in focus + waitForLauncherCondition("Search view is not in focus.", + launcher -> launcher.getAppsView().getSearchView().hasFocus()); + mLauncher.pressAndHoldKeyCode(KeyEvent.KEYCODE_C, 0); + // Upon key press, search recycler view should be loaded + waitForLauncherCondition("Search view not active.", + launcher -> launcher.getAppsView().getActiveRecyclerView() + instanceof SearchRecyclerView); + mLauncher.unpressKeyCode(KeyEvent.KEYCODE_C, 0); + } + + // Checks if main adapter view is selected, search bar is out of focus and scroller is at start. + private void assertOnMainAdapterAToZView() { + // All Apps State should be loaded + assertTrue("Launcher internal state is not All Apps", + isInState(() -> LauncherState.ALL_APPS)); + + // A-Z recycler view should be active. + waitForLauncherCondition("A-Z view not active.", + launcher -> !(launcher.getAppsView().getActiveRecyclerView() + instanceof SearchRecyclerView)); + // Personal Adapter should be selected. + waitForLauncherCondition("Not on Main Adapter View", + launcher -> launcher.getAppsView().getCurrentPage() + == ActivityAllAppsContainerView.AdapterHolder.MAIN); + // Search view should not be in focus + waitForLauncherCondition("Search view has focus.", + launcher -> !launcher.getAppsView().getSearchView().hasFocus()); + // Scroller should be at top + executeOnLauncher(launcher -> assertEquals( + "All Apps started in already scrolled state", 0, + getAllAppsScroll(launcher))); + } +} -- GitLab From 07ebb705d6fa456cd72a387cfe4bfc7b31abd82d Mon Sep 17 00:00:00 2001 From: Himanshu Gupta Date: Sun, 3 Mar 2024 20:19:04 +0000 Subject: [PATCH 005/985] Fixing Layout height for Private Space container Screenshot at max Font, max Display Size: Before: https://screenshot.googleplex.com/BwtrU5xE5h63RKZ.png After: https://photos.app.goo.gl/RXTvE6rM6PUx9wRK7 Bug: 311343337 Change-Id: I565c0c430b56e14f0fb1863b37c835c59c032730 Test: Manual --- res/layout/private_space_header.xml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/res/layout/private_space_header.xml b/res/layout/private_space_header.xml index 0b0af87d97..2b5db485de 100644 --- a/res/layout/private_space_header.xml +++ b/res/layout/private_space_header.xml @@ -87,7 +87,8 @@ Date: Sun, 3 Mar 2024 21:56:15 +0000 Subject: [PATCH 006/985] Revert Accidental tweak of work profile behaviour Context: In ag/25247534, while setting the `STATE_TRANSITION`, `updateCurrentState` was replaced accidentaly with `setCurrentState`. As a result, View is not updated to show work apps in paused mode, immediately after the click (as `AlphabeticalAppsList#updateAdapterItems()` is no longer called . This change fixes the same. Bug: 327950935 Change-Id: I263129ff35f45cb5dc6f95db4ed51335f15dbf6f Test: Manual flash and work profile creation. --- src/com/android/launcher3/allapps/WorkProfileManager.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/com/android/launcher3/allapps/WorkProfileManager.java b/src/com/android/launcher3/allapps/WorkProfileManager.java index a54e52c905..96998a3e38 100644 --- a/src/com/android/launcher3/allapps/WorkProfileManager.java +++ b/src/com/android/launcher3/allapps/WorkProfileManager.java @@ -73,7 +73,7 @@ public class WorkProfileManager extends UserProfileManager * Posts quite mode enable/disable call for work profile user */ public void setWorkProfileEnabled(boolean enabled) { - setCurrentState(STATE_TRANSITION); + updateCurrentState(STATE_TRANSITION); setQuietMode(!enabled); } -- GitLab From f584b32811db9bff933483071b0197508249e969 Mon Sep 17 00:00:00 2001 From: Sunny Goyal Date: Thu, 29 Feb 2024 11:55:59 -0800 Subject: [PATCH 007/985] Using fractions in MultiValueUpdateListener instead of absolute durations This ensures that any global animation scale applies properly Bug: 327645429 Flag: NONE Test: Manual Change-Id: I12205429dca5a87208fa9964b3307fb718af4fd0 --- .../launcher3/QuickstepTransitionManager.java | 92 +++--- .../taskbar/TaskbarDragController.java | 13 +- .../com/android/quickstep/TaskViewUtils.java | 15 +- .../com/android/quickstep/util/AnimUtils.java | 13 + .../quickstep/util/AppCloseConfig.java | 57 ---- .../util/MultiValueUpdateListener.java | 16 +- .../util/SplitAnimationController.kt | 305 +++++++++++------- .../quickstep/views/AllAppsEduView.java | 13 +- .../quickstep/views/FloatingTaskView.java | 12 +- 9 files changed, 275 insertions(+), 261 deletions(-) delete mode 100644 quickstep/src/com/android/quickstep/util/AppCloseConfig.java diff --git a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java index 75b8796c9e..66e20d75a0 100644 --- a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java +++ b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java @@ -64,6 +64,7 @@ import static com.android.launcher3.views.FloatingIconView.SHAPE_PROGRESS_DURATI import static com.android.launcher3.views.FloatingIconView.getFloatingIconView; import static com.android.quickstep.TaskAnimationManager.ENABLE_SHELL_TRANSITIONS; import static com.android.quickstep.TaskViewUtils.findTaskViewToLaunch; +import static com.android.quickstep.util.AnimUtils.clampToDuration; import static com.android.quickstep.util.AnimUtils.completeRunnableListCallback; import static com.android.systemui.shared.system.QuickStepContract.getWindowCornerRadius; import static com.android.systemui.shared.system.QuickStepContract.supportsRoundedCornersOnWindows; @@ -748,34 +749,35 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener final float finalShadowRadius = appTargetsAreTranslucent ? 0 : mMaxShadowRadius; MultiValueUpdateListener listener = new MultiValueUpdateListener() { - FloatProp mDx = new FloatProp(0, prop.dX, 0, APP_LAUNCH_DURATION, - mOpeningXInterpolator); - FloatProp mDy = new FloatProp(0, prop.dY, 0, APP_LAUNCH_DURATION, - mOpeningInterpolator); + FloatProp mDx = new FloatProp(0, prop.dX, mOpeningXInterpolator); + FloatProp mDy = new FloatProp(0, prop.dY, mOpeningInterpolator); FloatProp mIconScaleToFitScreen = new FloatProp(prop.initialAppIconScale, - prop.finalAppIconScale, 0, APP_LAUNCH_DURATION, mOpeningInterpolator); + prop.finalAppIconScale, mOpeningInterpolator); FloatProp mIconAlpha = new FloatProp(prop.iconAlphaStart, 0f, - APP_LAUNCH_ALPHA_START_DELAY, APP_LAUNCH_ALPHA_DURATION, LINEAR); + clampToDuration(LINEAR, APP_LAUNCH_ALPHA_START_DELAY, APP_LAUNCH_ALPHA_DURATION, + APP_LAUNCH_DURATION)); - FloatProp mWindowRadius = new FloatProp(initialWindowRadius, finalWindowRadius, 0, - APP_LAUNCH_DURATION, mOpeningInterpolator); - FloatProp mShadowRadius = new FloatProp(0, finalShadowRadius, 0, - APP_LAUNCH_DURATION, mOpeningInterpolator); + FloatProp mWindowRadius = new FloatProp(initialWindowRadius, finalWindowRadius, + mOpeningInterpolator); + FloatProp mShadowRadius = new FloatProp(0, finalShadowRadius, + mOpeningInterpolator); FloatProp mCropRectCenterX = new FloatProp(prop.cropCenterXStart, prop.cropCenterXEnd, - 0, APP_LAUNCH_DURATION, mOpeningInterpolator); + mOpeningInterpolator); FloatProp mCropRectCenterY = new FloatProp(prop.cropCenterYStart, prop.cropCenterYEnd, - 0, APP_LAUNCH_DURATION, mOpeningInterpolator); - FloatProp mCropRectWidth = new FloatProp(prop.cropWidthStart, prop.cropWidthEnd, 0, - APP_LAUNCH_DURATION, mOpeningInterpolator); - FloatProp mCropRectHeight = new FloatProp(prop.cropHeightStart, prop.cropHeightEnd, 0, - APP_LAUNCH_DURATION, mOpeningInterpolator); + mOpeningInterpolator); + FloatProp mCropRectWidth = new FloatProp(prop.cropWidthStart, prop.cropWidthEnd, + mOpeningInterpolator); + FloatProp mCropRectHeight = new FloatProp(prop.cropHeightStart, prop.cropHeightEnd, + mOpeningInterpolator); - FloatProp mNavFadeOut = new FloatProp(1f, 0f, 0, ANIMATION_NAV_FADE_OUT_DURATION, - NAV_FADE_OUT_INTERPOLATOR); - FloatProp mNavFadeIn = new FloatProp(0f, 1f, ANIMATION_DELAY_NAV_FADE_IN, - ANIMATION_NAV_FADE_IN_DURATION, NAV_FADE_IN_INTERPOLATOR); + FloatProp mNavFadeOut = new FloatProp(1f, 0f, clampToDuration( + NAV_FADE_OUT_INTERPOLATOR, 0, ANIMATION_NAV_FADE_OUT_DURATION, + APP_LAUNCH_DURATION)); + FloatProp mNavFadeIn = new FloatProp(0f, 1f, clampToDuration( + NAV_FADE_IN_INTERPOLATOR, ANIMATION_DELAY_NAV_FADE_IN, + ANIMATION_NAV_FADE_IN_DURATION, APP_LAUNCH_DURATION)); @Override public void onUpdate(float percent, boolean initOnly) { @@ -968,37 +970,36 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener appAnimator.addUpdateListener(new MultiValueUpdateListener() { float mAppWindowScale = 1; - final FloatProp mWidgetForegroundAlpha = new FloatProp(1 /* start */, - 0 /* end */, 0 /* delay */, - WIDGET_CROSSFADE_DURATION_MILLIS / 2 /* duration */, LINEAR); - final FloatProp mWidgetFallbackBackgroundAlpha = new FloatProp(0 /* start */, - 1 /* end */, 0 /* delay */, 75 /* duration */, LINEAR); - final FloatProp mPreviewAlpha = new FloatProp(0 /* start */, 1 /* end */, + final FloatProp mWidgetForegroundAlpha = new FloatProp(1, 0, clampToDuration( + LINEAR, 0, WIDGET_CROSSFADE_DURATION_MILLIS / 2, APP_LAUNCH_DURATION)); + + final FloatProp mWidgetFallbackBackgroundAlpha = new FloatProp(0, 1, + clampToDuration(LINEAR, 0, 75, APP_LAUNCH_DURATION)); + final FloatProp mPreviewAlpha = new FloatProp(0, 1, clampToDuration( + LINEAR, WIDGET_CROSSFADE_DURATION_MILLIS / 2 /* delay */, - WIDGET_CROSSFADE_DURATION_MILLIS / 2 /* duration */, LINEAR); + WIDGET_CROSSFADE_DURATION_MILLIS / 2 /* duration */, + APP_LAUNCH_DURATION)); final FloatProp mWindowRadius = new FloatProp(initialWindowRadius, finalWindowRadius, - 0 /* start */, APP_LAUNCH_DURATION, mOpeningInterpolator); - final FloatProp mCornerRadiusProgress = new FloatProp(0, 1, 0, APP_LAUNCH_DURATION, mOpeningInterpolator); + final FloatProp mCornerRadiusProgress = new FloatProp(0, 1, mOpeningInterpolator); // Window & widget background positioning bounds final FloatProp mDx = new FloatProp(widgetBackgroundBounds.centerX(), - windowTargetBounds.centerX(), 0 /* delay */, APP_LAUNCH_DURATION, - mOpeningXInterpolator); + windowTargetBounds.centerX(), mOpeningXInterpolator); final FloatProp mDy = new FloatProp(widgetBackgroundBounds.centerY(), - windowTargetBounds.centerY(), 0 /* delay */, APP_LAUNCH_DURATION, - mOpeningInterpolator); + windowTargetBounds.centerY(), mOpeningInterpolator); final FloatProp mWidth = new FloatProp(widgetBackgroundBounds.width(), - windowTargetBounds.width(), 0 /* delay */, APP_LAUNCH_DURATION, - mOpeningInterpolator); + windowTargetBounds.width(), mOpeningInterpolator); final FloatProp mHeight = new FloatProp(widgetBackgroundBounds.height(), - windowTargetBounds.height(), 0 /* delay */, APP_LAUNCH_DURATION, - mOpeningInterpolator); + windowTargetBounds.height(), mOpeningInterpolator); - final FloatProp mNavFadeOut = new FloatProp(1f, 0f, 0, ANIMATION_NAV_FADE_OUT_DURATION, - NAV_FADE_OUT_INTERPOLATOR); - final FloatProp mNavFadeIn = new FloatProp(0f, 1f, ANIMATION_DELAY_NAV_FADE_IN, - ANIMATION_NAV_FADE_IN_DURATION, NAV_FADE_IN_INTERPOLATOR); + final FloatProp mNavFadeOut = new FloatProp(1f, 0f, clampToDuration( + NAV_FADE_OUT_INTERPOLATOR, 0, ANIMATION_NAV_FADE_OUT_DURATION, + APP_LAUNCH_DURATION)); + final FloatProp mNavFadeIn = new FloatProp(0f, 1f, clampToDuration( + NAV_FADE_IN_INTERPOLATOR, ANIMATION_DELAY_NAV_FADE_IN, + ANIMATION_NAV_FADE_IN_DURATION, APP_LAUNCH_DURATION)); @Override public void onUpdate(float percent, boolean initOnly) { @@ -1508,11 +1509,10 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener float startShadowRadius = areAllTargetsTranslucent(appTargets) ? 0 : mMaxShadowRadius; closingAnimator.setDuration(duration); closingAnimator.addUpdateListener(new MultiValueUpdateListener() { - FloatProp mDy = new FloatProp(0, mClosingWindowTransY, 0, duration, DECELERATE_1_7); - FloatProp mScale = new FloatProp(1f, 1f, 0, duration, DECELERATE_1_7); - FloatProp mAlpha = new FloatProp(1f, 0f, 25, 125, LINEAR); - FloatProp mShadowRadius = new FloatProp(startShadowRadius, 0, 0, duration, - DECELERATE_1_7); + FloatProp mDy = new FloatProp(0, mClosingWindowTransY, DECELERATE_1_7); + FloatProp mScale = new FloatProp(1f, 1f, DECELERATE_1_7); + FloatProp mAlpha = new FloatProp(1f, 0f, clampToDuration(LINEAR, 25, 125, duration)); + FloatProp mShadowRadius = new FloatProp(startShadowRadius, 0, DECELERATE_1_7); @Override public void onUpdate(float percent, boolean initOnly) { diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java index faa67be895..189b6872d2 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java @@ -686,15 +686,10 @@ public class TaskbarDragController extends DragController im float toScale = iconSize / mDragIconSize; float toAlpha = (target == originalView) ? 1f : 0f; MultiValueUpdateListener listener = new MultiValueUpdateListener() { - final FloatProp mDx = new FloatProp(fromX, toPosition[0], 0, - ANIM_DURATION_RETURN_ICON_TO_TASKBAR, Interpolators.FAST_OUT_SLOW_IN); - final FloatProp mDy = new FloatProp(fromY, toPosition[1], 0, - ANIM_DURATION_RETURN_ICON_TO_TASKBAR, - FAST_OUT_SLOW_IN); - final FloatProp mScale = new FloatProp(1f, toScale, 0, - ANIM_DURATION_RETURN_ICON_TO_TASKBAR, FAST_OUT_SLOW_IN); - final FloatProp mAlpha = new FloatProp(1f, toAlpha, 0, - ANIM_DURATION_RETURN_ICON_TO_TASKBAR, Interpolators.ACCELERATE_2); + final FloatProp mDx = new FloatProp(fromX, toPosition[0], FAST_OUT_SLOW_IN); + final FloatProp mDy = new FloatProp(fromY, toPosition[1], FAST_OUT_SLOW_IN); + final FloatProp mScale = new FloatProp(1f, toScale, FAST_OUT_SLOW_IN); + final FloatProp mAlpha = new FloatProp(1f, toAlpha, Interpolators.ACCELERATE_2); @Override public void onUpdate(float percent, boolean initOnly) { animListener.updateDragShadow(mDx.value, mDy.value, mScale.value, mAlpha.value); diff --git a/quickstep/src/com/android/quickstep/TaskViewUtils.java b/quickstep/src/com/android/quickstep/TaskViewUtils.java index e30ea7a26f..8d4255c416 100644 --- a/quickstep/src/com/android/quickstep/TaskViewUtils.java +++ b/quickstep/src/com/android/quickstep/TaskViewUtils.java @@ -37,6 +37,7 @@ import static com.android.launcher3.QuickstepTransitionManager.SPLIT_DIVIDER_ANI import static com.android.launcher3.QuickstepTransitionManager.SPLIT_LAUNCH_DURATION; import static com.android.launcher3.Utilities.getDescendantCoordRelativeToAncestor; import static com.android.launcher3.util.MultiPropertyFactory.MULTI_PROPERTY_VALUE; +import static com.android.quickstep.util.AnimUtils.clampToDuration; import static com.android.quickstep.views.DesktopTaskView.isDesktopModeSupported; import android.animation.Animator; @@ -267,10 +268,16 @@ public final class TaskViewUtils { if (navBarTarget != null) { final Rect cropRect = new Rect(); out.addOnFrameListener(new MultiValueUpdateListener() { - FloatProp mNavFadeOut = new FloatProp(1f, 0f, 0, - ANIMATION_NAV_FADE_OUT_DURATION, NAV_FADE_OUT_INTERPOLATOR); - FloatProp mNavFadeIn = new FloatProp(0f, 1f, ANIMATION_DELAY_NAV_FADE_IN, - ANIMATION_NAV_FADE_IN_DURATION, NAV_FADE_IN_INTERPOLATOR); + FloatProp mNavFadeOut = new FloatProp(1f, 0f, clampToDuration( + NAV_FADE_OUT_INTERPOLATOR, + 0, + ANIMATION_NAV_FADE_OUT_DURATION, + out.getDuration())); + FloatProp mNavFadeIn = new FloatProp(0f, 1f, clampToDuration( + NAV_FADE_IN_INTERPOLATOR, + ANIMATION_DELAY_NAV_FADE_IN, + ANIMATION_NAV_FADE_IN_DURATION, + out.getDuration())); @Override public void onUpdate(float percent, boolean initOnly) { diff --git a/quickstep/src/com/android/quickstep/util/AnimUtils.java b/quickstep/src/com/android/quickstep/util/AnimUtils.java index 1f2a02c816..8e3d44f8d8 100644 --- a/quickstep/src/com/android/quickstep/util/AnimUtils.java +++ b/quickstep/src/com/android/quickstep/util/AnimUtils.java @@ -16,10 +16,12 @@ package com.android.quickstep.util; +import static com.android.app.animation.Interpolators.clampToProgress; import static com.android.launcher3.util.Executors.MAIN_EXECUTOR; import android.os.Bundle; import android.os.IRemoteCallback; +import android.view.animation.Interpolator; import com.android.launcher3.util.RunnableList; @@ -67,4 +69,15 @@ public class AnimUtils { } }; } + + /** + * Returns a function that runs the given interpolator such that the entire progress is set + * between the given duration. That is, we set the interpolation to 0 until startDelay and reach + * 1 by (startDelay + duration). + */ + public static Interpolator clampToDuration(Interpolator interpolator, float startDelay, + float duration, float totalDuration) { + return clampToProgress(interpolator, startDelay / totalDuration, + (startDelay + duration) / totalDuration); + } } diff --git a/quickstep/src/com/android/quickstep/util/AppCloseConfig.java b/quickstep/src/com/android/quickstep/util/AppCloseConfig.java deleted file mode 100644 index bec33797a3..0000000000 --- a/quickstep/src/com/android/quickstep/util/AppCloseConfig.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (C) 2021 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.util; - -import android.annotation.FloatRange; -import android.annotation.IntRange; - -/* - * Adds getter methods to {@link MultiValueUpdateListener} specific to app close animation, - * so that the entire animation can be defined in one place. - */ -public abstract class AppCloseConfig extends MultiValueUpdateListener { - - /** - * Returns the translation y of the workspace contents. - */ - public abstract float getWorkspaceTransY(); - - /* - * Returns the scale of the workspace contents. - */ - public abstract float getWorkspaceScale(); - - /* - * Returns the alpha of the window. - */ - public abstract @FloatRange(from = 0, to = 1) float getWindowAlpha(); - - /* - * Returns the alpha of the foreground layer of an adaptive icon. - */ - public abstract @IntRange(from = 0, to = 255) int getFgAlpha(); - - /* - * Returns the corner radius of the window and icon. - */ - public abstract float getCornerRadius(); - - /* - * Returns the interpolated progress of the animation. - */ - public abstract float getInterpolatedProgress(); - -} diff --git a/quickstep/src/com/android/quickstep/util/MultiValueUpdateListener.java b/quickstep/src/com/android/quickstep/util/MultiValueUpdateListener.java index 1c3c9c2fae..72fc2a67b5 100644 --- a/quickstep/src/com/android/quickstep/util/MultiValueUpdateListener.java +++ b/quickstep/src/com/android/quickstep/util/MultiValueUpdateListener.java @@ -18,6 +18,8 @@ package com.android.quickstep.util; import android.animation.ValueAnimator; import android.view.animation.Interpolator; +import com.android.launcher3.Utilities; + import java.util.ArrayList; /** @@ -31,14 +33,11 @@ public abstract class MultiValueUpdateListener implements ValueAnimator.Animator @Override public final void onAnimationUpdate(ValueAnimator animator) { final float percent = animator.getAnimatedFraction(); - final float currentPlayTime = percent * animator.getDuration(); for (int i = mAllProperties.size() - 1; i >= 0; i--) { FloatProp prop = mAllProperties.get(i); - float time = Math.max(0, currentPlayTime - prop.mDelay); - float newPercent = Math.min(1f, time / prop.mDuration); - newPercent = prop.mInterpolator.getInterpolation(newPercent); - prop.value = prop.mEnd * newPercent + prop.mStart * (1 - newPercent); + float interpolatedPercent = prop.mInterpolator.getInterpolation(percent); + prop.value = Utilities.mapRange(interpolatedPercent, prop.mStart, prop.mEnd); } onUpdate(percent, false /* initOnly */); } @@ -55,17 +54,12 @@ public abstract class MultiValueUpdateListener implements ValueAnimator.Animator private final float mStart; private final float mEnd; - private final float mDelay; - private final float mDuration; private final Interpolator mInterpolator; - public FloatProp(float start, float end, float delay, float duration, Interpolator i) { + public FloatProp(float start, float end, Interpolator i) { value = mStart = start; mEnd = end; - mDelay = delay; - mDuration = duration; mInterpolator = i; - mAllProperties.add(this); } diff --git a/quickstep/src/com/android/quickstep/util/SplitAnimationController.kt b/quickstep/src/com/android/quickstep/util/SplitAnimationController.kt index b7b1d8f754..8f5c9c1186 100644 --- a/quickstep/src/com/android/quickstep/util/SplitAnimationController.kt +++ b/quickstep/src/com/android/quickstep/util/SplitAnimationController.kt @@ -70,69 +70,84 @@ import java.util.Optional import java.util.function.Supplier /** - * Utils class to help run animations for initiating split screen from launcher. - * Will be expanded with future refactors. Works in conjunction with the state stored in - * [SplitSelectStateController] + * Utils class to help run animations for initiating split screen from launcher. Will be expanded + * with future refactors. Works in conjunction with the state stored in [SplitSelectStateController] */ class SplitAnimationController(val splitSelectStateController: SplitSelectStateController) { companion object { // Break this out into maybe enums? Abstractions into its own classes? Tbd. data class SplitAnimInitProps( - val originalView: View, - val originalBitmap: Bitmap?, - val iconDrawable: Drawable, - val fadeWithThumbnail: Boolean, - val isStagedTask: Boolean, - val iconView: View? + val originalView: View, + val originalBitmap: Bitmap?, + val iconDrawable: Drawable, + val fadeWithThumbnail: Boolean, + val isStagedTask: Boolean, + val iconView: View? ) } /** - * Returns different elements to animate for the initial split selection animation - * depending on the state of the surface from which the split was initiated + * Returns different elements to animate for the initial split selection animation depending on + * the state of the surface from which the split was initiated */ - fun getFirstAnimInitViews(taskViewSupplier: Supplier, - splitSelectSourceSupplier: Supplier) - : SplitAnimInitProps { + fun getFirstAnimInitViews( + taskViewSupplier: Supplier, + splitSelectSourceSupplier: Supplier + ): SplitAnimInitProps { val splitSelectSource = splitSelectSourceSupplier.get() if (!splitSelectStateController.isAnimateCurrentTaskDismissal) { // Initiating from home - return SplitAnimInitProps(splitSelectSource!!.view, originalBitmap = null, - splitSelectSource.drawable, fadeWithThumbnail = false, isStagedTask = true, - iconView = null) + return SplitAnimInitProps( + splitSelectSource!!.view, + originalBitmap = null, + splitSelectSource.drawable, + fadeWithThumbnail = false, + isStagedTask = true, + iconView = null + ) } else if (splitSelectStateController.isDismissingFromSplitPair) { // Initiating split from overview, but on a split pair val taskView = taskViewSupplier.get() - for (container : TaskIdAttributeContainer in taskView.taskIdAttributeContainers) { + for (container: TaskIdAttributeContainer in taskView.taskIdAttributeContainers) { if (container.task.getKey().getId() == splitSelectStateController.initialTaskId) { val drawable = getDrawable(container.iconView, splitSelectSource) - return SplitAnimInitProps(container.thumbnailView, - container.thumbnailView.thumbnail, drawable!!, - fadeWithThumbnail = true, isStagedTask = true, - iconView = container.iconView.asView() + return SplitAnimInitProps( + container.thumbnailView, + container.thumbnailView.thumbnail, + drawable!!, + fadeWithThumbnail = true, + isStagedTask = true, + iconView = container.iconView.asView() ) } } - throw IllegalStateException("Attempting to init split from existing split pair " + - "without a valid taskIdAttributeContainer") + throw IllegalStateException( + "Attempting to init split from existing split pair " + + "without a valid taskIdAttributeContainer" + ) } else { // Initiating split from overview on fullscreen task TaskView val taskView = taskViewSupplier.get() val drawable = getDrawable(taskView.iconView, splitSelectSource) - return SplitAnimInitProps(taskView.thumbnail, taskView.thumbnail.thumbnail, - drawable!!, fadeWithThumbnail = true, isStagedTask = true, - taskView.iconView.asView() + return SplitAnimInitProps( + taskView.thumbnail, + taskView.thumbnail.thumbnail, + drawable!!, + fadeWithThumbnail = true, + isStagedTask = true, + taskView.iconView.asView() ) } } /** - * Returns the drawable that's provided in iconView, however if that - * is null it falls back to the drawable that's in splitSelectSource. - * TaskView's icon drawable can be null if the TaskView is scrolled far enough off screen + * Returns the drawable that's provided in iconView, however if that is null it falls back to + * the drawable that's in splitSelectSource. TaskView's icon drawable can be null if the + * TaskView is scrolled far enough off screen + * * @return [Drawable] */ - fun getDrawable(iconView: TaskViewIcon, splitSelectSource: SplitSelectSource?) : Drawable? { + fun getDrawable(iconView: TaskViewIcon, splitSelectSource: SplitSelectSource?): Drawable? { if (iconView.drawable == null && splitSelectSource != null) { return splitSelectSource.drawable } @@ -140,21 +155,25 @@ class SplitAnimationController(val splitSelectStateController: SplitSelectStateC } /** - * When selecting first app from split pair, second app's thumbnail remains. This animates - * the second thumbnail by expanding it to take up the full taskViewWidth/Height and overlaying - * it with [TaskThumbnailView]'s splashView. Adds animations to the provided builder. - * Note: The app that **was not** selected as the first split app should be the container that's - * passed through. + * When selecting first app from split pair, second app's thumbnail remains. This animates the + * second thumbnail by expanding it to take up the full taskViewWidth/Height and overlaying it + * with [TaskThumbnailView]'s splashView. Adds animations to the provided builder. Note: The app + * that **was not** selected as the first split app should be the container that's passed + * through. * * @param builder Adds animation to this * @param taskIdAttributeContainer container of the app that **was not** selected * @param isPrimaryTaskSplitting if true, task that was split would be top/left in the pair - * (opposite of that representing [taskIdAttributeContainer]) + * (opposite of that representing [taskIdAttributeContainer]) */ - fun addInitialSplitFromPair(taskIdAttributeContainer: TaskIdAttributeContainer, - builder: PendingAnimation, deviceProfile: DeviceProfile, - taskViewWidth: Int, taskViewHeight: Int, - isPrimaryTaskSplitting: Boolean) { + fun addInitialSplitFromPair( + taskIdAttributeContainer: TaskIdAttributeContainer, + builder: PendingAnimation, + deviceProfile: DeviceProfile, + taskViewWidth: Int, + taskViewHeight: Int, + isPrimaryTaskSplitting: Boolean + ) { val thumbnail = taskIdAttributeContainer.thumbnailView val iconView: View = taskIdAttributeContainer.iconView.asView() builder.add(ObjectAnimator.ofFloat(thumbnail, TaskThumbnailView.SPLASH_ALPHA, 1f)) @@ -170,35 +189,42 @@ class SplitAnimationController(val splitSelectStateController: SplitSelectStateC ) ) builder.add( - ObjectAnimator.ofFloat( - iconView.splitTranslationY, - MULTI_PROPERTY_VALUE, - 0f - ) + ObjectAnimator.ofFloat(iconView.splitTranslationY, MULTI_PROPERTY_VALUE, 0f) ) } if (deviceProfile.isLeftRightSplit) { // Center view first so scaling happens uniformly, alternatively we can move pivotX to 0 val centerThumbnailTranslationX: Float = (taskViewWidth - thumbnail.width) / 2f val finalScaleX: Float = taskViewWidth.toFloat() / thumbnail.width - builder.add(ObjectAnimator.ofFloat(thumbnail, - TaskThumbnailView.SPLIT_SELECT_TRANSLATE_X, centerThumbnailTranslationX)) + builder.add( + ObjectAnimator.ofFloat( + thumbnail, + TaskThumbnailView.SPLIT_SELECT_TRANSLATE_X, + centerThumbnailTranslationX + ) + ) if (!enableOverviewIconMenu()) { // icons are anchored from Gravity.END, so need to use negative translation val centerIconTranslationX: Float = (taskViewWidth - iconView.width) / 2f - builder.add(ObjectAnimator.ofFloat(iconView, View.TRANSLATION_X, - -centerIconTranslationX)) + builder.add( + ObjectAnimator.ofFloat(iconView, View.TRANSLATION_X, -centerIconTranslationX) + ) } builder.add(ObjectAnimator.ofFloat(thumbnail, View.SCALE_X, finalScaleX)) // Reset other dimensions // TODO(b/271468547), can't set Y translate to 0, need to account for top space thumbnail.scaleY = 1f - val translateYResetVal: Float = if (!isPrimaryTaskSplitting) 0f else - deviceProfile.overviewTaskThumbnailTopMarginPx.toFloat() - builder.add(ObjectAnimator.ofFloat(thumbnail, + val translateYResetVal: Float = + if (!isPrimaryTaskSplitting) 0f + else deviceProfile.overviewTaskThumbnailTopMarginPx.toFloat() + builder.add( + ObjectAnimator.ofFloat( + thumbnail, TaskThumbnailView.SPLIT_SELECT_TRANSLATE_Y, - translateYResetVal)) + translateYResetVal + ) + ) } else { val thumbnailSize = taskViewHeight - deviceProfile.overviewTaskThumbnailTopMarginPx // Center view first so scaling happens uniformly, alternatively we can move pivotY to 0 @@ -214,16 +240,21 @@ class SplitAnimationController(val splitSelectStateController: SplitSelectStateC // translations otherwise this asymmetry causes problems.. if (isPrimaryTaskSplitting) { centerThumbnailTranslationY = (thumbnailSize - thumbnail.height) / 2f - centerThumbnailTranslationY += deviceProfile.overviewTaskThumbnailTopMarginPx - .toFloat() + centerThumbnailTranslationY += + deviceProfile.overviewTaskThumbnailTopMarginPx.toFloat() } else { centerThumbnailTranslationY = (thumbnailSize - thumbnail.height) / 2f } val finalScaleY: Float = thumbnailSize.toFloat() / thumbnail.height - builder.add(ObjectAnimator.ofFloat(thumbnail, - TaskThumbnailView.SPLIT_SELECT_TRANSLATE_Y, centerThumbnailTranslationY)) + builder.add( + ObjectAnimator.ofFloat( + thumbnail, + TaskThumbnailView.SPLIT_SELECT_TRANSLATE_Y, + centerThumbnailTranslationY + ) + ) - if (!enableOverviewIconMenu()) { + if (!enableOverviewIconMenu()) { // icons are anchored from Gravity.END, so need to use negative translation builder.add(ObjectAnimator.ofFloat(iconView, View.TRANSLATION_X, 0f)) } @@ -231,8 +262,9 @@ class SplitAnimationController(val splitSelectStateController: SplitSelectStateC // Reset other dimensions thumbnail.scaleX = 1f - builder.add(ObjectAnimator.ofFloat(thumbnail, - TaskThumbnailView.SPLIT_SELECT_TRANSLATE_X, 0f)) + builder.add( + ObjectAnimator.ofFloat(thumbnail, TaskThumbnailView.SPLIT_SELECT_TRANSLATE_X, 0f) + ) } } @@ -250,69 +282,94 @@ class SplitAnimationController(val splitSelectStateController: SplitSelectStateC * Returns [AnimatorSet] which slides initial split placeholder view offscreen and logs an event * for why split is being dismissed */ - fun createPlaceholderDismissAnim(launcher: StatefulActivity<*>, - splitDismissEvent: EventEnum, - duration: Long?) : AnimatorSet { + fun createPlaceholderDismissAnim( + launcher: StatefulActivity<*>, + splitDismissEvent: EventEnum, + duration: Long? + ): AnimatorSet { val animatorSet = AnimatorSet() duration?.let { animatorSet.duration = it } - val recentsView : RecentsView<*, *> = launcher.getOverviewPanel() - val floatingTask: FloatingTaskView = splitSelectStateController.firstFloatingTaskView - ?: return animatorSet + val recentsView: RecentsView<*, *> = launcher.getOverviewPanel() + val floatingTask: FloatingTaskView = + splitSelectStateController.firstFloatingTaskView ?: return animatorSet // We are in split selection state currently, transitioning to another state val dragLayer: BaseDragLayer<*> = launcher.dragLayer val onScreenRectF = RectF() - Utilities.getBoundsForViewInDragLayer(dragLayer, floatingTask, - Rect(0, 0, floatingTask.width, floatingTask.height), - false, null, onScreenRectF) + Utilities.getBoundsForViewInDragLayer( + dragLayer, + floatingTask, + Rect(0, 0, floatingTask.width, floatingTask.height), + false, + null, + onScreenRectF + ) // Get the part of the floatingTask that intersects with the DragLayer (i.e. the // on-screen portion) onScreenRectF.intersect( - dragLayer.left.toFloat(), - dragLayer.top.toFloat(), - dragLayer.right.toFloat(), - dragLayer.bottom - .toFloat() + dragLayer.left.toFloat(), + dragLayer.top.toFloat(), + dragLayer.right.toFloat(), + dragLayer.bottom.toFloat() ) - animatorSet.play(ObjectAnimator.ofFloat(floatingTask, + animatorSet.play( + ObjectAnimator.ofFloat( + floatingTask, FloatingTaskView.PRIMARY_TRANSLATE_OFFSCREEN, - recentsView.pagedOrientationHandler - .getFloatingTaskOffscreenTranslationTarget( - floatingTask, - onScreenRectF, - floatingTask.stagePosition, - launcher.deviceProfile - ))) - animatorSet.addListener(object : AnimatorListenerAdapter() { - override fun onAnimationEnd(animation: Animator) { - splitSelectStateController.resetState() - safeRemoveViewFromDragLayer(launcher, - splitSelectStateController.splitInstructionsView) + recentsView.pagedOrientationHandler.getFloatingTaskOffscreenTranslationTarget( + floatingTask, + onScreenRectF, + floatingTask.stagePosition, + launcher.deviceProfile + ) + ) + ) + animatorSet.addListener( + object : AnimatorListenerAdapter() { + override fun onAnimationEnd(animation: Animator) { + splitSelectStateController.resetState() + safeRemoveViewFromDragLayer( + launcher, + splitSelectStateController.splitInstructionsView + ) + } } - }) + ) splitSelectStateController.logExitReason(splitDismissEvent) return animatorSet } /** - * Returns a [PendingAnimation] to animate in the chip to instruct a user to select a second - * app for splitscreen + * Returns a [PendingAnimation] to animate in the chip to instruct a user to select a second app + * for splitscreen */ - fun getShowSplitInstructionsAnim(launcher: StatefulActivity<*>) : PendingAnimation { + fun getShowSplitInstructionsAnim(launcher: StatefulActivity<*>): PendingAnimation { safeRemoveViewFromDragLayer(launcher, splitSelectStateController.splitInstructionsView) val splitInstructionsView = SplitInstructionsView.getSplitInstructionsView(launcher) splitSelectStateController.splitInstructionsView = splitInstructionsView val timings = AnimUtils.getDeviceOverviewToSplitTimings(launcher.deviceProfile.isTablet) val anim = PendingAnimation(100 /*duration */) splitInstructionsView.alpha = 0f - anim.setViewAlpha(splitInstructionsView, 1f, - Interpolators.clampToProgress(Interpolators.LINEAR, - timings.instructionsContainerFadeInStartOffset, - timings.instructionsContainerFadeInEndOffset)) - anim.addFloat(splitInstructionsView, SplitInstructionsView.UNFOLD, 0.1f, 1f, - Interpolators.clampToProgress(Interpolators.EMPHASIZED_DECELERATE, - timings.instructionsUnfoldStartOffset, - timings.instructionsUnfoldEndOffset)) + anim.setViewAlpha( + splitInstructionsView, + 1f, + Interpolators.clampToProgress( + Interpolators.LINEAR, + timings.instructionsContainerFadeInStartOffset, + timings.instructionsContainerFadeInEndOffset + ) + ) + anim.addFloat( + splitInstructionsView, + SplitInstructionsView.UNFOLD, + 0.1f, + 1f, + Interpolators.clampToProgress( + Interpolators.EMPHASIZED_DECELERATE, + timings.instructionsUnfoldStartOffset, + timings.instructionsUnfoldEndOffset + ) + ) return anim } @@ -323,15 +380,20 @@ class SplitAnimationController(val splitSelectStateController: SplitSelectStateC /** * Animates the first placeholder view to fullscreen and launches its task. + * * TODO(b/276361926): Remove the [resetCallback] option once contextual launches */ - fun playAnimPlaceholderToFullscreen(launcher: StatefulActivity<*>, view: View, - resetCallback: Optional) { + fun playAnimPlaceholderToFullscreen( + launcher: StatefulActivity<*>, + view: View, + resetCallback: Optional + ) { val stagedTaskView = view as FloatingTaskView val isTablet: Boolean = launcher.deviceProfile.isTablet - val duration = if (isTablet) SplitAnimationTimings.TABLET_CONFIRM_DURATION else - SplitAnimationTimings.PHONE_CONFIRM_DURATION + val duration = + if (isTablet) SplitAnimationTimings.TABLET_CONFIRM_DURATION + else SplitAnimationTimings.PHONE_CONFIRM_DURATION val pendingAnimation = PendingAnimation(duration.toLong()) val firstTaskStartingBounds = Rect() val firstTaskEndingBounds = Rect() @@ -341,11 +403,12 @@ class SplitAnimationController(val splitSelectStateController: SplitSelectStateC splitSelectStateController.setLaunchingFirstAppFullscreen() stagedTaskView.addConfirmAnimation( - pendingAnimation, - RectF(firstTaskStartingBounds), - firstTaskEndingBounds, - false /* fadeWithThumbnail */, - true /* isStagedTask */) + pendingAnimation, + RectF(firstTaskStartingBounds), + firstTaskEndingBounds, + false /* fadeWithThumbnail */, + true /* isStagedTask */ + ) pendingAnimation.addEndListener { splitSelectStateController.launchInitialAppFullscreen { @@ -490,8 +553,8 @@ class SplitAnimationController(val splitSelectStateController: SplitSelectStateC * When the user taps an app pair icon to launch split, this will play the tasks' launch * animation from the position of the icon. * - * To find the root shell leash that we want to fade in, we do the following: - * The Changes we receive in transitionInfo are structured like this + * To find the root shell leash that we want to fade in, we do the following: The Changes we + * receive in transitionInfo are structured like this * * Root (grandparent) * | @@ -503,9 +566,9 @@ class SplitAnimationController(val splitSelectStateController: SplitSelectStateC * | * --> App 2 (right/bottom side child) (WINDOWING_MODE_MULTI_WINDOW) * - * We want to animate the Root (grandparent) so that it affects both apps and the divider. - * To do this, we find one of the nodes with WINDOWING_MODE_MULTI_WINDOW (one of the - * left-side ones, for simplicity) and traverse the tree until we find the grandparent. + * We want to animate the Root (grandparent) so that it affects both apps and the divider. To do + * this, we find one of the nodes with WINDOWING_MODE_MULTI_WINDOW (one of the left-side ones, + * for simplicity) and traverse the tree until we find the grandparent. * * This function is only called when we are animating the app pair in from scratch. It is NOT * called when we are animating in from an existing visible TaskView tile or an app that is @@ -544,8 +607,10 @@ class SplitAnimationController(val splitSelectStateController: SplitSelectStateC // TODO (b/316490565): Replace this logic when SplitBounds is available to // startAnimation() and we can know the precise taskIds of launching tasks. // Find a change that has WINDOWING_MODE_MULTI_WINDOW. - if (taskInfo.windowingMode == WINDOWING_MODE_MULTI_WINDOW && - (change.mode == TRANSIT_OPEN || change.mode == TRANSIT_TO_FRONT)) { + if ( + taskInfo.windowingMode == WINDOWING_MODE_MULTI_WINDOW && + (change.mode == TRANSIT_OPEN || change.mode == TRANSIT_TO_FRONT) + ) { // Check if it is a left/top app. val isLeftTopApp = (dp.isLeftRightSplit && change.endAbsBounds.left == 0) || @@ -614,8 +679,6 @@ class SplitAnimationController(val splitSelectStateController: SplitSelectStateC FloatProp( floatingView.startingPosition.left, dp.widthPx / 2f - floatingView.startingPosition.width() / 2f, - 0f /* delay */, - timings.getDuration().toFloat(), Interpolators.clampToProgress( timings.getStagedRectXInterpolator(), timings.stagedRectSlideStartOffset, @@ -626,8 +689,6 @@ class SplitAnimationController(val splitSelectStateController: SplitSelectStateC FloatProp( floatingView.startingPosition.top, dp.heightPx / 2f - floatingView.startingPosition.height() / 2f, - 0f /* delay */, - timings.getDuration().toFloat(), Interpolators.clampToProgress( Interpolators.EMPHASIZED, timings.stagedRectSlideStartOffset, @@ -638,8 +699,6 @@ class SplitAnimationController(val splitSelectStateController: SplitSelectStateC FloatProp( 1f /* start */, dp.widthPx / floatingView.startingPosition.width(), - 0f /* delay */, - timings.getDuration().toFloat(), Interpolators.clampToProgress( Interpolators.EMPHASIZED, timings.stagedRectSlideStartOffset, @@ -650,8 +709,6 @@ class SplitAnimationController(val splitSelectStateController: SplitSelectStateC FloatProp( 1f /* start */, dp.heightPx / floatingView.startingPosition.height(), - 0f /* delay */, - timings.getDuration().toFloat(), Interpolators.clampToProgress( Interpolators.EMPHASIZED, timings.stagedRectSlideStartOffset, diff --git a/quickstep/src/com/android/quickstep/views/AllAppsEduView.java b/quickstep/src/com/android/quickstep/views/AllAppsEduView.java index fdc8f1ff14..121d8ede11 100644 --- a/quickstep/src/com/android/quickstep/views/AllAppsEduView.java +++ b/quickstep/src/com/android/quickstep/views/AllAppsEduView.java @@ -22,6 +22,7 @@ import static com.android.launcher3.LauncherState.ALL_APPS; import static com.android.launcher3.LauncherState.NORMAL; import static com.android.launcher3.Utilities.EDGE_NAV_BAR; import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ALL_APPS_EDU_SHOWN; +import static com.android.quickstep.util.AnimUtils.clampToDuration; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; @@ -187,10 +188,14 @@ public class AllAppsEduView extends AbstractFloatingView { intro.setInterpolator(LINEAR); intro.setDuration(introDuration); intro.addUpdateListener((new MultiValueUpdateListener() { - FloatProp mCircleAlpha = new FloatProp(0, 255, 0, firstPart, LINEAR); - FloatProp mCircleScale = new FloatProp(2f, 1f, 0, firstPart, OVERSHOOT_1_7); - FloatProp mDeltaY = new FloatProp(0, transY, firstPart, secondPart, FAST_OUT_SLOW_IN); - FloatProp mGradientAlpha = new FloatProp(0, 255, firstPart, secondPart * 0.3f, LINEAR); + FloatProp mCircleAlpha = new FloatProp(0, 255, + clampToDuration(LINEAR, 0, firstPart, introDuration)); + FloatProp mCircleScale = new FloatProp(2f, 1f, + clampToDuration(OVERSHOOT_1_7, 0, firstPart, introDuration)); + FloatProp mDeltaY = new FloatProp(0, transY, + clampToDuration(FAST_OUT_SLOW_IN, firstPart, secondPart, introDuration)); + FloatProp mGradientAlpha = new FloatProp(0, 255, + clampToDuration(LINEAR, firstPart, secondPart * 0.3f, introDuration)); @Override public void onUpdate(float progress, boolean initOnly) { diff --git a/quickstep/src/com/android/quickstep/views/FloatingTaskView.java b/quickstep/src/com/android/quickstep/views/FloatingTaskView.java index 12a073fa84..18922a6fb3 100644 --- a/quickstep/src/com/android/quickstep/views/FloatingTaskView.java +++ b/quickstep/src/com/android/quickstep/views/FloatingTaskView.java @@ -328,20 +328,20 @@ public class FloatingTaskView extends FrameLayout { MultiValueUpdateListener listener = new MultiValueUpdateListener() { // SplitPlaceholderView: rectangle translates and stretches to new position - final FloatProp mDx = new FloatProp(0, prop.dX, 0, animDuration, + final FloatProp mDx = new FloatProp(0, prop.dX, clampToProgress(timings.getStagedRectXInterpolator(), timings.getStagedRectSlideStartOffset(), timings.getStagedRectSlideEndOffset())); - final FloatProp mDy = new FloatProp(0, prop.dY, 0, animDuration, + final FloatProp mDy = new FloatProp(0, prop.dY, clampToProgress(timings.getStagedRectYInterpolator(), timings.getStagedRectSlideStartOffset(), timings.getStagedRectSlideEndOffset())); - final FloatProp mTaskViewScaleX = new FloatProp(1f, prop.finalTaskViewScaleX, 0, - animDuration, clampToProgress(timings.getStagedRectScaleXInterpolator(), + final FloatProp mTaskViewScaleX = new FloatProp(1f, prop.finalTaskViewScaleX, + clampToProgress(timings.getStagedRectScaleXInterpolator(), timings.getStagedRectSlideStartOffset(), timings.getStagedRectSlideEndOffset())); - final FloatProp mTaskViewScaleY = new FloatProp(1f, prop.finalTaskViewScaleY, 0, - animDuration, clampToProgress(timings.getStagedRectScaleYInterpolator(), + final FloatProp mTaskViewScaleY = new FloatProp(1f, prop.finalTaskViewScaleY, + clampToProgress(timings.getStagedRectScaleYInterpolator(), timings.getStagedRectSlideStartOffset(), timings.getStagedRectSlideEndOffset())); @Override -- GitLab From e92f25d7cbacd451fca64c471d7acda6dff13cf8 Mon Sep 17 00:00:00 2001 From: Andy Wickham Date: Tue, 3 Oct 2023 12:48:57 -0700 Subject: [PATCH 008/985] Add custom extra width to trigger LPNH This is defined in dp from the edge of the nav handle. So if you set it to 48, you can invoke 48dp from the left or right of the handle (which is roughly the size of an average fingertip). You can also set it to a negative value to make the invocation region smaller. This applies to both navbar and stashed taskbar, and the minimum touch target is always 48dp. For reference, the navbar width is 108dp and taskbar is 220dp. Defaults to 0, i.e. you can only invoke within the visible navbar. Bug: 325118077 Flag: LEGACY CUSTOM_LPNH_THRESHOLDS DISABLED Test: Manual Change-Id: I904a484a99ac4af05de13573fac610b84fd7f0f1 --- .../uioverrides/flags/DeveloperOptionsUI.java | 5 +++++ .../NavHandleLongPressInputConsumer.java | 12 ++++++++++++ src/com/android/launcher3/LauncherPrefs.kt | 11 +++++++++-- src/com/android/launcher3/config/FeatureFlags.java | 7 +++++++ 4 files changed, 33 insertions(+), 2 deletions(-) diff --git a/quickstep/src/com/android/launcher3/uioverrides/flags/DeveloperOptionsUI.java b/quickstep/src/com/android/launcher3/uioverrides/flags/DeveloperOptionsUI.java index 369ff14c7d..6713964ada 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/flags/DeveloperOptionsUI.java +++ b/quickstep/src/com/android/launcher3/uioverrides/flags/DeveloperOptionsUI.java @@ -22,6 +22,7 @@ import static android.view.View.VISIBLE; import static com.android.launcher3.LauncherPrefs.ALL_APPS_OVERVIEW_THRESHOLD; import static com.android.launcher3.LauncherPrefs.PRIVATE_SPACE_APPS; +import static com.android.launcher3.config.FeatureFlags.LPNH_EXTRA_TOUCH_WIDTH_DP; import static com.android.launcher3.config.FeatureFlags.LPNH_HAPTIC_HINT_DELAY; import static com.android.launcher3.config.FeatureFlags.LPNH_HAPTIC_HINT_END_SCALE_PERCENT; import static com.android.launcher3.config.FeatureFlags.LPNH_HAPTIC_HINT_ITERATIONS; @@ -359,6 +360,10 @@ public class DeveloperOptionsUI { "Slop multiplier (applied to edge slop, " + "which is generally already 50% higher than touch slop)", 25, 200, 100, LPNH_SLOP_PERCENTAGE)); + category.addPreference(createSeekBarPreference( + "Extra width DP (how far outside the sides of the nav bar to trigger)", + // Stashed taskbar is currently 220dp; -86 (x2) would result in 48dp touch area. + -86, 100, 1, LPNH_EXTRA_TOUCH_WIDTH_DP)); category.addPreference(createSeekBarPreference("LPNH timeout", 100, 500, 1, LPNH_TIMEOUT_MS)); } diff --git a/quickstep/src/com/android/quickstep/inputconsumers/NavHandleLongPressInputConsumer.java b/quickstep/src/com/android/quickstep/inputconsumers/NavHandleLongPressInputConsumer.java index cf8750f205..e4a8619338 100644 --- a/quickstep/src/com/android/quickstep/inputconsumers/NavHandleLongPressInputConsumer.java +++ b/quickstep/src/com/android/quickstep/inputconsumers/NavHandleLongPressInputConsumer.java @@ -22,9 +22,11 @@ import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCH import static com.android.launcher3.util.Executors.MAIN_EXECUTOR; import android.content.Context; +import android.util.Log; import android.view.MotionEvent; import android.view.ViewConfiguration; +import com.android.launcher3.Utilities; import com.android.launcher3.config.FeatureFlags; import com.android.launcher3.logging.StatsLogManager; import com.android.launcher3.util.DisplayController; @@ -39,6 +41,8 @@ import com.android.systemui.shared.system.InputMonitorCompat; */ public class NavHandleLongPressInputConsumer extends DelegateInputConsumer { + private static final String TAG = "NavHandleLongPressIC"; + private final NavHandleLongPressHandler mNavHandleLongPressHandler; private final float mNavHandleWidth; private final float mScreenWidth; @@ -175,6 +179,14 @@ public class NavHandleLongPressInputConsumer extends DelegateInputConsumer { private boolean isInNavBarHorizontalArea(float x) { float areaFromMiddle = mNavHandleWidth / 2.0f; + if (FeatureFlags.CUSTOM_LPNH_THRESHOLDS.get()) { + areaFromMiddle += Utilities.dpToPx(FeatureFlags.LPNH_EXTRA_TOUCH_WIDTH_DP.get()); + } + int minAccessibleSize = Utilities.dpToPx(24); // Half of 48dp because this is per side. + if (areaFromMiddle < minAccessibleSize) { + Log.w(TAG, "Custom nav handle region is too small - resetting to 48dp"); + areaFromMiddle = minAccessibleSize; + } float distFromMiddle = Math.abs(mScreenWidth / 2.0f - x); return distFromMiddle < areaFromMiddle; diff --git a/src/com/android/launcher3/LauncherPrefs.kt b/src/com/android/launcher3/LauncherPrefs.kt index b0a644b269..27e084c715 100644 --- a/src/com/android/launcher3/LauncherPrefs.kt +++ b/src/com/android/launcher3/LauncherPrefs.kt @@ -309,6 +309,13 @@ class LauncherPrefs(private val encryptedContext: Context) { val LONG_PRESS_NAV_HANDLE_SLOP_PERCENTAGE = nonRestorableItem("LPNH_SLOP_PERCENTAGE", 100, EncryptionType.MOVE_TO_DEVICE_PROTECTED) @JvmField + val LONG_PRESS_NAV_HANDLE_EXTRA_TOUCH_WIDTH_DP = + nonRestorableItem( + "LPNH_EXTRA_TOUCH_WIDTH_DP", + 0, + EncryptionType.MOVE_TO_DEVICE_PROTECTED + ) + @JvmField val LONG_PRESS_NAV_HANDLE_TIMEOUT_MS = nonRestorableItem( "LPNH_TIMEOUT_MS", @@ -349,8 +356,8 @@ class LauncherPrefs(private val encryptedContext: Context) { @JvmField val PRIVATE_SPACE_APPS = nonRestorableItem("pref_private_space_apps", 0, EncryptionType.MOVE_TO_DEVICE_PROTECTED) - @JvmField val ENABLE_TWOLINE_ALLAPPS_TOGGLE = - backedUpItem("pref_enable_two_line_toggle", false) + @JvmField + val ENABLE_TWOLINE_ALLAPPS_TOGGLE = backedUpItem("pref_enable_two_line_toggle", false) @JvmField val THEMED_ICONS = backedUpItem(Themes.KEY_THEMED_ICONS, false, EncryptionType.MOVE_TO_DEVICE_PROTECTED) diff --git a/src/com/android/launcher3/config/FeatureFlags.java b/src/com/android/launcher3/config/FeatureFlags.java index 072a96ce6e..e25e0338af 100644 --- a/src/com/android/launcher3/config/FeatureFlags.java +++ b/src/com/android/launcher3/config/FeatureFlags.java @@ -17,6 +17,7 @@ package com.android.launcher3.config; import static com.android.launcher3.BuildConfig.WIDGET_ON_FIRST_SCREEN; +import static com.android.launcher3.LauncherPrefs.LONG_PRESS_NAV_HANDLE_EXTRA_TOUCH_WIDTH_DP; import static com.android.launcher3.LauncherPrefs.LONG_PRESS_NAV_HANDLE_HAPTIC_HINT_DELAY; import static com.android.launcher3.LauncherPrefs.LONG_PRESS_NAV_HANDLE_HAPTIC_HINT_END_SCALE_PERCENT; import static com.android.launcher3.LauncherPrefs.LONG_PRESS_NAV_HANDLE_HAPTIC_HINT_ITERATIONS; @@ -147,6 +148,12 @@ public final class FeatureFlags { "Controls touch slop percentage for lpnh", LONG_PRESS_NAV_HANDLE_SLOP_PERCENTAGE); + public static final IntFlag LPNH_EXTRA_TOUCH_WIDTH_DP = + FlagsFactory.getIntFlag(301680992, "LPNH_EXTRA_TOUCH_WIDTH_DP", 0, + "Controls extra dp on the nav bar sides to trigger LPNH." + + " Can be negative for a smaller touch region.", + LONG_PRESS_NAV_HANDLE_EXTRA_TOUCH_WIDTH_DP); + public static final IntFlag LPNH_TIMEOUT_MS = FlagsFactory.getIntFlag(301680992, "LPNH_TIMEOUT_MS", ViewConfiguration.getLongPressTimeout(), -- GitLab From c3ffd41ff0f150ea91ad2a324dd4613b7d0cd89f Mon Sep 17 00:00:00 2001 From: Sebastian Franco Date: Mon, 4 Mar 2024 13:43:52 -0600 Subject: [PATCH 009/985] Refactor migrateGridIfNeeded to pass the grid states and make it easier for unit testing No-op change Bug: 325286145 Flag: NA Test: compiling Change-Id: I703c08059b81e20111c17a142dc54335f18a5a87 --- .../android/launcher3/model/GridSizeMigrationUtil.java | 6 ++---- src/com/android/launcher3/model/ModelDbController.java | 8 ++++++-- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/com/android/launcher3/model/GridSizeMigrationUtil.java b/src/com/android/launcher3/model/GridSizeMigrationUtil.java index af66431d47..1d44f205f0 100644 --- a/src/com/android/launcher3/model/GridSizeMigrationUtil.java +++ b/src/com/android/launcher3/model/GridSizeMigrationUtil.java @@ -105,12 +105,10 @@ public class GridSizeMigrationUtil { */ public static boolean migrateGridIfNeeded( @NonNull Context context, - @NonNull InvariantDeviceProfile idp, + @NonNull DeviceGridState srcDeviceState, + @NonNull DeviceGridState destDeviceState, @NonNull DatabaseHelper target, @NonNull SQLiteDatabase source) { - - DeviceGridState srcDeviceState = new DeviceGridState(context); - DeviceGridState destDeviceState = new DeviceGridState(idp); if (!needsToMigrate(srcDeviceState, destDeviceState)) { return true; } diff --git a/src/com/android/launcher3/model/ModelDbController.java b/src/com/android/launcher3/model/ModelDbController.java index ba2b64d9c1..8ed554a12e 100644 --- a/src/com/android/launcher3/model/ModelDbController.java +++ b/src/com/android/launcher3/model/ModelDbController.java @@ -308,8 +308,12 @@ public class ModelDbController { mOpenHelper = (mContext instanceof SandboxContext) ? oldHelper : createDatabaseHelper(true /* forMigration */); try { - return GridSizeMigrationUtil.migrateGridIfNeeded(mContext, idp, mOpenHelper, - oldHelper.getWritableDatabase()); + // This is the current grid we have, given by the mContext + DeviceGridState srcDeviceState = new DeviceGridState(mContext); + // This is the state we want to migrate to that is given by the idp + DeviceGridState destDeviceState = new DeviceGridState(idp); + return GridSizeMigrationUtil.migrateGridIfNeeded(mContext, srcDeviceState, + destDeviceState, mOpenHelper, oldHelper.getWritableDatabase()); } catch (Exception e) { FileLog.e(TAG, "Failed to migrate grid", e); return false; -- GitLab From 91b06fb4ac8fcb51612bce3dd271088334d89700 Mon Sep 17 00:00:00 2001 From: Vinit Nayak Date: Mon, 4 Mar 2024 12:26:23 -0800 Subject: [PATCH 010/985] Revert "Revert "Implements the "Save App Pair" button in Overvie..." Revert submission 26420318-revert-26391074-save-app-pair-button-ZKCRCDSCSN Reason for revert: Test failure in question wasn't related to this topic b/328016248 Reverted changes: /q/submissionid:26420318-revert-26391074-save-app-pair-button-ZKCRCDSCSN Change-Id: I2a4dbb83720768a9d29a4371c77e3b9410ab2fea --- .../res/layout/overview_actions_container.xml | 10 ++ .../res/layout/overview_actions_container.xml | 9 ++ quickstep/res/values/strings.xml | 2 + .../android/quickstep/TaskOverlayFactory.java | 16 ++- .../quickstep/TaskShortcutFactory.java | 16 ++- .../quickstep/views/GroupedTaskView.java | 11 +- .../quickstep/views/OverviewActionsView.java | 125 +++++++++++++----- .../android/quickstep/views/RecentsView.java | 22 +-- .../testing/TestInformationHandler.java | 6 + .../testing/shared/TestProtocol.java | 1 + .../android/launcher3/tapl/BaseOverview.java | 7 +- .../tapl/LauncherInstrumentation.java | 5 + 12 files changed, 181 insertions(+), 49 deletions(-) diff --git a/go/quickstep/res/layout/overview_actions_container.xml b/go/quickstep/res/layout/overview_actions_container.xml index 48650aac20..077cfaee19 100644 --- a/go/quickstep/res/layout/overview_actions_container.xml +++ b/go/quickstep/res/layout/overview_actions_container.xml @@ -120,6 +120,16 @@ android:layout_height="1dp" android:layout_weight="1" android:visibility="gone" /> + +