From 4ef6bd5a7a2169f0aa7086964e51f6ef18c84ab1 Mon Sep 17 00:00:00 2001 From: Schneider Victor-tulias Date: Fri, 18 Jun 2021 15:33:38 -0700 Subject: [PATCH 1/9] Update All set screen icon Fixes: 191463446 Test: Manual Change-Id: I746bfb2eab950a01041493bd72d7dda30ac66d7b --- quickstep/res/drawable/ic_all_set.xml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/quickstep/res/drawable/ic_all_set.xml b/quickstep/res/drawable/ic_all_set.xml index a6852aa78e..656c59669c 100644 --- a/quickstep/res/drawable/ic_all_set.xml +++ b/quickstep/res/drawable/ic_all_set.xml @@ -15,10 +15,10 @@ --> + android:viewportHeight="42"> From 651abb99245f31b054c4aeb8b5604d607df85fec Mon Sep 17 00:00:00 2001 From: Jon Miranda Date: Fri, 18 Jun 2021 15:39:36 -0700 Subject: [PATCH 2/9] Fix bug where workspace alpha does not get set to 1 when animation gets cancelled. - Can also remove QSB from app launch animator, since its in the hotseat now. Bug: 189458349 Test: manual Change-Id: Ib41376e3f8c58166c6ee6fbfed38bdd443663df4 --- .../android/launcher3/QuickstepTransitionManager.java | 2 -- .../com/android/quickstep/util/WorkspaceRevealAnim.java | 9 +++++++++ 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java index 31cf51c3b3..dd248e4e83 100644 --- a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java +++ b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java @@ -497,8 +497,6 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener view -> viewsToAnimate.add(((CellLayout) view).getShortcutsAndWidgets())); viewsToAnimate.add(mLauncher.getHotseat()); - // Add QSB - viewsToAnimate.add(mLauncher.findViewById(R.id.search_container_all_apps)); viewsToAnimate.forEach(view -> { view.setLayerType(View.LAYER_TYPE_HARDWARE, null); diff --git a/quickstep/src/com/android/quickstep/util/WorkspaceRevealAnim.java b/quickstep/src/com/android/quickstep/util/WorkspaceRevealAnim.java index 50da93b828..df94d0bee6 100644 --- a/quickstep/src/com/android/quickstep/util/WorkspaceRevealAnim.java +++ b/quickstep/src/com/android/quickstep/util/WorkspaceRevealAnim.java @@ -24,6 +24,7 @@ import static com.android.launcher3.states.StateAnimationConfig.SKIP_OVERVIEW; import static com.android.launcher3.states.StateAnimationConfig.SKIP_SCRIM; import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; import android.animation.AnimatorSet; import android.animation.ObjectAnimator; import android.view.View; @@ -98,6 +99,14 @@ public class WorkspaceRevealAnim { alpha.setDuration(DURATION_MS); alpha.setInterpolator(Interpolators.DECELERATED_EASE); mAnimators.play(alpha); + + mAnimators.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + SCALE_PROPERTY.set(v, 1f); + v.setAlpha(1f); + } + }); } /** From aefcc5a300fa1718fdd187cd8080810387bc8f33 Mon Sep 17 00:00:00 2001 From: Brian Isganitis Date: Fri, 18 Jun 2021 19:58:18 +0000 Subject: [PATCH 3/9] Revert "Fix home settings landing page" This reverts commit 96cc3c533cd8cdbad0da04f91508bab018a446ad. Reason for revert: Causes back to close sub-settings (b/191257243). Change-Id: I3aa01bed1d73874176fc2568bac4ca714e9f2df7 Bug: 188565060 --- src/com/android/launcher3/settings/SettingsActivity.java | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/com/android/launcher3/settings/SettingsActivity.java b/src/com/android/launcher3/settings/SettingsActivity.java index dbd9c281a2..915e140aaf 100644 --- a/src/com/android/launcher3/settings/SettingsActivity.java +++ b/src/com/android/launcher3/settings/SettingsActivity.java @@ -113,12 +113,6 @@ public class SettingsActivity extends FragmentActivity Utilities.getPrefs(getApplicationContext()).registerOnSharedPreferenceChangeListener(this); } - @Override - protected void onStop() { - super.onStop(); - finish(); - } - /** * Obtains the preference fragment to instantiate in this activity. * From 3fd22847ac7b2b61296d4244af391fba6ec9fe5a Mon Sep 17 00:00:00 2001 From: Tony Wickham Date: Tue, 1 Jun 2021 16:54:07 -0700 Subject: [PATCH 4/9] Initial commit of taskbar stashing - Added StashedHandleViewController to provide properties such as ViewOutlineProvider to animate the handle that's shown in place of taskbar while it's stashed - Added TaskbarStashController to coordinate the stashed state, including orchestrating the animation across taskbar controllers - Added TaskbarStashInput consumer to detect long press in the nav region when taskbar is stashed Behavior: - Long pressing taskbar background animates to the stashed state by morphing the TaskbarView into the stashed handle view and offsetting the background offscreen - We persist the stashed state across app launches and reboot; to unstash, long press the stashed handle - We also visually unstash when going back home Test: long press tasbkar background when in an app to stash it, long press the resulting stashed handle to unstash; while stashed, swipe up to home to also unstash until launching another app Bug: 189503603 Change-Id: I698eff785388dff1ef717c76879719d6af236c2d --- quickstep/res/layout/taskbar.xml | 12 + quickstep/res/values/dimens.xml | 3 + .../taskbar/LauncherTaskbarUIController.java | 77 +++-- .../taskbar/StashedHandleViewController.java | 108 ++++++++ .../taskbar/TaskbarActivityContext.java | 5 +- .../launcher3/taskbar/TaskbarControllers.java | 10 +- .../launcher3/taskbar/TaskbarDragLayer.java | 18 +- .../taskbar/TaskbarDragLayerController.java | 10 + .../taskbar/TaskbarStashController.java | 262 ++++++++++++++++++ .../taskbar/TaskbarUIController.java | 4 + .../launcher3/taskbar/TaskbarView.java | 10 +- .../taskbar/TaskbarViewController.java | 49 +++- .../com/android/quickstep/AnimatedFloat.java | 10 + .../quickstep/BaseActivityInterface.java | 8 + .../com/android/quickstep/InputConsumer.java | 2 + .../quickstep/LauncherActivityInterface.java | 9 + .../quickstep/RecentsAnimationController.java | 11 + .../quickstep/TouchInteractionService.java | 9 + .../TaskbarStashInputConsumer.java | 66 +++++ .../launcher3/util/MultiValueAlpha.java | 9 + 20 files changed, 654 insertions(+), 38 deletions(-) create mode 100644 quickstep/src/com/android/launcher3/taskbar/StashedHandleViewController.java create mode 100644 quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java create mode 100644 quickstep/src/com/android/quickstep/inputconsumers/TaskbarStashInputConsumer.java diff --git a/quickstep/res/layout/taskbar.xml b/quickstep/res/layout/taskbar.xml index d61a8952a7..dfa17d6cc4 100644 --- a/quickstep/res/layout/taskbar.xml +++ b/quickstep/res/layout/taskbar.xml @@ -15,6 +15,7 @@ --> + + \ No newline at end of file diff --git a/quickstep/res/values/dimens.xml b/quickstep/res/values/dimens.xml index d8899a6e8e..4f62b34a5f 100644 --- a/quickstep/res/values/dimens.xml +++ b/quickstep/res/values/dimens.xml @@ -153,4 +153,7 @@ 16dp 16dp 48dp + 24dp + 220dp + 6dp diff --git a/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java b/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java index 7d0afe1aba..c98bc87168 100644 --- a/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java +++ b/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java @@ -50,21 +50,23 @@ public class LauncherTaskbarUIController extends TaskbarUIController { private final TaskbarHotseatController mHotseatController; private final TaskbarActivityContext mContext; - final TaskbarDragLayer mTaskbarDragLayer; - final TaskbarView mTaskbarView; + private final TaskbarDragLayer mTaskbarDragLayer; + private final TaskbarView mTaskbarView; private final AnimatedFloat mIconAlignmentForResumedState = new AnimatedFloat(this::onIconAlignmentRatioChanged); private final AnimatedFloat mIconAlignmentForGestureState = new AnimatedFloat(this::onIconAlignmentRatioChanged); + // Initialized in init. + private TaskbarControllers mControllers; private AnimatedFloat mTaskbarBackgroundAlpha; private AlphaProperty mIconAlphaForHome; - private boolean mIsAnimatingToLauncher; + private boolean mIsAnimatingToLauncherViaResume; + private boolean mIsAnimatingToLauncherViaGesture; private TaskbarKeyguardController mKeyguardController; private LauncherState mTargetStateOverride = null; - private TaskbarControllers mControllers; public LauncherTaskbarUIController( BaseQuickstepLauncher launcher, TaskbarActivityContext context) { @@ -80,13 +82,14 @@ public class LauncherTaskbarUIController extends TaskbarUIController { @Override protected void init(TaskbarControllers taskbarControllers) { - mTaskbarBackgroundAlpha = taskbarControllers.taskbarDragLayerController - .getTaskbarBackgroundAlpha(); - MultiValueAlpha taskbarIconAlpha = taskbarControllers.taskbarViewController - .getTaskbarIconAlpha(); - mIconAlphaForHome = taskbarIconAlpha.getProperty(ALPHA_INDEX_HOME); mControllers = taskbarControllers; + mTaskbarBackgroundAlpha = mControllers.taskbarDragLayerController + .getTaskbarBackgroundAlpha(); + + MultiValueAlpha taskbarIconAlpha = mControllers.taskbarViewController.getTaskbarIconAlpha(); + mIconAlphaForHome = taskbarIconAlpha.getProperty(ALPHA_INDEX_HOME); + mHotseatController.init(); mLauncher.setTaskbarUIController(this); mKeyguardController = taskbarControllers.taskbarKeyguardController; @@ -109,19 +112,17 @@ public class LauncherTaskbarUIController extends TaskbarUIController { @Override protected boolean isTaskbarTouchable() { - return !mIsAnimatingToLauncher && mTargetStateOverride == null; + return !isAnimatingToLauncher() && !mControllers.taskbarStashController.isStashed(); + } + + private boolean isAnimatingToLauncher() { + return mIsAnimatingToLauncherViaResume || mIsAnimatingToLauncherViaGesture; } @Override protected void updateContentInsets(Rect outContentInsets) { - // TaskbarDragLayer provides insets to other apps based on contentInsets. These - // insets should stay consistent even if we expand TaskbarDragLayer's bounds, e.g. - // to show a floating view like Folder. Thus, we set the contentInsets to be where - // mTaskbarView is, since its position never changes and insets rather than overlays. - outContentInsets.left = mTaskbarView.getLeft(); - outContentInsets.top = mTaskbarView.getTop(); - outContentInsets.right = mTaskbarDragLayer.getWidth() - mTaskbarView.getRight(); - outContentInsets.bottom = mTaskbarDragLayer.getHeight() - mTaskbarView.getBottom(); + int contentHeight = mControllers.taskbarStashController.getContentHeight(); + outContentInsets.top = mTaskbarDragLayer.getHeight() - contentHeight; } /** @@ -137,13 +138,20 @@ public class LauncherTaskbarUIController extends TaskbarUIController { } } + long duration = QuickstepTransitionManager.CONTENT_ALPHA_DURATION; ObjectAnimator anim = mIconAlignmentForResumedState.animateToValue( getCurrentIconAlignmentRatio(), isResumed ? 1 : 0) - .setDuration(QuickstepTransitionManager.CONTENT_ALPHA_DURATION); + .setDuration(duration); - anim.addListener(AnimatorListeners.forEndCallback(() -> mIsAnimatingToLauncher = false)); + anim.addListener(AnimatorListeners.forEndCallback( + () -> mIsAnimatingToLauncherViaResume = false)); anim.start(); - mIsAnimatingToLauncher = isResumed; + mIsAnimatingToLauncherViaResume = isResumed; + + if (!isResumed) { + TaskbarStashController stashController = mControllers.taskbarStashController; + stashController.animateToIsStashed(stashController.isStashedInApp(), duration); + } } /** @@ -155,36 +163,48 @@ public class LauncherTaskbarUIController extends TaskbarUIController { public Animator createAnimToLauncher(@NonNull LauncherState toState, @NonNull RecentsAnimationCallbacks callbacks, long duration) { + TaskbarStashController stashController = mControllers.taskbarStashController; ObjectAnimator animator = mIconAlignmentForGestureState - .animateToValue(mIconAlignmentForGestureState.value, 1) + .animateToValue(1) .setDuration(duration); animator.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { mTargetStateOverride = null; + animator.removeListener(this); } @Override public void onAnimationStart(Animator animation) { mTargetStateOverride = toState; + mIsAnimatingToLauncherViaGesture = true; + // TODO: base this on launcher state + stashController.animateToIsStashed(false, duration); } }); callbacks.addListener(new RecentsAnimationListener() { @Override public void onRecentsAnimationCanceled(ThumbnailData thumbnailData) { - endGestureStateOverride(); + endGestureStateOverride(true); } @Override public void onRecentsAnimationFinished(RecentsAnimationController controller) { - endGestureStateOverride(); + endGestureStateOverride(!controller.getFinishTargetIsLauncher()); } - private void endGestureStateOverride() { + private void endGestureStateOverride(boolean finishedToApp) { callbacks.removeListener(this); + mIsAnimatingToLauncherViaGesture = false; + mIconAlignmentForGestureState - .animateToValue(mIconAlignmentForGestureState.value, 0) + .animateToValue(0) .start(); + + if (finishedToApp) { + // We only need this for the exiting live tile case. + stashController.animateToIsStashed(stashController.isStashedInApp()); + } } }); return animator; @@ -215,6 +235,11 @@ public class LauncherTaskbarUIController extends TaskbarUIController { } } + @Override + public boolean onLongPressToUnstashTaskbar() { + return mControllers.taskbarStashController.onLongPressToUnstashTaskbar(); + } + /** * Should be called when one or more items in the Hotseat have changed. */ diff --git a/quickstep/src/com/android/launcher3/taskbar/StashedHandleViewController.java b/quickstep/src/com/android/launcher3/taskbar/StashedHandleViewController.java new file mode 100644 index 0000000000..8c14ff6d16 --- /dev/null +++ b/quickstep/src/com/android/launcher3/taskbar/StashedHandleViewController.java @@ -0,0 +1,108 @@ +/* + * 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.launcher3.taskbar; + +import android.animation.Animator; +import android.content.res.Resources; +import android.graphics.Outline; +import android.graphics.Rect; +import android.view.View; +import android.view.ViewOutlineProvider; + +import androidx.annotation.Nullable; + +import com.android.launcher3.R; +import com.android.launcher3.anim.RevealOutlineAnimation; +import com.android.launcher3.anim.RoundedRectRevealOutlineProvider; +import com.android.quickstep.AnimatedFloat; + +/** + * Handles properties/data collection, then passes the results to our stashed handle View to render. + */ +public class StashedHandleViewController { + + private final TaskbarActivityContext mActivity; + private final View mStashedHandleView; + private final int mStashedHandleWidth; + private final int mStashedHandleHeight; + private final AnimatedFloat mTaskbarStashedHandleAlpha = new AnimatedFloat( + this::updateStashedHandleAlpha); + + // Initialized in init. + private TaskbarControllers mControllers; + + // The bounds we want to clip to in the settled state when showing the stashed handle. + private final Rect mStashedHandleBounds = new Rect(); + private float mStashedHandleRadius; + + private boolean mIsAtStashedRevealBounds = true; + + public StashedHandleViewController(TaskbarActivityContext activity, View stashedHandleView) { + mActivity = activity; + mStashedHandleView = stashedHandleView; + final Resources resources = mActivity.getResources(); + mStashedHandleWidth = resources.getDimensionPixelSize(R.dimen.taskbar_stashed_handle_width); + mStashedHandleHeight = resources.getDimensionPixelSize( + R.dimen.taskbar_stashed_handle_height); + } + + public void init(TaskbarControllers controllers) { + mControllers = controllers; + mStashedHandleView.getLayoutParams().height = mActivity.getDeviceProfile().taskbarSize; + + updateStashedHandleAlpha(); + + final int stashedTaskbarHeight = mControllers.taskbarStashController.getStashedHeight(); + mStashedHandleView.setOutlineProvider(new ViewOutlineProvider() { + @Override + public void getOutline(View view, Outline outline) { + final int stashedCenterX = view.getWidth() / 2; + final int stashedCenterY = view.getHeight() - stashedTaskbarHeight / 2; + mStashedHandleBounds.set( + stashedCenterX - mStashedHandleWidth / 2, + stashedCenterY - mStashedHandleHeight / 2, + stashedCenterX + mStashedHandleWidth / 2, + stashedCenterY + mStashedHandleHeight / 2); + mStashedHandleRadius = view.getHeight() / 2f; + outline.setRoundRect(mStashedHandleBounds, mStashedHandleRadius); + } + }); + } + + public AnimatedFloat getStashedHandleAlpha() { + return mTaskbarStashedHandleAlpha; + } + + /** + * Creates and returns a {@link RevealOutlineAnimation} Animator that updates the stashed handle + * shape and size. When stashed, the shape is a thin rounded pill. When unstashed, the shape + * morphs into the size of where the taskbar icons will be. + */ + public @Nullable Animator createRevealAnimToIsStashed(boolean isStashed) { + if (mIsAtStashedRevealBounds == isStashed) { + return null; + } + mIsAtStashedRevealBounds = isStashed; + final RevealOutlineAnimation handleRevealProvider = new RoundedRectRevealOutlineProvider( + mStashedHandleRadius, mStashedHandleRadius, + mControllers.taskbarViewController.getIconLayoutBounds(), mStashedHandleBounds); + return handleRevealProvider.createRevealAnimator(mStashedHandleView, !isStashed); + } + + protected void updateStashedHandleAlpha() { + mStashedHandleView.setAlpha(mTaskbarStashedHandleAlpha.value); + } +} diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java index 41426108e5..f4703d3a99 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java @@ -115,6 +115,7 @@ public class TaskbarActivityContext extends ContextThemeWrapper implements Activ R.layout.taskbar, null, false); TaskbarView taskbarView = mDragLayer.findViewById(R.id.taskbar_view); FrameLayout navButtonsView = mDragLayer.findViewById(R.id.navbuttons_view); + View stashedHandleView = mDragLayer.findViewById(R.id.stashed_handle); // Construct controllers. mControllers = new TaskbarControllers(this, @@ -125,7 +126,9 @@ public class TaskbarActivityContext extends ContextThemeWrapper implements Activ R.color.popup_color_primary_light), new TaskbarDragLayerController(this, mDragLayer), new TaskbarViewController(this, taskbarView), - new TaskbarKeyguardController(this)); + new TaskbarKeyguardController(this), + new StashedHandleViewController(this, stashedHandleView), + new TaskbarStashController(this)); Display display = windowContext.getDisplay(); Context c = display.getDisplayId() == Display.DEFAULT_DISPLAY diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java index c48c28b9e5..8279a470f0 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java @@ -32,6 +32,8 @@ public class TaskbarControllers { public final TaskbarDragLayerController taskbarDragLayerController; public final TaskbarViewController taskbarViewController; public final TaskbarKeyguardController taskbarKeyguardController; + public final StashedHandleViewController stashedHandleViewController; + public final TaskbarStashController taskbarStashController; /** Do not store this controller, as it may change at runtime. */ @NonNull public TaskbarUIController uiController = TaskbarUIController.DEFAULT; @@ -43,7 +45,9 @@ public class TaskbarControllers { RotationButtonController rotationButtonController, TaskbarDragLayerController taskbarDragLayerController, TaskbarViewController taskbarViewController, - TaskbarKeyguardController taskbarKeyguardController) { + TaskbarKeyguardController taskbarKeyguardController, + StashedHandleViewController stashedHandleViewController, + TaskbarStashController taskbarStashController) { this.taskbarActivityContext = taskbarActivityContext; this.taskbarDragController = taskbarDragController; this.navButtonController = navButtonController; @@ -52,6 +56,8 @@ public class TaskbarControllers { this.taskbarDragLayerController = taskbarDragLayerController; this.taskbarViewController = taskbarViewController; this.taskbarKeyguardController = taskbarKeyguardController; + this.stashedHandleViewController = stashedHandleViewController; + this.taskbarStashController = taskbarStashController; } /** @@ -67,6 +73,8 @@ public class TaskbarControllers { taskbarDragLayerController.init(this); taskbarViewController.init(this); taskbarKeyguardController.init(navbarButtonsViewController); + stashedHandleViewController.init(this); + taskbarStashController.init(this); } /** diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayer.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayer.java index ac121ab5fa..cd1baf726d 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayer.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayer.java @@ -40,10 +40,11 @@ import com.android.systemui.shared.system.ViewTreeObserverWrapper.OnComputeInset public class TaskbarDragLayer extends BaseDragLayer { private final Paint mTaskbarBackgroundPaint; + private final OnComputeInsetsListener mTaskbarInsetsComputer = this::onComputeTaskbarInsets; private TaskbarDragLayerController.TaskbarDragLayerCallbacks mControllerCallbacks; - private final OnComputeInsetsListener mTaskbarInsetsComputer = this::onComputeTaskbarInsets; + private float mTaskbarBackgroundOffset; public TaskbarDragLayer(@NonNull Context context) { this(context, null); @@ -118,8 +119,10 @@ public class TaskbarDragLayer extends BaseDragLayer { @Override protected void dispatchDraw(Canvas canvas) { - canvas.drawRect(0, canvas.getHeight() - mControllerCallbacks.getTaskbarBackgroundHeight(), - canvas.getWidth(), canvas.getHeight(), mTaskbarBackgroundPaint); + float backgroundHeight = mControllerCallbacks.getTaskbarBackgroundHeight() + * (1f - mTaskbarBackgroundOffset); + canvas.drawRect(0, canvas.getHeight() - backgroundHeight, canvas.getWidth(), + canvas.getHeight(), mTaskbarBackgroundPaint); super.dispatchDraw(canvas); } @@ -132,6 +135,15 @@ public class TaskbarDragLayer extends BaseDragLayer { invalidate(); } + /** + * Sets the translation of the background color behind all the Taskbar contents. + * @param offset 0 is fully onscreen, 1 is fully offscreen. + */ + protected void setTaskbarBackgroundOffset(float offset) { + mTaskbarBackgroundOffset = offset; + invalidate(); + } + @Override public boolean dispatchTouchEvent(MotionEvent ev) { TestLogging.recordMotionEvent(TestProtocol.SEQUENCE_MAIN, "Touch event", ev); diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayerController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayerController.java index db5c387770..e15e9ffa71 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayerController.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayerController.java @@ -39,6 +39,8 @@ public class TaskbarDragLayerController { // Alpha properties for taskbar background. private final AnimatedFloat mBgTaskbar = new AnimatedFloat(this::updateBackgroundAlpha); private final AnimatedFloat mBgNavbar = new AnimatedFloat(this::updateBackgroundAlpha); + // Translation property for taskbar background. + private final AnimatedFloat mBgOffset = new AnimatedFloat(this::updateBackgroundOffset); // Initialized in init. private TaskbarControllers mControllers; @@ -78,10 +80,18 @@ public class TaskbarDragLayerController { return mBgNavbar; } + public AnimatedFloat getTaskbarBackgroundOffset() { + return mBgOffset; + } + private void updateBackgroundAlpha() { mTaskbarDragLayer.setTaskbarBackgroundAlpha(Math.max(mBgNavbar.value, mBgTaskbar.value)); } + private void updateBackgroundOffset() { + mTaskbarDragLayer.setTaskbarBackgroundOffset(mBgOffset.value); + } + /** * Callbacks for {@link TaskbarDragLayer} to interact with its controller. */ diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java new file mode 100644 index 0000000000..57600d7356 --- /dev/null +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java @@ -0,0 +1,262 @@ +/* + * 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.launcher3.taskbar; + +import static android.view.HapticFeedbackConstants.LONG_PRESS; + +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; +import android.animation.AnimatorSet; +import android.annotation.Nullable; +import android.content.SharedPreferences; +import android.content.res.Resources; + +import com.android.launcher3.R; +import com.android.launcher3.Utilities; +import com.android.launcher3.util.MultiValueAlpha.AlphaProperty; +import com.android.quickstep.AnimatedFloat; + +/** + * Coordinates between controllers such as TaskbarViewController and StashedHandleViewController to + * create a cohesive animation between stashed/unstashed states. + */ +public class TaskbarStashController { + + /** + * How long to stash/unstash when manually invoked via long press. + */ + private static final long TASKBAR_STASH_DURATION = 300; + + /** + * The scale TaskbarView animates to when being stashed. + */ + private static final float STASHED_TASKBAR_SCALE = 0.5f; + + /** + * The SharedPreferences key for whether user has manually stashed the taskbar. + */ + private static final String SHARED_PREFS_STASHED_KEY = "taskbar_is_stashed"; + + /** + * Whether taskbar should be stashed out of the box. + */ + private static final boolean DEFAULT_STASHED_PREF = false; + + private final TaskbarActivityContext mActivity; + private final SharedPreferences mPrefs; + private final int mStashedHeight; + private final int mUnstashedHeight; + + // Initialized in init. + private TaskbarControllers mControllers; + // Taskbar background properties. + private AnimatedFloat mTaskbarBackgroundOffset; + // TaskbarView icon properties. + private AlphaProperty mIconAlphaForStash; + private AnimatedFloat mIconScaleForStash; + private AnimatedFloat mIconTranslationYForStash; + // Stashed handle properties. + private AnimatedFloat mTaskbarStashedHandleAlpha; + + /** Whether the user has manually invoked taskbar stashing, which we persist. */ + private boolean mIsStashedInApp; + /** Whether we are currently visually stashed (might change based on launcher state). */ + private boolean mIsStashed = false; + + private @Nullable AnimatorSet mAnimator; + + public TaskbarStashController(TaskbarActivityContext activity) { + mActivity = activity; + mPrefs = Utilities.getPrefs(mActivity); + final Resources resources = mActivity.getResources(); + mStashedHeight = resources.getDimensionPixelSize(R.dimen.taskbar_stashed_size); + mUnstashedHeight = mActivity.getDeviceProfile().taskbarSize; + } + + public void init(TaskbarControllers controllers) { + mControllers = controllers; + + TaskbarDragLayerController dragLayerController = controllers.taskbarDragLayerController; + mTaskbarBackgroundOffset = dragLayerController.getTaskbarBackgroundOffset(); + + TaskbarViewController taskbarViewController = controllers.taskbarViewController; + mIconAlphaForStash = taskbarViewController.getTaskbarIconAlpha().getProperty( + TaskbarViewController.ALPHA_INDEX_STASH); + mIconScaleForStash = taskbarViewController.getTaskbarIconScaleForStash(); + mIconTranslationYForStash = taskbarViewController.getTaskbarIconTranslationYForStash(); + + StashedHandleViewController stashedHandleController = + controllers.stashedHandleViewController; + mTaskbarStashedHandleAlpha = stashedHandleController.getStashedHandleAlpha(); + + mIsStashedInApp = supportsStashing() + && mPrefs.getBoolean(SHARED_PREFS_STASHED_KEY, DEFAULT_STASHED_PREF); + } + + /** + * Returns whether the user can manually stash the taskbar based on the current device state. + */ + private boolean supportsStashing() { + return !mActivity.isThreeButtonNav(); + } + + /** + * Returns whether the taskbar is currently visually stashed. + */ + public boolean isStashed() { + return mIsStashed; + } + + /** + * Returns whether the user has manually stashed the taskbar in apps. + */ + public boolean isStashedInApp() { + return mIsStashedInApp; + } + + public int getContentHeight() { + return isStashed() ? mStashedHeight : mUnstashedHeight; + } + + public int getStashedHeight() { + return mStashedHeight; + } + + /** + * Should be called when long pressing the nav region when taskbar is present. + * @return Whether taskbar was stashed and now is unstashed. + */ + public boolean onLongPressToUnstashTaskbar() { + if (!isStashed()) { + // We only listen for long press on the nav region to unstash the taskbar. To stash the + // taskbar, we use an OnLongClickListener on TaskbarView instead. + return false; + } + if (updateAndAnimateIsStashedInApp(false)) { + mControllers.taskbarActivityContext.getDragLayer().performHapticFeedback(LONG_PRESS); + return true; + } + return false; + } + + /** + * Updates whether we should stash the taskbar when in apps, and animates to the changed state. + * @return Whether we started an animation to either be newly stashed or unstashed. + */ + public boolean updateAndAnimateIsStashedInApp(boolean isStashedInApp) { + if (!supportsStashing()) { + return false; + } + if (mIsStashedInApp != isStashedInApp) { + boolean wasStashed = mIsStashedInApp; + mIsStashedInApp = isStashedInApp; + mPrefs.edit().putBoolean(SHARED_PREFS_STASHED_KEY, mIsStashedInApp).apply(); + boolean isStashed = mIsStashedInApp; + if (wasStashed != isStashed) { + createAnimToIsStashed(isStashed, TASKBAR_STASH_DURATION).start(); + return true; + } + } + return false; + } + + /** + * Starts an animation to the new stashed state with a default duration. + */ + public void animateToIsStashed(boolean isStashed) { + animateToIsStashed(isStashed, TASKBAR_STASH_DURATION); + } + + /** + * Starts an animation to the new stashed state with the specified duration. + */ + public void animateToIsStashed(boolean isStashed, long duration) { + createAnimToIsStashed(isStashed, duration).start(); + } + + private Animator createAnimToIsStashed(boolean isStashed, long duration) { + AnimatorSet fullLengthAnimatorSet = new AnimatorSet(); + // Not exactly half and may overlap. See [first|second]HalfDurationScale below. + AnimatorSet firstHalfAnimatorSet = new AnimatorSet(); + AnimatorSet secondHalfAnimatorSet = new AnimatorSet(); + + final float firstHalfDurationScale; + final float secondHalfDurationScale; + + if (isStashed) { + firstHalfDurationScale = 0.75f; + secondHalfDurationScale = 0.5f; + final float stashTranslation = (mUnstashedHeight - mStashedHeight) / 2f; + + fullLengthAnimatorSet.playTogether( + mTaskbarBackgroundOffset.animateToValue(1), + mIconTranslationYForStash.animateToValue(stashTranslation) + ); + firstHalfAnimatorSet.playTogether( + mIconAlphaForStash.animateToValue(0), + mIconScaleForStash.animateToValue(STASHED_TASKBAR_SCALE) + ); + secondHalfAnimatorSet.playTogether( + mTaskbarStashedHandleAlpha.animateToValue(1) + ); + } else { + firstHalfDurationScale = 0.5f; + secondHalfDurationScale = 0.75f; + + fullLengthAnimatorSet.playTogether( + mTaskbarBackgroundOffset.animateToValue(0), + mIconScaleForStash.animateToValue(1), + mIconTranslationYForStash.animateToValue(0) + ); + firstHalfAnimatorSet.playTogether( + mTaskbarStashedHandleAlpha.animateToValue(0) + ); + secondHalfAnimatorSet.playTogether( + mIconAlphaForStash.animateToValue(1) + ); + } + + Animator stashedHandleRevealAnim = mControllers.stashedHandleViewController + .createRevealAnimToIsStashed(isStashed); + if (stashedHandleRevealAnim != null) { + fullLengthAnimatorSet.play(stashedHandleRevealAnim); + } + + fullLengthAnimatorSet.setDuration(duration); + firstHalfAnimatorSet.setDuration((long) (duration * firstHalfDurationScale)); + secondHalfAnimatorSet.setDuration((long) (duration * secondHalfDurationScale)); + secondHalfAnimatorSet.setStartDelay((long) (duration * (1 - secondHalfDurationScale))); + + if (mAnimator != null) { + mAnimator.cancel(); + } + mAnimator = new AnimatorSet(); + mAnimator.playTogether(fullLengthAnimatorSet, firstHalfAnimatorSet, + secondHalfAnimatorSet); + mAnimator.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationStart(Animator animation) { + mIsStashed = isStashed; + } + + @Override + public void onAnimationEnd(Animator animation) { + mAnimator = null; + } + }); + return mAnimator; + } +} diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java index 260cedc706..6d0e3c6baf 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java @@ -33,4 +33,8 @@ public class TaskbarUIController { } protected void updateContentInsets(Rect outContentInsets) { } + + protected boolean onLongPressToUnstashTaskbar() { + return false; + } } diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java index 7753f966dc..820d40af27 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java @@ -94,8 +94,10 @@ public class TaskbarView extends FrameLayout implements FolderIcon.FolderIconPar protected void init(TaskbarViewController.TaskbarViewCallbacks callbacks) { mControllerCallbacks = callbacks; - mIconClickListener = mControllerCallbacks.getOnClickListener(); - mIconLongClickListener = mControllerCallbacks.getOnLongClickListener(); + mIconClickListener = mControllerCallbacks.getIconOnClickListener(); + mIconLongClickListener = mControllerCallbacks.getIconOnLongClickListener(); + + setOnLongClickListener(mControllerCallbacks.getBackgroundOnLongClickListener()); } private void removeAndRecycle(View view) { @@ -235,6 +237,10 @@ public class TaskbarView extends FrameLayout implements FolderIcon.FolderIconPar return isShown() && mIconLayoutBounds.contains(xInOurCoordinates, yInOurCoorindates); } + public Rect getIconLayoutBounds() { + return mIconLayoutBounds; + } + // FolderIconParent implemented methods. @Override diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java index c7ac4a4f5b..50c26b30b2 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java @@ -17,8 +17,8 @@ package com.android.launcher3.taskbar; import static com.android.launcher3.LauncherAnimUtils.SCALE_PROPERTY; import static com.android.launcher3.LauncherAnimUtils.VIEW_TRANSLATE_X; -import static com.android.launcher3.LauncherAnimUtils.VIEW_TRANSLATE_Y; import static com.android.launcher3.anim.Interpolators.LINEAR; +import static com.android.quickstep.AnimatedFloat.VALUE; import android.graphics.Rect; import android.view.View; @@ -28,6 +28,7 @@ import com.android.launcher3.anim.AnimatorPlaybackController; import com.android.launcher3.anim.PendingAnimation; import com.android.launcher3.model.data.ItemInfo; import com.android.launcher3.util.MultiValueAlpha; +import com.android.quickstep.AnimatedFloat; /** * Handles properties/data collection, then passes the results to TaskbarView to render. @@ -38,10 +39,16 @@ public class TaskbarViewController { public static final int ALPHA_INDEX_HOME = 0; public static final int ALPHA_INDEX_IME = 1; public static final int ALPHA_INDEX_KEYGUARD = 2; + public static final int ALPHA_INDEX_STASH = 3; private final TaskbarActivityContext mActivity; private final TaskbarView mTaskbarView; private final MultiValueAlpha mTaskbarIconAlpha; + private final AnimatedFloat mTaskbarIconScaleForStash = new AnimatedFloat(this::updateScale); + private final AnimatedFloat mTaskbarIconTranslationYForHome = new AnimatedFloat( + this::updateTranslationY); + private final AnimatedFloat mTaskbarIconTranslationYForStash = new AnimatedFloat( + this::updateTranslationY); // Initialized in init. private TaskbarControllers mControllers; @@ -54,7 +61,7 @@ public class TaskbarViewController { public TaskbarViewController(TaskbarActivityContext activity, TaskbarView taskbarView) { mActivity = activity; mTaskbarView = taskbarView; - mTaskbarIconAlpha = new MultiValueAlpha(mTaskbarView, 3); + mTaskbarIconAlpha = new MultiValueAlpha(mTaskbarView, 4); mTaskbarIconAlpha.setUpdateVisibility(true); } @@ -62,6 +69,8 @@ public class TaskbarViewController { mControllers = controllers; mTaskbarView.init(new TaskbarViewCallbacks()); mTaskbarView.getLayoutParams().height = mActivity.getDeviceProfile().taskbarSize; + + mTaskbarIconScaleForStash.updateValue(1f); } public boolean areIconsVisible() { @@ -86,6 +95,32 @@ public class TaskbarViewController { mTaskbarView.setClickAndLongClickListenersForIcon(icon); } + public Rect getIconLayoutBounds() { + return mTaskbarView.getIconLayoutBounds(); + } + + public AnimatedFloat getTaskbarIconScaleForStash() { + return mTaskbarIconScaleForStash; + } + + public AnimatedFloat getTaskbarIconTranslationYForStash() { + return mTaskbarIconTranslationYForStash; + } + + /** + * Applies scale properties for the entire TaskbarView (rather than individual icons). + */ + private void updateScale() { + float scale = mTaskbarIconScaleForStash.value; + mTaskbarView.setScaleX(scale); + mTaskbarView.setScaleY(scale); + } + + private void updateTranslationY() { + mTaskbarView.setTranslationY(mTaskbarIconTranslationYForHome.value + + mTaskbarIconTranslationYForStash.value); + } + /** * Sets the taskbar icon alignment relative to Launcher hotseat icons * @param alignmentRatio [0, 1] @@ -116,7 +151,7 @@ public class TaskbarViewController { / launcherDp.numShownHotseatIcons; int offsetY = launcherDp.getTaskbarOffsetY(); - setter.setFloat(mTaskbarView, VIEW_TRANSLATE_Y, -offsetY, LINEAR); + setter.setFloat(mTaskbarIconTranslationYForHome, VALUE, -offsetY, LINEAR); int collapsedHeight = mActivity.getDeviceProfile().taskbarSize; int expandedHeight = collapsedHeight + offsetY; @@ -144,12 +179,16 @@ public class TaskbarViewController { * Callbacks for {@link TaskbarView} to interact with its controller. */ public class TaskbarViewCallbacks { - public View.OnClickListener getOnClickListener() { + public View.OnClickListener getIconOnClickListener() { return mActivity::onTaskbarIconClicked; } - public View.OnLongClickListener getOnLongClickListener() { + public View.OnLongClickListener getIconOnLongClickListener() { return mControllers.taskbarDragController::startDragOnLongClick; } + + public View.OnLongClickListener getBackgroundOnLongClickListener() { + return view -> mControllers.taskbarStashController.updateAndAnimateIsStashedInApp(true); + } } } diff --git a/quickstep/src/com/android/quickstep/AnimatedFloat.java b/quickstep/src/com/android/quickstep/AnimatedFloat.java index f7e8781573..95c871099b 100644 --- a/quickstep/src/com/android/quickstep/AnimatedFloat.java +++ b/quickstep/src/com/android/quickstep/AnimatedFloat.java @@ -53,6 +53,16 @@ public class AnimatedFloat { mUpdateCallback = updateCallback; } + /** + * Returns an animation from the current value to the given value. + */ + public ObjectAnimator animateToValue(float end) { + return animateToValue(value, end); + } + + /** + * Returns an animation from the given start value to the given end value. + */ public ObjectAnimator animateToValue(float start, float end) { cancelAnimation(); mValueAnimator = ObjectAnimator.ofFloat(this, VALUE, start, end); diff --git a/quickstep/src/com/android/quickstep/BaseActivityInterface.java b/quickstep/src/com/android/quickstep/BaseActivityInterface.java index 2699b0795b..1412b1add6 100644 --- a/quickstep/src/com/android/quickstep/BaseActivityInterface.java +++ b/quickstep/src/com/android/quickstep/BaseActivityInterface.java @@ -363,6 +363,14 @@ public abstract class BaseActivityInterface TYPE_NO_OP; diff --git a/quickstep/src/com/android/quickstep/LauncherActivityInterface.java b/quickstep/src/com/android/quickstep/LauncherActivityInterface.java index 799a4c2516..09474a1ac2 100644 --- a/quickstep/src/com/android/quickstep/LauncherActivityInterface.java +++ b/quickstep/src/com/android/quickstep/LauncherActivityInterface.java @@ -302,6 +302,15 @@ public final class LauncherActivityInterface extends } } + @Override + public boolean onLongPressToUnstashTaskbar() { + LauncherTaskbarUIController taskbarController = getTaskbarController(); + if (taskbarController == null) { + return super.onLongPressToUnstashTaskbar(); + } + return taskbarController.onLongPressToUnstashTaskbar(); + } + @Override protected int getOverviewScrimColorForState(BaseQuickstepLauncher launcher, LauncherState state) { diff --git a/quickstep/src/com/android/quickstep/RecentsAnimationController.java b/quickstep/src/com/android/quickstep/RecentsAnimationController.java index 0ebe13be8d..9e69ef9b52 100644 --- a/quickstep/src/com/android/quickstep/RecentsAnimationController.java +++ b/quickstep/src/com/android/quickstep/RecentsAnimationController.java @@ -46,6 +46,8 @@ public class RecentsAnimationController { private boolean mUseLauncherSysBarFlags = false; private boolean mSplitScreenMinimized = false; private boolean mFinishRequested = false; + // Only valid when mFinishRequested == true. + private boolean mFinishTargetIsLauncher; private RunnableList mPendingFinishCallbacks = new RunnableList(); public RecentsAnimationController(RecentsAnimationControllerCompat controller, @@ -145,6 +147,7 @@ public class RecentsAnimationController { // Finish not yet requested mFinishRequested = true; + mFinishTargetIsLauncher = toRecents; mOnFinishedListener.accept(this); mPendingFinishCallbacks.add(callback); UI_HELPER_EXECUTOR.execute(() -> { @@ -201,4 +204,12 @@ public class RecentsAnimationController { public RecentsAnimationControllerCompat getController() { return mController; } + + /** + * RecentsAnimationListeners can check this in onRecentsAnimationFinished() to determine whether + * the animation was finished to launcher vs an app. + */ + public boolean getFinishTargetIsLauncher() { + return mFinishTargetIsLauncher; + } } diff --git a/quickstep/src/com/android/quickstep/TouchInteractionService.java b/quickstep/src/com/android/quickstep/TouchInteractionService.java index 47ca3d2024..5d701d4e14 100644 --- a/quickstep/src/com/android/quickstep/TouchInteractionService.java +++ b/quickstep/src/com/android/quickstep/TouchInteractionService.java @@ -95,6 +95,7 @@ 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.inputconsumers.TaskbarStashInputConsumer; import com.android.quickstep.util.ActiveGestureLog; import com.android.quickstep.util.AssistantUtilities; import com.android.quickstep.util.ProtoTracer; @@ -673,6 +674,14 @@ public class TouchInteractionService extends Service implements PluginListener Date: Mon, 21 Jun 2021 10:41:41 +0000 Subject: [PATCH 5/9] Fix bug in equals implementation for search headers Fix: 191626327 Test: verified locally Change-Id: I8103059a2759a8533581ff86cb57b28913cf5731 --- .../launcher3/widget/model/WidgetsListSearchHeaderEntry.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/com/android/launcher3/widget/model/WidgetsListSearchHeaderEntry.java b/src/com/android/launcher3/widget/model/WidgetsListSearchHeaderEntry.java index c0f89bcbcc..055e4ecbe6 100644 --- a/src/com/android/launcher3/widget/model/WidgetsListSearchHeaderEntry.java +++ b/src/com/android/launcher3/widget/model/WidgetsListSearchHeaderEntry.java @@ -60,7 +60,7 @@ public final class WidgetsListSearchHeaderEntry extends WidgetsListBaseEntry WidgetsListSearchHeaderEntry otherEntry = (WidgetsListSearchHeaderEntry) obj; return mWidgets.equals(otherEntry.mWidgets) && mPkgItem.equals(otherEntry.mPkgItem) && mTitleSectionName.equals(otherEntry.mTitleSectionName) - && mIsWidgetListShown; + && mIsWidgetListShown == otherEntry.mIsWidgetListShown; } /** Returns a copy of this {@link WidgetsListSearchHeaderEntry} with the widget list shown. */ From 7b27e7d0613c5bd23a33b0368c06db2252b796eb Mon Sep 17 00:00:00 2001 From: Steven Ng Date: Mon, 21 Jun 2021 15:36:57 +0100 Subject: [PATCH 6/9] Copy minSpanX & minSpanY when copying from an existing ItemInfo Test: Drop Gmail widget to home screen and configure it. Then, drop the widget to a home screen that doesn't have sufficient space to accommodate it. The gmail widget can't be dropped to that home page and is returned to its original position. Fix: 190582606 Change-Id: I177c09562d059b658e835cbb7fdde0d7bc6565d2 --- src/com/android/launcher3/model/data/ItemInfo.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/com/android/launcher3/model/data/ItemInfo.java b/src/com/android/launcher3/model/data/ItemInfo.java index 3abcc2b826..7091d2b143 100644 --- a/src/com/android/launcher3/model/data/ItemInfo.java +++ b/src/com/android/launcher3/model/data/ItemInfo.java @@ -168,6 +168,8 @@ public class ItemInfo { cellY = info.cellY; spanX = info.spanX; spanY = info.spanY; + minSpanX = info.minSpanX; + minSpanY = info.minSpanY; rank = info.rank; screenId = info.screenId; itemType = info.itemType; From ded80076dbff226a3890d367ddbcb14417bcad9a Mon Sep 17 00:00:00 2001 From: Stevie Kideckel Date: Mon, 21 Jun 2021 14:47:04 +0000 Subject: [PATCH 7/9] Add spacing between items as decorations instead of margins There are bugs in the accounting for the margins if we manipulate the view directly, causing the wrong top to be reported and the view to be shifted when we call scrollToPosition. Item decorations ensure that the layout system for the recycler view always has the right details about the spacing. Fix: 191642682 Test: verified locally Change-Id: Ie80563757079e885c8178883ab16e314d01c5b32 --- res/layout/widgets_list_row_header.xml | 1 - res/layout/widgets_table_container.xml | 3 +-- res/values/dimens.xml | 2 +- res/values/id.xml | 1 + .../widget/picker/WidgetsListAdapter.java | 24 ++++++++++++++++++- .../widget/picker/WidgetsListHeader.java | 11 --------- .../widget/picker/WidgetsRecyclerView.java | 16 ++++++------- 7 files changed, 34 insertions(+), 24 deletions(-) diff --git a/res/layout/widgets_list_row_header.xml b/res/layout/widgets_list_row_header.xml index 0bfa2b2a5e..3eaa7ea627 100644 --- a/res/layout/widgets_list_row_header.xml +++ b/res/layout/widgets_list_row_header.xml @@ -20,7 +20,6 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginHorizontal="16dp" - android:layout_marginBottom="@dimen/widget_list_entry_bottom_margin" android:paddingVertical="@dimen/widget_list_header_view_vertical_padding" android:orientation="horizontal" launcher:appIconSize="48dp"> diff --git a/res/layout/widgets_table_container.xml b/res/layout/widgets_table_container.xml index 4f70a05374..fac21fdcf0 100644 --- a/res/layout/widgets_table_container.xml +++ b/res/layout/widgets_table_container.xml @@ -18,5 +18,4 @@ android:id="@+id/widgets_table" android:layout_width="match_parent" android:layout_height="wrap_content" - android:layout_marginHorizontal="16dp" - android:layout_marginBottom="@dimen/widget_list_entry_bottom_margin"/> + android:layout_marginHorizontal="16dp"/> diff --git a/res/values/dimens.xml b/res/values/dimens.xml index 251f04a66e..416179e402 100644 --- a/res/values/dimens.xml +++ b/res/values/dimens.xml @@ -147,7 +147,7 @@ 4dp 20dp - 2dp + 2dp 0.5dp 1dp diff --git a/res/values/id.xml b/res/values/id.xml index 1bd40cec4a..1709c5961e 100644 --- a/res/values/id.xml +++ b/res/values/id.xml @@ -16,6 +16,7 @@ --> + diff --git a/src/com/android/launcher3/widget/picker/WidgetsListAdapter.java b/src/com/android/launcher3/widget/picker/WidgetsListAdapter.java index 5d9adf0e71..b668c90031 100644 --- a/src/com/android/launcher3/widget/picker/WidgetsListAdapter.java +++ b/src/com/android/launcher3/widget/picker/WidgetsListAdapter.java @@ -18,6 +18,7 @@ package com.android.launcher3.widget.picker; import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_WIDGETSTRAY_APP_EXPANDED; import android.content.Context; +import android.graphics.Rect; import android.os.Process; import android.util.Log; import android.util.Size; @@ -34,6 +35,7 @@ import androidx.annotation.Nullable; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; import androidx.recyclerview.widget.RecyclerView.Adapter; +import androidx.recyclerview.widget.RecyclerView.LayoutParams; import androidx.recyclerview.widget.RecyclerView.ViewHolder; import com.android.launcher3.BaseActivity; @@ -107,7 +109,8 @@ public class WidgetsListAdapter extends Adapter implements OnHeaderC @Nullable private Predicate mFilter = null; @Nullable private RecyclerView mRecyclerView; @Nullable private PackageUserKey mPendingClickHeader; - private int mShortcutPreviewPadding; + private final int mShortcutPreviewPadding; + private final int mSpacingBetweenEntries; private final WidgetPreviewLoadedCallback mPreviewLoadedCallback = ignored -> updateVisibleEntries(); @@ -141,11 +144,28 @@ public class WidgetsListAdapter extends Adapter implements OnHeaderC mShortcutPreviewPadding = 2 * context.getResources() .getDimensionPixelSize(R.dimen.widget_preview_shortcut_padding); + mSpacingBetweenEntries = + context.getResources().getDimensionPixelSize(R.dimen.widget_list_entry_spacing); } @Override public void onAttachedToRecyclerView(@NonNull RecyclerView recyclerView) { mRecyclerView = recyclerView; + + mRecyclerView.addItemDecoration(new RecyclerView.ItemDecoration() { + @Override + public void getItemOffsets( + @NonNull Rect outRect, + @NonNull View view, + @NonNull RecyclerView parent, + @NonNull RecyclerView.State state) { + super.getItemOffsets(outRect, view, parent, state); + int position = ((LayoutParams) view.getLayoutParams()).getViewLayoutPosition(); + boolean isHeader = + view.getTag(R.id.tag_widget_entry) instanceof WidgetsListBaseEntry.Header; + outRect.top += position > 0 && isHeader ? mSpacingBetweenEntries : 0; + } + }); } @Override @@ -329,7 +349,9 @@ public class WidgetsListAdapter extends Adapter implements OnHeaderC @Override public void onBindViewHolder(ViewHolder holder, int pos) { ViewHolderBinder viewHolderBinder = mViewHolderBinders.get(getItemViewType(pos)); + WidgetsListBaseEntry entry = mVisibleEntries.get(pos); viewHolderBinder.bindViewHolder(holder, mVisibleEntries.get(pos), pos); + holder.itemView.setTag(R.id.tag_widget_entry, entry); } @Override diff --git a/src/com/android/launcher3/widget/picker/WidgetsListHeader.java b/src/com/android/launcher3/widget/picker/WidgetsListHeader.java index cdab964279..ef2adbb809 100644 --- a/src/com/android/launcher3/widget/picker/WidgetsListHeader.java +++ b/src/com/android/launcher3/widget/picker/WidgetsListHeader.java @@ -30,7 +30,6 @@ import android.widget.TextView; import androidx.annotation.Nullable; import androidx.annotation.UiThread; -import androidx.recyclerview.widget.RecyclerView; import com.android.launcher3.DeviceProfile; import com.android.launcher3.LauncherAppState; @@ -59,7 +58,6 @@ public final class WidgetsListHeader extends LinearLayout implements ItemInfoUpd @Nullable private HandlerRunnable mIconLoadRequest; @Nullable private Drawable mIconDrawable; private final int mIconSize; - private final int mBottomMarginSize; private ImageView mAppIcon; private TextView mTitle; @@ -86,8 +84,6 @@ public final class WidgetsListHeader extends LinearLayout implements ItemInfoUpd R.styleable.WidgetsListRowHeader, defStyleAttr, /* defStyleRes= */ 0); mIconSize = a.getDimensionPixelSize(R.styleable.WidgetsListRowHeader_appIconSize, grid.iconSizePx); - mBottomMarginSize = - getResources().getDimensionPixelSize(R.dimen.widget_list_entry_bottom_margin); } @Override @@ -146,13 +142,6 @@ public final class WidgetsListHeader extends LinearLayout implements ItemInfoUpd public void setExpanded(boolean isExpanded) { this.mIsExpanded = isExpanded; mExpandToggle.setChecked(isExpanded); - if (getLayoutParams() instanceof RecyclerView.LayoutParams) { - int bottomMargin = isExpanded ? 0 : mBottomMarginSize; - RecyclerView.LayoutParams layoutParams = - ((RecyclerView.LayoutParams) getLayoutParams()); - layoutParams.bottomMargin = bottomMargin; - setLayoutParams(layoutParams); - } } /** Sets the {@link WidgetsListDrawableState} and refreshes the background drawable. */ diff --git a/src/com/android/launcher3/widget/picker/WidgetsRecyclerView.java b/src/com/android/launcher3/widget/picker/WidgetsRecyclerView.java index 3ee8b33b53..7671841878 100644 --- a/src/com/android/launcher3/widget/picker/WidgetsRecyclerView.java +++ b/src/com/android/launcher3/widget/picker/WidgetsRecyclerView.java @@ -52,7 +52,7 @@ public class WidgetsRecyclerView extends BaseRecyclerView implements OnItemTouch private HeaderViewDimensionsProvider mHeaderViewDimensionsProvider; private int mLastVisibleWidgetContentTableHeight = 0; private int mWidgetHeaderHeight = 0; - private final int mCollapsedHeaderBottomMarginSize; + private final int mSpacingBetweenEntries; @Nullable private OnContentChangeListener mOnContentChangeListener; public WidgetsRecyclerView(Context context) { @@ -72,9 +72,9 @@ public class WidgetsRecyclerView extends BaseRecyclerView implements OnItemTouch ActivityContext activity = ActivityContext.lookupContext(getContext()); DeviceProfile grid = activity.getDeviceProfile(); - // The bottom margin used when the header is not expanded. - mCollapsedHeaderBottomMarginSize = - getResources().getDimensionPixelSize(R.dimen.widget_list_entry_bottom_margin); + // The spacing used between entries. + mSpacingBetweenEntries = + getResources().getDimensionPixelSize(R.dimen.widget_list_entry_spacing); } @Override @@ -270,16 +270,16 @@ public class WidgetsRecyclerView extends BaseRecyclerView implements OnItemTouch if (untilIndex > mAdapter.getItems().size()) { untilIndex = mAdapter.getItems().size(); } - int expandedHeaderPosition = mAdapter.getSelectedHeaderPosition().orElse(-1); int totalItemsHeight = 0; for (int i = 0; i < untilIndex; i++) { WidgetsListBaseEntry entry = mAdapter.getItems().get(i); if (entry instanceof WidgetsListHeaderEntry || entry instanceof WidgetsListSearchHeaderEntry) { totalItemsHeight += mWidgetHeaderHeight; - if (expandedHeaderPosition != i) { - // If the header is collapsed, include the bottom margin it will use. - totalItemsHeight += mCollapsedHeaderBottomMarginSize; + if (i > 0) { + // Each header contains the spacing between entries as top decoration, except + // the first one. + totalItemsHeight += mSpacingBetweenEntries; } } else if (entry instanceof WidgetsListContentEntry) { totalItemsHeight += mLastVisibleWidgetContentTableHeight; From 9c10d08e1e20b5b3e004bd94e7e5c371bf086c7f Mon Sep 17 00:00:00 2001 From: Tony Wickham Date: Mon, 21 Jun 2021 12:41:36 -0700 Subject: [PATCH 8/9] Ensure mConsumer isn't set to null in reset(). mResetGestureInputConsumer is not initialized until onUserUnlocked(), meaning it might still be null in reset(). Use NO_OP input consumer in that case. Test: none Bug: 191669813 Change-Id: Ib9edde50fba0b6164390ec2b5c877d3db74ddfeb --- .../com/android/quickstep/TouchInteractionService.java | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/quickstep/src/com/android/quickstep/TouchInteractionService.java b/quickstep/src/com/android/quickstep/TouchInteractionService.java index 7956fcc562..7cb6800146 100644 --- a/quickstep/src/com/android/quickstep/TouchInteractionService.java +++ b/quickstep/src/com/android/quickstep/TouchInteractionService.java @@ -807,7 +807,13 @@ public class TouchInteractionService extends Service implements PluginListener Date: Fri, 18 Jun 2021 17:10:59 -0700 Subject: [PATCH 9/9] Fixing animation end not-called when cancelling state the animation recursively Bug: 190856140 Test: Manual Change-Id: I5d6a00c1d1c0e95e615b7f2115e3e4ebb56b987f --- .../android/quickstep/views/RecentsView.java | 2 +- .../anim/AnimatorPlaybackController.java | 13 +++++++-- .../launcher3/statemanager/StateManager.java | 28 +++++++++++-------- 3 files changed, 28 insertions(+), 15 deletions(-) diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java index df7f8b5a2a..8c3e5b513b 100644 --- a/quickstep/src/com/android/quickstep/views/RecentsView.java +++ b/quickstep/src/com/android/quickstep/views/RecentsView.java @@ -2245,7 +2245,7 @@ public abstract class RecentsView> { // Cancel the current animation. This will reset mState to mCurrentStableState, so store it. STATE_TYPE fromState = mState; - mConfig.reset(); + cancelAnimation(); if (!animated) { mAtomicAnimationFactory.cancelAllStateElementAnimation(); @@ -303,7 +303,7 @@ public class StateManager> { public AnimatorPlaybackController createAnimationToNewWorkspace(STATE_TYPE state, StateAnimationConfig config) { config.userControlled = true; - mConfig.reset(); + cancelAnimation(); config.copyTo(mConfig); mConfig.playbackController = createAnimationToNewWorkspaceInternal(state) .createPlaybackController(); @@ -393,6 +393,11 @@ public class StateManager> { */ public void cancelAnimation() { mConfig.reset(); + // It could happen that a new animation is set as a result of an endListener on the + // existing animation. + while (mConfig.currentAnimation != null || mConfig.playbackController != null) { + mConfig.reset(); + } } public void setCurrentUserControlledAnimation(AnimatorPlaybackController controller) { @@ -508,14 +513,19 @@ public class StateManager> { * Cancels the current animation and resets config variables. */ public void reset() { + AnimatorSet anim = currentAnimation; + AnimatorPlaybackController pc = playbackController; + DEFAULT.copyTo(this); targetState = null; + currentAnimation = null; + playbackController = null; + changeId++; - if (playbackController != null) { - playbackController.getAnimationPlayer().cancel(); - playbackController.dispatchOnCancel(); - } else if (currentAnimation != null) { - AnimatorSet anim = currentAnimation; + if (pc != null) { + pc.getAnimationPlayer().cancel(); + pc.dispatchOnCancel().dispatchOnEnd(); + } else if (anim != null) { anim.setDuration(0); if (!anim.isStarted()) { // If the animation is not started the listeners do not get notified, @@ -525,10 +535,6 @@ public class StateManager> { } anim.cancel(); } - - currentAnimation = null; - playbackController = null; - changeId++; } @Override