Loading core/api/system-current.txt +1 −0 Original line number Diff line number Diff line Loading @@ -2958,6 +2958,7 @@ package android.companion.virtual { method @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public void close(); method @NonNull @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public android.companion.virtual.audio.VirtualAudioDevice createVirtualAudioDevice(@NonNull android.hardware.display.VirtualDisplay, @Nullable java.util.concurrent.Executor, @Nullable android.companion.virtual.audio.VirtualAudioDevice.AudioConfigurationChangeCallback); method @Nullable public android.hardware.display.VirtualDisplay createVirtualDisplay(@IntRange(from=1) int, @IntRange(from=1) int, @IntRange(from=1) int, @Nullable android.view.Surface, int, @Nullable java.util.concurrent.Executor, @Nullable android.hardware.display.VirtualDisplay.Callback); method @Nullable public android.hardware.display.VirtualDisplay createVirtualDisplay(@IntRange(from=1) int, @IntRange(from=1) int, @IntRange(from=1) int, @NonNull java.util.List<java.lang.String>, @Nullable android.view.Surface, int, @Nullable java.util.concurrent.Executor, @Nullable android.hardware.display.VirtualDisplay.Callback); method @NonNull @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public android.hardware.input.VirtualDpad createVirtualDpad(@NonNull android.hardware.display.VirtualDisplay, @NonNull String, int, int); method @NonNull @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public android.hardware.input.VirtualKeyboard createVirtualKeyboard(@NonNull android.hardware.display.VirtualDisplay, @NonNull String, int, int); method @NonNull @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public android.hardware.input.VirtualMouse createVirtualMouse(@NonNull android.hardware.display.VirtualDisplay, @NonNull String, int, int); core/java/android/companion/virtual/VirtualDeviceManager.java +61 −3 Original line number Diff line number Diff line Loading @@ -350,14 +350,72 @@ public final class VirtualDeviceManager { @VirtualDisplayFlag int flags, @Nullable @CallbackExecutor Executor executor, @Nullable VirtualDisplay.Callback callback) { // TODO(b/205343547): Handle display groups properly instead of creating a new display // group for every new virtual display created using this API. // belongs to the same display group. VirtualDisplayConfig config = new VirtualDisplayConfig.Builder( getVirtualDisplayName(), width, height, densityDpi) .setSurface(surface) .setFlags(getVirtualDisplayFlags(flags)) .build(); return createVirtualDisplayInternal(config, executor, callback); } /** * Creates a virtual display for this virtual device. All displays created on the same * device belongs to the same display group. * * @param width The width of the virtual display in pixels, must be greater than 0. * @param height The height of the virtual display in pixels, must be greater than 0. * @param densityDpi The density of the virtual display in dpi, must be greater than 0. * @param displayCategories The categories of the virtual display, indicating the type of * activities allowed to run on the display. Activities can declare their type using * {@link android.content.pm.ActivityInfo#targetDisplayCategory}. * @param surface The surface to which the content of the virtual display should * be rendered, or null if there is none initially. The surface can also be set later using * {@link VirtualDisplay#setSurface(Surface)}. * @param flags A combination of virtual display flags accepted by * {@link DisplayManager#createVirtualDisplay}. In addition, the following flags are * automatically set for all virtual devices: * {@link DisplayManager#VIRTUAL_DISPLAY_FLAG_PUBLIC VIRTUAL_DISPLAY_FLAG_PUBLIC} and * {@link DisplayManager#VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY * VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY}. * @param executor The executor on which {@code callback} will be invoked. This is ignored * if {@code callback} is {@code null}. If {@code callback} is specified, this executor must * not be null. * @param callback Callback to call when the state of the {@link VirtualDisplay} changes * @return The newly created virtual display, or {@code null} if the application could * not create the virtual display. * * @see DisplayManager#createVirtualDisplay */ @Nullable public VirtualDisplay createVirtualDisplay( @IntRange(from = 1) int width, @IntRange(from = 1) int height, @IntRange(from = 1) int densityDpi, @NonNull List<String> displayCategories, @Nullable Surface surface, @VirtualDisplayFlag int flags, @Nullable @CallbackExecutor Executor executor, @Nullable VirtualDisplay.Callback callback) { VirtualDisplayConfig config = new VirtualDisplayConfig.Builder( getVirtualDisplayName(), width, height, densityDpi) .setDisplayCategories(displayCategories) .setSurface(surface) .setFlags(getVirtualDisplayFlags(flags)) .build(); return createVirtualDisplayInternal(config, executor, callback); } /** * @hide */ @Nullable private VirtualDisplay createVirtualDisplayInternal( @NonNull VirtualDisplayConfig config, @Nullable @CallbackExecutor Executor executor, @Nullable VirtualDisplay.Callback callback) { // TODO(b/205343547): Handle display groups properly instead of creating a new display // group for every new virtual display created using this API. // belongs to the same display group. IVirtualDisplayCallback callbackWrapper = new DisplayManagerGlobal.VirtualDisplayCallback(callback, executor); final int displayId; Loading core/java/android/hardware/display/VirtualDisplayConfig.java +60 −6 Original line number Diff line number Diff line Loading @@ -30,6 +30,9 @@ import android.view.Surface; import com.android.internal.util.DataClass; import java.util.ArrayList; import java.util.List; /** * Holds configuration used to create {@link VirtualDisplay} instances. See * {@link MediaProjection#createVirtualDisplay(VirtualDisplayConfig, VirtualDisplay.Callback, Handler)}. Loading Loading @@ -99,6 +102,13 @@ public final class VirtualDisplayConfig implements Parcelable { */ private boolean mWindowManagerMirroring = false; /** * The display categories. If set, only corresponding activities from the same category can be * shown on the display. */ @DataClass.PluralOf("displayCategory") @NonNull private List<String> mDisplayCategories = new ArrayList<>(); // Code below generated by codegen v1.0.23. Loading @@ -124,7 +134,8 @@ public final class VirtualDisplayConfig implements Parcelable { @Nullable Surface surface, @Nullable String uniqueId, int displayIdToMirror, boolean windowManagerMirroring) { boolean windowManagerMirroring, @NonNull List<String> displayCategories) { this.mName = name; com.android.internal.util.AnnotationValidations.validate( NonNull.class, null, mName); Loading @@ -147,6 +158,9 @@ public final class VirtualDisplayConfig implements Parcelable { this.mUniqueId = uniqueId; this.mDisplayIdToMirror = displayIdToMirror; this.mWindowManagerMirroring = windowManagerMirroring; this.mDisplayCategories = displayCategories; com.android.internal.util.AnnotationValidations.validate( NonNull.class, null, mDisplayCategories); // onConstructed(); // You can define this method to get a callback } Loading Loading @@ -233,6 +247,15 @@ public final class VirtualDisplayConfig implements Parcelable { return mWindowManagerMirroring; } /** * The display categories. If set, only corresponding activities from the same category can be * shown on the display. */ @DataClass.Generated.Member public @NonNull List<String> getDisplayCategories() { return mDisplayCategories; } @Override @DataClass.Generated.Member public void writeToParcel(@NonNull Parcel dest, int flags) { Loading @@ -252,6 +275,7 @@ public final class VirtualDisplayConfig implements Parcelable { if (mSurface != null) dest.writeTypedObject(mSurface, flags); if (mUniqueId != null) dest.writeString(mUniqueId); dest.writeInt(mDisplayIdToMirror); dest.writeStringList(mDisplayCategories); } @Override Loading @@ -275,6 +299,8 @@ public final class VirtualDisplayConfig implements Parcelable { Surface surface = (flg & 0x20) == 0 ? null : (Surface) in.readTypedObject(Surface.CREATOR); String uniqueId = (flg & 0x40) == 0 ? null : in.readString(); int displayIdToMirror = in.readInt(); List<String> displayCategories = new ArrayList<>(); in.readStringList(displayCategories); this.mName = name; com.android.internal.util.AnnotationValidations.validate( Loading @@ -298,6 +324,9 @@ public final class VirtualDisplayConfig implements Parcelable { this.mUniqueId = uniqueId; this.mDisplayIdToMirror = displayIdToMirror; this.mWindowManagerMirroring = windowManagerMirroring; this.mDisplayCategories = displayCategories; com.android.internal.util.AnnotationValidations.validate( NonNull.class, null, mDisplayCategories); // onConstructed(); // You can define this method to get a callback } Loading Loading @@ -332,6 +361,7 @@ public final class VirtualDisplayConfig implements Parcelable { private @Nullable String mUniqueId; private int mDisplayIdToMirror; private boolean mWindowManagerMirroring; private @NonNull List<String> mDisplayCategories; private long mBuilderFieldsSet = 0L; Loading Loading @@ -478,10 +508,30 @@ public final class VirtualDisplayConfig implements Parcelable { return this; } /** * The display categories. If set, only corresponding activities from the same category can be * shown on the display. */ @DataClass.Generated.Member public @NonNull Builder setDisplayCategories(@NonNull List<String> value) { checkNotUsed(); mBuilderFieldsSet |= 0x200; mDisplayCategories = value; return this; } /** @see #setDisplayCategories */ @DataClass.Generated.Member public @NonNull Builder addDisplayCategory(@NonNull String value) { if (mDisplayCategories == null) setDisplayCategories(new ArrayList<>()); mDisplayCategories.add(value); return this; } /** Builds the instance. This builder should not be touched after calling this! */ public @NonNull VirtualDisplayConfig build() { checkNotUsed(); mBuilderFieldsSet |= 0x200; // Mark builder used mBuilderFieldsSet |= 0x400; // Mark builder used if ((mBuilderFieldsSet & 0x10) == 0) { mFlags = 0; Loading @@ -498,6 +548,9 @@ public final class VirtualDisplayConfig implements Parcelable { if ((mBuilderFieldsSet & 0x100) == 0) { mWindowManagerMirroring = false; } if ((mBuilderFieldsSet & 0x200) == 0) { mDisplayCategories = new ArrayList<>(); } VirtualDisplayConfig o = new VirtualDisplayConfig( mName, mWidth, Loading @@ -507,12 +560,13 @@ public final class VirtualDisplayConfig implements Parcelable { mSurface, mUniqueId, mDisplayIdToMirror, mWindowManagerMirroring); mWindowManagerMirroring, mDisplayCategories); return o; } private void checkNotUsed() { if ((mBuilderFieldsSet & 0x200) != 0) { if ((mBuilderFieldsSet & 0x400) != 0) { throw new IllegalStateException( "This Builder should not be reused. Use a new Builder instance instead"); } Loading @@ -520,10 +574,10 @@ public final class VirtualDisplayConfig implements Parcelable { } @DataClass.Generated( time = 1646227247934L, time = 1668534501320L, codegenVersion = "1.0.23", sourceFile = "frameworks/base/core/java/android/hardware/display/VirtualDisplayConfig.java", inputSignatures = "private @android.annotation.NonNull java.lang.String mName\nprivate @android.annotation.IntRange int mWidth\nprivate @android.annotation.IntRange int mHeight\nprivate @android.annotation.IntRange int mDensityDpi\nprivate @android.hardware.display.DisplayManager.VirtualDisplayFlag int mFlags\nprivate @android.annotation.Nullable android.view.Surface mSurface\nprivate @android.annotation.Nullable java.lang.String mUniqueId\nprivate int mDisplayIdToMirror\nprivate boolean mWindowManagerMirroring\nclass VirtualDisplayConfig extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genParcelable=true, genAidl=true, genBuilder=true)") inputSignatures = "private @android.annotation.NonNull java.lang.String mName\nprivate @android.annotation.IntRange int mWidth\nprivate @android.annotation.IntRange int mHeight\nprivate @android.annotation.IntRange int mDensityDpi\nprivate @android.hardware.display.DisplayManager.VirtualDisplayFlag int mFlags\nprivate @android.annotation.Nullable android.view.Surface mSurface\nprivate @android.annotation.Nullable java.lang.String mUniqueId\nprivate int mDisplayIdToMirror\nprivate boolean mWindowManagerMirroring\nprivate @com.android.internal.util.DataClass.PluralOf(\"displayCategory\") @android.annotation.NonNull java.util.List<java.lang.String> mDisplayCategories\nclass VirtualDisplayConfig extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genParcelable=true, genAidl=true, genBuilder=true)") @Deprecated private void __metadata() {} Loading services/companion/java/com/android/server/companion/virtual/GenericWindowPolicyController.java +23 −3 Original line number Diff line number Diff line Loading @@ -130,6 +130,7 @@ public class GenericWindowPolicyController extends DisplayWindowPolicyController @Nullable private final @AssociationRequest.DeviceProfile String mDeviceProfile; @Nullable private final SecureWindowCallback mSecureWindowCallback; @Nullable private final List<String> mDisplayCategories; /** * Creates a window policy controller that is generic to the different use cases of virtual Loading Loading @@ -168,7 +169,8 @@ public class GenericWindowPolicyController extends DisplayWindowPolicyController @NonNull PipBlockedCallback pipBlockedCallback, @NonNull ActivityBlockedCallback activityBlockedCallback, @NonNull SecureWindowCallback secureWindowCallback, @AssociationRequest.DeviceProfile String deviceProfile) { @AssociationRequest.DeviceProfile String deviceProfile, @NonNull List<String> displayCategories) { super(); mAllowedUsers = allowedUsers; mAllowedCrossTaskNavigations = new ArraySet<>(allowedCrossTaskNavigations); Loading @@ -182,6 +184,7 @@ public class GenericWindowPolicyController extends DisplayWindowPolicyController mDeviceProfile = deviceProfile; mPipBlockedCallback = pipBlockedCallback; mSecureWindowCallback = secureWindowCallback; mDisplayCategories = displayCategories; } /** Loading Loading @@ -350,6 +353,15 @@ public class GenericWindowPolicyController extends DisplayWindowPolicyController } } private boolean activityMatchesDisplayCategory(ActivityInfo activityInfo) { if (mDisplayCategories.isEmpty()) { return activityInfo.targetDisplayCategory == null; } return activityInfo.targetDisplayCategory != null && mDisplayCategories.contains(activityInfo.targetDisplayCategory); } private boolean canContainActivity(ActivityInfo activityInfo, int windowFlags, int systemWindowFlags) { if ((activityInfo.flags & FLAG_CAN_DISPLAY_ON_REMOTE_DEVICES) == 0) { Loading @@ -357,9 +369,17 @@ public class GenericWindowPolicyController extends DisplayWindowPolicyController } ComponentName activityComponent = activityInfo.getComponentName(); if (BLOCKED_APP_STREAMING_COMPONENT.equals(activityComponent)) { // The error dialog alerting users that streaming is blocked is always allowed. // The error dialog alerting users that streaming is blocked is always allowed. Need to // run before the clauses below to ensure error dialog always shows up. return true; } if (!activityMatchesDisplayCategory(activityInfo)) { Slog.d(TAG, String.format( "The activity's target display category: %s is not found on virtual display" + " with the following allowed display categories: %s", activityInfo.targetDisplayCategory, mDisplayCategories.toString())); return false; } final UserHandle activityUser = UserHandle.getUserHandleForUid(activityInfo.applicationInfo.uid); if (!mAllowedUsers.contains(activityUser)) { Loading services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java +5 −2 Original line number Diff line number Diff line Loading @@ -74,6 +74,7 @@ import com.android.server.companion.virtual.audio.VirtualAudioController; import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.List; import java.util.Map; import java.util.Set; import java.util.function.Consumer; Loading Loading @@ -628,7 +629,8 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub mInputController.dump(fout); } GenericWindowPolicyController createWindowPolicyController() { GenericWindowPolicyController createWindowPolicyController( @NonNull List<String> displayCategories) { synchronized (mVirtualDeviceLock) { final GenericWindowPolicyController gwpc = new GenericWindowPolicyController(FLAG_SECURE, Loading @@ -643,7 +645,8 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub this::onEnteringPipBlocked, this::onActivityBlocked, this::onSecureWindowShown, mAssociationInfo.getDeviceProfile()); mAssociationInfo.getDeviceProfile(), displayCategories); gwpc.registerRunningAppsChangedListener(/* listener= */ this); return gwpc; } Loading Loading
core/api/system-current.txt +1 −0 Original line number Diff line number Diff line Loading @@ -2958,6 +2958,7 @@ package android.companion.virtual { method @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public void close(); method @NonNull @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public android.companion.virtual.audio.VirtualAudioDevice createVirtualAudioDevice(@NonNull android.hardware.display.VirtualDisplay, @Nullable java.util.concurrent.Executor, @Nullable android.companion.virtual.audio.VirtualAudioDevice.AudioConfigurationChangeCallback); method @Nullable public android.hardware.display.VirtualDisplay createVirtualDisplay(@IntRange(from=1) int, @IntRange(from=1) int, @IntRange(from=1) int, @Nullable android.view.Surface, int, @Nullable java.util.concurrent.Executor, @Nullable android.hardware.display.VirtualDisplay.Callback); method @Nullable public android.hardware.display.VirtualDisplay createVirtualDisplay(@IntRange(from=1) int, @IntRange(from=1) int, @IntRange(from=1) int, @NonNull java.util.List<java.lang.String>, @Nullable android.view.Surface, int, @Nullable java.util.concurrent.Executor, @Nullable android.hardware.display.VirtualDisplay.Callback); method @NonNull @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public android.hardware.input.VirtualDpad createVirtualDpad(@NonNull android.hardware.display.VirtualDisplay, @NonNull String, int, int); method @NonNull @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public android.hardware.input.VirtualKeyboard createVirtualKeyboard(@NonNull android.hardware.display.VirtualDisplay, @NonNull String, int, int); method @NonNull @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public android.hardware.input.VirtualMouse createVirtualMouse(@NonNull android.hardware.display.VirtualDisplay, @NonNull String, int, int);
core/java/android/companion/virtual/VirtualDeviceManager.java +61 −3 Original line number Diff line number Diff line Loading @@ -350,14 +350,72 @@ public final class VirtualDeviceManager { @VirtualDisplayFlag int flags, @Nullable @CallbackExecutor Executor executor, @Nullable VirtualDisplay.Callback callback) { // TODO(b/205343547): Handle display groups properly instead of creating a new display // group for every new virtual display created using this API. // belongs to the same display group. VirtualDisplayConfig config = new VirtualDisplayConfig.Builder( getVirtualDisplayName(), width, height, densityDpi) .setSurface(surface) .setFlags(getVirtualDisplayFlags(flags)) .build(); return createVirtualDisplayInternal(config, executor, callback); } /** * Creates a virtual display for this virtual device. All displays created on the same * device belongs to the same display group. * * @param width The width of the virtual display in pixels, must be greater than 0. * @param height The height of the virtual display in pixels, must be greater than 0. * @param densityDpi The density of the virtual display in dpi, must be greater than 0. * @param displayCategories The categories of the virtual display, indicating the type of * activities allowed to run on the display. Activities can declare their type using * {@link android.content.pm.ActivityInfo#targetDisplayCategory}. * @param surface The surface to which the content of the virtual display should * be rendered, or null if there is none initially. The surface can also be set later using * {@link VirtualDisplay#setSurface(Surface)}. * @param flags A combination of virtual display flags accepted by * {@link DisplayManager#createVirtualDisplay}. In addition, the following flags are * automatically set for all virtual devices: * {@link DisplayManager#VIRTUAL_DISPLAY_FLAG_PUBLIC VIRTUAL_DISPLAY_FLAG_PUBLIC} and * {@link DisplayManager#VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY * VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY}. * @param executor The executor on which {@code callback} will be invoked. This is ignored * if {@code callback} is {@code null}. If {@code callback} is specified, this executor must * not be null. * @param callback Callback to call when the state of the {@link VirtualDisplay} changes * @return The newly created virtual display, or {@code null} if the application could * not create the virtual display. * * @see DisplayManager#createVirtualDisplay */ @Nullable public VirtualDisplay createVirtualDisplay( @IntRange(from = 1) int width, @IntRange(from = 1) int height, @IntRange(from = 1) int densityDpi, @NonNull List<String> displayCategories, @Nullable Surface surface, @VirtualDisplayFlag int flags, @Nullable @CallbackExecutor Executor executor, @Nullable VirtualDisplay.Callback callback) { VirtualDisplayConfig config = new VirtualDisplayConfig.Builder( getVirtualDisplayName(), width, height, densityDpi) .setDisplayCategories(displayCategories) .setSurface(surface) .setFlags(getVirtualDisplayFlags(flags)) .build(); return createVirtualDisplayInternal(config, executor, callback); } /** * @hide */ @Nullable private VirtualDisplay createVirtualDisplayInternal( @NonNull VirtualDisplayConfig config, @Nullable @CallbackExecutor Executor executor, @Nullable VirtualDisplay.Callback callback) { // TODO(b/205343547): Handle display groups properly instead of creating a new display // group for every new virtual display created using this API. // belongs to the same display group. IVirtualDisplayCallback callbackWrapper = new DisplayManagerGlobal.VirtualDisplayCallback(callback, executor); final int displayId; Loading
core/java/android/hardware/display/VirtualDisplayConfig.java +60 −6 Original line number Diff line number Diff line Loading @@ -30,6 +30,9 @@ import android.view.Surface; import com.android.internal.util.DataClass; import java.util.ArrayList; import java.util.List; /** * Holds configuration used to create {@link VirtualDisplay} instances. See * {@link MediaProjection#createVirtualDisplay(VirtualDisplayConfig, VirtualDisplay.Callback, Handler)}. Loading Loading @@ -99,6 +102,13 @@ public final class VirtualDisplayConfig implements Parcelable { */ private boolean mWindowManagerMirroring = false; /** * The display categories. If set, only corresponding activities from the same category can be * shown on the display. */ @DataClass.PluralOf("displayCategory") @NonNull private List<String> mDisplayCategories = new ArrayList<>(); // Code below generated by codegen v1.0.23. Loading @@ -124,7 +134,8 @@ public final class VirtualDisplayConfig implements Parcelable { @Nullable Surface surface, @Nullable String uniqueId, int displayIdToMirror, boolean windowManagerMirroring) { boolean windowManagerMirroring, @NonNull List<String> displayCategories) { this.mName = name; com.android.internal.util.AnnotationValidations.validate( NonNull.class, null, mName); Loading @@ -147,6 +158,9 @@ public final class VirtualDisplayConfig implements Parcelable { this.mUniqueId = uniqueId; this.mDisplayIdToMirror = displayIdToMirror; this.mWindowManagerMirroring = windowManagerMirroring; this.mDisplayCategories = displayCategories; com.android.internal.util.AnnotationValidations.validate( NonNull.class, null, mDisplayCategories); // onConstructed(); // You can define this method to get a callback } Loading Loading @@ -233,6 +247,15 @@ public final class VirtualDisplayConfig implements Parcelable { return mWindowManagerMirroring; } /** * The display categories. If set, only corresponding activities from the same category can be * shown on the display. */ @DataClass.Generated.Member public @NonNull List<String> getDisplayCategories() { return mDisplayCategories; } @Override @DataClass.Generated.Member public void writeToParcel(@NonNull Parcel dest, int flags) { Loading @@ -252,6 +275,7 @@ public final class VirtualDisplayConfig implements Parcelable { if (mSurface != null) dest.writeTypedObject(mSurface, flags); if (mUniqueId != null) dest.writeString(mUniqueId); dest.writeInt(mDisplayIdToMirror); dest.writeStringList(mDisplayCategories); } @Override Loading @@ -275,6 +299,8 @@ public final class VirtualDisplayConfig implements Parcelable { Surface surface = (flg & 0x20) == 0 ? null : (Surface) in.readTypedObject(Surface.CREATOR); String uniqueId = (flg & 0x40) == 0 ? null : in.readString(); int displayIdToMirror = in.readInt(); List<String> displayCategories = new ArrayList<>(); in.readStringList(displayCategories); this.mName = name; com.android.internal.util.AnnotationValidations.validate( Loading @@ -298,6 +324,9 @@ public final class VirtualDisplayConfig implements Parcelable { this.mUniqueId = uniqueId; this.mDisplayIdToMirror = displayIdToMirror; this.mWindowManagerMirroring = windowManagerMirroring; this.mDisplayCategories = displayCategories; com.android.internal.util.AnnotationValidations.validate( NonNull.class, null, mDisplayCategories); // onConstructed(); // You can define this method to get a callback } Loading Loading @@ -332,6 +361,7 @@ public final class VirtualDisplayConfig implements Parcelable { private @Nullable String mUniqueId; private int mDisplayIdToMirror; private boolean mWindowManagerMirroring; private @NonNull List<String> mDisplayCategories; private long mBuilderFieldsSet = 0L; Loading Loading @@ -478,10 +508,30 @@ public final class VirtualDisplayConfig implements Parcelable { return this; } /** * The display categories. If set, only corresponding activities from the same category can be * shown on the display. */ @DataClass.Generated.Member public @NonNull Builder setDisplayCategories(@NonNull List<String> value) { checkNotUsed(); mBuilderFieldsSet |= 0x200; mDisplayCategories = value; return this; } /** @see #setDisplayCategories */ @DataClass.Generated.Member public @NonNull Builder addDisplayCategory(@NonNull String value) { if (mDisplayCategories == null) setDisplayCategories(new ArrayList<>()); mDisplayCategories.add(value); return this; } /** Builds the instance. This builder should not be touched after calling this! */ public @NonNull VirtualDisplayConfig build() { checkNotUsed(); mBuilderFieldsSet |= 0x200; // Mark builder used mBuilderFieldsSet |= 0x400; // Mark builder used if ((mBuilderFieldsSet & 0x10) == 0) { mFlags = 0; Loading @@ -498,6 +548,9 @@ public final class VirtualDisplayConfig implements Parcelable { if ((mBuilderFieldsSet & 0x100) == 0) { mWindowManagerMirroring = false; } if ((mBuilderFieldsSet & 0x200) == 0) { mDisplayCategories = new ArrayList<>(); } VirtualDisplayConfig o = new VirtualDisplayConfig( mName, mWidth, Loading @@ -507,12 +560,13 @@ public final class VirtualDisplayConfig implements Parcelable { mSurface, mUniqueId, mDisplayIdToMirror, mWindowManagerMirroring); mWindowManagerMirroring, mDisplayCategories); return o; } private void checkNotUsed() { if ((mBuilderFieldsSet & 0x200) != 0) { if ((mBuilderFieldsSet & 0x400) != 0) { throw new IllegalStateException( "This Builder should not be reused. Use a new Builder instance instead"); } Loading @@ -520,10 +574,10 @@ public final class VirtualDisplayConfig implements Parcelable { } @DataClass.Generated( time = 1646227247934L, time = 1668534501320L, codegenVersion = "1.0.23", sourceFile = "frameworks/base/core/java/android/hardware/display/VirtualDisplayConfig.java", inputSignatures = "private @android.annotation.NonNull java.lang.String mName\nprivate @android.annotation.IntRange int mWidth\nprivate @android.annotation.IntRange int mHeight\nprivate @android.annotation.IntRange int mDensityDpi\nprivate @android.hardware.display.DisplayManager.VirtualDisplayFlag int mFlags\nprivate @android.annotation.Nullable android.view.Surface mSurface\nprivate @android.annotation.Nullable java.lang.String mUniqueId\nprivate int mDisplayIdToMirror\nprivate boolean mWindowManagerMirroring\nclass VirtualDisplayConfig extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genParcelable=true, genAidl=true, genBuilder=true)") inputSignatures = "private @android.annotation.NonNull java.lang.String mName\nprivate @android.annotation.IntRange int mWidth\nprivate @android.annotation.IntRange int mHeight\nprivate @android.annotation.IntRange int mDensityDpi\nprivate @android.hardware.display.DisplayManager.VirtualDisplayFlag int mFlags\nprivate @android.annotation.Nullable android.view.Surface mSurface\nprivate @android.annotation.Nullable java.lang.String mUniqueId\nprivate int mDisplayIdToMirror\nprivate boolean mWindowManagerMirroring\nprivate @com.android.internal.util.DataClass.PluralOf(\"displayCategory\") @android.annotation.NonNull java.util.List<java.lang.String> mDisplayCategories\nclass VirtualDisplayConfig extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genParcelable=true, genAidl=true, genBuilder=true)") @Deprecated private void __metadata() {} Loading
services/companion/java/com/android/server/companion/virtual/GenericWindowPolicyController.java +23 −3 Original line number Diff line number Diff line Loading @@ -130,6 +130,7 @@ public class GenericWindowPolicyController extends DisplayWindowPolicyController @Nullable private final @AssociationRequest.DeviceProfile String mDeviceProfile; @Nullable private final SecureWindowCallback mSecureWindowCallback; @Nullable private final List<String> mDisplayCategories; /** * Creates a window policy controller that is generic to the different use cases of virtual Loading Loading @@ -168,7 +169,8 @@ public class GenericWindowPolicyController extends DisplayWindowPolicyController @NonNull PipBlockedCallback pipBlockedCallback, @NonNull ActivityBlockedCallback activityBlockedCallback, @NonNull SecureWindowCallback secureWindowCallback, @AssociationRequest.DeviceProfile String deviceProfile) { @AssociationRequest.DeviceProfile String deviceProfile, @NonNull List<String> displayCategories) { super(); mAllowedUsers = allowedUsers; mAllowedCrossTaskNavigations = new ArraySet<>(allowedCrossTaskNavigations); Loading @@ -182,6 +184,7 @@ public class GenericWindowPolicyController extends DisplayWindowPolicyController mDeviceProfile = deviceProfile; mPipBlockedCallback = pipBlockedCallback; mSecureWindowCallback = secureWindowCallback; mDisplayCategories = displayCategories; } /** Loading Loading @@ -350,6 +353,15 @@ public class GenericWindowPolicyController extends DisplayWindowPolicyController } } private boolean activityMatchesDisplayCategory(ActivityInfo activityInfo) { if (mDisplayCategories.isEmpty()) { return activityInfo.targetDisplayCategory == null; } return activityInfo.targetDisplayCategory != null && mDisplayCategories.contains(activityInfo.targetDisplayCategory); } private boolean canContainActivity(ActivityInfo activityInfo, int windowFlags, int systemWindowFlags) { if ((activityInfo.flags & FLAG_CAN_DISPLAY_ON_REMOTE_DEVICES) == 0) { Loading @@ -357,9 +369,17 @@ public class GenericWindowPolicyController extends DisplayWindowPolicyController } ComponentName activityComponent = activityInfo.getComponentName(); if (BLOCKED_APP_STREAMING_COMPONENT.equals(activityComponent)) { // The error dialog alerting users that streaming is blocked is always allowed. // The error dialog alerting users that streaming is blocked is always allowed. Need to // run before the clauses below to ensure error dialog always shows up. return true; } if (!activityMatchesDisplayCategory(activityInfo)) { Slog.d(TAG, String.format( "The activity's target display category: %s is not found on virtual display" + " with the following allowed display categories: %s", activityInfo.targetDisplayCategory, mDisplayCategories.toString())); return false; } final UserHandle activityUser = UserHandle.getUserHandleForUid(activityInfo.applicationInfo.uid); if (!mAllowedUsers.contains(activityUser)) { Loading
services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java +5 −2 Original line number Diff line number Diff line Loading @@ -74,6 +74,7 @@ import com.android.server.companion.virtual.audio.VirtualAudioController; import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.List; import java.util.Map; import java.util.Set; import java.util.function.Consumer; Loading Loading @@ -628,7 +629,8 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub mInputController.dump(fout); } GenericWindowPolicyController createWindowPolicyController() { GenericWindowPolicyController createWindowPolicyController( @NonNull List<String> displayCategories) { synchronized (mVirtualDeviceLock) { final GenericWindowPolicyController gwpc = new GenericWindowPolicyController(FLAG_SECURE, Loading @@ -643,7 +645,8 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub this::onEnteringPipBlocked, this::onActivityBlocked, this::onSecureWindowShown, mAssociationInfo.getDeviceProfile()); mAssociationInfo.getDeviceProfile(), displayCategories); gwpc.registerRunningAppsChangedListener(/* listener= */ this); return gwpc; } Loading