Merge "PiP: Update menu state AFTER animation is done for show/hide/resize." into sc-dev

This commit is contained in:
Ben Lin
2021-05-12 21:34:48 +00:00
committed by Android (Google) Code Review
7 changed files with 117 additions and 35 deletions

View File

@@ -207,6 +207,24 @@ public class PipAnimationController {
public void onPipAnimationCancel(TaskInfo taskInfo, PipTransitionAnimator animator) {}
}
/**
* A handler class that could register itself to apply the transaction instead of the
* animation controller doing it. For example, the menu controller can be one such handler.
*/
public static class PipTransactionHandler {
/**
* Called when the animation controller is about to apply a transaction. Allow a registered
* handler to apply the transaction instead.
*
* @return true if handled by the handler, false otherwise.
*/
public boolean handlePipTransaction(SurfaceControl leash, SurfaceControl.Transaction tx,
Rect destinationBounds) {
return false;
}
}
/**
* Animator for PiP transition animation which supports both alpha and bounds animation.
* @param <T> Type of property to animate, either alpha (float) or bounds (Rect)
@@ -225,6 +243,7 @@ public class PipAnimationController {
private T mEndValue;
private float mStartingAngle;
private PipAnimationCallback mPipAnimationCallback;
private PipTransactionHandler mPipTransactionHandler;
private PipSurfaceTransactionHelper.SurfaceControlTransactionFactory
mSurfaceControlTransactionFactory;
private PipSurfaceTransactionHelper mSurfaceTransactionHelper;
@@ -293,6 +312,20 @@ public class PipAnimationController {
mPipAnimationCallback = callback;
return this;
}
PipTransitionAnimator<T> setPipTransactionHandler(PipTransactionHandler handler) {
mPipTransactionHandler = handler;
return this;
}
boolean handlePipTransaction(SurfaceControl leash, SurfaceControl.Transaction tx,
Rect destinationBounds) {
if (mPipTransactionHandler != null) {
return mPipTransactionHandler.handlePipTransaction(leash, tx, destinationBounds);
}
return false;
}
@VisibleForTesting
@TransitionDirection public int getTransitionDirection() {
return mTransitionDirection;
@@ -499,7 +532,9 @@ public class PipAnimationController {
getSurfaceTransactionHelper().scaleAndCrop(tx, leash,
initialSourceValue, bounds, insets);
}
tx.apply();
if (!handlePipTransaction(leash, tx, bounds)) {
tx.apply();
}
}
private void applyRotation(SurfaceControl.Transaction tx, SurfaceControl leash,

View File

@@ -200,6 +200,19 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
}
};
private final PipAnimationController.PipTransactionHandler mPipTransactionHandler =
new PipAnimationController.PipTransactionHandler() {
@Override
public boolean handlePipTransaction(SurfaceControl leash,
SurfaceControl.Transaction tx, Rect destinationBounds) {
if (mPipMenuController.isMenuVisible()) {
mPipMenuController.movePipMenu(leash, tx, destinationBounds);
return true;
}
return false;
}
};
private ActivityManager.RunningTaskInfo mTaskInfo;
// To handle the edge case that onTaskInfoChanged callback is received during the entering
// PiP transition, where we do not want to intercept the transition but still want to apply the
@@ -433,8 +446,10 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
// removePipImmediately is expected when the following animation finishes.
ValueAnimator animator = mPipAnimationController
.getAnimator(mTaskInfo, mLeash, mPipBoundsState.getBounds(), 1f, 0f)
.getAnimator(mTaskInfo, mLeash, mPipBoundsState.getBounds(),
1f /* alphaStart */, 0f /* alphaEnd */)
.setTransitionDirection(TRANSITION_DIRECTION_REMOVE_STACK)
.setPipTransactionHandler(mPipTransactionHandler)
.setPipAnimationCallback(mPipAnimationCallback);
animator.setDuration(mExitAnimationDuration);
animator.setInterpolator(Interpolators.ALPHA_OUT);
@@ -573,6 +588,7 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
.getAnimator(mTaskInfo, mLeash, destinationBounds, 0f, 1f)
.setTransitionDirection(TRANSITION_DIRECTION_TO_PIP)
.setPipAnimationCallback(mPipAnimationCallback)
.setPipTransactionHandler(mPipTransactionHandler)
.setDuration(durationMs)
.start();
// mState is set right after the animation is kicked off to block any resize
@@ -749,6 +765,7 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
mPipAnimationController
.getAnimator(mTaskInfo, mLeash, mPipBoundsState.getBounds(), alphaStart, alphaEnd)
.setTransitionDirection(TRANSITION_DIRECTION_SAME)
.setPipTransactionHandler(mPipTransactionHandler)
.setDuration(show ? mEnterAnimationDuration : mExitAnimationDuration)
.start();
mHasFadeOut = !show;
@@ -1226,6 +1243,7 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
sourceHintRect, direction, startingAngle, rotationDelta);
animator.setTransitionDirection(direction)
.setPipAnimationCallback(mPipAnimationCallback)
.setPipTransactionHandler(mPipTransactionHandler)
.setDuration(durationMs)
.start();
if (rotationDelta != Surface.ROTATION_0 && direction == TRANSITION_DIRECTION_TO_PIP) {

View File

@@ -111,14 +111,14 @@ public class PipTransition extends PipTransitionController {
final Rect sourceHintRect =
PipBoundsAlgorithm.getValidSourceHintRect(
taskInfo.pictureInPictureParams, currentBounds);
animator = mPipAnimationController.getAnimator(taskInfo, leash,
currentBounds, currentBounds, destinationBounds, sourceHintRect,
TRANSITION_DIRECTION_TO_PIP, 0 /* startingAngle */, Surface.ROTATION_0);
animator = mPipAnimationController.getAnimator(taskInfo, leash, currentBounds,
currentBounds, destinationBounds, sourceHintRect, TRANSITION_DIRECTION_TO_PIP,
0 /* startingAngle */, Surface.ROTATION_0);
} else if (mOneShotAnimationType == ANIM_TYPE_ALPHA) {
t.setAlpha(leash, 0f);
t.apply();
animator = mPipAnimationController.getAnimator(taskInfo, leash,
destinationBounds, 0f, 1f);
animator = mPipAnimationController.getAnimator(taskInfo, leash, destinationBounds,
0f, 1f);
mOneShotAnimationType = ANIM_TYPE_BOUNDS;
} else {
throw new RuntimeException("Unrecognized animation type: "

View File

@@ -70,12 +70,19 @@ public class PhonePipMenuController implements PipMenuController {
*/
public interface Listener {
/**
* Called when the PIP menu visibility changes.
* Called when the PIP menu visibility change has started.
*
* @param menuState the current state of the menu
* @param menuState the new, about-to-change state of the menu
* @param resize whether or not to resize the PiP with the state change
*/
void onPipMenuStateChanged(int menuState, boolean resize, Runnable callback);
void onPipMenuStateChangeStart(int menuState, boolean resize, Runnable callback);
/**
* Called when the PIP menu state has finished changing/animating.
*
* @param menuState the new state of the menu.
*/
void onPipMenuStateChangeFinish(int menuState);
/**
* Called when the PIP requested to be expanded.
@@ -485,15 +492,15 @@ public class PhonePipMenuController implements PipMenuController {
/**
* Handles changes in menu visibility.
*/
void onMenuStateChanged(int menuState, boolean resize, Runnable callback) {
void onMenuStateChangeStart(int menuState, boolean resize, Runnable callback) {
if (DEBUG) {
Log.d(TAG, "onMenuStateChanged() mMenuState=" + mMenuState
Log.d(TAG, "onMenuStateChangeStart() mMenuState=" + mMenuState
+ " menuState=" + menuState + " resize=" + resize
+ " callers=\n" + Debug.getCallers(5, " "));
}
if (menuState != mMenuState) {
mListeners.forEach(l -> l.onPipMenuStateChanged(menuState, resize, callback));
mListeners.forEach(l -> l.onPipMenuStateChangeStart(menuState, resize, callback));
if (menuState == MENU_STATE_FULL) {
// Once visible, start listening for media action changes. This call will trigger
// the menu actions to be updated again.
@@ -511,6 +518,12 @@ public class PhonePipMenuController implements PipMenuController {
Log.e(TAG, "Unable to update focus as menu appears/disappears", e);
}
}
}
void onMenuStateChangeFinish(int menuState) {
if (menuState != mMenuState) {
mListeners.forEach(l -> l.onPipMenuStateChangeFinish(menuState));
}
mMenuState = menuState;
}

View File

@@ -276,17 +276,18 @@ public class PipMenuView extends FrameLayout {
}
mMenuContainerAnimator.setInterpolator(Interpolators.ALPHA_IN);
mMenuContainerAnimator.setDuration(ANIMATION_HIDE_DURATION_MS);
if (allowMenuTimeout) {
mMenuContainerAnimator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
mMenuContainerAnimator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
notifyMenuStateChangeFinish(menuState);
if (allowMenuTimeout) {
repostDelayedHide(INITIAL_DISMISS_DELAY);
}
});
}
}
});
if (withDelay) {
// starts the menu container animation after window expansion is completed
notifyMenuStateChange(menuState, resizeMenuOnShow, () -> {
notifyMenuStateChangeStart(menuState, resizeMenuOnShow, () -> {
if (mMenuContainerAnimator == null) {
return;
}
@@ -295,11 +296,11 @@ public class PipMenuView extends FrameLayout {
mMenuContainerAnimator.start();
});
} else {
notifyMenuStateChange(menuState, resizeMenuOnShow, null);
notifyMenuStateChangeStart(menuState, resizeMenuOnShow, null);
setVisibility(VISIBLE);
mMenuContainerAnimator.start();
}
updateActionViews(stackBounds);
updateActionViews(menuState, stackBounds);
} else {
// If we are already visible, then just start the delayed dismiss and unregister any
// existing input consumers from the previous drag
@@ -352,7 +353,7 @@ public class PipMenuView extends FrameLayout {
if (mMenuState != MENU_STATE_NONE) {
cancelDelayedHide();
if (notifyMenuVisibility) {
notifyMenuStateChange(MENU_STATE_NONE, resize, null);
notifyMenuStateChangeStart(MENU_STATE_NONE, resize, null);
}
mMenuContainerAnimator = new AnimatorSet();
ObjectAnimator menuAnim = ObjectAnimator.ofFloat(mMenuContainer, View.ALPHA,
@@ -371,6 +372,9 @@ public class PipMenuView extends FrameLayout {
@Override
public void onAnimationEnd(Animator animation) {
setVisibility(GONE);
if (notifyMenuVisibility) {
notifyMenuStateChangeFinish(MENU_STATE_NONE);
}
if (animationFinishedRunnable != null) {
animationFinishedRunnable.run();
}
@@ -399,11 +403,11 @@ public class PipMenuView extends FrameLayout {
mActions.clear();
mActions.addAll(actions);
if (mMenuState == MENU_STATE_FULL) {
updateActionViews(stackBounds);
updateActionViews(mMenuState, stackBounds);
}
}
private void updateActionViews(Rect stackBounds) {
private void updateActionViews(int menuState, Rect stackBounds) {
ViewGroup expandContainer = findViewById(R.id.expand_container);
ViewGroup actionsContainer = findViewById(R.id.actions_container);
actionsContainer.setOnTouchListener((v, ev) -> {
@@ -412,13 +416,13 @@ public class PipMenuView extends FrameLayout {
});
// Update the expand button only if it should show with the menu
expandContainer.setVisibility(mMenuState == MENU_STATE_FULL
expandContainer.setVisibility(menuState == MENU_STATE_FULL
? View.VISIBLE
: View.INVISIBLE);
FrameLayout.LayoutParams expandedLp =
(FrameLayout.LayoutParams) expandContainer.getLayoutParams();
if (mActions.isEmpty() || mMenuState == MENU_STATE_CLOSE || mMenuState == MENU_STATE_NONE) {
if (mActions.isEmpty() || menuState == MENU_STATE_CLOSE || menuState == MENU_STATE_NONE) {
actionsContainer.setVisibility(View.INVISIBLE);
// Update the expand container margin to adjust the center of the expand button to
@@ -488,9 +492,13 @@ public class PipMenuView extends FrameLayout {
expandContainer.requestLayout();
}
private void notifyMenuStateChange(int menuState, boolean resize, Runnable callback) {
private void notifyMenuStateChangeStart(int menuState, boolean resize, Runnable callback) {
mController.onMenuStateChangeStart(menuState, resize, callback);
}
private void notifyMenuStateChangeFinish(int menuState) {
mMenuState = menuState;
mController.onMenuStateChanged(menuState, resize, callback);
mController.onMenuStateChangeFinish(menuState);
}
private void expandPip() {

View File

@@ -419,13 +419,13 @@ public class PipResizeGestureHandler {
// Reset the down to begin resizing from this point
mDownPoint.set(mLastPoint);
mDownSecondPoint.set(mLastSecondPoint);
}
if (mThresholdCrossed) {
if (mPhonePipMenuController.isMenuVisible()) {
mPhonePipMenuController.hideMenu();
}
}
if (mThresholdCrossed) {
mAngle = mPinchResizingAlgorithm.calculateBoundsAndAngle(mDownPoint,
mDownSecondPoint, mLastPoint, mLastSecondPoint, mMinSize, mMaxSize,
mDownBounds, mLastResizeBounds);

View File

@@ -129,8 +129,13 @@ public class PipTouchHandler {
*/
private class PipMenuListener implements PhonePipMenuController.Listener {
@Override
public void onPipMenuStateChanged(int menuState, boolean resize, Runnable callback) {
setMenuState(menuState, resize, callback);
public void onPipMenuStateChangeStart(int menuState, boolean resize, Runnable callback) {
PipTouchHandler.this.onPipMenuStateChangeStart(menuState, resize, callback);
}
@Override
public void onPipMenuStateChangeFinish(int menuState) {
setMenuState(menuState);
}
@Override
@@ -646,9 +651,9 @@ public class PipTouchHandler {
}
/**
* Sets the menu visibility.
* Called when the PiP menu state is in the process of animating/changing from one to another.
*/
private void setMenuState(int menuState, boolean resize, Runnable callback) {
private void onPipMenuStateChangeStart(int menuState, boolean resize, Runnable callback) {
if (mMenuState == menuState && !resize) {
return;
}
@@ -686,6 +691,9 @@ public class PipTouchHandler {
mSavedSnapFraction = -1f;
}
}
}
private void setMenuState(int menuState) {
mMenuState = menuState;
updateMovementBounds();
// If pip menu has dismissed, we should register the A11y ActionReplacingConnection for pip