summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Winson Chung <winsonc@google.com> 2017-08-10 15:57:18 -0700
committer Winson Chung <winsonc@google.com> 2017-08-23 15:06:32 -0700
commit298f95b1ad04b2cc9f46f221dcc2d3932f532fdd (patch)
tree7f98f095da863630b346dbb37a0a55c6cc6edd40
parent230e02584171feb0fc17706a1b70734172a89623 (diff)
Move PiP state check exception to the client side
- When calling enterPictureInPictureMode(), the state of the activity in the client may be out of sync with the state of the activity in the system, causing an exception to be thrown erroneously. Instead, fail silently in the system if this occurs, and throw the exception in the client when it attempts to enter PiP from an invalid state. Bug: 63753007 Test: android.server.cts.ActivityManagerPinnedStackTests Change-Id: Ia99cc086805edc31f997d4325f7a5ccd7c85a77e
-rw-r--r--core/java/android/app/Activity.java41
-rw-r--r--core/java/android/app/Instrumentation.java3
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java2
-rw-r--r--services/core/java/com/android/server/am/ActivityRecord.java13
-rw-r--r--services/core/java/com/android/server/am/ActivityStack.java4
5 files changed, 36 insertions, 27 deletions
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 3fa89279e9cc..757795e06cfb 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -762,6 +762,10 @@ public class Activity extends ContextThemeWrapper
private boolean mDestroyed;
private boolean mDoReportFullyDrawn = true;
private boolean mRestoredFromBundle;
+
+ /** {@code true} if the activity lifecycle is in a state which supports picture-in-picture.
+ * This only affects the client-side exception, the actual state check still happens in AMS. */
+ private boolean mCanEnterPictureInPicture = false;
/** true if the activity is going through a transient pause */
/*package*/ boolean mTemporaryPause = false;
/** true if the activity is being destroyed in order to recreate it with a new configuration */
@@ -2091,6 +2095,10 @@ public class Activity extends ContextThemeWrapper
if (params == null) {
throw new IllegalArgumentException("Expected non-null picture-in-picture params");
}
+ if (!mCanEnterPictureInPicture) {
+ throw new IllegalStateException("Activity must be resumed to enter"
+ + " picture-in-picture");
+ }
return ActivityManagerNative.getDefault().enterPictureInPictureMode(mToken, params);
} catch (RemoteException e) {
return false;
@@ -6957,25 +6965,29 @@ public class Activity extends ContextThemeWrapper
return mParent != null ? mParent.getActivityToken() : mToken;
}
- final void performCreateCommon() {
- mVisibleFromClient = !mWindow.getWindowStyle().getBoolean(
- com.android.internal.R.styleable.Window_windowNoDisplay, false);
- mFragments.dispatchActivityCreated();
- mActivityTransitionState.setEnterActivityOptions(this, getActivityOptions());
- }
-
final void performCreate(Bundle icicle) {
- restoreHasCurrentPermissionRequest(icicle);
- onCreate(icicle);
- mActivityTransitionState.readState(icicle);
- performCreateCommon();
+ performCreate(icicle, null);
}
final void performCreate(Bundle icicle, PersistableBundle persistentState) {
+ mCanEnterPictureInPicture = true;
restoreHasCurrentPermissionRequest(icicle);
- onCreate(icicle, persistentState);
+ if (persistentState != null) {
+ onCreate(icicle, persistentState);
+ } else {
+ onCreate(icicle);
+ }
mActivityTransitionState.readState(icicle);
- performCreateCommon();
+
+ mVisibleFromClient = !mWindow.getWindowStyle().getBoolean(
+ com.android.internal.R.styleable.Window_windowNoDisplay, false);
+ mFragments.dispatchActivityCreated();
+ mActivityTransitionState.setEnterActivityOptions(this, getActivityOptions());
+ }
+
+ final void performNewIntent(Intent intent) {
+ mCanEnterPictureInPicture = true;
+ onNewIntent(intent);
}
final void performStart() {
@@ -7126,6 +7138,9 @@ public class Activity extends ContextThemeWrapper
mDoReportFullyDrawn = false;
mFragments.doLoaderStop(mChangingConfigurations /*retain*/);
+ // Disallow entering picture-in-picture after the activity has been stopped
+ mCanEnterPictureInPicture = false;
+
if (!mStopped) {
if (mWindow != null) {
mWindow.closeAllPanels();
diff --git a/core/java/android/app/Instrumentation.java b/core/java/android/app/Instrumentation.java
index 467fc952ffee..e260967f92d0 100644
--- a/core/java/android/app/Instrumentation.java
+++ b/core/java/android/app/Instrumentation.java
@@ -48,6 +48,7 @@ import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.ViewConfiguration;
import android.view.Window;
+
import com.android.internal.content.ReferrerIntent;
import java.io.File;
@@ -1305,7 +1306,7 @@ public class Instrumentation {
* @param intent The new intent being received.
*/
public void callActivityOnNewIntent(Activity activity, Intent intent) {
- activity.onNewIntent(intent);
+ activity.performNewIntent(intent);
}
/**
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 32d34450e2c1..5c5a6b7ac205 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -8045,7 +8045,7 @@ public class ActivityManagerService extends IActivityManager.Stub
// Activity supports picture-in-picture, now check that we can enter PiP at this
// point, if it is
if (!r.checkEnterPictureInPictureState("enterPictureInPictureMode",
- false /* noThrow */, false /* beforeStopping */)) {
+ false /* beforeStopping */)) {
return false;
}
diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java
index e5985c58e5af..874bd1e7625b 100644
--- a/services/core/java/com/android/server/am/ActivityRecord.java
+++ b/services/core/java/com/android/server/am/ActivityRecord.java
@@ -1186,10 +1186,9 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo
* @param beforeStopping Whether this check is for an auto-enter-pip operation, that is to say
* the activity has requested to enter PiP when it would otherwise be stopped.
*
- * @return whether this activity is currently allowed to enter PIP, throwing an exception if
- * the activity is not currently visible and {@param noThrow} is not set.
+ * @return whether this activity is currently allowed to enter PIP.
*/
- boolean checkEnterPictureInPictureState(String caller, boolean noThrow, boolean beforeStopping) {
+ boolean checkEnterPictureInPictureState(String caller, boolean beforeStopping) {
if (!supportsPictureInPicture()) {
return false;
}
@@ -1237,13 +1236,7 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo
return isNotLockedOrOnKeyguard && !hasPinnedStack;
}
default:
- if (noThrow) {
- return false;
- } else {
- throw new IllegalStateException(caller
- + ": Current activity is not visible (state=" + state.name() + ") "
- + "r=" + this);
- }
+ return false;
}
}
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index c2656a188dc8..eb3177a6e1c9 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -2076,7 +2076,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY, "Making invisible: " + r + " " + r.state);
try {
final boolean canEnterPictureInPicture = r.checkEnterPictureInPictureState(
- "makeInvisible", true /* noThrow */, true /* beforeStopping */);
+ "makeInvisible", true /* beforeStopping */);
// Defer telling the client it is hidden if it can enter Pip and isn't current stopped
// or stopping. This gives it a chance to enter Pip in onPause().
final boolean deferHidingClient = canEnterPictureInPicture
@@ -2390,7 +2390,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
// represent the last resumed activity. However, the last focus stack does if it isn't null.
final ActivityRecord lastResumed = lastFocusedStack.mResumedActivity;
lastResumedCanPip = lastResumed != null && lastResumed.checkEnterPictureInPictureState(
- "resumeTopActivity", true /* noThrow */, userLeaving /* beforeStopping */);
+ "resumeTopActivity", userLeaving /* beforeStopping */);
}
// If the flag RESUME_WHILE_PAUSING is set, then continue to schedule the previous activity
// to be paused, while at the same time resuming the new resume activity only if the