Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 5bbe9dc2 authored by Alan Stokes's avatar Alan Stokes Committed by Automerger Merge Worker
Browse files

Merge "Grant SYSTEM_ALERT_WINDOW during screen capture." into rvc-dev am: 9b081e49

Change-Id: I6b5216374df2f6c74f3f527d42133c4bae546cd6
parents 8577bd79 9b081e49
Loading
Loading
Loading
Loading
+6 −2
Original line number Diff line number Diff line
@@ -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,
+51 −1
Original line number Diff line number Diff line
@@ -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;