Fix flickering issues with divider during split animation

This CL makes changes to the "split divider placeholder view", which was intended to cover up the backdrop a little during the split confirm animation. The placeholder view is now larger (fullscreen) and fades in with the animation movement, so there is no longer a period of time when it looks like an awkward rectangle.

New timings and interpolators confirmed with UX. Also renamed some variables and added comments for clarity.

Fixes: 344573331
Test: Manually verified that the visual bug no longer happens on large and small screen, and from desktop and Overview.
Flag: EXEMPT bugfix
Change-Id: I3b37f2b0478035d7a3181ae7c23962fe75a13b2c
This commit is contained in:
Jeremy Sim
2024-06-13 12:41:39 -07:00
parent 6e02de9c2b
commit 91fb2f2e5e
6 changed files with 46 additions and 49 deletions

View File

@@ -27,6 +27,8 @@ public class PhoneSplitToConfirmTimings
public int getPlaceholderIconFadeInEnd() { return 133; }
public int getStagedRectSlideStart() { return 0; }
public int getStagedRectSlideEnd() { return 333; }
public int getBackingScrimFadeInStart() { return 0; }
public int getBackingScrimFadeInEnd() { return 266; }
public int getDuration() { return PHONE_CONFIRM_DURATION; }
}

View File

@@ -281,64 +281,45 @@ class SplitAnimationController(val splitSelectStateController: SplitSelectStateC
}
/**
* Creates and returns a view to fade in at .4 animation progress and adds it to the provided
* [pendingAnimation]. Assumes that animation will be the final split placeholder launch anim.
*
* [secondPlaceholderEndingBounds] refers to the second placeholder view that gets added on
* screen, not the logical second app. For landscape it's the left app and for portrait the top
* one.
* Creates and returns a fullscreen scrim to fade in behind the split confirm animation, and
* adds it to the provided [pendingAnimation].
*/
fun addDividerPlaceholderViewToAnim(
fun addScrimBehindAnim(
pendingAnimation: PendingAnimation,
container: RecentsViewContainer,
secondPlaceholderEndingBounds: Rect,
context: Context
): View {
val mSplitDividerPlaceholderView = View(context)
val scrim = View(context)
val recentsView = container.getOverviewPanel<RecentsView<*, *>>()
val dp: com.android.launcher3.DeviceProfile = container.getDeviceProfile()
val dp: DeviceProfile = container.getDeviceProfile()
// Add it before/under the most recently added first floating taskView
val firstAddedSplitViewIndex: Int =
container
.getDragLayer()
.indexOfChild(recentsView.splitSelectController.firstFloatingTaskView)
container.getDragLayer().addView(mSplitDividerPlaceholderView, firstAddedSplitViewIndex)
val lp = mSplitDividerPlaceholderView.layoutParams as InsettableFrameLayout.LayoutParams
container.getDragLayer().addView(scrim, firstAddedSplitViewIndex)
// Make the scrim fullscreen
val lp = scrim.layoutParams as InsettableFrameLayout.LayoutParams
lp.topMargin = 0
lp.height = dp.heightPx
lp.width = dp.widthPx
if (dp.isLeftRightSplit) {
lp.height = secondPlaceholderEndingBounds.height()
lp.width =
container
.asContext()
.resources
.getDimensionPixelSize(R.dimen.split_divider_handle_region_height)
mSplitDividerPlaceholderView.translationX =
secondPlaceholderEndingBounds.right - lp.width / 2f
mSplitDividerPlaceholderView.translationY = 0f
} else {
lp.height =
container
.asContext()
.resources
.getDimensionPixelSize(R.dimen.split_divider_handle_region_height)
lp.width = secondPlaceholderEndingBounds.width()
mSplitDividerPlaceholderView.translationY =
secondPlaceholderEndingBounds.top - lp.height / 2f
mSplitDividerPlaceholderView.translationX = 0f
}
mSplitDividerPlaceholderView.alpha = 0f
mSplitDividerPlaceholderView.setBackgroundColor(
scrim.alpha = 0f
scrim.setBackgroundColor(
container.asContext().resources.getColor(R.color.taskbar_background_dark)
)
val timings = AnimUtils.getDeviceSplitToConfirmTimings(dp.isTablet)
val timings = AnimUtils.getDeviceSplitToConfirmTimings(dp.isTablet) as SplitToConfirmTimings
pendingAnimation.setViewAlpha(
mSplitDividerPlaceholderView,
scrim,
1f,
Interpolators.clampToProgress(timings.stagedRectScaleXInterpolator, 0.4f, 1f)
Interpolators.clampToProgress(
timings.backingScrimFadeInterpolator,
timings.backingScrimFadeInStartOffset,
timings.backingScrimFadeInEndOffset
)
)
return mSplitDividerPlaceholderView
return scrim
}
/** Does not play any animation if user is not currently in split selection state. */

View File

@@ -17,6 +17,7 @@
package com.android.quickstep.util;
import static com.android.app.animation.Interpolators.EMPHASIZED;
import static com.android.app.animation.Interpolators.LINEAR;
import android.view.animation.Interpolator;
@@ -31,6 +32,8 @@ abstract class SplitToConfirmTimings implements SplitAnimationTimings {
abstract public int getPlaceholderIconFadeInEnd();
abstract public int getStagedRectSlideStart();
abstract public int getStagedRectSlideEnd();
abstract public int getBackingScrimFadeInStart();
abstract public int getBackingScrimFadeInEnd();
// Common timings
public int getInstructionsFadeStart() { return 0; }
@@ -39,6 +42,7 @@ abstract class SplitToConfirmTimings implements SplitAnimationTimings {
public Interpolator getStagedRectYInterpolator() { return EMPHASIZED; }
public Interpolator getStagedRectScaleXInterpolator() { return EMPHASIZED; }
public Interpolator getStagedRectScaleYInterpolator() { return EMPHASIZED; }
public Interpolator getBackingScrimFadeInterpolator() { return LINEAR; }
abstract public int getDuration();
@@ -48,4 +52,10 @@ abstract class SplitToConfirmTimings implements SplitAnimationTimings {
public float getInstructionsFadeEndOffset() {
return (float) getInstructionsFadeEnd() / getDuration();
}
public float getBackingScrimFadeInStartOffset() {
return (float) getBackingScrimFadeInStart() / getDuration();
}
public float getBackingScrimFadeInEndOffset() {
return (float) getBackingScrimFadeInEnd() / getDuration();
}
}

View File

@@ -163,9 +163,8 @@ public class SplitToWorkspaceController {
new RectF(firstTaskStartingBounds), firstTaskEndingBounds,
false /* fadeWithThumbnail */, true /* isStagedTask */);
View mSplitDividerPlaceholderView = recentsView.getSplitSelectController()
.getSplitAnimationController().addDividerPlaceholderViewToAnim(pendingAnimation,
mLauncher, secondTaskEndingBounds, view.getContext());
View backingScrim = recentsView.getSplitSelectController().getSplitAnimationController()
.addScrimBehindAnim(pendingAnimation, mLauncher, view.getContext());
FloatingTaskView secondFloatingTaskView = FloatingTaskView.getFloatingTaskView(mLauncher,
view, bitmap, icon, secondTaskStartingBounds);
@@ -197,7 +196,7 @@ public class SplitToWorkspaceController {
private void cleanUp() {
mLauncher.getDragLayer().removeView(firstFloatingTaskView);
mLauncher.getDragLayer().removeView(secondFloatingTaskView);
mLauncher.getDragLayer().removeView(mSplitDividerPlaceholderView);
mLauncher.getDragLayer().removeView(backingScrim);
mController.getSplitAnimationController().removeSplitInstructionsView(mLauncher);
mController.resetState();
}

View File

@@ -27,6 +27,8 @@ public class TabletSplitToConfirmTimings
public int getPlaceholderIconFadeInEnd() { return 250; }
public int getStagedRectSlideStart() { return 0; }
public int getStagedRectSlideEnd() { return 500; }
public int getBackingScrimFadeInStart() { return 0; }
public int getBackingScrimFadeInEnd() { return 400; }
public int getDuration() { return TABLET_CONFIRM_DURATION; }
}

View File

@@ -738,7 +738,11 @@ public abstract class RecentsView<CONTAINER_TYPE extends Context & RecentsViewCo
private int mSplitHiddenTaskViewIndex = -1;
@Nullable
private FloatingTaskView mSecondFloatingTaskView;
private View mSplitDividerPlaceholderView;
/**
* A fullscreen scrim that goes behind the splitscreen animation to hide color conflicts and
* possible flickers. Removed after tasks + divider finish animating in.
*/
private View mSplitScrim;
/**
* The task to be removed and immediately re-added. Should not be added to task pool.
@@ -4926,9 +4930,8 @@ public abstract class RecentsView<CONTAINER_TYPE extends Context & RecentsViewCo
mSplitSelectStateController.getActiveSplitStagePosition(), firstTaskEndingBounds,
secondTaskEndingBounds);
mSplitDividerPlaceholderView = mSplitSelectStateController
.getSplitAnimationController().addDividerPlaceholderViewToAnim(pendingAnimation,
mContainer, secondTaskEndingBounds, getContext());
mSplitScrim = mSplitSelectStateController.getSplitAnimationController()
.addScrimBehindAnim(pendingAnimation, mContainer, getContext());
FloatingTaskView firstFloatingTaskView =
mSplitSelectStateController.getFirstFloatingTaskView();
firstFloatingTaskView.getBoundsOnScreen(firstTaskStartingBounds);
@@ -4983,7 +4986,7 @@ public abstract class RecentsView<CONTAINER_TYPE extends Context & RecentsViewCo
safeRemoveDragLayerView(mSplitSelectStateController.getFirstFloatingTaskView());
safeRemoveDragLayerView(mSecondFloatingTaskView);
safeRemoveDragLayerView(mSplitSelectStateController.getSplitInstructionsView());
safeRemoveDragLayerView(mSplitDividerPlaceholderView);
safeRemoveDragLayerView(mSplitScrim);
mSecondFloatingTaskView = null;
mSplitSelectSource = null;
mSplitSelectStateController.getSplitAnimationController()