Migrate to using DisplayLayout instead of DisplayInfo

- No need to keep two sources of truth, can just use display
  layout to  store/calcualte all the info we need
- Update the display layout on display configuration changed
  as well
- KI: When changing displays, the min size of the pip also
  changes so we will need to calculate that based on the
  smallest display size

Bug: 175644531
Test: atest PinnedStacktests
Test: atest WMShellUnitTests
Change-Id: I34614a8f739311c7b382b6848e4752fa68c91cfb
This commit is contained in:
Winson Chung
2021-01-22 14:23:01 -08:00
parent 7cb084a470
commit 4dc41ab58b
7 changed files with 98 additions and 84 deletions

View File

@@ -30,6 +30,8 @@ import android.util.TypedValue;
import android.view.DisplayInfo;
import android.view.Gravity;
import com.android.wm.shell.common.DisplayLayout;
import java.io.PrintWriter;
/**
@@ -190,9 +192,9 @@ public class PipBoundsAlgorithm {
size = adjustSizeToAspectRatio(overrideMinSize, aspectRatio);
} else {
// Calculate the default size using the display size and default min edge size.
final DisplayInfo displayInfo = mPipBoundsState.getDisplayInfo();
final DisplayLayout displayLayout = mPipBoundsState.getDisplayLayout();
size = getSizeForAspectRatio(aspectRatio, mDefaultMinSize,
displayInfo.logicalWidth, displayInfo.logicalHeight);
displayLayout.width(), displayLayout.height());
}
}
@@ -232,7 +234,7 @@ public class PipBoundsAlgorithm {
final Size defaultSize;
final Rect insetBounds = new Rect();
getInsetBounds(insetBounds);
final DisplayInfo displayInfo = mPipBoundsState.getDisplayInfo();
final DisplayLayout displayLayout = mPipBoundsState.getDisplayLayout();
final Size overrideMinSize = mPipBoundsState.getOverrideMinSize();
if (overrideMinSize != null) {
// The override minimal size is set, use that as the default size making sure it's
@@ -241,7 +243,7 @@ public class PipBoundsAlgorithm {
} else {
// Calculate the default size using the display size and default min edge size.
defaultSize = getSizeForAspectRatio(mDefaultAspectRatio,
mDefaultMinSize, displayInfo.logicalWidth, displayInfo.logicalHeight);
mDefaultMinSize, displayLayout.width(), displayLayout.height());
}
// Now that we have the default size, apply the snap fraction if valid or position the
@@ -264,12 +266,12 @@ public class PipBoundsAlgorithm {
* Populates the bounds on the screen that the PIP can be visible in.
*/
public void getInsetBounds(Rect outRect) {
final DisplayInfo displayInfo = mPipBoundsState.getDisplayInfo();
final DisplayLayout displayLayout = mPipBoundsState.getDisplayLayout();
Rect insets = mPipBoundsState.getDisplayLayout().stableInsets();
outRect.set(insets.left + mScreenEdgeInsets.x,
insets.top + mScreenEdgeInsets.y,
displayInfo.logicalWidth - insets.right - mScreenEdgeInsets.x,
displayInfo.logicalHeight - insets.bottom - mScreenEdgeInsets.y);
displayLayout.width() - insets.right - mScreenEdgeInsets.x,
displayLayout.height() - insets.bottom - mScreenEdgeInsets.y);
}
/**

View File

@@ -24,6 +24,7 @@ import android.content.Context;
import android.graphics.Point;
import android.graphics.Rect;
import android.util.Size;
import android.view.Display;
import android.view.DisplayInfo;
import com.android.internal.annotations.VisibleForTesting;
@@ -68,7 +69,7 @@ public final class PipBoundsState {
private int mStashOffset;
private @Nullable PipReentryState mPipReentryState;
private @Nullable ComponentName mLastPipComponentName;
private final @NonNull DisplayInfo mDisplayInfo = new DisplayInfo();
private int mDisplayId = Display.DEFAULT_DISPLAY;
private final @NonNull DisplayLayout mDisplayLayout = new DisplayLayout();
/** The current minimum edge size of PIP. */
private int mMinEdgeSize;
@@ -238,26 +239,20 @@ public final class PipBoundsState {
return mLastPipComponentName;
}
/** Get the current display info. */
@NonNull
public DisplayInfo getDisplayInfo() {
return mDisplayInfo;
/** Get the current display id. */
public int getDisplayId() {
return mDisplayId;
}
/** Update the display info. */
public void setDisplayInfo(@NonNull DisplayInfo displayInfo) {
mDisplayInfo.copyFrom(displayInfo);
}
/** Set the rotation of the display. */
public void setDisplayRotation(int rotation) {
mDisplayInfo.rotation = rotation;
/** Set the current display id for the associated display layout. */
public void setDisplayId(int displayId) {
mDisplayId = displayId;
}
/** Returns the display's bounds. */
@NonNull
public Rect getDisplayBounds() {
return new Rect(0, 0, mDisplayInfo.logicalWidth, mDisplayInfo.logicalHeight);
return new Rect(0, 0, mDisplayLayout.width(), mDisplayLayout.height());
}
/** Update the display layout. */
@@ -474,7 +469,7 @@ public final class PipBoundsState {
pw.println(innerPrefix + "mExpandedMovementBounds=" + mExpandedMovementBounds);
pw.println(innerPrefix + "mLastPipComponentName=" + mLastPipComponentName);
pw.println(innerPrefix + "mAspectRatio=" + mAspectRatio);
pw.println(innerPrefix + "mDisplayInfo=" + mDisplayInfo);
pw.println(innerPrefix + "mDisplayId=" + mDisplayId);
pw.println(innerPrefix + "mDisplayLayout=" + mDisplayLayout);
pw.println(innerPrefix + "mStashedState=" + mStashedState);
pw.println(innerPrefix + "mStashOffset=" + mStashOffset);

View File

@@ -55,6 +55,7 @@ import android.os.RemoteException;
import android.util.Log;
import android.util.Rational;
import android.util.Size;
import android.view.Display;
import android.view.SurfaceControl;
import android.window.TaskOrganizer;
import android.window.WindowContainerToken;
@@ -324,7 +325,7 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
mPipUiEventLoggerLogger.log(
PipUiEventLogger.PipUiEventEnum.PICTURE_IN_PICTURE_EXPAND_TO_FULLSCREEN);
final boolean orientationDiffers = initialConfig.windowConfiguration.getRotation()
!= mPipBoundsState.getDisplayInfo().rotation;
!= mPipBoundsState.getDisplayLayout().rotation();
final WindowContainerTransaction wct = new WindowContainerTransaction();
final Rect destinationBounds = initialConfig.windowConfiguration.getBounds();
final int direction = syncWithSplitScreenBounds(destinationBounds)
@@ -437,7 +438,7 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
// If the displayId of the task is different than what PipBoundsHandler has, then update
// it. This is possible if we entered PiP on an external display.
if (info.displayId != mPipBoundsState.getDisplayInfo().displayId
if (info.displayId != mPipBoundsState.getDisplayId()
&& mOnDisplayIdChangeCallback != null) {
mOnDisplayIdChangeCallback.accept(info.displayId);
}
@@ -605,6 +606,10 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
mState = State.UNDEFINED;
mPipUiEventLoggerLogger.setTaskInfo(null);
mPipMenuController.detach();
if (info.displayId != Display.DEFAULT_DISPLAY && mOnDisplayIdChangeCallback != null) {
mOnDisplayIdChangeCallback.accept(Display.DEFAULT_DISPLAY);
}
}
@Override

View File

@@ -19,8 +19,6 @@ package com.android.wm.shell.pip.phone;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
import static android.content.pm.PackageManager.FEATURE_PICTURE_IN_PICTURE;
import static android.view.Surface.ROTATION_0;
import static android.view.Surface.ROTATION_180;
import static android.view.WindowManager.INPUT_CONSUMER_PIP;
import static com.android.wm.shell.pip.PipAnimationController.isOutPipDirection;
@@ -86,7 +84,6 @@ public class PipController implements PipTaskOrganizer.PipTransitionCallback {
private PipTouchHandler mTouchHandler;
protected final PipImpl mImpl = new PipImpl();
private final DisplayInfo mTmpDisplayInfo = new DisplayInfo();
private final Rect mTmpInsetBounds = new Rect();
private boolean mIsInFixedRotation;
@@ -145,7 +142,7 @@ public class PipController implements PipTaskOrganizer.PipTransitionCallback {
}
};
private final DisplayController.OnDisplaysChangedListener mFixedRotationListener =
private final DisplayController.OnDisplaysChangedListener mDisplaysChangedListener =
new DisplayController.OnDisplaysChangedListener() {
@Override
public void onFixedRotationStarted(int displayId, int newRotation) {
@@ -159,8 +156,20 @@ public class PipController implements PipTaskOrganizer.PipTransitionCallback {
@Override
public void onDisplayAdded(int displayId) {
mPipBoundsState.setDisplayLayout(
mDisplayController.getDisplayLayout(displayId));
if (displayId != mPipBoundsState.getDisplayId()) {
return;
}
onDisplayChanged(mDisplayController.getDisplayLayout(displayId),
false /* saveRestoreSnapFraction */);
}
@Override
public void onDisplayConfigurationChanged(int displayId, Configuration newConfig) {
if (displayId != mPipBoundsState.getDisplayId()) {
return;
}
onDisplayChanged(mDisplayController.getDisplayLayout(displayId),
true /* saveRestoreSnapFraction */);
}
};
@@ -261,12 +270,9 @@ public class PipController implements PipTaskOrganizer.PipTransitionCallback {
INPUT_CONSUMER_PIP, mainExecutor);
mPipTaskOrganizer.registerPipTransitionCallback(this);
mPipTaskOrganizer.registerOnDisplayIdChangeCallback((int displayId) -> {
final DisplayInfo newDisplayInfo = new DisplayInfo();
displayController.getDisplay(displayId).getDisplayInfo(newDisplayInfo);
mPipBoundsState.setDisplayInfo(newDisplayInfo);
updateMovementBounds(null /* toBounds */, false /* fromRotation */,
false /* fromImeAdjustment */, false /* fromShelfAdjustment */,
null /* wct */);
mPipBoundsState.setDisplayId(displayId);
onDisplayChanged(displayController.getDisplayLayout(displayId),
false /* saveRestoreSnapFraction */);
});
mPipBoundsState.setOnMinimalSizeChangeCallback(
() -> {
@@ -291,13 +297,12 @@ public class PipController implements PipTaskOrganizer.PipTransitionCallback {
mPipInputConsumer.setRegistrationListener(mTouchHandler::onRegistrationChanged);
}
displayController.addDisplayChangingController(mRotationController);
displayController.addDisplayWindowListener(mFixedRotationListener);
displayController.addDisplayWindowListener(mDisplaysChangedListener);
// Ensure that we have the display info in case we get calls to update the bounds before the
// listener calls back
final DisplayInfo displayInfo = new DisplayInfo();
context.getDisplay().getDisplayInfo(displayInfo);
mPipBoundsState.setDisplayInfo(displayInfo);
mPipBoundsState.setDisplayId(context.getDisplayId());
mPipBoundsState.setDisplayLayout(new DisplayLayout(context, context.getDisplay()));
try {
mWindowManagerShellWrapper.addPinnedStackListener(mPinnedStackListener);
@@ -363,11 +368,42 @@ public class PipController implements PipTaskOrganizer.PipTransitionCallback {
}
private void onOverlayChanged() {
mPipBoundsState.setDisplayLayout(new DisplayLayout(mContext, mContext.getDisplay()));
updateMovementBounds(null /* toBounds */,
false /* fromRotation */, false /* fromImeAdjustment */,
false /* fromShelfAdjustment */,
null /* windowContainerTransaction */);
onDisplayChanged(new DisplayLayout(mContext, mContext.getDisplay()),
false /* saveRestoreSnapFraction */);
}
private void onDisplayChanged(DisplayLayout layout, boolean saveRestoreSnapFraction) {
Runnable updateDisplayLayout = () -> {
mPipBoundsState.setDisplayLayout(layout);
updateMovementBounds(null /* toBounds */,
false /* fromRotation */, false /* fromImeAdjustment */,
false /* fromShelfAdjustment */,
null /* windowContainerTransaction */);
};
if (saveRestoreSnapFraction) {
// Calculate the snap fraction of the current stack along the old movement bounds
final PipSnapAlgorithm pipSnapAlgorithm = mPipBoundsAlgorithm.getSnapAlgorithm();
final Rect postChangeStackBounds = new Rect(mPipBoundsState.getBounds());
final float snapFraction = pipSnapAlgorithm.getSnapFraction(postChangeStackBounds,
mPipBoundsAlgorithm.getMovementBounds(postChangeStackBounds),
mPipBoundsState.getStashedState());
updateDisplayLayout.run();
// Calculate the stack bounds in the new orientation based on same fraction along the
// rotated movement bounds.
final Rect postChangeMovementBounds = mPipBoundsAlgorithm.getMovementBounds(
postChangeStackBounds, false /* adjustForIme */);
pipSnapAlgorithm.applySnapFraction(postChangeStackBounds, postChangeMovementBounds,
snapFraction, mPipBoundsState.getStashedState(),
mPipBoundsState.getStashOffset(),
mPipBoundsState.getDisplayBounds());
mTouchHandler.getMotionHelper().movePip(postChangeStackBounds);
} else {
updateDisplayLayout.run();
}
}
private void registerSessionListenerForCurrentUser() {
@@ -500,7 +536,7 @@ public class PipController implements PipTaskOrganizer.PipTransitionCallback {
// Populate inset / normal bounds and DisplayInfo from mPipBoundsHandler before
// passing to mTouchHandler/mPipTaskOrganizer
final Rect outBounds = new Rect(toBounds);
mTmpDisplayInfo.copyFrom(mPipBoundsState.getDisplayInfo());
final int rotation = mPipBoundsState.getDisplayLayout().rotation();
mPipBoundsAlgorithm.getInsetBounds(mTmpInsetBounds);
mPipBoundsState.setNormalBounds(mPipBoundsAlgorithm.getNormalBounds());
@@ -512,8 +548,7 @@ public class PipController implements PipTaskOrganizer.PipTransitionCallback {
mPipTaskOrganizer.onMovementBoundsChanged(outBounds, fromRotation, fromImeAdjustment,
fromShelfAdjustment, wct);
mTouchHandler.onMovementBoundsChanged(mTmpInsetBounds, mPipBoundsState.getNormalBounds(),
outBounds, fromImeAdjustment, fromShelfAdjustment,
mTmpDisplayInfo.rotation);
outBounds, fromImeAdjustment, fromShelfAdjustment, rotation);
}
/**
@@ -525,13 +560,6 @@ public class PipController implements PipTaskOrganizer.PipTransitionCallback {
// Update the display layout, note that we have to do this on every rotation even if we
// aren't in PIP since we need to update the display layout to get the right resources
mPipBoundsState.getDisplayLayout().rotateTo(context.getResources(), toRotation);
// Populate the new {@link #mDisplayInfo}.
// The {@link DisplayInfo} queried from DisplayManager would be the one before rotation,
// therefore, the width/height may require a swap first.
// Moving forward, we should get the new dimensions after rotation from DisplayLayout.
mPipBoundsState.setDisplayRotation(toRotation);
updateDisplayInfoIfNeeded();
}
/**
@@ -543,9 +571,8 @@ public class PipController implements PipTaskOrganizer.PipTransitionCallback {
private boolean onDisplayRotationChanged(Context context, Rect outBounds, Rect oldBounds,
Rect outInsetBounds,
int displayId, int fromRotation, int toRotation, WindowContainerTransaction t) {
// Bail early if the event is not sent to current {@link #mDisplayInfo}
if ((displayId != mPipBoundsState.getDisplayInfo().displayId)
|| (fromRotation == toRotation)) {
// Bail early if the event is not sent to current display
if ((displayId != mPipBoundsState.getDisplayId()) || (fromRotation == toRotation)) {
return false;
}
@@ -570,13 +597,6 @@ public class PipController implements PipTaskOrganizer.PipTransitionCallback {
// Update the display layout
mPipBoundsState.getDisplayLayout().rotateTo(context.getResources(), toRotation);
// Populate the new {@link #mDisplayInfo}.
// The {@link DisplayInfo} queried from DisplayManager would be the one before rotation,
// therefore, the width/height may require a swap first.
// Moving forward, we should get the new dimensions after rotation from DisplayLayout.
mPipBoundsState.getDisplayInfo().rotation = toRotation;
updateDisplayInfoIfNeeded();
// Calculate the stack bounds in the new orientation based on same fraction along the
// rotated movement bounds.
final Rect postChangeMovementBounds = mPipBoundsAlgorithm.getMovementBounds(
@@ -591,21 +611,6 @@ public class PipController implements PipTaskOrganizer.PipTransitionCallback {
return true;
}
private void updateDisplayInfoIfNeeded() {
final DisplayInfo displayInfo = mPipBoundsState.getDisplayInfo();
final boolean updateNeeded;
if ((displayInfo.rotation == ROTATION_0) || (displayInfo.rotation == ROTATION_180)) {
updateNeeded = (displayInfo.logicalWidth > displayInfo.logicalHeight);
} else {
updateNeeded = (displayInfo.logicalWidth < displayInfo.logicalHeight);
}
if (updateNeeded) {
final int newLogicalHeight = displayInfo.logicalWidth;
displayInfo.logicalWidth = displayInfo.logicalHeight;
displayInfo.logicalHeight = newLogicalHeight;
}
}
private void dump(PrintWriter pw) {
final String innerPrefix = " ";
pw.println(TAG);

View File

@@ -36,6 +36,7 @@ import android.view.DisplayInfo;
import com.android.wm.shell.R;
import com.android.wm.shell.WindowManagerShellWrapper;
import com.android.wm.shell.common.DisplayLayout;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.TaskStackListenerCallback;
import com.android.wm.shell.common.TaskStackListenerImpl;
@@ -138,7 +139,8 @@ public class TvPipController implements PipTaskOrganizer.PipTransitionCallback,
mMainExecutor = mainExecutor;
mPipBoundsState = pipBoundsState;
mPipBoundsState.setDisplayInfo(getDisplayInfo());
mPipBoundsState.setDisplayId(context.getDisplayId());
mPipBoundsState.setDisplayLayout(new DisplayLayout(context, context.getDisplay()));
mPipBoundsAlgorithm = pipBoundsAlgorithm;
mPipMediaController = pipMediaController;

View File

@@ -24,12 +24,14 @@ import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.testing.TestableResources;
import android.util.Size;
import android.view.Display;
import android.view.DisplayInfo;
import android.view.Gravity;
import androidx.test.filters.SmallTest;
import com.android.wm.shell.ShellTestCase;
import com.android.wm.shell.common.DisplayLayout;
import org.junit.Before;
import org.junit.Test;
@@ -62,7 +64,8 @@ public class PipBoundsAlgorithmTest extends ShellTestCase {
mPipBoundsState = new PipBoundsState(mContext);
mPipBoundsAlgorithm = new PipBoundsAlgorithm(mContext, mPipBoundsState);
mPipBoundsState.setDisplayInfo(mDefaultDisplayInfo);
mPipBoundsState.setDisplayLayout(
new DisplayLayout(mDefaultDisplayInfo, mContext.getResources(), true, true));
}
private void initializeMockResources() {

View File

@@ -38,6 +38,7 @@ import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.util.Rational;
import android.util.Size;
import android.view.Display;
import android.view.DisplayInfo;
import android.window.WindowContainerToken;
@@ -45,6 +46,7 @@ import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.ShellTestCase;
import com.android.wm.shell.TestShellExecutor;
import com.android.wm.shell.common.DisplayController;
import com.android.wm.shell.common.DisplayLayout;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.pip.phone.PhonePipMenuController;
import com.android.wm.shell.legacysplitscreen.LegacySplitScreen;
@@ -196,11 +198,11 @@ public class PipTaskOrganizerTest extends ShellTestCase {
private void preparePipTaskOrg() {
final DisplayInfo info = new DisplayInfo();
mPipBoundsState.setDisplayInfo(info);
mPipBoundsState.setDisplayLayout(new DisplayLayout(info,
mContext.getResources(), true, true));
when(mMockPipBoundsAlgorithm.getEntryDestinationBounds()).thenReturn(new Rect());
when(mMockPipBoundsAlgorithm.getAdjustedDestinationBounds(any(), anyFloat()))
.thenReturn(new Rect());
mPipBoundsState.setDisplayInfo(info);
mSpiedPipTaskOrganizer.setOneShotAnimationType(PipAnimationController.ANIM_TYPE_ALPHA);
doNothing().when(mSpiedPipTaskOrganizer).enterPipWithAlphaAnimation(any(), anyLong());
doNothing().when(mSpiedPipTaskOrganizer).scheduleAnimateResizePip(any(), anyInt(), any());