diff --git a/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java b/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java index 4c96fbae9d..da10bfb0fa 100644 --- a/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java +++ b/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java @@ -23,6 +23,7 @@ import android.animation.AnimatorListenerAdapter; import android.animation.ObjectAnimator; import android.graphics.Rect; import android.view.MotionEvent; +import android.view.View; import androidx.annotation.NonNull; @@ -241,7 +242,11 @@ public class LauncherTaskbarUIController extends TaskbarUIController { return mContext.getDragController().isDragging(); } - void setTaskbarViewVisible(boolean isVisible) { + public View getRootView() { + return mTaskbarDragLayer; + } + + private void setTaskbarViewVisible(boolean isVisible) { mIconAlphaForHome.setValue(isVisible ? 1 : 0); mLauncher.getHotseat().setIconsAlpha(isVisible ? 0f : 1f); } diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java index ec0355b133..a90f17d227 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java @@ -36,6 +36,7 @@ import android.view.ContextThemeWrapper; import android.view.Display; import android.view.Gravity; import android.view.LayoutInflater; +import android.view.RoundedCorner; import android.view.View; import android.view.WindowManager; import android.widget.FrameLayout; @@ -83,6 +84,7 @@ public class TaskbarActivityContext extends ContextThemeWrapper implements Activ private final TaskbarControllers mControllers; private final WindowManager mWindowManager; + private final RoundedCorner mLeftCorner, mRightCorner; private WindowManager.LayoutParams mWindowLayoutParams; private boolean mIsFullscreen; // The size we should return to when we call setTaskbarWindowFullscreen(false) @@ -136,10 +138,12 @@ public class TaskbarActivityContext extends ContextThemeWrapper implements Activ ? windowContext.getApplicationContext() : windowContext.getApplicationContext().createDisplayContext(display); mWindowManager = c.getSystemService(WindowManager.class); + mLeftCorner = display.getRoundedCorner(RoundedCorner.POSITION_BOTTOM_LEFT); + mRightCorner = display.getRoundedCorner(RoundedCorner.POSITION_BOTTOM_RIGHT); } public void init() { - mLastRequestedNonFullscreenHeight = mDeviceProfile.taskbarSize; + mLastRequestedNonFullscreenHeight = getDefaultTaskbarWindowHeight(); mWindowLayoutParams = new WindowManager.LayoutParams( MATCH_PARENT, mLastRequestedNonFullscreenHeight, @@ -169,6 +173,14 @@ public class TaskbarActivityContext extends ContextThemeWrapper implements Activ return mNavMode == Mode.THREE_BUTTONS; } + public RoundedCorner getLeftCorner() { + return mLeftCorner; + } + + public RoundedCorner getRightCorner() { + return mRightCorner; + } + @Override public LayoutInflater getLayoutInflater() { return mLayoutInflater; @@ -250,8 +262,12 @@ public class TaskbarActivityContext extends ContextThemeWrapper implements Activ setTaskbarWindowHeight(fullscreen ? MATCH_PARENT : mLastRequestedNonFullscreenHeight); } + public boolean isTaskbarWindowFullscreen() { + return mIsFullscreen; + } + /** - * Updates the TaskbarContainer height (pass deviceProfile.taskbarSize to reset). + * Updates the TaskbarContainer height (pass {@link #getDefaultTaskbarWindowHeight()} to reset). */ public void setTaskbarWindowHeight(int height) { if (mWindowLayoutParams.height == height || mIsDestroyed) { @@ -271,6 +287,14 @@ public class TaskbarActivityContext extends ContextThemeWrapper implements Activ mWindowManager.updateViewLayout(mDragLayer, mWindowLayoutParams); } + /** + * Returns the default height of the window, including the static corner radii above taskbar. + */ + public int getDefaultTaskbarWindowHeight() { + return mDeviceProfile.taskbarSize + + Math.max(mLeftCorner.getRadius(), mRightCorner.getRadius()); + } + protected void onTaskbarIconClicked(View view) { Object tag = view.getTag(); if (tag instanceof Task) { diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayer.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayer.java index cd1baf726d..0848c35bf2 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayer.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayer.java @@ -18,6 +18,7 @@ package com.android.launcher3.taskbar; import android.content.Context; import android.graphics.Canvas; import android.graphics.Paint; +import android.graphics.Path; import android.util.AttributeSet; import android.view.MotionEvent; import android.view.View; @@ -40,9 +41,12 @@ import com.android.systemui.shared.system.ViewTreeObserverWrapper.OnComputeInset public class TaskbarDragLayer extends BaseDragLayer { private final Paint mTaskbarBackgroundPaint; + private final Path mInvertedLeftCornerPath, mInvertedRightCornerPath; private final OnComputeInsetsListener mTaskbarInsetsComputer = this::onComputeTaskbarInsets; + // Initialized in init. private TaskbarDragLayerController.TaskbarDragLayerCallbacks mControllerCallbacks; + private float mLeftCornerRadius, mRightCornerRadius; private float mTaskbarBackgroundOffset; @@ -65,10 +69,32 @@ public class TaskbarDragLayer extends BaseDragLayer { mTaskbarBackgroundPaint = new Paint(); mTaskbarBackgroundPaint.setColor(getResources().getColor(R.color.taskbar_background)); mTaskbarBackgroundPaint.setAlpha(0); + mTaskbarBackgroundPaint.setFlags(Paint.ANTI_ALIAS_FLAG); + mTaskbarBackgroundPaint.setStyle(Paint.Style.FILL); + + // Will be set in init(), but this ensures they are always non-null. + mInvertedLeftCornerPath = new Path(); + mInvertedRightCornerPath = new Path(); } public void init(TaskbarDragLayerController.TaskbarDragLayerCallbacks callbacks) { mControllerCallbacks = callbacks; + + // Create the paths for the inverted rounded corners above the taskbar. Start with a filled + // square, and then subtracting out a circle from the appropriate corner. + mLeftCornerRadius = mActivity.getLeftCorner().getRadius(); + mRightCornerRadius = mActivity.getRightCorner().getRadius(); + Path square = new Path(); + square.addRect(0, 0, mLeftCornerRadius, mLeftCornerRadius, Path.Direction.CW); + Path circle = new Path(); + circle.addCircle(mLeftCornerRadius, 0, mLeftCornerRadius, Path.Direction.CW); + mInvertedLeftCornerPath.op(square, circle, Path.Op.DIFFERENCE); + square.reset(); + square.addRect(0, 0, mRightCornerRadius, mRightCornerRadius, Path.Direction.CW); + circle.reset(); + circle.addCircle(0, 0, mRightCornerRadius, Path.Direction.CW); + mInvertedRightCornerPath.op(square, circle, Path.Op.DIFFERENCE); + recreateControllers(); } @@ -121,8 +147,20 @@ public class TaskbarDragLayer extends BaseDragLayer { protected void dispatchDraw(Canvas canvas) { float backgroundHeight = mControllerCallbacks.getTaskbarBackgroundHeight() * (1f - mTaskbarBackgroundOffset); - canvas.drawRect(0, canvas.getHeight() - backgroundHeight, canvas.getWidth(), - canvas.getHeight(), mTaskbarBackgroundPaint); + canvas.save(); + canvas.translate(0, canvas.getHeight() - backgroundHeight); + + // Draw the background behind taskbar content. + canvas.drawRect(0, 0, canvas.getWidth(), backgroundHeight, mTaskbarBackgroundPaint); + + // Draw the inverted rounded corners above the taskbar. + canvas.translate(0, -mLeftCornerRadius); + canvas.drawPath(mInvertedLeftCornerPath, mTaskbarBackgroundPaint); + canvas.translate(0, mLeftCornerRadius); + canvas.translate(canvas.getWidth() - mRightCornerRadius, -mRightCornerRadius); + canvas.drawPath(mInvertedRightCornerPath, mTaskbarBackgroundPaint); + + canvas.restore(); super.dispatchDraw(canvas); } diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayerController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayerController.java index 14150b9e25..0afa480667 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayerController.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayerController.java @@ -16,6 +16,7 @@ package com.android.launcher3.taskbar; import static com.android.launcher3.AbstractFloatingView.TYPE_ALL; +import static com.android.systemui.shared.system.ViewTreeObserverWrapper.InsetsInfo.TOUCHABLE_INSETS_CONTENT; import static com.android.systemui.shared.system.ViewTreeObserverWrapper.InsetsInfo.TOUCHABLE_INSETS_FRAME; import static com.android.systemui.shared.system.ViewTreeObserverWrapper.InsetsInfo.TOUCHABLE_INSETS_REGION; @@ -132,13 +133,14 @@ public class TaskbarDragLayerController { // Let touches pass through us. insetsInfo.setTouchableInsets(TOUCHABLE_INSETS_REGION); } else if (mControllers.navbarButtonsViewController.isImeVisible()) { - insetsInfo.setTouchableInsets(TOUCHABLE_INSETS_FRAME); + insetsInfo.setTouchableInsets(TOUCHABLE_INSETS_CONTENT); } else if (!mControllers.uiController.isTaskbarTouchable()) { // Let touches pass through us. insetsInfo.setTouchableInsets(TOUCHABLE_INSETS_REGION); } else if (mControllers.taskbarViewController.areIconsVisible()) { // Buttons are visible, take over the full taskbar area - insetsInfo.setTouchableInsets(TOUCHABLE_INSETS_FRAME); + insetsInfo.setTouchableInsets(mActivity.isTaskbarWindowFullscreen() + ? TOUCHABLE_INSETS_FRAME : TOUCHABLE_INSETS_CONTENT); } else { insetsInfo.setTouchableInsets(TOUCHABLE_INSETS_REGION); } diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java index 6b95f08090..1882762a67 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java @@ -165,8 +165,9 @@ public class TaskbarViewController { int offsetY = launcherDp.getTaskbarOffsetY(); setter.setFloat(mTaskbarIconTranslationYForHome, VALUE, -offsetY, LINEAR); - int collapsedHeight = mActivity.getDeviceProfile().taskbarSize; - int expandedHeight = collapsedHeight + offsetY; + int collapsedHeight = mActivity.getDefaultTaskbarWindowHeight(); + int expandedHeight = Math.max(collapsedHeight, + mActivity.getDeviceProfile().taskbarSize + offsetY); setter.addOnFrameListener(anim -> mActivity.setTaskbarWindowHeight( anim.getAnimatedFraction() > 0 ? expandedHeight : collapsedHeight)); diff --git a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java index c05ffd5c66..fe16b33069 100644 --- a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java +++ b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java @@ -676,8 +676,13 @@ public abstract class AbsSwipeUpHandler, private void onAnimatorPlaybackControllerCreated(AnimatorControllerWithResistance anim) { mLauncherTransitionController = anim; - mLauncherTransitionController.getNormalController().dispatchOnStart(); - updateLauncherTransitionProgress(); + mStateCallback.runOnceAtState(STATE_GESTURE_STARTED, () -> { + // Wait until the gesture is started (touch slop was passed) to start in sync with + // mWindowTransitionController. This ensures we don't hide the taskbar background when + // long pressing to stash it, for instance. + mLauncherTransitionController.getNormalController().dispatchOnStart(); + updateLauncherTransitionProgress(); + }); } public Intent getLaunchIntent() { @@ -913,6 +918,9 @@ public abstract class AbsSwipeUpHandler, // Fast-finish the attaching animation if it's still running. maybeUpdateRecentsAttachedState(false); final GestureEndTarget endTarget = mGestureState.getEndTarget(); + // Wait until the given View (if supplied) draws before resuming the last task. + View postResumeLastTask = mActivityInterface.onSettledOnEndTarget(endTarget); + if (endTarget != NEW_TASK) { InteractionJankMonitorWrapper.cancel( InteractionJankMonitorWrapper.CUJ_QUICK_SWITCH); @@ -921,6 +929,7 @@ public abstract class AbsSwipeUpHandler, InteractionJankMonitorWrapper.cancel( InteractionJankMonitorWrapper.CUJ_APP_CLOSE_TO_HOME); } + switch (endTarget) { case HOME: mStateCallback.setState(STATE_SCALED_CONTROLLER_HOME | STATE_CAPTURE_SCREENSHOT); @@ -935,7 +944,12 @@ public abstract class AbsSwipeUpHandler, mStateCallback.setState(STATE_START_NEW_TASK | STATE_CAPTURE_SCREENSHOT); break; case LAST_TASK: - mStateCallback.setState(STATE_RESUME_LAST_TASK); + if (postResumeLastTask != null) { + ViewUtils.postFrameDrawn(postResumeLastTask, + () -> mStateCallback.setState(STATE_RESUME_LAST_TASK)); + } else { + mStateCallback.setState(STATE_RESUME_LAST_TASK); + } TaskViewUtils.setDividerBarShown(mRecentsAnimationTargets.nonApps, true); break; } diff --git a/quickstep/src/com/android/quickstep/BaseActivityInterface.java b/quickstep/src/com/android/quickstep/BaseActivityInterface.java index 53179f20ba..e781160603 100644 --- a/quickstep/src/com/android/quickstep/BaseActivityInterface.java +++ b/quickstep/src/com/android/quickstep/BaseActivityInterface.java @@ -40,6 +40,7 @@ import android.graphics.Rect; import android.os.Build; import android.view.Gravity; import android.view.MotionEvent; +import android.view.View; import androidx.annotation.Nullable; import androidx.annotation.UiThread; @@ -412,6 +413,15 @@ public abstract class BaseActivityInterface