Merge "Add Activity#onPictureInPictureUiStateChanged and PictureInPictureUiState." into sc-dev

This commit is contained in:
Ben Lin
2021-04-20 17:45:38 +00:00
committed by Android (Google) Code Review
12 changed files with 295 additions and 0 deletions

View File

@@ -4023,6 +4023,7 @@ package android.app {
method public void onPictureInPictureModeChanged(boolean, android.content.res.Configuration);
method @Deprecated public void onPictureInPictureModeChanged(boolean);
method public boolean onPictureInPictureRequested();
method public void onPictureInPictureUiStateChanged(@NonNull android.app.PictureInPictureUiState);
method @CallSuper protected void onPostCreate(@Nullable android.os.Bundle);
method public void onPostCreate(@Nullable android.os.Bundle, @Nullable android.os.PersistableBundle);
method @CallSuper protected void onPostResume();
@@ -6415,6 +6416,13 @@ package android.app {
method public android.app.PictureInPictureParams.Builder setSourceRectHint(android.graphics.Rect);
}
public final class PictureInPictureUiState implements android.os.Parcelable {
method public int describeContents();
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;
}
public class Presentation extends android.app.Dialog {
ctor public Presentation(android.content.Context, android.view.Display);
ctor public Presentation(android.content.Context, android.view.Display, int);

View File

@@ -347,6 +347,10 @@ package android.app {
method public boolean isSeamlessResizeEnabled();
}
public final class PictureInPictureUiState implements android.os.Parcelable {
ctor public PictureInPictureUiState(boolean);
}
public class StatusBarManager {
method public void clickNotification(@Nullable String, int, int, boolean);
method @RequiresPermission(android.Manifest.permission.STATUS_BAR) public void collapsePanels();

View File

@@ -2812,6 +2812,29 @@ public class Activity extends ContextThemeWrapper
onPictureInPictureModeChanged(isInPictureInPictureMode);
}
/**
* Called by the system when the activity is in PiP and has state changes.
*
* Compare to {@link #onPictureInPictureModeChanged(boolean, Configuration)}, which is only
* called when PiP mode changes (meaning, enters or exits PiP), this can be called at any time
* while the activity is in PiP mode. Therefore, all invocation can only happen after
* {@link #onPictureInPictureModeChanged(boolean, Configuration)} is called with true, and
* before {@link #onPictureInPictureModeChanged(boolean, Configuration)} is called with false.
* You would not need to worry about cases where this is called and the activity is not in
* Picture-In-Picture mode. For managing cases where the activity enters/exits
* Picture-in-Picture (e.g. resources clean-up on exit), use
* {@link #onPictureInPictureModeChanged(boolean, Configuration)}.
*
* The default state is everything declared in {@link PictureInPictureUiState} is false, such as
* {@link PictureInPictureUiState#isStashed()}.
*
* @param pipState the new Picture-in-Picture state.
*/
public void onPictureInPictureUiStateChanged(@NonNull PictureInPictureUiState pipState) {
// Left deliberately empty. There should be no side effects if a direct
// subclass of Activity does not call super.
}
/**
* Called by the system when the activity changes to and from picture-in-picture mode.
*

View File

@@ -3999,6 +3999,12 @@ public final class ActivityThread extends ClientTransactionHandler
}
}
@Override
public void handlePictureInPictureStateChanged(@NonNull ActivityClientRecord r,
PictureInPictureUiState pipState) {
r.activity.onPictureInPictureUiStateChanged(pipState);
}
/**
* Register a splash screen manager to this process.
*/

View File

@@ -159,6 +159,10 @@ public abstract class ClientTransactionHandler {
/** Request that an activity enter picture-in-picture. */
public abstract void handlePictureInPictureRequested(@NonNull ActivityClientRecord r);
/** Signal to an activity (that is currently in PiP) of PiP state changes. */
public abstract void handlePictureInPictureStateChanged(@NonNull ActivityClientRecord r,
PictureInPictureUiState pipState);
/** Whether the activity want to handle splash screen exit animation */
public abstract boolean isHandleSplashScreenExit(@NonNull IBinder token);

View File

@@ -36,6 +36,7 @@ import android.app.IUidObserver;
import android.app.IUserSwitchObserver;
import android.app.Notification;
import android.app.PendingIntent;
import android.app.PictureInPictureUiState;
import android.app.ProfilerInfo;
import android.app.WaitResult;
import android.app.assist.AssistContent;
@@ -330,4 +331,9 @@ interface IActivityTaskManager {
*/
void onSplashScreenViewCopyFinished(int taskId,
in SplashScreenView.SplashScreenViewParcelable material);
/**
* When the Picture-in-picture state has changed.
*/
void onPictureInPictureStateChanged(in PictureInPictureUiState pipState);
}

View File

@@ -0,0 +1,19 @@
/**
* Copyright (c) 2021, The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.app;
parcelable PictureInPictureUiState;

View File

@@ -0,0 +1,83 @@
/*
* Copyright (C) 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.app;
import android.annotation.NonNull;
import android.annotation.TestApi;
import android.os.Parcel;
import android.os.Parcelable;
import java.util.Objects;
/**
* Used by {@link Activity#onPictureInPictureUiStateChanged(PictureInPictureUiState)}.
*/
public final class PictureInPictureUiState implements Parcelable {
private boolean mIsStashed;
/** {@hide} */
PictureInPictureUiState(Parcel in) {
mIsStashed = in.readBoolean();
}
/** {@hide} */
@TestApi
public PictureInPictureUiState(boolean isStashed) {
mIsStashed = isStashed;
}
/**
* Returns whether Picture-in-Picture is stashed or not.
*/
public boolean isStashed() {
return mIsStashed;
}
@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);
}
@Override
public int hashCode() {
return Objects.hash(mIsStashed);
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(@NonNull Parcel out, int flags) {
out.writeBoolean(mIsStashed);
}
public static final @android.annotation.NonNull Creator<PictureInPictureUiState> CREATOR =
new Creator<PictureInPictureUiState>() {
public PictureInPictureUiState createFromParcel(Parcel in) {
return new PictureInPictureUiState(in);
}
public PictureInPictureUiState[] newArray(int size) {
return new PictureInPictureUiState[size];
}
};
}

View File

@@ -0,0 +1,93 @@
/*
* Copyright 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.app.servertransaction;
import android.annotation.Nullable;
import android.app.ActivityThread.ActivityClientRecord;
import android.app.ClientTransactionHandler;
import android.app.PictureInPictureUiState;
import android.os.Parcel;
/**
* Request an activity to enter picture-in-picture mode.
* @hide
*/
public final class PipStateTransactionItem extends ActivityTransactionItem {
private PictureInPictureUiState mPipState;
@Override
public void execute(ClientTransactionHandler client, ActivityClientRecord r,
PendingTransactionActions pendingActions) {
client.handlePictureInPictureStateChanged(r, mPipState);
}
// ObjectPoolItem implementation
private PipStateTransactionItem() {}
/** Obtain an instance initialized with provided params. */
public static PipStateTransactionItem obtain(PictureInPictureUiState pipState) {
PipStateTransactionItem instance = ObjectPool.obtain(PipStateTransactionItem.class);
if (instance == null) {
instance = new PipStateTransactionItem();
}
instance.mPipState = pipState;
return instance;
}
@Override
public void recycle() {
mPipState = null;
ObjectPool.recycle(this);
}
// Parcelable implementation
/** Write to Parcel. */
@Override
public void writeToParcel(Parcel dest, int flags) {
mPipState.writeToParcel(dest, flags);
}
/** Read from Parcel. */
private PipStateTransactionItem(Parcel in) {
mPipState = PictureInPictureUiState.CREATOR.createFromParcel(in);
}
public static final @android.annotation.NonNull Creator<PipStateTransactionItem> CREATOR =
new Creator<PipStateTransactionItem>() {
public PipStateTransactionItem createFromParcel(Parcel in) {
return new PipStateTransactionItem(in);
}
public PipStateTransactionItem[] newArray(int size) {
return new PipStateTransactionItem[size];
}
};
@Override
public boolean equals(@Nullable Object o) {
return this == o;
}
@Override
public String toString() {
return "PipStateTransactionItem{}";
}
}

View File

@@ -19,10 +19,14 @@ package com.android.wm.shell.pip;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.ActivityTaskManager;
import android.app.PictureInPictureUiState;
import android.content.ComponentName;
import android.content.Context;
import android.graphics.Point;
import android.graphics.Rect;
import android.os.RemoteException;
import android.util.Log;
import android.util.Size;
import android.view.Display;
@@ -185,7 +189,18 @@ public final class PipBoundsState {
/** Dictate where PiP currently should be stashed, if at all. */
public void setStashed(@StashType int stashedState) {
if (mStashedState == stashedState) {
return;
}
mStashedState = stashedState;
try {
ActivityTaskManager.getService().onPictureInPictureStateChanged(
new PictureInPictureUiState(stashedState != STASH_TYPE_NONE /* isStashed */)
);
} catch (RemoteException e) {
Log.e(TAG, "Unable to set alert PiP state change.");
}
}
/**

View File

@@ -45,8 +45,10 @@ import android.app.ActivityTaskManager;
import android.app.IActivityClientController;
import android.app.IRequestFinishCallback;
import android.app.PictureInPictureParams;
import android.app.PictureInPictureUiState;
import android.app.servertransaction.ClientTransaction;
import android.app.servertransaction.EnterPipRequestedItem;
import android.app.servertransaction.PipStateTransactionItem;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
@@ -779,6 +781,26 @@ class ActivityClientController extends IActivityClientController.Stub {
}
}
/**
* Alert the client that the Picture-in-Picture state has changed.
*/
void onPictureInPictureStateChanged(@NonNull ActivityRecord r,
PictureInPictureUiState pipState) {
if (!r.inPinnedWindowingMode()) {
throw new IllegalStateException("Activity is not in PIP mode");
}
try {
final ClientTransaction transaction = ClientTransaction.obtain(
r.app.getThread(), r.token);
transaction.addCallback(PipStateTransactionItem.obtain(pipState));
mService.getLifecycleManager().scheduleTransaction(transaction);
} catch (Exception e) {
Slog.w(TAG, "Failed to send pip state transaction item: "
+ r.intent.getComponent(), e);
}
}
@Override
public void toggleFreeformWindowingMode(IBinder token) {
final long ident = Binder.clearCallingIdentity();

View File

@@ -141,6 +141,7 @@ import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.PictureInPictureParams;
import android.app.PictureInPictureUiState;
import android.app.ProfilerInfo;
import android.app.RemoteAction;
import android.app.WaitResult;
@@ -3644,6 +3645,17 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
}
}
@Override
public void onPictureInPictureStateChanged(PictureInPictureUiState pipState) {
enforceTaskPermission("onPictureInPictureStateChanged");
final Task rootPinnedStask = mRootWindowContainer.getDefaultTaskDisplayArea()
.getRootPinnedTask();
if (rootPinnedStask != null && rootPinnedStask.getTopMostActivity() != null) {
mWindowManager.mAtmService.mActivityClientController.onPictureInPictureStateChanged(
rootPinnedStask.getTopMostActivity(), pipState);
}
}
void dumpLastANRLocked(PrintWriter pw) {
pw.println("ACTIVITY MANAGER LAST ANR (dumpsys activity lastanr)");
if (mLastANRState == null) {