Merge "Grant SYSTEM_ALERT_WINDOW during screen capture." into rvc-dev
This commit is contained in:
@@ -23,8 +23,6 @@ import android.app.Activity;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.media.projection.IMediaProjection;
|
||||
import android.os.Handler;
|
||||
import android.os.IBinder;
|
||||
import android.os.RemoteException;
|
||||
@@ -86,6 +84,12 @@ public final class MediaProjectionManager {
|
||||
* capture request. Will be null if the result from the
|
||||
* startActivityForResult() is anything other than RESULT_OK.
|
||||
*
|
||||
* Starting from Android {@link android.os.Build.VERSION_CODES#R}, if your application requests
|
||||
* the {@link android.Manifest.permission#SYSTEM_ALERT_WINDOW} permission, and the
|
||||
* user has not explicitly denied it, the permission will be automatically granted until the
|
||||
* projection is stopped. This allows for user controls to be displayed on top of the screen
|
||||
* being captured.
|
||||
*
|
||||
* @param resultCode The result code from {@link android.app.Activity#onActivityResult(int,
|
||||
* int, android.content.Intent)}
|
||||
* @param resultData The resulting data from {@link android.app.Activity#onActivityResult(int,
|
||||
|
||||
@@ -22,6 +22,7 @@ import android.app.AppOpsManager;
|
||||
import android.app.IProcessObserver;
|
||||
import android.content.Context;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.PackageInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.PackageManager.NameNotFoundException;
|
||||
import android.content.pm.ServiceInfo;
|
||||
@@ -43,6 +44,7 @@ import android.os.UserHandle;
|
||||
import android.util.ArrayMap;
|
||||
import android.util.Slog;
|
||||
|
||||
import com.android.internal.util.ArrayUtils;
|
||||
import com.android.internal.util.DumpUtils;
|
||||
import com.android.server.LocalServices;
|
||||
import com.android.server.SystemService;
|
||||
@@ -399,11 +401,12 @@ public final class MediaProjectionManagerService extends SystemService
|
||||
public final UserHandle userHandle;
|
||||
private final int mTargetSdkVersion;
|
||||
private final boolean mIsPrivileged;
|
||||
private final int mType;
|
||||
|
||||
private IMediaProjectionCallback mCallback;
|
||||
private IBinder mToken;
|
||||
private IBinder.DeathRecipient mDeathEater;
|
||||
private int mType;
|
||||
private boolean mRestoreSystemAlertWindow;
|
||||
|
||||
MediaProjection(int type, int uid, String packageName, int targetSdkVersion,
|
||||
boolean isPrivileged) {
|
||||
@@ -494,6 +497,35 @@ public final class MediaProjectionManagerService extends SystemService
|
||||
"MediaProjectionCallbacks must be valid, aborting MediaProjection", e);
|
||||
return;
|
||||
}
|
||||
if (mType == MediaProjectionManager.TYPE_SCREEN_CAPTURE) {
|
||||
final long token = Binder.clearCallingIdentity();
|
||||
try {
|
||||
// We allow an app running a current screen capture session to use
|
||||
// SYSTEM_ALERT_WINDOW for the duration of the session, to enable
|
||||
// them to overlay their UX on top of what is being captured.
|
||||
// We only do this if the app requests the permission, and the appop
|
||||
// is in its default state (the user has neither explicitly allowed nor
|
||||
// disallowed it).
|
||||
final PackageInfo packageInfo = mPackageManager.getPackageInfoAsUser(
|
||||
packageName, PackageManager.GET_PERMISSIONS,
|
||||
UserHandle.getUserId(uid));
|
||||
if (ArrayUtils.contains(packageInfo.requestedPermissions,
|
||||
Manifest.permission.SYSTEM_ALERT_WINDOW)) {
|
||||
final int currentMode = mAppOps.unsafeCheckOpRawNoThrow(
|
||||
AppOpsManager.OP_SYSTEM_ALERT_WINDOW, uid, packageName);
|
||||
if (currentMode == AppOpsManager.MODE_DEFAULT) {
|
||||
mAppOps.setMode(AppOpsManager.OP_SYSTEM_ALERT_WINDOW, uid,
|
||||
packageName, AppOpsManager.MODE_ALLOWED);
|
||||
mRestoreSystemAlertWindow = true;
|
||||
}
|
||||
}
|
||||
} catch (PackageManager.NameNotFoundException e) {
|
||||
Slog.w(TAG, "Package not found, aborting MediaProjection", e);
|
||||
return;
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(token);
|
||||
}
|
||||
}
|
||||
startProjectionLocked(this);
|
||||
}
|
||||
}
|
||||
@@ -507,6 +539,24 @@ public final class MediaProjectionManagerService extends SystemService
|
||||
+ "pid=" + Binder.getCallingPid() + ")");
|
||||
return;
|
||||
}
|
||||
if (mRestoreSystemAlertWindow) {
|
||||
final long token = Binder.clearCallingIdentity();
|
||||
try {
|
||||
// Put the appop back how it was, unless it has been changed from what
|
||||
// we set it to.
|
||||
// Note that WindowManager takes care of removing any existing overlay
|
||||
// windows when we do this.
|
||||
final int currentMode = mAppOps.unsafeCheckOpRawNoThrow(
|
||||
AppOpsManager.OP_SYSTEM_ALERT_WINDOW, uid, packageName);
|
||||
if (currentMode == AppOpsManager.MODE_ALLOWED) {
|
||||
mAppOps.setMode(AppOpsManager.OP_SYSTEM_ALERT_WINDOW, uid, packageName,
|
||||
AppOpsManager.MODE_DEFAULT);
|
||||
}
|
||||
mRestoreSystemAlertWindow = false;
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(token);
|
||||
}
|
||||
}
|
||||
stopProjectionLocked(this);
|
||||
mToken.unlinkToDeath(mDeathEater, 0);
|
||||
mToken = null;
|
||||
|
||||
Reference in New Issue
Block a user