Loading core/api/current.txt +1 −0 Original line number Diff line number Diff line Loading @@ -7225,6 +7225,7 @@ package android.app { public final class PictureInPictureUiState implements android.os.Parcelable { method public int describeContents(); method @FlaggedApi("android.app.enable_pip_ui_state_callback_on_entering") public boolean isEnteringPip(); method public boolean isStashed(); method public void writeToParcel(@NonNull android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator<android.app.PictureInPictureUiState> CREATOR; core/java/android/app/IActivityTaskManager.aidl +3 −1 Original line number Diff line number Diff line Loading @@ -332,8 +332,10 @@ interface IActivityTaskManager { /** * When the Picture-in-picture state has changed. * @param pipState the {@link PictureInPictureUiState} is sent to current pip task if there is * any -or- the top most task (state like entering PiP does not require a pinned task). */ void onPictureInPictureStateChanged(in PictureInPictureUiState pipState); void onPictureInPictureUiStateChanged(in PictureInPictureUiState pipState); /** * Re-attach navbar to the display during a recents transition. Loading core/java/android/app/PictureInPictureUiState.java +82 −6 Original line number Diff line number Diff line Loading @@ -16,8 +16,10 @@ package android.app; import android.annotation.FlaggedApi; import android.annotation.NonNull; import android.annotation.TestApi; import android.content.res.Configuration; import android.os.Parcel; import android.os.Parcelable; Loading @@ -28,23 +30,30 @@ import java.util.Objects; */ public final class PictureInPictureUiState implements Parcelable { private boolean mIsStashed; private final boolean mIsStashed; private final boolean mIsEnteringPip; /** {@hide} */ PictureInPictureUiState(Parcel in) { mIsStashed = in.readBoolean(); mIsEnteringPip = in.readBoolean(); } /** {@hide} */ @TestApi public PictureInPictureUiState(boolean isStashed) { this(isStashed, false /* isEnteringPip */); } private PictureInPictureUiState(boolean isStashed, boolean isEnteringPip) { mIsStashed = isStashed; mIsEnteringPip = isEnteringPip; } /** * Returns whether Picture-in-Picture is stashed or not. A stashed PiP means it is only * partially visible to the user, with some parts of it being off-screen. This is usually * an UI state that is triggered by the user, such as flinging the PiP to the edge or letting go * partially visible to the user, with some parts of it being off-screen. This is usually a * UI state that is triggered by the user, such as flinging the PiP to the edge or letting go * of PiP while dragging partially off-screen. * * Developers can use this in conjunction with Loading @@ -61,17 +70,44 @@ public final class PictureInPictureUiState implements Parcelable { return mIsStashed; } /** * Returns {@code true} if the app is going to enter Picture-in-Picture (PiP) mode. * * This state is associated with the entering PiP animation. When that animation starts, * whether via auto enter PiP or calling * {@link Activity#enterPictureInPictureMode(PictureInPictureParams)} explicitly, app can expect * {@link Activity#onPictureInPictureUiStateChanged(PictureInPictureUiState)} callback with * {@link #isEnteringPip()} to be {@code true} first, * followed by {@link Activity#onPictureInPictureModeChanged(boolean, Configuration)} when it * fully settles in PiP mode. * * When app receives the * {@link Activity#onPictureInPictureUiStateChanged(PictureInPictureUiState)} callback with * {@link #isEnteringPip()} being {@code true}, it's recommended to hide certain UI elements, * such as video controls, to archive a clean entering PiP animation. * * In case an application wants to restore the previously hidden UI elements when exiting * PiP, it is recommended to do that in * {@code onPictureInPictureModeChanged(isInPictureInPictureMode=false)} callback rather * than the beginning of exit PiP animation. */ @FlaggedApi(Flags.FLAG_ENABLE_PIP_UI_STATE_CALLBACK_ON_ENTERING) public boolean isEnteringPip() { return mIsEnteringPip; } @Override public boolean equals(Object o) { if (this == o) return true; if (!(o instanceof PictureInPictureUiState)) return false; PictureInPictureUiState that = (PictureInPictureUiState) o; return Objects.equals(mIsStashed, that.mIsStashed); return mIsStashed == that.mIsStashed && mIsEnteringPip == that.mIsEnteringPip; } @Override public int hashCode() { return Objects.hash(mIsStashed); return Objects.hash(mIsStashed, mIsEnteringPip); } @Override Loading @@ -82,6 +118,7 @@ public final class PictureInPictureUiState implements Parcelable { @Override public void writeToParcel(@NonNull Parcel out, int flags) { out.writeBoolean(mIsStashed); out.writeBoolean(mIsEnteringPip); } public static final @android.annotation.NonNull Creator<PictureInPictureUiState> CREATOR = Loading @@ -93,4 +130,43 @@ public final class PictureInPictureUiState implements Parcelable { return new PictureInPictureUiState[size]; } }; /** * Builder class for {@link PictureInPictureUiState}. * @hide */ @FlaggedApi(Flags.FLAG_ENABLE_PIP_UI_STATE_CALLBACK_ON_ENTERING) public static final class Builder { private boolean mIsStashed; private boolean mIsEnteringPip; /** Empty constructor. */ public Builder() { } /** * Sets the {@link #mIsStashed} state. * @return The same {@link Builder} instance. */ public Builder setStashed(boolean isStashed) { mIsStashed = isStashed; return this; } /** * Sets the {@link #mIsEnteringPip} state. * @return The same {@link Builder} instance. */ public Builder setEnteringPip(boolean isEnteringPip) { mIsEnteringPip = isEnteringPip; return this; } /** * @return The constructed {@link PictureInPictureUiState} instance. */ public PictureInPictureUiState build() { return new PictureInPictureUiState(mIsStashed, mIsEnteringPip); } } } libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/PipBoundsState.java +1 −1 Original line number Diff line number Diff line Loading @@ -260,7 +260,7 @@ public class PipBoundsState { mStashedState = stashedState; try { ActivityTaskManager.getService().onPictureInPictureStateChanged( ActivityTaskManager.getService().onPictureInPictureUiStateChanged( new PictureInPictureUiState(stashedState != STASH_TYPE_NONE /* isStashed */) ); } catch (RemoteException | IllegalStateException e) { Loading libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionController.java +28 −0 Original line number Diff line number Diff line Loading @@ -23,12 +23,16 @@ import static com.android.wm.shell.pip.PipAnimationController.TRANSITION_DIRECTI import static com.android.wm.shell.pip.PipAnimationController.isInPipDirection; import android.annotation.Nullable; import android.app.ActivityTaskManager; import android.app.Flags; import android.app.PictureInPictureParams; import android.app.PictureInPictureUiState; import android.app.TaskInfo; import android.content.ComponentName; import android.content.pm.ActivityInfo; import android.graphics.Rect; import android.os.IBinder; import android.os.RemoteException; import android.view.SurfaceControl; import android.view.WindowManager; import android.window.TransitionInfo; Loading @@ -37,11 +41,13 @@ import android.window.WindowContainerTransaction; import androidx.annotation.NonNull; import com.android.internal.protolog.common.ProtoLog; import com.android.wm.shell.ShellTaskOrganizer; import com.android.wm.shell.common.pip.PipBoundsAlgorithm; import com.android.wm.shell.common.pip.PipBoundsState; import com.android.wm.shell.common.pip.PipMenuController; import com.android.wm.shell.common.split.SplitScreenUtils; import com.android.wm.shell.protolog.ShellProtoLogGroup; import com.android.wm.shell.sysui.ShellInit; import com.android.wm.shell.transition.Transitions; Loading Loading @@ -181,6 +187,17 @@ public abstract class PipTransitionController implements Transitions.TransitionH final PipTransitionCallback callback = mPipTransitionCallbacks.get(i); callback.onPipTransitionStarted(direction, pipBounds); } if (isInPipDirection(direction) && Flags.enablePipUiStateCallbackOnEntering()) { try { ActivityTaskManager.getService().onPictureInPictureUiStateChanged( new PictureInPictureUiState.Builder() .setEnteringPip(true) .build()); } catch (RemoteException | IllegalStateException e) { ProtoLog.e(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE, "Failed to set alert PiP state change."); } } } protected void sendOnPipTransitionFinished( Loading @@ -189,6 +206,17 @@ public abstract class PipTransitionController implements Transitions.TransitionH final PipTransitionCallback callback = mPipTransitionCallbacks.get(i); callback.onPipTransitionFinished(direction); } if (isInPipDirection(direction) && Flags.enablePipUiStateCallbackOnEntering()) { try { ActivityTaskManager.getService().onPictureInPictureUiStateChanged( new PictureInPictureUiState.Builder() .setEnteringPip(false) .build()); } catch (RemoteException | IllegalStateException e) { ProtoLog.e(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE, "Failed to set alert PiP state change."); } } } protected void sendOnPipTransitionCancelled( Loading Loading
core/api/current.txt +1 −0 Original line number Diff line number Diff line Loading @@ -7225,6 +7225,7 @@ package android.app { public final class PictureInPictureUiState implements android.os.Parcelable { method public int describeContents(); method @FlaggedApi("android.app.enable_pip_ui_state_callback_on_entering") public boolean isEnteringPip(); method public boolean isStashed(); method public void writeToParcel(@NonNull android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator<android.app.PictureInPictureUiState> CREATOR;
core/java/android/app/IActivityTaskManager.aidl +3 −1 Original line number Diff line number Diff line Loading @@ -332,8 +332,10 @@ interface IActivityTaskManager { /** * When the Picture-in-picture state has changed. * @param pipState the {@link PictureInPictureUiState} is sent to current pip task if there is * any -or- the top most task (state like entering PiP does not require a pinned task). */ void onPictureInPictureStateChanged(in PictureInPictureUiState pipState); void onPictureInPictureUiStateChanged(in PictureInPictureUiState pipState); /** * Re-attach navbar to the display during a recents transition. Loading
core/java/android/app/PictureInPictureUiState.java +82 −6 Original line number Diff line number Diff line Loading @@ -16,8 +16,10 @@ package android.app; import android.annotation.FlaggedApi; import android.annotation.NonNull; import android.annotation.TestApi; import android.content.res.Configuration; import android.os.Parcel; import android.os.Parcelable; Loading @@ -28,23 +30,30 @@ import java.util.Objects; */ public final class PictureInPictureUiState implements Parcelable { private boolean mIsStashed; private final boolean mIsStashed; private final boolean mIsEnteringPip; /** {@hide} */ PictureInPictureUiState(Parcel in) { mIsStashed = in.readBoolean(); mIsEnteringPip = in.readBoolean(); } /** {@hide} */ @TestApi public PictureInPictureUiState(boolean isStashed) { this(isStashed, false /* isEnteringPip */); } private PictureInPictureUiState(boolean isStashed, boolean isEnteringPip) { mIsStashed = isStashed; mIsEnteringPip = isEnteringPip; } /** * Returns whether Picture-in-Picture is stashed or not. A stashed PiP means it is only * partially visible to the user, with some parts of it being off-screen. This is usually * an UI state that is triggered by the user, such as flinging the PiP to the edge or letting go * partially visible to the user, with some parts of it being off-screen. This is usually a * UI state that is triggered by the user, such as flinging the PiP to the edge or letting go * of PiP while dragging partially off-screen. * * Developers can use this in conjunction with Loading @@ -61,17 +70,44 @@ public final class PictureInPictureUiState implements Parcelable { return mIsStashed; } /** * Returns {@code true} if the app is going to enter Picture-in-Picture (PiP) mode. * * This state is associated with the entering PiP animation. When that animation starts, * whether via auto enter PiP or calling * {@link Activity#enterPictureInPictureMode(PictureInPictureParams)} explicitly, app can expect * {@link Activity#onPictureInPictureUiStateChanged(PictureInPictureUiState)} callback with * {@link #isEnteringPip()} to be {@code true} first, * followed by {@link Activity#onPictureInPictureModeChanged(boolean, Configuration)} when it * fully settles in PiP mode. * * When app receives the * {@link Activity#onPictureInPictureUiStateChanged(PictureInPictureUiState)} callback with * {@link #isEnteringPip()} being {@code true}, it's recommended to hide certain UI elements, * such as video controls, to archive a clean entering PiP animation. * * In case an application wants to restore the previously hidden UI elements when exiting * PiP, it is recommended to do that in * {@code onPictureInPictureModeChanged(isInPictureInPictureMode=false)} callback rather * than the beginning of exit PiP animation. */ @FlaggedApi(Flags.FLAG_ENABLE_PIP_UI_STATE_CALLBACK_ON_ENTERING) public boolean isEnteringPip() { return mIsEnteringPip; } @Override public boolean equals(Object o) { if (this == o) return true; if (!(o instanceof PictureInPictureUiState)) return false; PictureInPictureUiState that = (PictureInPictureUiState) o; return Objects.equals(mIsStashed, that.mIsStashed); return mIsStashed == that.mIsStashed && mIsEnteringPip == that.mIsEnteringPip; } @Override public int hashCode() { return Objects.hash(mIsStashed); return Objects.hash(mIsStashed, mIsEnteringPip); } @Override Loading @@ -82,6 +118,7 @@ public final class PictureInPictureUiState implements Parcelable { @Override public void writeToParcel(@NonNull Parcel out, int flags) { out.writeBoolean(mIsStashed); out.writeBoolean(mIsEnteringPip); } public static final @android.annotation.NonNull Creator<PictureInPictureUiState> CREATOR = Loading @@ -93,4 +130,43 @@ public final class PictureInPictureUiState implements Parcelable { return new PictureInPictureUiState[size]; } }; /** * Builder class for {@link PictureInPictureUiState}. * @hide */ @FlaggedApi(Flags.FLAG_ENABLE_PIP_UI_STATE_CALLBACK_ON_ENTERING) public static final class Builder { private boolean mIsStashed; private boolean mIsEnteringPip; /** Empty constructor. */ public Builder() { } /** * Sets the {@link #mIsStashed} state. * @return The same {@link Builder} instance. */ public Builder setStashed(boolean isStashed) { mIsStashed = isStashed; return this; } /** * Sets the {@link #mIsEnteringPip} state. * @return The same {@link Builder} instance. */ public Builder setEnteringPip(boolean isEnteringPip) { mIsEnteringPip = isEnteringPip; return this; } /** * @return The constructed {@link PictureInPictureUiState} instance. */ public PictureInPictureUiState build() { return new PictureInPictureUiState(mIsStashed, mIsEnteringPip); } } }
libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/PipBoundsState.java +1 −1 Original line number Diff line number Diff line Loading @@ -260,7 +260,7 @@ public class PipBoundsState { mStashedState = stashedState; try { ActivityTaskManager.getService().onPictureInPictureStateChanged( ActivityTaskManager.getService().onPictureInPictureUiStateChanged( new PictureInPictureUiState(stashedState != STASH_TYPE_NONE /* isStashed */) ); } catch (RemoteException | IllegalStateException e) { Loading
libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionController.java +28 −0 Original line number Diff line number Diff line Loading @@ -23,12 +23,16 @@ import static com.android.wm.shell.pip.PipAnimationController.TRANSITION_DIRECTI import static com.android.wm.shell.pip.PipAnimationController.isInPipDirection; import android.annotation.Nullable; import android.app.ActivityTaskManager; import android.app.Flags; import android.app.PictureInPictureParams; import android.app.PictureInPictureUiState; import android.app.TaskInfo; import android.content.ComponentName; import android.content.pm.ActivityInfo; import android.graphics.Rect; import android.os.IBinder; import android.os.RemoteException; import android.view.SurfaceControl; import android.view.WindowManager; import android.window.TransitionInfo; Loading @@ -37,11 +41,13 @@ import android.window.WindowContainerTransaction; import androidx.annotation.NonNull; import com.android.internal.protolog.common.ProtoLog; import com.android.wm.shell.ShellTaskOrganizer; import com.android.wm.shell.common.pip.PipBoundsAlgorithm; import com.android.wm.shell.common.pip.PipBoundsState; import com.android.wm.shell.common.pip.PipMenuController; import com.android.wm.shell.common.split.SplitScreenUtils; import com.android.wm.shell.protolog.ShellProtoLogGroup; import com.android.wm.shell.sysui.ShellInit; import com.android.wm.shell.transition.Transitions; Loading Loading @@ -181,6 +187,17 @@ public abstract class PipTransitionController implements Transitions.TransitionH final PipTransitionCallback callback = mPipTransitionCallbacks.get(i); callback.onPipTransitionStarted(direction, pipBounds); } if (isInPipDirection(direction) && Flags.enablePipUiStateCallbackOnEntering()) { try { ActivityTaskManager.getService().onPictureInPictureUiStateChanged( new PictureInPictureUiState.Builder() .setEnteringPip(true) .build()); } catch (RemoteException | IllegalStateException e) { ProtoLog.e(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE, "Failed to set alert PiP state change."); } } } protected void sendOnPipTransitionFinished( Loading @@ -189,6 +206,17 @@ public abstract class PipTransitionController implements Transitions.TransitionH final PipTransitionCallback callback = mPipTransitionCallbacks.get(i); callback.onPipTransitionFinished(direction); } if (isInPipDirection(direction) && Flags.enablePipUiStateCallbackOnEntering()) { try { ActivityTaskManager.getService().onPictureInPictureUiStateChanged( new PictureInPictureUiState.Builder() .setEnteringPip(false) .build()); } catch (RemoteException | IllegalStateException e) { ProtoLog.e(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE, "Failed to set alert PiP state change."); } } } protected void sendOnPipTransitionCancelled( Loading