Loading libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/Pip2Module.java +7 −2 Original line number Diff line number Diff line Loading @@ -20,6 +20,7 @@ import android.annotation.NonNull; import android.content.Context; import android.os.Handler; import com.android.wm.shell.RootTaskDisplayAreaOrganizer; import com.android.wm.shell.ShellTaskOrganizer; import com.android.wm.shell.common.DisplayController; import com.android.wm.shell.common.DisplayInsetsController; Loading @@ -38,6 +39,7 @@ import com.android.wm.shell.common.pip.PipUtils; import com.android.wm.shell.common.pip.SizeSpecSource; import com.android.wm.shell.dagger.WMShellBaseModule; import com.android.wm.shell.dagger.WMSingleton; import com.android.wm.shell.desktopmode.DesktopRepository; import com.android.wm.shell.pip2.phone.PhonePipMenuController; import com.android.wm.shell.pip2.phone.PipController; import com.android.wm.shell.pip2.phone.PipMotionHelper; Loading Loading @@ -128,8 +130,11 @@ public abstract class Pip2Module { static PipScheduler providePipScheduler(Context context, PipBoundsState pipBoundsState, @ShellMainThread ShellExecutor mainExecutor, PipTransitionState pipTransitionState) { return new PipScheduler(context, pipBoundsState, mainExecutor, pipTransitionState); PipTransitionState pipTransitionState, Optional<DesktopRepository> desktopRepositoryOptional, RootTaskDisplayAreaOrganizer rootTaskDisplayAreaOrganizer) { return new PipScheduler(context, pipBoundsState, mainExecutor, pipTransitionState, desktopRepositoryOptional, rootTaskDisplayAreaOrganizer); } @WMSingleton Loading libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipScheduler.java +57 −2 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ package com.android.wm.shell.pip2.phone; import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; import static com.android.wm.shell.transition.Transitions.TRANSIT_EXIT_PIP; Loading @@ -25,6 +26,7 @@ import android.content.Context; import android.graphics.Matrix; import android.graphics.Rect; import android.view.SurfaceControl; import android.window.DisplayAreaInfo; import android.window.WindowContainerToken; import android.window.WindowContainerTransaction; Loading @@ -33,13 +35,19 @@ import androidx.annotation.Nullable; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.protolog.ProtoLog; import com.android.window.flags.Flags; import com.android.wm.shell.RootTaskDisplayAreaOrganizer; import com.android.wm.shell.common.ShellExecutor; import com.android.wm.shell.common.pip.PipBoundsState; import com.android.wm.shell.desktopmode.DesktopRepository; import com.android.wm.shell.pip.PipTransitionController; import com.android.wm.shell.pip2.PipSurfaceTransactionHelper; import com.android.wm.shell.pip2.animation.PipAlphaAnimator; import com.android.wm.shell.protolog.ShellProtoLogGroup; import java.util.Objects; import java.util.Optional; /** * Scheduler for Shell initiated PiP transitions and animations. */ Loading @@ -50,6 +58,8 @@ public class PipScheduler { private final PipBoundsState mPipBoundsState; private final ShellExecutor mMainExecutor; private final PipTransitionState mPipTransitionState; private final Optional<DesktopRepository> mDesktopRepositoryOptional; private final RootTaskDisplayAreaOrganizer mRootTaskDisplayAreaOrganizer; private PipTransitionController mPipTransitionController; private PipSurfaceTransactionHelper.SurfaceControlTransactionFactory mSurfaceControlTransactionFactory; Loading @@ -61,11 +71,15 @@ public class PipScheduler { public PipScheduler(Context context, PipBoundsState pipBoundsState, ShellExecutor mainExecutor, PipTransitionState pipTransitionState) { PipTransitionState pipTransitionState, Optional<DesktopRepository> desktopRepositoryOptional, RootTaskDisplayAreaOrganizer rootTaskDisplayAreaOrganizer) { mContext = context; mPipBoundsState = pipBoundsState; mMainExecutor = mainExecutor; mPipTransitionState = pipTransitionState; mDesktopRepositoryOptional = desktopRepositoryOptional; mRootTaskDisplayAreaOrganizer = rootTaskDisplayAreaOrganizer; mSurfaceControlTransactionFactory = new PipSurfaceTransactionHelper.VsyncSurfaceControlTransactionFactory(); Loading @@ -87,7 +101,7 @@ public class PipScheduler { wct.setBounds(pipTaskToken, null); // if we are hitting a multi-activity case // windowing mode change will reparent to original host task wct.setWindowingMode(pipTaskToken, WINDOWING_MODE_UNDEFINED); wct.setWindowingMode(pipTaskToken, getOutPipWindowingMode()); return wct; } Loading Loading @@ -241,6 +255,47 @@ public class PipScheduler { maybeUpdateMovementBounds(); } /** Returns whether the display is in freeform windowing mode. */ private boolean isDisplayInFreeform() { final DisplayAreaInfo tdaInfo = mRootTaskDisplayAreaOrganizer.getDisplayAreaInfo( Objects.requireNonNull(mPipTransitionState.getPipTaskInfo()).displayId); if (tdaInfo != null) { return tdaInfo.configuration.windowConfiguration.getWindowingMode() == WINDOWING_MODE_FREEFORM; } return false; } /** Returns whether PiP is exiting while we're in desktop mode. */ private boolean isPipExitingToDesktopMode() { return Flags.enableDesktopWindowingPip() && mDesktopRepositoryOptional.isPresent() && (mDesktopRepositoryOptional.get().getVisibleTaskCount( Objects.requireNonNull(mPipTransitionState.getPipTaskInfo()).displayId) > 0 || isDisplayInFreeform()); } /** * The windowing mode to restore to when resizing out of PIP direction. Defaults to undefined * and can be overridden to restore to an alternate windowing mode. */ private int getOutPipWindowingMode() { // If we are exiting PiP while the device is in Desktop mode (the task should expand to // freeform windowing mode): // 1) If the display windowing mode is freeform, set windowing mode to undefined so it will // resolve the windowing mode to the display's windowing mode. // 2) If the display windowing mode is not freeform, set windowing mode to freeform. if (isPipExitingToDesktopMode()) { if (isDisplayInFreeform()) { return WINDOWING_MODE_UNDEFINED; } else { return WINDOWING_MODE_FREEFORM; } } // By default, or if the task is going to fullscreen, reset the windowing mode to undefined. return WINDOWING_MODE_UNDEFINED; } @VisibleForTesting void setSurfaceControlTransactionFactory( @NonNull PipSurfaceTransactionHelper.SurfaceControlTransactionFactory factory) { Loading libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip2/phone/PipSchedulerTest.java +8 −1 Original line number Diff line number Diff line Loading @@ -42,8 +42,10 @@ import android.window.WindowContainerTransaction; import androidx.test.filters.SmallTest; import com.android.wm.shell.RootTaskDisplayAreaOrganizer; import com.android.wm.shell.common.ShellExecutor; import com.android.wm.shell.common.pip.PipBoundsState; import com.android.wm.shell.desktopmode.DesktopRepository; import com.android.wm.shell.pip.PipTransitionController; import com.android.wm.shell.pip2.PipSurfaceTransactionHelper; import com.android.wm.shell.pip2.animation.PipAlphaAnimator; Loading @@ -56,6 +58,8 @@ import org.mockito.Captor; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import java.util.Optional; /** * Unit test against {@link PipScheduler} */ Loading @@ -79,6 +83,8 @@ public class PipSchedulerTest { @Mock private PipSurfaceTransactionHelper.SurfaceControlTransactionFactory mMockFactory; @Mock private SurfaceControl.Transaction mMockTransaction; @Mock private PipAlphaAnimator mMockAlphaAnimator; @Mock private Optional<DesktopRepository> mMockOptionalDesktopRepository; @Mock private RootTaskDisplayAreaOrganizer mRootTaskDisplayAreaOrganizer; @Captor private ArgumentCaptor<Runnable> mRunnableArgumentCaptor; @Captor private ArgumentCaptor<WindowContainerTransaction> mWctArgumentCaptor; Loading @@ -96,7 +102,8 @@ public class PipSchedulerTest { .thenReturn(mMockTransaction); mPipScheduler = new PipScheduler(mMockContext, mMockPipBoundsState, mMockMainExecutor, mMockPipTransitionState); mMockPipTransitionState, mMockOptionalDesktopRepository, mRootTaskDisplayAreaOrganizer); mPipScheduler.setPipTransitionController(mMockPipTransitionController); mPipScheduler.setSurfaceControlTransactionFactory(mMockFactory); mPipScheduler.setPipAlphaAnimatorSupplier((context, leash, tx, direction) -> Loading Loading
libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/Pip2Module.java +7 −2 Original line number Diff line number Diff line Loading @@ -20,6 +20,7 @@ import android.annotation.NonNull; import android.content.Context; import android.os.Handler; import com.android.wm.shell.RootTaskDisplayAreaOrganizer; import com.android.wm.shell.ShellTaskOrganizer; import com.android.wm.shell.common.DisplayController; import com.android.wm.shell.common.DisplayInsetsController; Loading @@ -38,6 +39,7 @@ import com.android.wm.shell.common.pip.PipUtils; import com.android.wm.shell.common.pip.SizeSpecSource; import com.android.wm.shell.dagger.WMShellBaseModule; import com.android.wm.shell.dagger.WMSingleton; import com.android.wm.shell.desktopmode.DesktopRepository; import com.android.wm.shell.pip2.phone.PhonePipMenuController; import com.android.wm.shell.pip2.phone.PipController; import com.android.wm.shell.pip2.phone.PipMotionHelper; Loading Loading @@ -128,8 +130,11 @@ public abstract class Pip2Module { static PipScheduler providePipScheduler(Context context, PipBoundsState pipBoundsState, @ShellMainThread ShellExecutor mainExecutor, PipTransitionState pipTransitionState) { return new PipScheduler(context, pipBoundsState, mainExecutor, pipTransitionState); PipTransitionState pipTransitionState, Optional<DesktopRepository> desktopRepositoryOptional, RootTaskDisplayAreaOrganizer rootTaskDisplayAreaOrganizer) { return new PipScheduler(context, pipBoundsState, mainExecutor, pipTransitionState, desktopRepositoryOptional, rootTaskDisplayAreaOrganizer); } @WMSingleton Loading
libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipScheduler.java +57 −2 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ package com.android.wm.shell.pip2.phone; import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; import static com.android.wm.shell.transition.Transitions.TRANSIT_EXIT_PIP; Loading @@ -25,6 +26,7 @@ import android.content.Context; import android.graphics.Matrix; import android.graphics.Rect; import android.view.SurfaceControl; import android.window.DisplayAreaInfo; import android.window.WindowContainerToken; import android.window.WindowContainerTransaction; Loading @@ -33,13 +35,19 @@ import androidx.annotation.Nullable; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.protolog.ProtoLog; import com.android.window.flags.Flags; import com.android.wm.shell.RootTaskDisplayAreaOrganizer; import com.android.wm.shell.common.ShellExecutor; import com.android.wm.shell.common.pip.PipBoundsState; import com.android.wm.shell.desktopmode.DesktopRepository; import com.android.wm.shell.pip.PipTransitionController; import com.android.wm.shell.pip2.PipSurfaceTransactionHelper; import com.android.wm.shell.pip2.animation.PipAlphaAnimator; import com.android.wm.shell.protolog.ShellProtoLogGroup; import java.util.Objects; import java.util.Optional; /** * Scheduler for Shell initiated PiP transitions and animations. */ Loading @@ -50,6 +58,8 @@ public class PipScheduler { private final PipBoundsState mPipBoundsState; private final ShellExecutor mMainExecutor; private final PipTransitionState mPipTransitionState; private final Optional<DesktopRepository> mDesktopRepositoryOptional; private final RootTaskDisplayAreaOrganizer mRootTaskDisplayAreaOrganizer; private PipTransitionController mPipTransitionController; private PipSurfaceTransactionHelper.SurfaceControlTransactionFactory mSurfaceControlTransactionFactory; Loading @@ -61,11 +71,15 @@ public class PipScheduler { public PipScheduler(Context context, PipBoundsState pipBoundsState, ShellExecutor mainExecutor, PipTransitionState pipTransitionState) { PipTransitionState pipTransitionState, Optional<DesktopRepository> desktopRepositoryOptional, RootTaskDisplayAreaOrganizer rootTaskDisplayAreaOrganizer) { mContext = context; mPipBoundsState = pipBoundsState; mMainExecutor = mainExecutor; mPipTransitionState = pipTransitionState; mDesktopRepositoryOptional = desktopRepositoryOptional; mRootTaskDisplayAreaOrganizer = rootTaskDisplayAreaOrganizer; mSurfaceControlTransactionFactory = new PipSurfaceTransactionHelper.VsyncSurfaceControlTransactionFactory(); Loading @@ -87,7 +101,7 @@ public class PipScheduler { wct.setBounds(pipTaskToken, null); // if we are hitting a multi-activity case // windowing mode change will reparent to original host task wct.setWindowingMode(pipTaskToken, WINDOWING_MODE_UNDEFINED); wct.setWindowingMode(pipTaskToken, getOutPipWindowingMode()); return wct; } Loading Loading @@ -241,6 +255,47 @@ public class PipScheduler { maybeUpdateMovementBounds(); } /** Returns whether the display is in freeform windowing mode. */ private boolean isDisplayInFreeform() { final DisplayAreaInfo tdaInfo = mRootTaskDisplayAreaOrganizer.getDisplayAreaInfo( Objects.requireNonNull(mPipTransitionState.getPipTaskInfo()).displayId); if (tdaInfo != null) { return tdaInfo.configuration.windowConfiguration.getWindowingMode() == WINDOWING_MODE_FREEFORM; } return false; } /** Returns whether PiP is exiting while we're in desktop mode. */ private boolean isPipExitingToDesktopMode() { return Flags.enableDesktopWindowingPip() && mDesktopRepositoryOptional.isPresent() && (mDesktopRepositoryOptional.get().getVisibleTaskCount( Objects.requireNonNull(mPipTransitionState.getPipTaskInfo()).displayId) > 0 || isDisplayInFreeform()); } /** * The windowing mode to restore to when resizing out of PIP direction. Defaults to undefined * and can be overridden to restore to an alternate windowing mode. */ private int getOutPipWindowingMode() { // If we are exiting PiP while the device is in Desktop mode (the task should expand to // freeform windowing mode): // 1) If the display windowing mode is freeform, set windowing mode to undefined so it will // resolve the windowing mode to the display's windowing mode. // 2) If the display windowing mode is not freeform, set windowing mode to freeform. if (isPipExitingToDesktopMode()) { if (isDisplayInFreeform()) { return WINDOWING_MODE_UNDEFINED; } else { return WINDOWING_MODE_FREEFORM; } } // By default, or if the task is going to fullscreen, reset the windowing mode to undefined. return WINDOWING_MODE_UNDEFINED; } @VisibleForTesting void setSurfaceControlTransactionFactory( @NonNull PipSurfaceTransactionHelper.SurfaceControlTransactionFactory factory) { Loading
libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip2/phone/PipSchedulerTest.java +8 −1 Original line number Diff line number Diff line Loading @@ -42,8 +42,10 @@ import android.window.WindowContainerTransaction; import androidx.test.filters.SmallTest; import com.android.wm.shell.RootTaskDisplayAreaOrganizer; import com.android.wm.shell.common.ShellExecutor; import com.android.wm.shell.common.pip.PipBoundsState; import com.android.wm.shell.desktopmode.DesktopRepository; import com.android.wm.shell.pip.PipTransitionController; import com.android.wm.shell.pip2.PipSurfaceTransactionHelper; import com.android.wm.shell.pip2.animation.PipAlphaAnimator; Loading @@ -56,6 +58,8 @@ import org.mockito.Captor; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import java.util.Optional; /** * Unit test against {@link PipScheduler} */ Loading @@ -79,6 +83,8 @@ public class PipSchedulerTest { @Mock private PipSurfaceTransactionHelper.SurfaceControlTransactionFactory mMockFactory; @Mock private SurfaceControl.Transaction mMockTransaction; @Mock private PipAlphaAnimator mMockAlphaAnimator; @Mock private Optional<DesktopRepository> mMockOptionalDesktopRepository; @Mock private RootTaskDisplayAreaOrganizer mRootTaskDisplayAreaOrganizer; @Captor private ArgumentCaptor<Runnable> mRunnableArgumentCaptor; @Captor private ArgumentCaptor<WindowContainerTransaction> mWctArgumentCaptor; Loading @@ -96,7 +102,8 @@ public class PipSchedulerTest { .thenReturn(mMockTransaction); mPipScheduler = new PipScheduler(mMockContext, mMockPipBoundsState, mMockMainExecutor, mMockPipTransitionState); mMockPipTransitionState, mMockOptionalDesktopRepository, mRootTaskDisplayAreaOrganizer); mPipScheduler.setPipTransitionController(mMockPipTransitionController); mPipScheduler.setSurfaceControlTransactionFactory(mMockFactory); mPipScheduler.setPipAlphaAnimatorSupplier((context, leash, tx, direction) -> Loading