Loading core/java/android/app/TaskInfo.java +21 −3 Original line number Diff line number Diff line Loading @@ -23,6 +23,7 @@ import android.annotation.Nullable; import android.compat.annotation.UnsupportedAppUsage; import android.content.ComponentName; import android.content.Intent; import android.content.pm.ActivityInfo; import android.content.res.Configuration; import android.os.Parcel; import android.os.RemoteException; Loading Loading @@ -161,6 +162,13 @@ public class TaskInfo { */ public @WindowConfiguration.ActivityType int topActivityType; /** * The {@link ActivityInfo} of the top activity in this task. * @hide */ @Nullable public ActivityInfo topActivityInfo; TaskInfo() { // Do nothing } Loading Loading @@ -219,6 +227,9 @@ public class TaskInfo { pictureInPictureParams = source.readInt() != 0 ? PictureInPictureParams.CREATOR.createFromParcel(source) : null; topActivityInfo = source.readInt() != 0 ? ActivityInfo.CREATOR.createFromParcel(source) : null; } /** Loading Loading @@ -262,6 +273,12 @@ public class TaskInfo { dest.writeInt(1); pictureInPictureParams.writeToParcel(dest, flags); } if (topActivityInfo == null) { dest.writeInt(0); } else { dest.writeInt(1); topActivityInfo.writeToParcel(dest, flags); } } @Override Loading @@ -278,6 +295,7 @@ public class TaskInfo { + " resizeMode=" + resizeMode + " token=" + token + " topActivityType=" + topActivityType + " pictureInPictureParams=" + pictureInPictureParams; + " pictureInPictureParams=" + pictureInPictureParams + " topActivityInfo=" + topActivityInfo; } } packages/SystemUI/src/com/android/systemui/pip/PipBoundsHandler.java +34 −3 Original line number Diff line number Diff line Loading @@ -67,7 +67,7 @@ public class PipBoundsHandler { private ComponentName mLastPipComponentName; private float mReentrySnapFraction = INVALID_SNAP_FRACTION; private Size mReentrySize = null; private Size mReentrySize; private float mDefaultAspectRatio; private float mMinAspectRatio; Loading @@ -77,6 +77,7 @@ public class PipBoundsHandler { private int mDefaultMinSize; private Point mScreenEdgeInsets; private int mCurrentMinSize; private Size mOverrideMinimalSize; private boolean mIsImeShowing; private int mImeHeight; Loading Loading @@ -226,11 +227,14 @@ public class PipBoundsHandler { /** * @return {@link Rect} of the destination PiP window bounds. */ Rect getDestinationBounds(float aspectRatio, Rect bounds) { Rect getDestinationBounds(float aspectRatio, Rect bounds, Size minimalSize) { final Rect destinationBounds; final Rect defaultBounds = getDefaultBounds(mReentrySnapFraction, mReentrySize); if (bounds == null) { destinationBounds = new Rect(defaultBounds); if (mReentrySnapFraction == INVALID_SNAP_FRACTION && mReentrySize == null) { mOverrideMinimalSize = minimalSize; } } else { destinationBounds = new Rect(bounds); } Loading Loading @@ -335,7 +339,6 @@ public class PipBoundsHandler { */ private void transformBoundsToAspectRatio(Rect stackBounds, float aspectRatio, boolean useCurrentMinEdgeSize) { // Save the snap fraction and adjust the size based on the new aspect ratio. final float snapFraction = mSnapAlgorithm.getSnapFraction(stackBounds, getMovementBounds(stackBounds)); Loading @@ -354,9 +357,37 @@ public class PipBoundsHandler { final int left = (int) (stackBounds.centerX() - size.getWidth() / 2f); final int top = (int) (stackBounds.centerY() - size.getHeight() / 2f); stackBounds.set(left, top, left + size.getWidth(), top + size.getHeight()); // apply the override minimal size if applicable, this minimal size is specified by app if (mOverrideMinimalSize != null) { transformBoundsToMinimalSize(stackBounds, aspectRatio, mOverrideMinimalSize); } mSnapAlgorithm.applySnapFraction(stackBounds, getMovementBounds(stackBounds), snapFraction); } /** * Transforms a given bounds to meet the minimal size constraints. * This function assumes the given {@param stackBounds} qualifies {@param aspectRatio}. */ private void transformBoundsToMinimalSize(Rect stackBounds, float aspectRatio, Size minimalSize) { if (minimalSize == null) return; final Size adjustedMinimalSize; final float minimalSizeAspectRatio = minimalSize.getWidth() / (float) minimalSize.getHeight(); if (minimalSizeAspectRatio > aspectRatio) { // minimal size is wider, fixed the width and increase the height adjustedMinimalSize = new Size( minimalSize.getWidth(), (int) (minimalSize.getWidth() / aspectRatio)); } else { adjustedMinimalSize = new Size( (int) (minimalSize.getHeight() * aspectRatio), minimalSize.getHeight()); } final Rect containerBounds = new Rect(stackBounds); Gravity.apply(mDefaultStackGravity, adjustedMinimalSize.getWidth(), adjustedMinimalSize.getHeight(), containerBounds, stackBounds); } /** * @return the default bounds to show the PIP, if a {@param snapFraction} and {@param size} are * provided, then it will apply the default bounds to the provided snap fraction and size. Loading packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java +14 −17 Original line number Diff line number Diff line Loading @@ -30,11 +30,13 @@ import android.app.ActivityTaskManager; import android.app.ITaskOrganizerController; import android.app.PictureInPictureParams; import android.content.Context; import android.content.pm.ActivityInfo; import android.graphics.Rect; import android.os.Handler; import android.os.Looper; import android.os.RemoteException; import android.util.Log; import android.util.Size; import android.view.ITaskOrganizer; import android.view.IWindowContainer; import android.view.SurfaceControl; Loading Loading @@ -204,26 +206,12 @@ public class PipTaskOrganizer extends ITaskOrganizer.Stub { mOneShotAnimationType = animationType; } /** * Callback to issue the final {@link WindowContainerTransaction} on end of movements. * @param destinationBounds the final bounds. */ public void onMotionMovementEnd(Rect destinationBounds) { try { mLastReportedBounds.set(destinationBounds); final WindowContainerTransaction wct = new WindowContainerTransaction(); wct.setBounds(mToken, destinationBounds); mTaskOrganizerController.applyContainerTransaction(wct, null /* ITaskOrganizer */); } catch (RemoteException e) { Log.w(TAG, "Failed to apply window container transaction", e); } } @Override public void taskAppeared(ActivityManager.RunningTaskInfo info) { Objects.requireNonNull(info, "Requires RunningTaskInfo"); final Rect destinationBounds = mPipBoundsHandler.getDestinationBounds( getAspectRatioOrDefault(info.pictureInPictureParams), null /* bounds */); getAspectRatioOrDefault(info.pictureInPictureParams), null /* bounds */, getMinimalSize(info.topActivityInfo)); Objects.requireNonNull(destinationBounds, "Missing destination bounds"); mTaskInfo = info; mToken = mTaskInfo.token; Loading Loading @@ -276,7 +264,8 @@ public class PipTaskOrganizer extends ITaskOrganizer.Stub { return; } final Rect destinationBounds = mPipBoundsHandler.getDestinationBounds( getAspectRatioOrDefault(newParams), null /* bounds */); getAspectRatioOrDefault(newParams), null /* bounds */, getMinimalSize(info.topActivityInfo)); Objects.requireNonNull(destinationBounds, "Missing destination bounds"); scheduleAnimateResizePip(destinationBounds, mEnterExitAnimationDuration, null); } Loading Loading @@ -446,6 +435,14 @@ public class PipTaskOrganizer extends ITaskOrganizer.Stub { .start()); } private Size getMinimalSize(ActivityInfo activityInfo) { if (activityInfo == null || activityInfo.windowLayout == null) { return null; } final ActivityInfo.WindowLayout windowLayout = activityInfo.windowLayout; return new Size(windowLayout.minWidth, windowLayout.minHeight); } private float getAspectRatioOrDefault(@Nullable PictureInPictureParams params) { return params == null ? mPipBoundsHandler.getDefaultAspectRatio() Loading packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java +1 −1 Original line number Diff line number Diff line Loading @@ -426,7 +426,7 @@ public class PipMotionHelper implements PipAppOpsListener.Callback, cancelAnimations(); mAnimatedBoundsPhysicsAnimator .withEndActions(() -> mPipTaskOrganizer.onMotionMovementEnd(mAnimatedBounds)) .withEndActions(() -> mPipTaskOrganizer.scheduleFinishResizePip(mAnimatedBounds)) .addUpdateListener(mResizePipUpdateListener) .start(); } Loading packages/SystemUI/tests/src/com/android/systemui/pip/PipBoundsHandlerTest.java +59 −13 Original line number Diff line number Diff line Loading @@ -24,6 +24,7 @@ import android.graphics.Rect; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; import android.testing.TestableResources; import android.util.Size; import android.view.DisplayInfo; import android.view.Gravity; Loading Loading @@ -51,6 +52,7 @@ public class PipBoundsHandlerTest extends SysuiTestCase { private static final float MIN_ASPECT_RATIO = 0.5f; private static final float MAX_ASPECT_RATIO = 2f; private static final Rect EMPTY_CURRENT_BOUNDS = null; private static final Size EMPTY_MINIMAL_SIZE = null; private PipBoundsHandler mPipBoundsHandler; private DisplayInfo mDefaultDisplayInfo; Loading Loading @@ -119,7 +121,7 @@ public class PipBoundsHandlerTest extends SysuiTestCase { }; for (float aspectRatio : aspectRatios) { final Rect destinationBounds = mPipBoundsHandler.getDestinationBounds( aspectRatio, EMPTY_CURRENT_BOUNDS); aspectRatio, EMPTY_CURRENT_BOUNDS, EMPTY_MINIMAL_SIZE); final float actualAspectRatio = destinationBounds.width() / (destinationBounds.height() * 1f); assertEquals("Destination bounds matches the given aspect ratio", Loading @@ -135,7 +137,7 @@ public class PipBoundsHandlerTest extends SysuiTestCase { }; for (float aspectRatio : invalidAspectRatios) { final Rect destinationBounds = mPipBoundsHandler.getDestinationBounds( aspectRatio, EMPTY_CURRENT_BOUNDS); aspectRatio, EMPTY_CURRENT_BOUNDS, EMPTY_MINIMAL_SIZE); final float actualAspectRatio = destinationBounds.width() / (destinationBounds.height() * 1f); assertEquals("Destination bounds fallbacks to default aspect ratio", Loading @@ -151,7 +153,7 @@ public class PipBoundsHandlerTest extends SysuiTestCase { currentBounds.right = (int) (currentBounds.height() * aspectRatio) + currentBounds.left; final Rect destinationBounds = mPipBoundsHandler.getDestinationBounds( aspectRatio, currentBounds); aspectRatio, currentBounds, EMPTY_MINIMAL_SIZE); final float actualAspectRatio = destinationBounds.width() / (destinationBounds.height() * 1f); Loading @@ -159,15 +161,59 @@ public class PipBoundsHandlerTest extends SysuiTestCase { aspectRatio, actualAspectRatio, ASPECT_RATIO_ERROR_MARGIN); } @Test public void getDestinationBounds_withMinSize_returnMinBounds() { final float[] aspectRatios = new float[] { (MIN_ASPECT_RATIO + DEFAULT_ASPECT_RATIO) / 2, DEFAULT_ASPECT_RATIO, (MAX_ASPECT_RATIO + DEFAULT_ASPECT_RATIO) / 2 }; final Size[] minimalSizes = new Size[] { new Size((int) (100 * aspectRatios[0]), 100), new Size((int) (100 * aspectRatios[1]), 100), new Size((int) (100 * aspectRatios[2]), 100) }; for (int i = 0; i < aspectRatios.length; i++) { final float aspectRatio = aspectRatios[i]; final Size minimalSize = minimalSizes[i]; final Rect destinationBounds = mPipBoundsHandler.getDestinationBounds( aspectRatio, EMPTY_CURRENT_BOUNDS, minimalSize); assertTrue("Destination bounds is no smaller than minimal requirement", (destinationBounds.width() == minimalSize.getWidth() && destinationBounds.height() >= minimalSize.getHeight()) || (destinationBounds.height() == minimalSize.getHeight() && destinationBounds.width() >= minimalSize.getWidth())); final float actualAspectRatio = destinationBounds.width() / (destinationBounds.height() * 1f); assertEquals("Destination bounds matches the given aspect ratio", aspectRatio, actualAspectRatio, ASPECT_RATIO_ERROR_MARGIN); } } @Test public void getDestinationBounds_withCurrentBounds_ignoreMinBounds() { final float aspectRatio = (DEFAULT_ASPECT_RATIO + MAX_ASPECT_RATIO) / 2; final Rect currentBounds = new Rect(0, 0, 0, 100); currentBounds.right = (int) (currentBounds.height() * aspectRatio) + currentBounds.left; final Size minSize = new Size(currentBounds.width() / 2, currentBounds.height() / 2); final Rect destinationBounds = mPipBoundsHandler.getDestinationBounds( aspectRatio, currentBounds, minSize); assertTrue("Destination bounds ignores minimal size", destinationBounds.width() > minSize.getWidth() && destinationBounds.height() > minSize.getHeight()); } @Test public void setShelfHeight_offsetBounds() { final int shelfHeight = 100; final Rect oldPosition = mPipBoundsHandler.getDestinationBounds( DEFAULT_ASPECT_RATIO, EMPTY_CURRENT_BOUNDS); DEFAULT_ASPECT_RATIO, EMPTY_CURRENT_BOUNDS, EMPTY_MINIMAL_SIZE); mPipBoundsHandler.setShelfHeight(true, shelfHeight); final Rect newPosition = mPipBoundsHandler.getDestinationBounds( DEFAULT_ASPECT_RATIO, EMPTY_CURRENT_BOUNDS); DEFAULT_ASPECT_RATIO, EMPTY_CURRENT_BOUNDS, EMPTY_MINIMAL_SIZE); oldPosition.offset(0, -shelfHeight); assertBoundsWithMargin("offsetBounds by shelf", oldPosition, newPosition); Loading @@ -177,11 +223,11 @@ public class PipBoundsHandlerTest extends SysuiTestCase { public void onImeVisibilityChanged_offsetBounds() { final int imeHeight = 100; final Rect oldPosition = mPipBoundsHandler.getDestinationBounds( DEFAULT_ASPECT_RATIO, EMPTY_CURRENT_BOUNDS); DEFAULT_ASPECT_RATIO, EMPTY_CURRENT_BOUNDS, EMPTY_MINIMAL_SIZE); mPipBoundsHandler.onImeVisibilityChanged(true, imeHeight); final Rect newPosition = mPipBoundsHandler.getDestinationBounds( DEFAULT_ASPECT_RATIO, EMPTY_CURRENT_BOUNDS); DEFAULT_ASPECT_RATIO, EMPTY_CURRENT_BOUNDS, EMPTY_MINIMAL_SIZE); oldPosition.offset(0, -imeHeight); assertBoundsWithMargin("offsetBounds by IME", oldPosition, newPosition); Loading @@ -191,13 +237,13 @@ public class PipBoundsHandlerTest extends SysuiTestCase { public void onSaveReentryBounds_restoreLastPosition() { final ComponentName componentName = new ComponentName(mContext, "component1"); final Rect oldPosition = mPipBoundsHandler.getDestinationBounds( DEFAULT_ASPECT_RATIO, EMPTY_CURRENT_BOUNDS); DEFAULT_ASPECT_RATIO, EMPTY_CURRENT_BOUNDS, EMPTY_MINIMAL_SIZE); oldPosition.offset(0, -100); mPipBoundsHandler.onSaveReentryBounds(componentName, oldPosition); final Rect newPosition = mPipBoundsHandler.getDestinationBounds( DEFAULT_ASPECT_RATIO, EMPTY_CURRENT_BOUNDS); DEFAULT_ASPECT_RATIO, EMPTY_CURRENT_BOUNDS, EMPTY_MINIMAL_SIZE); assertBoundsWithMargin("restoreLastPosition", oldPosition, newPosition); } Loading @@ -206,14 +252,14 @@ public class PipBoundsHandlerTest extends SysuiTestCase { public void onResetReentryBounds_useDefaultBounds() { final ComponentName componentName = new ComponentName(mContext, "component1"); final Rect defaultBounds = mPipBoundsHandler.getDestinationBounds( DEFAULT_ASPECT_RATIO, EMPTY_CURRENT_BOUNDS); DEFAULT_ASPECT_RATIO, EMPTY_CURRENT_BOUNDS, EMPTY_MINIMAL_SIZE); final Rect newBounds = new Rect(defaultBounds); newBounds.offset(0, -100); mPipBoundsHandler.onSaveReentryBounds(componentName, newBounds); mPipBoundsHandler.onResetReentryBounds(componentName); final Rect actualBounds = mPipBoundsHandler.getDestinationBounds( DEFAULT_ASPECT_RATIO, EMPTY_CURRENT_BOUNDS); DEFAULT_ASPECT_RATIO, EMPTY_CURRENT_BOUNDS, EMPTY_MINIMAL_SIZE); assertBoundsWithMargin("useDefaultBounds", defaultBounds, actualBounds); } Loading @@ -222,14 +268,14 @@ public class PipBoundsHandlerTest extends SysuiTestCase { public void onResetReentryBounds_componentMismatch_restoreLastPosition() { final ComponentName componentName = new ComponentName(mContext, "component1"); final Rect defaultBounds = mPipBoundsHandler.getDestinationBounds( DEFAULT_ASPECT_RATIO, EMPTY_CURRENT_BOUNDS); DEFAULT_ASPECT_RATIO, EMPTY_CURRENT_BOUNDS, EMPTY_MINIMAL_SIZE); final Rect newBounds = new Rect(defaultBounds); newBounds.offset(0, -100); mPipBoundsHandler.onSaveReentryBounds(componentName, newBounds); mPipBoundsHandler.onResetReentryBounds(new ComponentName(mContext, "component2")); final Rect actualBounds = mPipBoundsHandler.getDestinationBounds( DEFAULT_ASPECT_RATIO, EMPTY_CURRENT_BOUNDS); DEFAULT_ASPECT_RATIO, EMPTY_CURRENT_BOUNDS, EMPTY_MINIMAL_SIZE); assertBoundsWithMargin("restoreLastPosition", newBounds, actualBounds); } Loading Loading
core/java/android/app/TaskInfo.java +21 −3 Original line number Diff line number Diff line Loading @@ -23,6 +23,7 @@ import android.annotation.Nullable; import android.compat.annotation.UnsupportedAppUsage; import android.content.ComponentName; import android.content.Intent; import android.content.pm.ActivityInfo; import android.content.res.Configuration; import android.os.Parcel; import android.os.RemoteException; Loading Loading @@ -161,6 +162,13 @@ public class TaskInfo { */ public @WindowConfiguration.ActivityType int topActivityType; /** * The {@link ActivityInfo} of the top activity in this task. * @hide */ @Nullable public ActivityInfo topActivityInfo; TaskInfo() { // Do nothing } Loading Loading @@ -219,6 +227,9 @@ public class TaskInfo { pictureInPictureParams = source.readInt() != 0 ? PictureInPictureParams.CREATOR.createFromParcel(source) : null; topActivityInfo = source.readInt() != 0 ? ActivityInfo.CREATOR.createFromParcel(source) : null; } /** Loading Loading @@ -262,6 +273,12 @@ public class TaskInfo { dest.writeInt(1); pictureInPictureParams.writeToParcel(dest, flags); } if (topActivityInfo == null) { dest.writeInt(0); } else { dest.writeInt(1); topActivityInfo.writeToParcel(dest, flags); } } @Override Loading @@ -278,6 +295,7 @@ public class TaskInfo { + " resizeMode=" + resizeMode + " token=" + token + " topActivityType=" + topActivityType + " pictureInPictureParams=" + pictureInPictureParams; + " pictureInPictureParams=" + pictureInPictureParams + " topActivityInfo=" + topActivityInfo; } }
packages/SystemUI/src/com/android/systemui/pip/PipBoundsHandler.java +34 −3 Original line number Diff line number Diff line Loading @@ -67,7 +67,7 @@ public class PipBoundsHandler { private ComponentName mLastPipComponentName; private float mReentrySnapFraction = INVALID_SNAP_FRACTION; private Size mReentrySize = null; private Size mReentrySize; private float mDefaultAspectRatio; private float mMinAspectRatio; Loading @@ -77,6 +77,7 @@ public class PipBoundsHandler { private int mDefaultMinSize; private Point mScreenEdgeInsets; private int mCurrentMinSize; private Size mOverrideMinimalSize; private boolean mIsImeShowing; private int mImeHeight; Loading Loading @@ -226,11 +227,14 @@ public class PipBoundsHandler { /** * @return {@link Rect} of the destination PiP window bounds. */ Rect getDestinationBounds(float aspectRatio, Rect bounds) { Rect getDestinationBounds(float aspectRatio, Rect bounds, Size minimalSize) { final Rect destinationBounds; final Rect defaultBounds = getDefaultBounds(mReentrySnapFraction, mReentrySize); if (bounds == null) { destinationBounds = new Rect(defaultBounds); if (mReentrySnapFraction == INVALID_SNAP_FRACTION && mReentrySize == null) { mOverrideMinimalSize = minimalSize; } } else { destinationBounds = new Rect(bounds); } Loading Loading @@ -335,7 +339,6 @@ public class PipBoundsHandler { */ private void transformBoundsToAspectRatio(Rect stackBounds, float aspectRatio, boolean useCurrentMinEdgeSize) { // Save the snap fraction and adjust the size based on the new aspect ratio. final float snapFraction = mSnapAlgorithm.getSnapFraction(stackBounds, getMovementBounds(stackBounds)); Loading @@ -354,9 +357,37 @@ public class PipBoundsHandler { final int left = (int) (stackBounds.centerX() - size.getWidth() / 2f); final int top = (int) (stackBounds.centerY() - size.getHeight() / 2f); stackBounds.set(left, top, left + size.getWidth(), top + size.getHeight()); // apply the override minimal size if applicable, this minimal size is specified by app if (mOverrideMinimalSize != null) { transformBoundsToMinimalSize(stackBounds, aspectRatio, mOverrideMinimalSize); } mSnapAlgorithm.applySnapFraction(stackBounds, getMovementBounds(stackBounds), snapFraction); } /** * Transforms a given bounds to meet the minimal size constraints. * This function assumes the given {@param stackBounds} qualifies {@param aspectRatio}. */ private void transformBoundsToMinimalSize(Rect stackBounds, float aspectRatio, Size minimalSize) { if (minimalSize == null) return; final Size adjustedMinimalSize; final float minimalSizeAspectRatio = minimalSize.getWidth() / (float) minimalSize.getHeight(); if (minimalSizeAspectRatio > aspectRatio) { // minimal size is wider, fixed the width and increase the height adjustedMinimalSize = new Size( minimalSize.getWidth(), (int) (minimalSize.getWidth() / aspectRatio)); } else { adjustedMinimalSize = new Size( (int) (minimalSize.getHeight() * aspectRatio), minimalSize.getHeight()); } final Rect containerBounds = new Rect(stackBounds); Gravity.apply(mDefaultStackGravity, adjustedMinimalSize.getWidth(), adjustedMinimalSize.getHeight(), containerBounds, stackBounds); } /** * @return the default bounds to show the PIP, if a {@param snapFraction} and {@param size} are * provided, then it will apply the default bounds to the provided snap fraction and size. Loading
packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java +14 −17 Original line number Diff line number Diff line Loading @@ -30,11 +30,13 @@ import android.app.ActivityTaskManager; import android.app.ITaskOrganizerController; import android.app.PictureInPictureParams; import android.content.Context; import android.content.pm.ActivityInfo; import android.graphics.Rect; import android.os.Handler; import android.os.Looper; import android.os.RemoteException; import android.util.Log; import android.util.Size; import android.view.ITaskOrganizer; import android.view.IWindowContainer; import android.view.SurfaceControl; Loading Loading @@ -204,26 +206,12 @@ public class PipTaskOrganizer extends ITaskOrganizer.Stub { mOneShotAnimationType = animationType; } /** * Callback to issue the final {@link WindowContainerTransaction} on end of movements. * @param destinationBounds the final bounds. */ public void onMotionMovementEnd(Rect destinationBounds) { try { mLastReportedBounds.set(destinationBounds); final WindowContainerTransaction wct = new WindowContainerTransaction(); wct.setBounds(mToken, destinationBounds); mTaskOrganizerController.applyContainerTransaction(wct, null /* ITaskOrganizer */); } catch (RemoteException e) { Log.w(TAG, "Failed to apply window container transaction", e); } } @Override public void taskAppeared(ActivityManager.RunningTaskInfo info) { Objects.requireNonNull(info, "Requires RunningTaskInfo"); final Rect destinationBounds = mPipBoundsHandler.getDestinationBounds( getAspectRatioOrDefault(info.pictureInPictureParams), null /* bounds */); getAspectRatioOrDefault(info.pictureInPictureParams), null /* bounds */, getMinimalSize(info.topActivityInfo)); Objects.requireNonNull(destinationBounds, "Missing destination bounds"); mTaskInfo = info; mToken = mTaskInfo.token; Loading Loading @@ -276,7 +264,8 @@ public class PipTaskOrganizer extends ITaskOrganizer.Stub { return; } final Rect destinationBounds = mPipBoundsHandler.getDestinationBounds( getAspectRatioOrDefault(newParams), null /* bounds */); getAspectRatioOrDefault(newParams), null /* bounds */, getMinimalSize(info.topActivityInfo)); Objects.requireNonNull(destinationBounds, "Missing destination bounds"); scheduleAnimateResizePip(destinationBounds, mEnterExitAnimationDuration, null); } Loading Loading @@ -446,6 +435,14 @@ public class PipTaskOrganizer extends ITaskOrganizer.Stub { .start()); } private Size getMinimalSize(ActivityInfo activityInfo) { if (activityInfo == null || activityInfo.windowLayout == null) { return null; } final ActivityInfo.WindowLayout windowLayout = activityInfo.windowLayout; return new Size(windowLayout.minWidth, windowLayout.minHeight); } private float getAspectRatioOrDefault(@Nullable PictureInPictureParams params) { return params == null ? mPipBoundsHandler.getDefaultAspectRatio() Loading
packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java +1 −1 Original line number Diff line number Diff line Loading @@ -426,7 +426,7 @@ public class PipMotionHelper implements PipAppOpsListener.Callback, cancelAnimations(); mAnimatedBoundsPhysicsAnimator .withEndActions(() -> mPipTaskOrganizer.onMotionMovementEnd(mAnimatedBounds)) .withEndActions(() -> mPipTaskOrganizer.scheduleFinishResizePip(mAnimatedBounds)) .addUpdateListener(mResizePipUpdateListener) .start(); } Loading
packages/SystemUI/tests/src/com/android/systemui/pip/PipBoundsHandlerTest.java +59 −13 Original line number Diff line number Diff line Loading @@ -24,6 +24,7 @@ import android.graphics.Rect; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; import android.testing.TestableResources; import android.util.Size; import android.view.DisplayInfo; import android.view.Gravity; Loading Loading @@ -51,6 +52,7 @@ public class PipBoundsHandlerTest extends SysuiTestCase { private static final float MIN_ASPECT_RATIO = 0.5f; private static final float MAX_ASPECT_RATIO = 2f; private static final Rect EMPTY_CURRENT_BOUNDS = null; private static final Size EMPTY_MINIMAL_SIZE = null; private PipBoundsHandler mPipBoundsHandler; private DisplayInfo mDefaultDisplayInfo; Loading Loading @@ -119,7 +121,7 @@ public class PipBoundsHandlerTest extends SysuiTestCase { }; for (float aspectRatio : aspectRatios) { final Rect destinationBounds = mPipBoundsHandler.getDestinationBounds( aspectRatio, EMPTY_CURRENT_BOUNDS); aspectRatio, EMPTY_CURRENT_BOUNDS, EMPTY_MINIMAL_SIZE); final float actualAspectRatio = destinationBounds.width() / (destinationBounds.height() * 1f); assertEquals("Destination bounds matches the given aspect ratio", Loading @@ -135,7 +137,7 @@ public class PipBoundsHandlerTest extends SysuiTestCase { }; for (float aspectRatio : invalidAspectRatios) { final Rect destinationBounds = mPipBoundsHandler.getDestinationBounds( aspectRatio, EMPTY_CURRENT_BOUNDS); aspectRatio, EMPTY_CURRENT_BOUNDS, EMPTY_MINIMAL_SIZE); final float actualAspectRatio = destinationBounds.width() / (destinationBounds.height() * 1f); assertEquals("Destination bounds fallbacks to default aspect ratio", Loading @@ -151,7 +153,7 @@ public class PipBoundsHandlerTest extends SysuiTestCase { currentBounds.right = (int) (currentBounds.height() * aspectRatio) + currentBounds.left; final Rect destinationBounds = mPipBoundsHandler.getDestinationBounds( aspectRatio, currentBounds); aspectRatio, currentBounds, EMPTY_MINIMAL_SIZE); final float actualAspectRatio = destinationBounds.width() / (destinationBounds.height() * 1f); Loading @@ -159,15 +161,59 @@ public class PipBoundsHandlerTest extends SysuiTestCase { aspectRatio, actualAspectRatio, ASPECT_RATIO_ERROR_MARGIN); } @Test public void getDestinationBounds_withMinSize_returnMinBounds() { final float[] aspectRatios = new float[] { (MIN_ASPECT_RATIO + DEFAULT_ASPECT_RATIO) / 2, DEFAULT_ASPECT_RATIO, (MAX_ASPECT_RATIO + DEFAULT_ASPECT_RATIO) / 2 }; final Size[] minimalSizes = new Size[] { new Size((int) (100 * aspectRatios[0]), 100), new Size((int) (100 * aspectRatios[1]), 100), new Size((int) (100 * aspectRatios[2]), 100) }; for (int i = 0; i < aspectRatios.length; i++) { final float aspectRatio = aspectRatios[i]; final Size minimalSize = minimalSizes[i]; final Rect destinationBounds = mPipBoundsHandler.getDestinationBounds( aspectRatio, EMPTY_CURRENT_BOUNDS, minimalSize); assertTrue("Destination bounds is no smaller than minimal requirement", (destinationBounds.width() == minimalSize.getWidth() && destinationBounds.height() >= minimalSize.getHeight()) || (destinationBounds.height() == minimalSize.getHeight() && destinationBounds.width() >= minimalSize.getWidth())); final float actualAspectRatio = destinationBounds.width() / (destinationBounds.height() * 1f); assertEquals("Destination bounds matches the given aspect ratio", aspectRatio, actualAspectRatio, ASPECT_RATIO_ERROR_MARGIN); } } @Test public void getDestinationBounds_withCurrentBounds_ignoreMinBounds() { final float aspectRatio = (DEFAULT_ASPECT_RATIO + MAX_ASPECT_RATIO) / 2; final Rect currentBounds = new Rect(0, 0, 0, 100); currentBounds.right = (int) (currentBounds.height() * aspectRatio) + currentBounds.left; final Size minSize = new Size(currentBounds.width() / 2, currentBounds.height() / 2); final Rect destinationBounds = mPipBoundsHandler.getDestinationBounds( aspectRatio, currentBounds, minSize); assertTrue("Destination bounds ignores minimal size", destinationBounds.width() > minSize.getWidth() && destinationBounds.height() > minSize.getHeight()); } @Test public void setShelfHeight_offsetBounds() { final int shelfHeight = 100; final Rect oldPosition = mPipBoundsHandler.getDestinationBounds( DEFAULT_ASPECT_RATIO, EMPTY_CURRENT_BOUNDS); DEFAULT_ASPECT_RATIO, EMPTY_CURRENT_BOUNDS, EMPTY_MINIMAL_SIZE); mPipBoundsHandler.setShelfHeight(true, shelfHeight); final Rect newPosition = mPipBoundsHandler.getDestinationBounds( DEFAULT_ASPECT_RATIO, EMPTY_CURRENT_BOUNDS); DEFAULT_ASPECT_RATIO, EMPTY_CURRENT_BOUNDS, EMPTY_MINIMAL_SIZE); oldPosition.offset(0, -shelfHeight); assertBoundsWithMargin("offsetBounds by shelf", oldPosition, newPosition); Loading @@ -177,11 +223,11 @@ public class PipBoundsHandlerTest extends SysuiTestCase { public void onImeVisibilityChanged_offsetBounds() { final int imeHeight = 100; final Rect oldPosition = mPipBoundsHandler.getDestinationBounds( DEFAULT_ASPECT_RATIO, EMPTY_CURRENT_BOUNDS); DEFAULT_ASPECT_RATIO, EMPTY_CURRENT_BOUNDS, EMPTY_MINIMAL_SIZE); mPipBoundsHandler.onImeVisibilityChanged(true, imeHeight); final Rect newPosition = mPipBoundsHandler.getDestinationBounds( DEFAULT_ASPECT_RATIO, EMPTY_CURRENT_BOUNDS); DEFAULT_ASPECT_RATIO, EMPTY_CURRENT_BOUNDS, EMPTY_MINIMAL_SIZE); oldPosition.offset(0, -imeHeight); assertBoundsWithMargin("offsetBounds by IME", oldPosition, newPosition); Loading @@ -191,13 +237,13 @@ public class PipBoundsHandlerTest extends SysuiTestCase { public void onSaveReentryBounds_restoreLastPosition() { final ComponentName componentName = new ComponentName(mContext, "component1"); final Rect oldPosition = mPipBoundsHandler.getDestinationBounds( DEFAULT_ASPECT_RATIO, EMPTY_CURRENT_BOUNDS); DEFAULT_ASPECT_RATIO, EMPTY_CURRENT_BOUNDS, EMPTY_MINIMAL_SIZE); oldPosition.offset(0, -100); mPipBoundsHandler.onSaveReentryBounds(componentName, oldPosition); final Rect newPosition = mPipBoundsHandler.getDestinationBounds( DEFAULT_ASPECT_RATIO, EMPTY_CURRENT_BOUNDS); DEFAULT_ASPECT_RATIO, EMPTY_CURRENT_BOUNDS, EMPTY_MINIMAL_SIZE); assertBoundsWithMargin("restoreLastPosition", oldPosition, newPosition); } Loading @@ -206,14 +252,14 @@ public class PipBoundsHandlerTest extends SysuiTestCase { public void onResetReentryBounds_useDefaultBounds() { final ComponentName componentName = new ComponentName(mContext, "component1"); final Rect defaultBounds = mPipBoundsHandler.getDestinationBounds( DEFAULT_ASPECT_RATIO, EMPTY_CURRENT_BOUNDS); DEFAULT_ASPECT_RATIO, EMPTY_CURRENT_BOUNDS, EMPTY_MINIMAL_SIZE); final Rect newBounds = new Rect(defaultBounds); newBounds.offset(0, -100); mPipBoundsHandler.onSaveReentryBounds(componentName, newBounds); mPipBoundsHandler.onResetReentryBounds(componentName); final Rect actualBounds = mPipBoundsHandler.getDestinationBounds( DEFAULT_ASPECT_RATIO, EMPTY_CURRENT_BOUNDS); DEFAULT_ASPECT_RATIO, EMPTY_CURRENT_BOUNDS, EMPTY_MINIMAL_SIZE); assertBoundsWithMargin("useDefaultBounds", defaultBounds, actualBounds); } Loading @@ -222,14 +268,14 @@ public class PipBoundsHandlerTest extends SysuiTestCase { public void onResetReentryBounds_componentMismatch_restoreLastPosition() { final ComponentName componentName = new ComponentName(mContext, "component1"); final Rect defaultBounds = mPipBoundsHandler.getDestinationBounds( DEFAULT_ASPECT_RATIO, EMPTY_CURRENT_BOUNDS); DEFAULT_ASPECT_RATIO, EMPTY_CURRENT_BOUNDS, EMPTY_MINIMAL_SIZE); final Rect newBounds = new Rect(defaultBounds); newBounds.offset(0, -100); mPipBoundsHandler.onSaveReentryBounds(componentName, newBounds); mPipBoundsHandler.onResetReentryBounds(new ComponentName(mContext, "component2")); final Rect actualBounds = mPipBoundsHandler.getDestinationBounds( DEFAULT_ASPECT_RATIO, EMPTY_CURRENT_BOUNDS); DEFAULT_ASPECT_RATIO, EMPTY_CURRENT_BOUNDS, EMPTY_MINIMAL_SIZE); assertBoundsWithMargin("restoreLastPosition", newBounds, actualBounds); } Loading