Merge "Move default pip position to right above the shelf." into pi-dev

This commit is contained in:
Tracy Zhou
2018-03-19 20:15:14 +00:00
committed by Android (Google) Code Review
14 changed files with 229 additions and 59 deletions

View File

@@ -385,4 +385,10 @@ public abstract class ActivityManagerInternal {
* Returns a list that contains the memory stats for currently running processes.
*/
public abstract List<ProcessMemoryState> getMemoryStateForProcesses();
/**
* This enforces {@code func} can only be called if either the caller is Recents activity or
* has {@code permission}.
*/
public abstract void enforceCallerIsRecentsOrHasPermission(String permission, String func);
}

View File

@@ -47,16 +47,24 @@ oneway interface IPinnedStackListener {
* 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, int displayRotation);
boolean fromImeAdjustment, boolean fromShelfAdjustment, int displayRotation);
/**
* Called when window manager decides to adjust the pinned stack bounds because of the IME, or
* when the listener is first registered to allow the listener to synchronized its state with
* the controller. This call will always be followed by a onMovementBoundsChanged() call
* with fromImeAdjustement set to true.
* with fromImeAdjustement set to {@code true}.
*/
void onImeVisibilityChanged(boolean imeVisible, int imeHeight);
/**
* Called when window manager decides to adjust the pinned stack bounds because of the shelf, or
* when the listener is first registered to allow the listener to synchronized its state with
* the controller. This call will always be followed by a onMovementBoundsChanged() call
* with fromShelfAdjustment set to {@code true}.
*/
void onShelfVisibilityChanged(boolean shelfVisible, int shelfHeight);
/**
* Called when window manager decides to adjust the minimized state, or when the listener
* is first registered to allow the listener to synchronized its state with the controller.

View File

@@ -284,7 +284,12 @@ interface IWindowManager
*/
oneway void setPipVisibility(boolean visible);
/**
/**
* Called by System UI to notify of changes to the visibility and height of the shelf.
*/
void setShelfHeight(boolean visible, int shelfHeight);
/**
* Called by System UI to enable or disable haptic feedback on the navigation bar buttons.
*/
void setNavBarVirtualKeyHapticFeedbackEnabled(boolean enabled);
@@ -295,8 +300,8 @@ interface IWindowManager
boolean hasNavigationBar();
/**
* Get the position of the nav bar
*/
* Get the position of the nav bar
*/
int getNavBarPosition();
/**

View File

@@ -325,14 +325,14 @@ public class PipSnapAlgorithm {
* {@param stackBounds}.
*/
public void getMovementBounds(Rect stackBounds, Rect insetBounds, Rect movementBoundsOut,
int imeHeight) {
int bottomOffset) {
// Adjust the right/bottom to ensure the stack bounds never goes offscreen
movementBoundsOut.set(insetBounds);
movementBoundsOut.right = Math.max(insetBounds.left, insetBounds.right -
stackBounds.width());
movementBoundsOut.bottom = Math.max(insetBounds.top, insetBounds.bottom -
stackBounds.height());
movementBoundsOut.bottom -= imeHeight;
movementBoundsOut.bottom -= bottomOffset;
}
/**

View File

@@ -2956,8 +2956,8 @@
<item name="config_pictureInPictureAspectRatioLimitForMinSize" format="float" type="dimen">1.777778</item>
<!-- The default gravity for the picture-in-picture window.
Currently, this maps to Gravity.TOP | Gravity.RIGHT -->
<integer name="config_defaultPictureInPictureGravity">0x35</integer>
Currently, this maps to Gravity.BOTTOM | Gravity.RIGHT -->
<integer name="config_defaultPictureInPictureGravity">0x55</integer>
<!-- The minimum aspect ratio (width/height) that is supported for picture-in-picture. Any
ratio smaller than this is considered too tall and thin to be usable. Currently, this

View File

@@ -23,7 +23,6 @@ import android.graphics.Rect;
import android.os.Handler;
import android.os.RemoteException;
import android.util.Log;
import android.view.RemoteAnimationAdapter;
import android.view.WindowManager;
import android.view.WindowManagerGlobal;
@@ -124,4 +123,12 @@ public class WindowManagerWrapper {
Log.w(TAG, "Failed to enable or disable navigation bar button haptics: ", e);
}
}
public void setShelfHeight(boolean visible, int shelfHeight) {
try {
WindowManagerGlobal.getWindowManagerService().setShelfHeight(visible, shelfHeight);
} catch (RemoteException e) {
Log.w(TAG, "Failed to set shelf height");
}
}
}

View File

@@ -132,6 +132,13 @@ public class PipManager implements BasePipManager {
});
}
@Override
public void onShelfVisibilityChanged(boolean shelfVisible, int shelfHeight) {
mHandler.post(() -> {
mTouchHandler.onShelfVisibilityChanged(shelfVisible, shelfHeight);
});
}
@Override
public void onMinimizedStateChanged(boolean isMinimized) {
mHandler.post(() -> {
@@ -141,10 +148,11 @@ public class PipManager implements BasePipManager {
@Override
public void onMovementBoundsChanged(Rect insetBounds, Rect normalBounds,
Rect animatingBounds, boolean fromImeAdjustement, int displayRotation) {
Rect animatingBounds, boolean fromImeAdjustment, boolean fromShelfAdjustment,
int displayRotation) {
mHandler.post(() -> {
mTouchHandler.onMovementBoundsChanged(insetBounds, normalBounds, animatingBounds,
fromImeAdjustement, displayRotation);
fromImeAdjustment, fromShelfAdjustment, displayRotation);
});
}

View File

@@ -16,8 +16,6 @@
package com.android.systemui.pip.phone;
import static android.app.ActivityManager.StackId.INVALID_STACK_ID;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
import static com.android.systemui.Interpolators.FAST_OUT_LINEAR_IN;
@@ -71,7 +69,7 @@ public class PipMotionHelper implements Handler.Callback {
private static final int EXPAND_STACK_TO_MENU_DURATION = 250;
private static final int EXPAND_STACK_TO_FULLSCREEN_DURATION = 300;
private static final int MINIMIZE_STACK_MAX_DURATION = 200;
private static final int IME_SHIFT_DURATION = 300;
private static final int SHIFT_DURATION = 300;
// The fraction of the stack width that the user has to drag offscreen to minimize the PiP
private static final float MINIMIZE_OFFSCREEN_FRACTION = 0.3f;
@@ -354,11 +352,11 @@ public class PipMotionHelper implements Handler.Callback {
}
/**
* Animates the PiP to offset it from the IME.
* Animates the PiP to offset it from the IME or shelf.
*/
void animateToIMEOffset(Rect toBounds) {
void animateToOffset(Rect toBounds) {
cancelAnimations();
resizeAndAnimatePipUnchecked(toBounds, IME_SHIFT_DURATION);
resizeAndAnimatePipUnchecked(toBounds, SHIFT_DURATION);
}
/**

View File

@@ -120,6 +120,8 @@ public class PipTouchHandler {
private boolean mIsImeShowing;
private int mImeHeight;
private int mImeOffset;
private boolean mIsShelfShowing;
private int mShelfHeight;
private float mSavedSnapFraction = -1f;
private boolean mSendingHoverAccessibilityEvents;
private boolean mMovementWithinMinimize;
@@ -249,13 +251,20 @@ public class PipTouchHandler {
mImeHeight = imeHeight;
}
public void onShelfVisibilityChanged(boolean shelfVisible, int shelfHeight) {
mIsShelfShowing = shelfVisible;
mShelfHeight = shelfHeight;
}
public void onMovementBoundsChanged(Rect insetBounds, Rect normalBounds, Rect animatingBounds,
boolean fromImeAdjustement, int displayRotation) {
boolean fromImeAdjustment, boolean fromShelfAdjustment, int displayRotation) {
final int bottomOffset = mIsImeShowing ? mImeHeight : 0;
// Re-calculate the expanded bounds
mNormalBounds = normalBounds;
Rect normalMovementBounds = new Rect();
mSnapAlgorithm.getMovementBounds(mNormalBounds, insetBounds, normalMovementBounds,
mIsImeShowing ? mImeHeight : 0);
bottomOffset);
// Calculate the expanded size
float aspectRatio = (float) normalBounds.width() / normalBounds.height();
@@ -266,40 +275,23 @@ public class PipTouchHandler {
mExpandedBounds.set(0, 0, expandedSize.getWidth(), expandedSize.getHeight());
Rect expandedMovementBounds = new Rect();
mSnapAlgorithm.getMovementBounds(mExpandedBounds, insetBounds, expandedMovementBounds,
mIsImeShowing ? mImeHeight : 0);
bottomOffset);
// If this is from an IME adjustment, then we should move the PiP so that it is not occluded
// by the IME
if (fromImeAdjustement) {
// If this is from an IME or shelf adjustment, then we should move the PiP so that it is not
// occluded by the IME or shelf.
if (fromImeAdjustment || fromShelfAdjustment) {
if (mTouchState.isUserInteracting()) {
// Defer the update of the current movement bounds until after the user finishes
// touching the screen
} else {
final Rect bounds = new Rect(animatingBounds);
final Rect toMovementBounds = mMenuState == MENU_STATE_FULL
? expandedMovementBounds
: normalMovementBounds;
if (mIsImeShowing) {
// IME visible, apply the IME offset if the space allows for it
final int imeOffset = toMovementBounds.bottom - Math.max(toMovementBounds.top,
toMovementBounds.bottom - mImeOffset);
if (bounds.top == mMovementBounds.bottom) {
// If the PIP is currently resting on top of the IME, then adjust it with
// the showing IME
bounds.offsetTo(bounds.left, toMovementBounds.bottom - imeOffset);
} else {
bounds.offset(0, Math.min(0, toMovementBounds.bottom - imeOffset
- bounds.top));
}
} else {
// IME hidden
if (bounds.top >= (mMovementBounds.bottom - mImeOffset)) {
// If the PIP is resting on top of the IME, then adjust it with the hiding
// IME
bounds.offsetTo(bounds.left, toMovementBounds.bottom);
}
}
mMotionHelper.animateToIMEOffset(bounds);
animateToOffset(animatingBounds, toMovementBounds,
fromImeAdjustment,
fromImeAdjustment ? mIsImeShowing : mIsShelfShowing,
// Shelf height serves as an offset, but does not change movement bounds.
fromImeAdjustment ? mImeOffset : mShelfHeight);
}
}
@@ -321,6 +313,26 @@ public class PipTouchHandler {
}
}
private void animateToOffset(Rect animatingBounds, Rect toMovementBounds,
boolean fromImeAdjustment, boolean showing, int offset) {
final Rect bounds = new Rect(animatingBounds);
if (showing) {
// IME/shelf visible, apply the IME/shelf offset if the space allows for it
final int calculatedOffset = toMovementBounds.bottom - Math.max(toMovementBounds.top,
toMovementBounds.bottom - offset);
bounds.offset(0,
Math.min(0, toMovementBounds.bottom - calculatedOffset - bounds.top));
} else {
// IME/shelf hidden
if (bounds.top >= (mMovementBounds.bottom - offset)) {
bounds.offset(0, toMovementBounds.bottom - bounds.top -
// Counter going back home from search where keyboard is up.
(fromImeAdjustment ? mShelfHeight : 0));
}
}
mMotionHelper.animateToOffset(bounds);
}
private void onRegistrationChanged(boolean isRegistered) {
mAccessibilityManager.setPictureInPictureActionReplacingConnection(isRegistered
? new PipAccessibilityInteractionConnection(mMotionHelper,
@@ -801,6 +813,8 @@ public class PipTouchHandler {
pw.println(innerPrefix + "mIsMinimized=" + mIsMinimized);
pw.println(innerPrefix + "mIsImeShowing=" + mIsImeShowing);
pw.println(innerPrefix + "mImeHeight=" + mImeHeight);
pw.println(innerPrefix + "mIsShelfShowing=" + mIsShelfShowing);
pw.println(innerPrefix + "mShelfHeight=" + mShelfHeight);
pw.println(innerPrefix + "mSavedSnapFraction=" + mSavedSnapFraction);
pw.println(innerPrefix + "mEnableDragToEdgeDismiss=" + ENABLE_DISMISS_DRAG_TO_EDGE);
pw.println(innerPrefix + "mEnableMinimize=" + ENABLE_MINIMIZE);

View File

@@ -199,12 +199,16 @@ public class PipManager implements BasePipManager {
}
}
@Override
public void onShelfVisibilityChanged(boolean shelfVisible, int shelfHeight) {}
@Override
public void onMinimizedStateChanged(boolean isMinimized) {}
@Override
public void onMovementBoundsChanged(Rect insetBounds, Rect normalBounds,
Rect animatingBounds, boolean fromImeAdjustement, int displayRotation) {
Rect animatingBounds, boolean fromImeAdjustment, boolean fromShelfAdjustment,
int displayRotation) {
mHandler.post(() -> {
mDefaultPipBounds.set(normalBounds);
});

View File

@@ -26259,10 +26259,12 @@ public class ActivityManagerService extends IActivityManager.Stub
return mUserController.mMaxRunningUsers;
}
@Override
public boolean isCallerRecents(int callingUid) {
return getRecentTasks().isCallerRecents(callingUid);
}
@Override
public boolean isRecentsComponentHomeActivity(int userId) {
return getRecentTasks().isRecentsComponentHomeActivity(userId);
}
@@ -26301,6 +26303,11 @@ public class ActivityManagerService extends IActivityManager.Stub
}
return processMemoryStates;
}
@Override
public void enforceCallerIsRecentsOrHasPermission(String permission, String func) {
ActivityManagerService.this.enforceCallerIsRecentsOrHasPermission(permission, func);
}
}
/**

View File

@@ -88,6 +88,8 @@ class PinnedStackController {
private boolean mIsMinimized;
private boolean mIsImeShowing;
private int mImeHeight;
private boolean mIsShelfShowing;
private int mShelfHeight;
// The set of actions and aspect-ratio for the that are currently allowed on the PiP activity
private ArrayList<RemoteAction> mActions = new ArrayList<>();
@@ -213,9 +215,11 @@ class PinnedStackController {
listener.onListenerRegistered(mCallbacks);
mPinnedStackListener = listener;
notifyImeVisibilityChanged(mIsImeShowing, mImeHeight);
notifyShelfVisibilityChanged(mIsShelfShowing, mShelfHeight);
// The movement bounds notification needs to be sent before the minimized state, since
// SystemUI may use the bounds to retore the minimized position
notifyMovementBoundsChanged(false /* fromImeAdjustment */);
notifyMovementBoundsChanged(false /* fromImeAdjustment */,
false /* fromShelfAdjustment */);
notifyActionsChanged(mActions);
notifyMinimizeChanged(mIsMinimized);
} catch (RemoteException e) {
@@ -297,7 +301,9 @@ class PinnedStackController {
mSnapAlgorithm.applySnapFraction(defaultBounds, movementBounds, snapFraction);
} else {
Gravity.apply(mDefaultStackGravity, size.getWidth(), size.getHeight(), insetBounds,
0, mIsImeShowing ? mImeHeight : 0, defaultBounds);
0, Math.max(mIsImeShowing ? mImeHeight : 0,
mIsShelfShowing ? mShelfHeight : 0),
defaultBounds);
}
return defaultBounds;
}
@@ -310,7 +316,7 @@ class PinnedStackController {
*/
synchronized void onDisplayInfoChanged() {
mDisplayInfo.copyFrom(mDisplayContent.getDisplayInfo());
notifyMovementBoundsChanged(false /* fromImeAdjustment */);
notifyMovementBoundsChanged(false /* fromImeAdjustment */, false /* fromShelfAdjustment */);
}
/**
@@ -342,14 +348,15 @@ class PinnedStackController {
// 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 */);
false /* adjustForIme */, false /* adjustForShelf */);
mSnapAlgorithm.applySnapFraction(postChangeStackBounds, postChangeMovementBounds,
snapFraction);
if (mIsMinimized) {
applyMinimizedOffset(postChangeStackBounds, postChangeMovementBounds);
}
notifyMovementBoundsChanged(false /* fromImeAdjustment */);
notifyMovementBoundsChanged(false /* fromImeAdjustment */,
false /* fromShelfAdjustment */);
outBounds.set(postChangeStackBounds);
return true;
@@ -373,7 +380,22 @@ class PinnedStackController {
mIsImeShowing = imeShowing;
mImeHeight = imeHeight;
notifyImeVisibilityChanged(imeShowing, imeHeight);
notifyMovementBoundsChanged(true /* fromImeAdjustment */);
notifyMovementBoundsChanged(true /* fromImeAdjustment */, false /* fromShelfAdjustment */);
}
/**
* Sets the shelf state and height.
*/
void setAdjustedForShelf(boolean adjustedForShelf, int shelfHeight) {
final boolean shelfShowing = adjustedForShelf && shelfHeight > 0;
if (shelfShowing == mIsShelfShowing && shelfHeight == mShelfHeight) {
return;
}
mIsShelfShowing = shelfShowing;
mShelfHeight = shelfHeight;
notifyShelfVisibilityChanged(shelfShowing, shelfHeight);
notifyMovementBoundsChanged(false /* fromImeAdjustment */, true /* fromShelfAdjustment */);
}
/**
@@ -382,7 +404,8 @@ class PinnedStackController {
void setAspectRatio(float aspectRatio) {
if (Float.compare(mAspectRatio, aspectRatio) != 0) {
mAspectRatio = aspectRatio;
notifyMovementBoundsChanged(false /* fromImeAdjustment */);
notifyMovementBoundsChanged(false /* fromImeAdjustment */,
false /* fromShelfAdjustment */);
}
}
@@ -417,6 +440,16 @@ class PinnedStackController {
}
}
private void notifyShelfVisibilityChanged(boolean shelfVisible, int shelfHeight) {
if (mPinnedStackListener != null) {
try {
mPinnedStackListener.onShelfVisibilityChanged(shelfVisible, shelfHeight);
} catch (RemoteException e) {
Slog.e(TAG_WM, "Error delivering bounds changed event.", e);
}
}
}
/**
* Notifies listeners that the PIP minimized state has changed.
*/
@@ -446,7 +479,8 @@ class PinnedStackController {
/**
* Notifies listeners that the PIP movement bounds have changed.
*/
private void notifyMovementBoundsChanged(boolean fromImeAdjustement) {
private void notifyMovementBoundsChanged(boolean fromImeAdjustment,
boolean fromShelfAdjustment) {
synchronized (mService.mWindowMap) {
if (mPinnedStackListener == null) {
return;
@@ -467,7 +501,8 @@ class PinnedStackController {
animatingBounds.set(normalBounds);
}
mPinnedStackListener.onMovementBoundsChanged(insetBounds, normalBounds,
animatingBounds, fromImeAdjustement, mDisplayInfo.rotation);
animatingBounds, fromImeAdjustment, fromShelfAdjustment,
mDisplayInfo.rotation);
} catch (RemoteException e) {
Slog.e(TAG_WM, "Error delivering actions changed event.", e);
}
@@ -493,7 +528,8 @@ class PinnedStackController {
*/
private Rect getMovementBounds(Rect stackBounds) {
synchronized (mService.mWindowMap) {
return getMovementBounds(stackBounds, true /* adjustForIme */);
return getMovementBounds(stackBounds, true /* adjustForIme */,
true /* adjustForShelf */);
}
}
@@ -501,14 +537,15 @@ class PinnedStackController {
* @return the movement bounds for the given {@param stackBounds} and the current state of the
* controller.
*/
private Rect getMovementBounds(Rect stackBounds, boolean adjustForIme) {
private Rect getMovementBounds(Rect stackBounds, boolean adjustForIme, boolean adjustForShelf) {
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);
Math.max((adjustForIme && mIsImeShowing) ? mImeHeight : 0,
(adjustForShelf && mIsShelfShowing) ? mShelfHeight : 0));
return movementBounds;
}
}
@@ -549,6 +586,9 @@ class PinnedStackController {
pw.print(prefix + " movementBounds="); getMovementBounds(mTmpRect).printShortString(pw);
pw.println();
pw.println(prefix + " mIsImeShowing=" + mIsImeShowing);
pw.println(prefix + " mImeHeight=" + mImeHeight);
pw.println(prefix + " mIsShelfShowing=" + mIsShelfShowing);
pw.println(prefix + " mShelfHeight=" + mShelfHeight);
pw.println(prefix + " mIsMinimized=" + mIsMinimized);
if (mActions.isEmpty()) {
pw.println(prefix + " mActions=[]");

View File

@@ -5891,6 +5891,16 @@ public class WindowManagerService extends IWindowManager.Stub
}
}
@Override
public void setShelfHeight(boolean visible, int shelfHeight) {
mAmInternal.enforceCallerIsRecentsOrHasPermission(android.Manifest.permission.STATUS_BAR,
"setShelfHeight()");
synchronized (mWindowMap) {
getDefaultDisplayContentLocked().getPinnedStackController().setAdjustedForShelf(visible,
shelfHeight);
}
}
@Override
public void statusBarVisibilityChanged(int visibility) {
if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.STATUS_BAR)

View File

@@ -0,0 +1,63 @@
package com.android.server.wm;
import static android.view.Display.DEFAULT_DISPLAY;
import android.os.RemoteException;
import android.platform.test.annotations.Presubmit;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
import android.view.IPinnedStackListener;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@SmallTest
@Presubmit
@RunWith(AndroidJUnit4.class)
public class PinnedStackControllerTest extends WindowTestsBase {
@Mock private IPinnedStackListener mIPinnedStackListener;
@Mock private IPinnedStackListener.Stub mIPinnedStackListenerStub;
@Before
public void setUp() throws Exception {
super.setUp();
MockitoAnnotations.initMocks(this);
when(mIPinnedStackListener.asBinder()).thenReturn(mIPinnedStackListenerStub);
}
@Test
public void setShelfHeight_shelfVisibilityChangedTriggered() throws RemoteException {
sWm.mSupportsPictureInPicture = true;
sWm.registerPinnedStackListener(DEFAULT_DISPLAY, mIPinnedStackListener);
verify(mIPinnedStackListener).onImeVisibilityChanged(false, 0);
verify(mIPinnedStackListener).onShelfVisibilityChanged(false, 0);
verify(mIPinnedStackListener).onMovementBoundsChanged(any(), any(), any(), eq(false),
eq(false), anyInt());
verify(mIPinnedStackListener).onActionsChanged(any());
verify(mIPinnedStackListener).onMinimizedStateChanged(anyBoolean());
reset(mIPinnedStackListener);
final int SHELF_HEIGHT = 300;
sWm.setShelfHeight(true, SHELF_HEIGHT);
verify(mIPinnedStackListener).onShelfVisibilityChanged(true, SHELF_HEIGHT);
verify(mIPinnedStackListener).onMovementBoundsChanged(any(), any(), any(), eq(false),
eq(true), anyInt());
verify(mIPinnedStackListener, never()).onImeVisibilityChanged(anyBoolean(), anyInt());
}
}