Merge "Tightening up rotation behavior for PIP (3/3)" into oc-dev

am: c2627353c4

Change-Id: I867999bac435926e9f54fb33e489ea3f44d1dad0
This commit is contained in:
Winson Chung
2017-04-18 00:01:44 +00:00
committed by android-build-merger
8 changed files with 170 additions and 89 deletions

View File

@@ -28,4 +28,9 @@ interface IPinnedStackController {
* Notifies the controller that the PiP is currently minimized.
*/
oneway void setIsMinimized(boolean isMinimized);
/**
* @return what WM considers to be the current device rotation.
*/
int getDisplayRotation();
}

View File

@@ -41,9 +41,13 @@ oneway interface IPinnedStackListener {
* current state with the aspect ratio applied. The {@param animatingBounds} are provided
* to indicate the current target bounds of the pinned stack (the final bounds if animating,
* the current bounds if not), which may be helpful in calculating dependent animation bounds.
*
* The {@param displayRotation} is provided so that the client can verify when making certain
* calls that it will not provide stale information based on an old display rotation (ie. if
* the WM has changed in the mean time but the client has not received onMovementBoundsChanged).
*/
void onMovementBoundsChanged(in Rect insetBounds, in Rect normalBounds, in Rect animatingBounds,
boolean fromImeAdjustement);
boolean fromImeAdjustement, int displayRotation);
/**
* Called when window manager decides to adjust the pinned stack bounds because of the IME, or

View File

@@ -143,10 +143,10 @@ public class PipManager implements BasePipManager {
@Override
public void onMovementBoundsChanged(Rect insetBounds, Rect normalBounds,
Rect animatingBounds, boolean fromImeAdjustement) {
Rect animatingBounds, boolean fromImeAdjustement, int displayRotation) {
mHandler.post(() -> {
mTouchHandler.onMovementBoundsChanged(insetBounds, normalBounds, animatingBounds,
fromImeAdjustement);
fromImeAdjustement, displayRotation);
});
}

View File

@@ -220,6 +220,13 @@ public class PipMenuActivity extends Activity {
finish();
}
@Override
protected void onStop() {
super.onStop();
cancelDelayedFinish();
}
@Override
protected void onDestroy() {
super.onDestroy();

View File

@@ -316,7 +316,8 @@ public class PipMotionHelper {
* Animates the PiP from the expanded state to the normal state after the menu is hidden.
*/
void animateToUnexpandedState(Rect normalBounds, float savedSnapFraction,
Rect normalMovementBounds, Rect currentMovementBounds, boolean minimized) {
Rect normalMovementBounds, Rect currentMovementBounds, boolean minimized,
boolean immediate) {
if (savedSnapFraction < 0f) {
// If there are no saved snap fractions, then just use the current bounds
savedSnapFraction = mSnapAlgorithm.getSnapFraction(new Rect(mBounds),
@@ -326,7 +327,11 @@ public class PipMotionHelper {
if (minimized) {
normalBounds = getClosestMinimizedBounds(normalBounds, normalMovementBounds);
}
resizeAndAnimatePipUnchecked(normalBounds, SHRINK_STACK_FROM_MENU_DURATION);
if (immediate) {
movePip(normalBounds);
} else {
resizeAndAnimatePipUnchecked(normalBounds, SHRINK_STACK_FROM_MENU_DURATION);
}
}
/**

View File

@@ -89,6 +89,11 @@ public class PipTouchHandler implements TunerService.Tunable {
private Rect mExpandedMovementBounds = new Rect();
private int mExpandedShortestEdgeSize;
// Used to workaround an issue where the WM rotation happens before we are notified, allowing
// us to send stale bounds
private int mDeferResizeToNormalBoundsUntilRotation = -1;
private int mDisplayRotation;
private Handler mHandler = new Handler();
private Runnable mShowDismissAffordance = new Runnable() {
@Override
@@ -250,7 +255,7 @@ public class PipTouchHandler implements TunerService.Tunable {
}
public void onMovementBoundsChanged(Rect insetBounds, Rect normalBounds, Rect animatingBounds,
boolean fromImeAdjustement) {
boolean fromImeAdjustement, int displayRotation) {
// Re-calculate the expanded bounds
mNormalBounds = normalBounds;
Rect normalMovementBounds = new Rect();
@@ -304,7 +309,17 @@ public class PipTouchHandler implements TunerService.Tunable {
// above
mNormalMovementBounds = normalMovementBounds;
mExpandedMovementBounds = expandedMovementBounds;
mDisplayRotation = displayRotation;
updateMovementBounds(mMenuState);
// If we have a deferred resize, apply it now
if (mDeferResizeToNormalBoundsUntilRotation == displayRotation) {
mMotionHelper.animateToUnexpandedState(normalBounds, mSavedSnapFraction,
mNormalMovementBounds, mMovementBounds, mIsMinimized,
true /* immediate */);
mSavedSnapFraction = -1f;
mDeferResizeToNormalBoundsUntilRotation = -1;
}
}
private void onRegistrationChanged(boolean isRegistered) {
@@ -474,11 +489,34 @@ public class PipTouchHandler implements TunerService.Tunable {
// Try and restore the PiP to the closest edge, using the saved snap fraction
// if possible
if (resize) {
Rect normalBounds = new Rect(mNormalBounds);
mMotionHelper.animateToUnexpandedState(normalBounds, mSavedSnapFraction,
mNormalMovementBounds, mMovementBounds, mIsMinimized);
// This is a very special case: when the menu is expanded and visible, navigating to
// another activity can trigger auto-enter PiP, and if the revealed activity has a
// forced rotation set, then the controller will get updated with the new rotation
// of the display. However, at the same time, SystemUI will try to hide the menu by
// creating an animation to the normal bounds which are now stale. In such a case
// we defer the animation to the normal bounds until after the next
// onMovementBoundsChanged() call to get the bounds in the new orientation
if (mDeferResizeToNormalBoundsUntilRotation == -1) {
try {
int displayRotation = mPinnedStackController.getDisplayRotation();
if (mDisplayRotation != displayRotation) {
mDeferResizeToNormalBoundsUntilRotation = displayRotation;
}
} catch (RemoteException e) {
Log.e(TAG, "Could not get display rotation from controller");
}
}
if (mDeferResizeToNormalBoundsUntilRotation == -1) {
Rect normalBounds = new Rect(mNormalBounds);
mMotionHelper.animateToUnexpandedState(normalBounds, mSavedSnapFraction,
mNormalMovementBounds, mMovementBounds, mIsMinimized,
false /* immediate */);
mSavedSnapFraction = -1f;
}
} else {
mSavedSnapFraction = -1f;
}
mSavedSnapFraction = -1f;
}
mMenuState = menuState;
updateMovementBounds(menuState);

View File

@@ -178,7 +178,7 @@ public class PipManager implements BasePipManager {
@Override
public void onMovementBoundsChanged(Rect insetBounds, Rect normalBounds,
Rect animatingBounds, boolean fromImeAdjustement) {
Rect animatingBounds, boolean fromImeAdjustement, int displayRotation) {
mHandler.post(() -> {
mDefaultPipBounds.set(normalBounds);
});

View File

@@ -26,7 +26,6 @@ import android.app.RemoteAction;
import android.content.pm.ParceledListSlice;
import android.content.res.Resources;
import android.graphics.Point;
import android.graphics.PointF;
import android.graphics.Rect;
import android.os.Handler;
import android.os.IBinder;
@@ -123,6 +122,13 @@ class PinnedStackController {
mSnapAlgorithm.setMinimized(isMinimized);
});
}
@Override
public int getDisplayRotation() {
synchronized (mService.mWindowMap) {
return mDisplayInfo.rotation;
}
}
}
/**
@@ -221,22 +227,26 @@ class PinnedStackController {
* @return the size of the PIP based on the given {@param aspectRatio}.
*/
Size getSize(float aspectRatio) {
return mSnapAlgorithm.getSizeForAspectRatio(aspectRatio, mMinSize,
mDisplayInfo.logicalWidth, mDisplayInfo.logicalHeight);
synchronized (mService.mWindowMap) {
return mSnapAlgorithm.getSizeForAspectRatio(aspectRatio, mMinSize,
mDisplayInfo.logicalWidth, mDisplayInfo.logicalHeight);
}
}
/**
* @return the default bounds to show the PIP when there is no active PIP.
*/
Rect getDefaultBounds() {
final Rect insetBounds = new Rect();
getInsetBounds(insetBounds);
synchronized (mService.mWindowMap) {
final Rect insetBounds = new Rect();
getInsetBounds(insetBounds);
final Rect defaultBounds = new Rect();
final Size size = getSize(mDefaultAspectRatio);
Gravity.apply(mDefaultStackGravity, size.getWidth(), size.getHeight(), insetBounds,
0, mIsImeShowing ? mImeHeight : 0, defaultBounds);
return defaultBounds;
final Rect defaultBounds = new Rect();
final Size size = getSize(mDefaultAspectRatio);
Gravity.apply(mDefaultStackGravity, size.getWidth(), size.getHeight(), insetBounds,
0, mIsImeShowing ? mImeHeight : 0, defaultBounds);
return defaultBounds;
}
}
/**
@@ -254,42 +264,44 @@ class PinnedStackController {
* new orientation of the device if necessary.
*/
boolean onTaskStackBoundsChanged(Rect targetBounds, Rect outBounds) {
final DisplayInfo displayInfo = mDisplayContent.getDisplayInfo();
if (mDisplayInfo.equals(displayInfo)) {
// We are already in the right orientation, ignore
outBounds.setEmpty();
return false;
} else if (targetBounds.isEmpty()) {
// The stack is null, we are just initializing the stack, so just store the display info
// and ignore
synchronized (mService.mWindowMap) {
final DisplayInfo displayInfo = mDisplayContent.getDisplayInfo();
if (mDisplayInfo.equals(displayInfo)) {
// We are already in the right orientation, ignore
outBounds.setEmpty();
return false;
} else if (targetBounds.isEmpty()) {
// The stack is null, we are just initializing the stack, so just store the display
// info and ignore
mDisplayInfo.copyFrom(displayInfo);
outBounds.setEmpty();
return false;
}
mTmpRect.set(targetBounds);
final Rect postChangeStackBounds = mTmpRect;
// Calculate the snap fraction of the current stack along the old movement bounds
final Rect preChangeMovementBounds = getMovementBounds(postChangeStackBounds);
final float snapFraction = mSnapAlgorithm.getSnapFraction(postChangeStackBounds,
preChangeMovementBounds);
mDisplayInfo.copyFrom(displayInfo);
outBounds.setEmpty();
return false;
// Calculate the stack bounds in the new orientation to the same same fraction along the
// rotated movement bounds.
final Rect postChangeMovementBounds = getMovementBounds(postChangeStackBounds,
false /* adjustForIme */);
mSnapAlgorithm.applySnapFraction(postChangeStackBounds, postChangeMovementBounds,
snapFraction);
if (mIsMinimized) {
applyMinimizedOffset(postChangeStackBounds, postChangeMovementBounds);
}
notifyMovementBoundsChanged(false /* fromImeAdjustment */);
outBounds.set(postChangeStackBounds);
return true;
}
mTmpRect.set(targetBounds);
final Rect postChangeStackBounds = mTmpRect;
// Calculate the snap fraction of the current stack along the old movement bounds
final Rect preChangeMovementBounds = getMovementBounds(postChangeStackBounds);
final float snapFraction = mSnapAlgorithm.getSnapFraction(postChangeStackBounds,
preChangeMovementBounds);
mDisplayInfo.copyFrom(displayInfo);
// Calculate the stack bounds in the new orientation to the same same fraction along the
// rotated movement bounds.
final Rect postChangeMovementBounds = getMovementBounds(postChangeStackBounds,
false /* adjustForIme */);
mSnapAlgorithm.applySnapFraction(postChangeStackBounds, postChangeMovementBounds,
snapFraction);
if (mIsMinimized) {
applyMinimizedOffset(postChangeStackBounds, postChangeMovementBounds);
}
notifyMovementBoundsChanged(false /* fromImeAdjustment */);
outBounds.set(postChangeStackBounds);
return true;
}
/**
@@ -378,25 +390,27 @@ class PinnedStackController {
* Notifies listeners that the PIP movement bounds have changed.
*/
private void notifyMovementBoundsChanged(boolean fromImeAdjustement) {
if (mPinnedStackListener != null) {
try {
final Rect insetBounds = new Rect();
getInsetBounds(insetBounds);
final Rect normalBounds = getDefaultBounds();
if (isValidPictureInPictureAspectRatio(mAspectRatio)) {
transformBoundsToAspectRatio(normalBounds, mAspectRatio);
synchronized (mService.mWindowMap) {
if (mPinnedStackListener != null) {
try {
final Rect insetBounds = new Rect();
getInsetBounds(insetBounds);
final Rect normalBounds = getDefaultBounds();
if (isValidPictureInPictureAspectRatio(mAspectRatio)) {
transformBoundsToAspectRatio(normalBounds, mAspectRatio);
}
final Rect animatingBounds = mTmpAnimatingBoundsRect;
final TaskStack pinnedStack = mDisplayContent.getStackById(PINNED_STACK_ID);
if (pinnedStack != null) {
pinnedStack.getAnimationOrCurrentBounds(animatingBounds);
} else {
animatingBounds.set(normalBounds);
}
mPinnedStackListener.onMovementBoundsChanged(insetBounds, normalBounds,
animatingBounds, fromImeAdjustement, mDisplayInfo.rotation);
} catch (RemoteException e) {
Slog.e(TAG_WM, "Error delivering actions changed event.", e);
}
final Rect animatingBounds = mTmpAnimatingBoundsRect;
final TaskStack pinnedStack = mDisplayContent.getStackById(PINNED_STACK_ID);
if (pinnedStack != null) {
pinnedStack.getAnimationOrCurrentBounds(animatingBounds);
} else {
animatingBounds.set(normalBounds);
}
mPinnedStackListener.onMovementBoundsChanged(insetBounds, normalBounds,
animatingBounds, fromImeAdjustement);
} catch (RemoteException e) {
Slog.e(TAG_WM, "Error delivering actions changed event.", e);
}
}
}
@@ -405,11 +419,13 @@ class PinnedStackController {
* @return the bounds on the screen that the PIP can be visible in.
*/
private void getInsetBounds(Rect outRect) {
mService.mPolicy.getStableInsetsLw(mDisplayInfo.rotation, mDisplayInfo.logicalWidth,
mDisplayInfo.logicalHeight, mTmpInsets);
outRect.set(mTmpInsets.left + mScreenEdgeInsets.x, mTmpInsets.top + mScreenEdgeInsets.y,
mDisplayInfo.logicalWidth - mTmpInsets.right - mScreenEdgeInsets.x,
mDisplayInfo.logicalHeight - mTmpInsets.bottom - mScreenEdgeInsets.y);
synchronized (mService.mWindowMap) {
mService.mPolicy.getStableInsetsLw(mDisplayInfo.rotation, mDisplayInfo.logicalWidth,
mDisplayInfo.logicalHeight, mTmpInsets);
outRect.set(mTmpInsets.left + mScreenEdgeInsets.x, mTmpInsets.top + mScreenEdgeInsets.y,
mDisplayInfo.logicalWidth - mTmpInsets.right - mScreenEdgeInsets.x,
mDisplayInfo.logicalHeight - mTmpInsets.bottom - mScreenEdgeInsets.y);
}
}
/**
@@ -417,7 +433,9 @@ class PinnedStackController {
* controller.
*/
private Rect getMovementBounds(Rect stackBounds) {
return getMovementBounds(stackBounds, true /* adjustForIme */);
synchronized (mService.mWindowMap) {
return getMovementBounds(stackBounds, true /* adjustForIme */);
}
}
/**
@@ -425,23 +443,27 @@ class PinnedStackController {
* controller.
*/
private Rect getMovementBounds(Rect stackBounds, boolean adjustForIme) {
final Rect movementBounds = new Rect();
getInsetBounds(movementBounds);
synchronized (mService.mWindowMap) {
final Rect movementBounds = new Rect();
getInsetBounds(movementBounds);
// Apply the movement bounds adjustments based on the current state
mSnapAlgorithm.getMovementBounds(stackBounds, movementBounds, movementBounds,
(adjustForIme && mIsImeShowing) ? mImeHeight : 0);
return movementBounds;
// Apply the movement bounds adjustments based on the current state
mSnapAlgorithm.getMovementBounds(stackBounds, movementBounds, movementBounds,
(adjustForIme && mIsImeShowing) ? mImeHeight : 0);
return movementBounds;
}
}
/**
* Applies the minimized offsets to the given stack bounds.
*/
private void applyMinimizedOffset(Rect stackBounds, Rect movementBounds) {
mTmpDisplaySize.set(mDisplayInfo.logicalWidth, mDisplayInfo.logicalHeight);
mService.getStableInsetsLocked(mDisplayContent.getDisplayId(), mStableInsets);
mSnapAlgorithm.applyMinimizedOffset(stackBounds, movementBounds, mTmpDisplaySize,
mStableInsets);
synchronized (mService.mWindowMap) {
mTmpDisplaySize.set(mDisplayInfo.logicalWidth, mDisplayInfo.logicalHeight);
mService.getStableInsetsLocked(mDisplayContent.getDisplayId(), mStableInsets);
mSnapAlgorithm.applyMinimizedOffset(stackBounds, movementBounds, mTmpDisplaySize,
mStableInsets);
}
}
/**