Merge "PiP: Update menu state AFTER animation is done for show/hide/resize." into sc-dev
This commit is contained in:
@@ -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,
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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: "
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user