Loading core/java/android/app/AppOpsManager.java +11 −1 Original line number Diff line number Diff line Loading @@ -245,8 +245,10 @@ public class AppOpsManager { public static final int OP_READ_PHONE_NUMBER = 65; /** @hide Request package installs through package installer */ public static final int OP_REQUEST_INSTALL_PACKAGES = 66; /** @hide Enter picture-in-picture when hidden. */ public static final int OP_ENTER_PICTURE_IN_PICTURE_ON_HIDE = 67; /** @hide */ public static final int _NUM_OP = 67; public static final int _NUM_OP = 68; /** Access to coarse location information. */ public static final String OPSTR_COARSE_LOCATION = "android:coarse_location"; Loading Loading @@ -464,6 +466,7 @@ public class AppOpsManager { OP_AUDIO_ACCESSIBILITY_VOLUME, OP_READ_PHONE_NUMBER, OP_REQUEST_INSTALL_PACKAGES, OP_ENTER_PICTURE_IN_PICTURE_ON_HIDE, }; /** Loading Loading @@ -538,6 +541,7 @@ public class AppOpsManager { null, // OP_AUDIO_ACCESSIBILITY_VOLUME OPSTR_READ_PHONE_NUMBER, null, // OP_REQUEST_INSTALL_PACKAGES null, }; /** Loading Loading @@ -612,6 +616,7 @@ public class AppOpsManager { "AUDIO_ACCESSIBILITY_VOLUME", "READ_PHONE_NUMBER", "REQUEST_INSTALL_PACKAGES", "OP_ENTER_PICTURE_IN_PICTURE_ON_HIDE", }; /** Loading Loading @@ -686,6 +691,7 @@ public class AppOpsManager { null, // no permission for changing accessibility volume Manifest.permission.READ_PHONE_NUMBER, Manifest.permission.REQUEST_INSTALL_PACKAGES, null, // no permission for entering picture-in-picture on hide }; /** Loading Loading @@ -761,6 +767,7 @@ public class AppOpsManager { UserManager.DISALLOW_ADJUST_VOLUME, //AUDIO_ACCESSIBILITY_VOLUME null, // READ_PHONE_NUMBER null, // REQUEST_INSTALL_PACKAGES null, // ENTER_PICTURE_IN_PICTURE_ON_HIDE }; /** Loading Loading @@ -835,6 +842,7 @@ public class AppOpsManager { false, // AUDIO_ACCESSIBILITY_VOLUME false, // READ_PHONE_NUMBER false, // REQUEST_INSTALL_PACKAGES false, // ENTER_PICTURE_IN_PICTURE_ON_HIDE }; /** Loading Loading @@ -908,6 +916,7 @@ public class AppOpsManager { AppOpsManager.MODE_ALLOWED, // OP_AUDIO_ACCESSIBILITY_VOLUME AppOpsManager.MODE_ALLOWED, AppOpsManager.MODE_DEFAULT, // OP_REQUEST_INSTALL_PACKAGES AppOpsManager.MODE_ALLOWED, // OP_ENTER_PICTURE_IN_PICTURE_ON_HIDE }; /** Loading Loading @@ -985,6 +994,7 @@ public class AppOpsManager { false, // OP_AUDIO_ACCESSIBILITY_VOLUME false, false, // OP_REQUEST_INSTALL_PACKAGES false, // OP_ENTER_PICTURE_IN_PICTURE_ON_HIDE }; /** Loading core/java/android/provider/Settings.java +13 −0 Original line number Diff line number Diff line Loading @@ -1333,6 +1333,19 @@ public final class Settings { public static final String ACTION_VR_LISTENER_SETTINGS = "android.settings.VR_LISTENER_SETTINGS"; /** * Activity Action: Show Picture-in-picture settings. * <p> * Input: Nothing. * <p> * Output: Nothing. * * @hide */ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) public static final String ACTION_PICTURE_IN_PICTURE_SETTINGS = "android.settings.PICTURE_IN_PICTURE_SETTINGS"; /** * Activity Action: Show Storage Manager settings. * <p> Loading proto/src/metrics_constants.proto +10 −0 Original line number Diff line number Diff line Loading @@ -3321,6 +3321,16 @@ message MetricsEvent { // Indicates number of terms read on the terms screen. PROVISIONING_TERMS_READ = 811; // Logs that the user has edited the picture-in-picture settings. // CATEGORY: SETTINGS SETTINGS_MANAGE_PICTURE_IN_PICTURE = 812; // ACTION: Allow "Enable picture-in-picture on hide" for an app APP_PICTURE_IN_PICTURE_ON_HIDE_ALLOW = 813; // ACTION: Deny "Enable picture-in-picture on hide" for an app APP_PICTURE_IN_PICTURE_ON_HIDE_DENY = 814; // ---- End O Constants, all O constants go above this line ---- // Add new aosp constants above this line. Loading services/core/java/com/android/server/am/ActivityRecord.java +21 −2 Original line number Diff line number Diff line Loading @@ -22,6 +22,8 @@ import static android.app.ActivityManager.StackId.DOCKED_STACK_ID; import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID; import static android.app.ActivityManager.StackId.HOME_STACK_ID; import static android.app.ActivityManager.StackId.PINNED_STACK_ID; import static android.app.AppOpsManager.MODE_ALLOWED; import static android.app.AppOpsManager.OP_ENTER_PICTURE_IN_PICTURE_ON_HIDE; import static android.content.Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS; import static android.content.pm.ActivityInfo.CONFIG_ORIENTATION; import static android.content.pm.ActivityInfo.CONFIG_SCREEN_LAYOUT; Loading Loading @@ -64,6 +66,7 @@ import static com.android.server.am.TaskRecord.INVALID_TASK_ID; import android.annotation.NonNull; import android.app.ActivityManager.TaskDescription; import android.app.ActivityOptions; import android.app.AppOpsManager; import android.app.PendingIntent; import android.app.PictureInPictureArgs; import android.app.ResultInfo; Loading @@ -75,6 +78,7 @@ import android.content.res.CompatibilityInfo; import android.content.res.Configuration; import android.graphics.Bitmap; import android.graphics.Rect; import android.os.Binder; import android.os.Bundle; import android.os.Debug; import android.os.IBinder; Loading Loading @@ -911,13 +915,15 @@ final class ActivityRecord implements AppWindowContainerListener { case PAUSED: // When pausing, only allow enter PiP if not on the lockscreen and there is not // already an existing PiP activity return !isKeyguardLocked && !hasPinnedStack && supportsPictureInPictureWhilePausing; return !isKeyguardLocked && !hasPinnedStack && supportsPictureInPictureWhilePausing && checkEnterPictureInPictureOnHideAppOpsState(); case STOPPING: // When stopping in a valid state, then only allow enter PiP as in the pause state. // Otherwise, fall through to throw an exception if the caller is trying to enter // PiP in an invalid stopping state. if (supportsPictureInPictureWhilePausing) { return !isKeyguardLocked && !hasPinnedStack; return !isKeyguardLocked && !hasPinnedStack && checkEnterPictureInPictureOnHideAppOpsState(); } default: throw new IllegalStateException(caller Loading @@ -926,6 +932,19 @@ final class ActivityRecord implements AppWindowContainerListener { } } /** * @return Whether AppOps allows this package to enter picture-in-picture when it is hidden. */ private boolean checkEnterPictureInPictureOnHideAppOpsState() { try { return service.getAppOpsService().checkOperation(OP_ENTER_PICTURE_IN_PICTURE_ON_HIDE, appInfo.uid, packageName) == MODE_ALLOWED; } catch (RemoteException e) { // Local call } return false; } boolean canGoInDockedStack() { return !isHomeActivity() && isResizeableOrForced(); } Loading Loading
core/java/android/app/AppOpsManager.java +11 −1 Original line number Diff line number Diff line Loading @@ -245,8 +245,10 @@ public class AppOpsManager { public static final int OP_READ_PHONE_NUMBER = 65; /** @hide Request package installs through package installer */ public static final int OP_REQUEST_INSTALL_PACKAGES = 66; /** @hide Enter picture-in-picture when hidden. */ public static final int OP_ENTER_PICTURE_IN_PICTURE_ON_HIDE = 67; /** @hide */ public static final int _NUM_OP = 67; public static final int _NUM_OP = 68; /** Access to coarse location information. */ public static final String OPSTR_COARSE_LOCATION = "android:coarse_location"; Loading Loading @@ -464,6 +466,7 @@ public class AppOpsManager { OP_AUDIO_ACCESSIBILITY_VOLUME, OP_READ_PHONE_NUMBER, OP_REQUEST_INSTALL_PACKAGES, OP_ENTER_PICTURE_IN_PICTURE_ON_HIDE, }; /** Loading Loading @@ -538,6 +541,7 @@ public class AppOpsManager { null, // OP_AUDIO_ACCESSIBILITY_VOLUME OPSTR_READ_PHONE_NUMBER, null, // OP_REQUEST_INSTALL_PACKAGES null, }; /** Loading Loading @@ -612,6 +616,7 @@ public class AppOpsManager { "AUDIO_ACCESSIBILITY_VOLUME", "READ_PHONE_NUMBER", "REQUEST_INSTALL_PACKAGES", "OP_ENTER_PICTURE_IN_PICTURE_ON_HIDE", }; /** Loading Loading @@ -686,6 +691,7 @@ public class AppOpsManager { null, // no permission for changing accessibility volume Manifest.permission.READ_PHONE_NUMBER, Manifest.permission.REQUEST_INSTALL_PACKAGES, null, // no permission for entering picture-in-picture on hide }; /** Loading Loading @@ -761,6 +767,7 @@ public class AppOpsManager { UserManager.DISALLOW_ADJUST_VOLUME, //AUDIO_ACCESSIBILITY_VOLUME null, // READ_PHONE_NUMBER null, // REQUEST_INSTALL_PACKAGES null, // ENTER_PICTURE_IN_PICTURE_ON_HIDE }; /** Loading Loading @@ -835,6 +842,7 @@ public class AppOpsManager { false, // AUDIO_ACCESSIBILITY_VOLUME false, // READ_PHONE_NUMBER false, // REQUEST_INSTALL_PACKAGES false, // ENTER_PICTURE_IN_PICTURE_ON_HIDE }; /** Loading Loading @@ -908,6 +916,7 @@ public class AppOpsManager { AppOpsManager.MODE_ALLOWED, // OP_AUDIO_ACCESSIBILITY_VOLUME AppOpsManager.MODE_ALLOWED, AppOpsManager.MODE_DEFAULT, // OP_REQUEST_INSTALL_PACKAGES AppOpsManager.MODE_ALLOWED, // OP_ENTER_PICTURE_IN_PICTURE_ON_HIDE }; /** Loading Loading @@ -985,6 +994,7 @@ public class AppOpsManager { false, // OP_AUDIO_ACCESSIBILITY_VOLUME false, false, // OP_REQUEST_INSTALL_PACKAGES false, // OP_ENTER_PICTURE_IN_PICTURE_ON_HIDE }; /** Loading
core/java/android/provider/Settings.java +13 −0 Original line number Diff line number Diff line Loading @@ -1333,6 +1333,19 @@ public final class Settings { public static final String ACTION_VR_LISTENER_SETTINGS = "android.settings.VR_LISTENER_SETTINGS"; /** * Activity Action: Show Picture-in-picture settings. * <p> * Input: Nothing. * <p> * Output: Nothing. * * @hide */ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) public static final String ACTION_PICTURE_IN_PICTURE_SETTINGS = "android.settings.PICTURE_IN_PICTURE_SETTINGS"; /** * Activity Action: Show Storage Manager settings. * <p> Loading
proto/src/metrics_constants.proto +10 −0 Original line number Diff line number Diff line Loading @@ -3321,6 +3321,16 @@ message MetricsEvent { // Indicates number of terms read on the terms screen. PROVISIONING_TERMS_READ = 811; // Logs that the user has edited the picture-in-picture settings. // CATEGORY: SETTINGS SETTINGS_MANAGE_PICTURE_IN_PICTURE = 812; // ACTION: Allow "Enable picture-in-picture on hide" for an app APP_PICTURE_IN_PICTURE_ON_HIDE_ALLOW = 813; // ACTION: Deny "Enable picture-in-picture on hide" for an app APP_PICTURE_IN_PICTURE_ON_HIDE_DENY = 814; // ---- End O Constants, all O constants go above this line ---- // Add new aosp constants above this line. Loading
services/core/java/com/android/server/am/ActivityRecord.java +21 −2 Original line number Diff line number Diff line Loading @@ -22,6 +22,8 @@ import static android.app.ActivityManager.StackId.DOCKED_STACK_ID; import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID; import static android.app.ActivityManager.StackId.HOME_STACK_ID; import static android.app.ActivityManager.StackId.PINNED_STACK_ID; import static android.app.AppOpsManager.MODE_ALLOWED; import static android.app.AppOpsManager.OP_ENTER_PICTURE_IN_PICTURE_ON_HIDE; import static android.content.Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS; import static android.content.pm.ActivityInfo.CONFIG_ORIENTATION; import static android.content.pm.ActivityInfo.CONFIG_SCREEN_LAYOUT; Loading Loading @@ -64,6 +66,7 @@ import static com.android.server.am.TaskRecord.INVALID_TASK_ID; import android.annotation.NonNull; import android.app.ActivityManager.TaskDescription; import android.app.ActivityOptions; import android.app.AppOpsManager; import android.app.PendingIntent; import android.app.PictureInPictureArgs; import android.app.ResultInfo; Loading @@ -75,6 +78,7 @@ import android.content.res.CompatibilityInfo; import android.content.res.Configuration; import android.graphics.Bitmap; import android.graphics.Rect; import android.os.Binder; import android.os.Bundle; import android.os.Debug; import android.os.IBinder; Loading Loading @@ -911,13 +915,15 @@ final class ActivityRecord implements AppWindowContainerListener { case PAUSED: // When pausing, only allow enter PiP if not on the lockscreen and there is not // already an existing PiP activity return !isKeyguardLocked && !hasPinnedStack && supportsPictureInPictureWhilePausing; return !isKeyguardLocked && !hasPinnedStack && supportsPictureInPictureWhilePausing && checkEnterPictureInPictureOnHideAppOpsState(); case STOPPING: // When stopping in a valid state, then only allow enter PiP as in the pause state. // Otherwise, fall through to throw an exception if the caller is trying to enter // PiP in an invalid stopping state. if (supportsPictureInPictureWhilePausing) { return !isKeyguardLocked && !hasPinnedStack; return !isKeyguardLocked && !hasPinnedStack && checkEnterPictureInPictureOnHideAppOpsState(); } default: throw new IllegalStateException(caller Loading @@ -926,6 +932,19 @@ final class ActivityRecord implements AppWindowContainerListener { } } /** * @return Whether AppOps allows this package to enter picture-in-picture when it is hidden. */ private boolean checkEnterPictureInPictureOnHideAppOpsState() { try { return service.getAppOpsService().checkOperation(OP_ENTER_PICTURE_IN_PICTURE_ON_HIDE, appInfo.uid, packageName) == MODE_ALLOWED; } catch (RemoteException e) { // Local call } return false; } boolean canGoInDockedStack() { return !isHomeActivity() && isResizeableOrForced(); } Loading