diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java index 7141259d7dce7..90c37d1999e1d 100644 --- a/core/java/android/app/Activity.java +++ b/core/java/android/app/Activity.java @@ -6432,6 +6432,20 @@ public class Activity extends ContextThemeWrapper } } + /** + * Ensures the activity's result is immediately returned to the caller when {@link #finish()} + * is invoked + * + *
Should be invoked alongside {@link #setResult(int, Intent)}, so the provided results are
+ * in place before finishing. Must only be invoked during MediaProjection setup.
+ *
+ * @hide
+ */
+ @RequiresPermission(android.Manifest.permission.MANAGE_MEDIA_PROJECTION)
+ public final void setForceSendResultForMediaProjection() {
+ ActivityClient.getInstance().setForceSendResultForMediaProjection(mToken);
+ }
+
/**
* Call this to set the result that your activity will return to its
* caller.
diff --git a/core/java/android/app/ActivityClient.java b/core/java/android/app/ActivityClient.java
index 73678d9f2ddad..1d3b5e2aa4ee8 100644
--- a/core/java/android/app/ActivityClient.java
+++ b/core/java/android/app/ActivityClient.java
@@ -17,6 +17,7 @@
package android.app;
import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
import android.content.ComponentName;
import android.content.Intent;
import android.content.res.Configuration;
@@ -184,6 +185,15 @@ public class ActivityClient {
}
}
+ @RequiresPermission(android.Manifest.permission.MANAGE_MEDIA_PROJECTION)
+ void setForceSendResultForMediaProjection(IBinder token) {
+ try {
+ getActivityClientController().setForceSendResultForMediaProjection(token);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
public boolean isTopOfTask(IBinder token) {
try {
return getActivityClientController().isTopOfTask(token);
diff --git a/core/java/android/app/IActivityClientController.aidl b/core/java/android/app/IActivityClientController.aidl
index 0138186974a67..7aeb2b26dd15e 100644
--- a/core/java/android/app/IActivityClientController.aidl
+++ b/core/java/android/app/IActivityClientController.aidl
@@ -67,6 +67,12 @@ interface IActivityClientController {
boolean finishActivityAffinity(in IBinder token);
/** Finish all activities that were started for result from the specified activity. */
void finishSubActivity(in IBinder token, in String resultWho, int requestCode);
+ /**
+ * Indicates that when the activity finsihes, the result should be immediately sent to the
+ * originating activity. Must only be invoked during MediaProjection setup.
+ */
+ @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.MANAGE_MEDIA_PROJECTION)")
+ void setForceSendResultForMediaProjection(in IBinder token);
boolean isTopOfTask(in IBinder token);
boolean willActivityBeVisible(in IBinder token);
diff --git a/services/core/java/com/android/server/wm/ActivityClientController.java b/services/core/java/com/android/server/wm/ActivityClientController.java
index 47aa58751900b..f53b51d705574 100644
--- a/services/core/java/com/android/server/wm/ActivityClientController.java
+++ b/services/core/java/com/android/server/wm/ActivityClientController.java
@@ -43,6 +43,7 @@ import static com.android.server.wm.ActivityTaskManagerService.RELAUNCH_REASON_N
import static com.android.server.wm.ActivityTaskManagerService.TAG_SWITCH;
import static com.android.server.wm.ActivityTaskManagerService.enforceNotIsolatedCaller;
+import android.Manifest;
import android.annotation.ColorInt;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -462,8 +463,8 @@ class ActivityClientController extends IActivityClientController.Stub {
// Explicitly dismissing the activity so reset its relaunch flag.
r.mRelaunchReason = RELAUNCH_REASON_NONE;
} else {
- r.finishIfPossible(resultCode, resultData, resultGrants,
- "app-request", true /* oomAdj */);
+ r.finishIfPossible(resultCode, resultData, resultGrants, "app-request",
+ true /* oomAdj */);
res = r.finishing;
if (!res) {
Slog.i(TAG, "Failed to finish by app-request");
@@ -524,6 +525,23 @@ class ActivityClientController extends IActivityClientController.Stub {
}
}
+ @Override
+ public void setForceSendResultForMediaProjection(IBinder token) {
+ // Require that this is invoked only during MediaProjection setup.
+ mService.mAmInternal.enforceCallingPermission(
+ Manifest.permission.MANAGE_MEDIA_PROJECTION,
+ "setForceSendResultForMediaProjection");
+
+ final ActivityRecord r;
+ synchronized (mGlobalLock) {
+ r = ActivityRecord.isInRootTaskLocked(token);
+ if (r == null || !r.isInHistory()) {
+ return;
+ }
+ r.setForceSendResultForMediaProjection();
+ }
+ }
+
@Override
public boolean isTopOfTask(IBinder token) {
synchronized (mGlobalLock) {
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 0672559e0a9d6..3a103f19c41d0 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -595,6 +595,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
// pre-NYC apps that don't have a sense of being resized.
int mRelaunchReason = RELAUNCH_REASON_NONE;
+ private boolean mForceSendResultForMediaProjection = false;
+
TaskDescription taskDescription; // the recents information for this activity
// The locusId associated with this activity, if set.
@@ -3257,7 +3259,12 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
mAtmService.mUgmInternal.grantUriPermissionUncheckedFromIntent(resultGrants,
resultTo.getUriPermissionsLocked());
}
- resultTo.addResultLocked(this, resultWho, requestCode, resultCode, resultData);
+ if (mForceSendResultForMediaProjection) {
+ resultTo.sendResult(this.getUid(), resultWho, requestCode, resultCode,
+ resultData, resultGrants, true /* forceSendForMediaProjection */);
+ } else {
+ resultTo.addResultLocked(this, resultWho, requestCode, resultCode, resultData);
+ }
resultTo = null;
} else if (DEBUG_RESULTS) {
Slog.v(TAG_RESULTS, "No result destination from " + this);
@@ -3451,6 +3458,10 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
}
}
+ void setForceSendResultForMediaProjection() {
+ mForceSendResultForMediaProjection = true;
+ }
+
private void prepareActivityHideTransitionAnimationIfOvarlay() {
if (mTaskOverlay) {
prepareActivityHideTransitionAnimation();
@@ -4541,6 +4552,12 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
void sendResult(int callingUid, String resultWho, int requestCode, int resultCode,
Intent data, NeededUriGrants dataGrants) {
+ sendResult(callingUid, resultWho, requestCode, resultCode, data, dataGrants,
+ false /* forceSendForMediaProjection */);
+ }
+
+ private void sendResult(int callingUid, String resultWho, int requestCode, int resultCode,
+ Intent data, NeededUriGrants dataGrants, boolean forceSendForMediaProjection) {
if (callingUid > 0) {
mAtmService.mUgmInternal.grantUriPermissionUncheckedFromIntent(dataGrants,
getUriPermissionsLocked());
@@ -4549,8 +4566,10 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
if (DEBUG_RESULTS) {
Slog.v(TAG, "Send activity result to " + this
+ " : who=" + resultWho + " req=" + requestCode
- + " res=" + resultCode + " data=" + data);
+ + " res=" + resultCode + " data=" + data
+ + " forceSendForMediaProjection=" + forceSendForMediaProjection);
}
+
if (isState(RESUMED) && attachedToProcess()) {
try {
final ArrayList