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

Commit eb6af01a authored by Marvin Ramin's avatar Marvin Ramin
Browse files

Add VDM APIs to support permission streaming

Introduces the stream_permissions flag to guard these APIs.

VDM introduces VD#getDisplayName (proxied from CDM
AssociationInfo#getDisplayName) to enable showing the correct device
name in the streamed permission Dialog.

VDM offers the stream_permissions flag by blocking any Activity being
launched which matches the permission Dialog ComponentName in GWPC

Bug: 291737919
Test: atest VirtualDevicePermissionTest AppStreamingPermissionTest
Change-Id: I0afa6959944f241e155efc711f4c0d7b23f953bf
parent c11a0da8
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -9682,6 +9682,7 @@ package android.companion.virtual {
    method public int describeContents();
    method public int getDeviceId();
    method @FlaggedApi("android.companion.virtual.flags.vdm_public_apis") @NonNull public int[] getDisplayIds();
    method @FlaggedApi("android.companion.virtual.flags.vdm_public_apis") @Nullable public CharSequence getDisplayName();
    method @Nullable public String getName();
    method @Nullable public String getPersistentDeviceId();
    method @FlaggedApi("android.companion.virtual.flags.vdm_public_apis") public boolean hasCustomSensorSupport();
+26 −0
Original line number Diff line number Diff line
@@ -44,6 +44,7 @@ public final class VirtualDevice implements Parcelable {
    private final int mId;
    private final @Nullable String mPersistentId;
    private final @Nullable String mName;
    private final @Nullable CharSequence mDisplayName;

    /**
     * Creates a new instance of {@link VirtualDevice}.
@@ -53,6 +54,18 @@ public final class VirtualDevice implements Parcelable {
     */
    public VirtualDevice(@NonNull IVirtualDevice virtualDevice, int id,
            @Nullable String persistentId, @Nullable String name) {
        this(virtualDevice, id, persistentId, name, null);
    }

    /**
     * Creates a new instance of {@link VirtualDevice}. Only to be used by the
     * VirtualDeviceManagerService.
     *
     * @hide
     */
    public VirtualDevice(@NonNull IVirtualDevice virtualDevice, int id,
            @Nullable String persistentId, @Nullable String name,
            @Nullable CharSequence displayName) {
        if (id <= Context.DEVICE_ID_DEFAULT) {
            throw new IllegalArgumentException("VirtualDevice ID must be greater than "
                    + Context.DEVICE_ID_DEFAULT);
@@ -61,6 +74,7 @@ public final class VirtualDevice implements Parcelable {
        mId = id;
        mPersistentId = persistentId;
        mName = name;
        mDisplayName = displayName;
    }

    private VirtualDevice(@NonNull Parcel parcel) {
@@ -68,6 +82,7 @@ public final class VirtualDevice implements Parcelable {
        mId = parcel.readInt();
        mPersistentId = parcel.readString8();
        mName = parcel.readString8();
        mDisplayName = parcel.readCharSequence();
    }

    /**
@@ -111,6 +126,15 @@ public final class VirtualDevice implements Parcelable {
        return mName;
    }

    /**
     * Returns the human-readable name of the virtual device, if defined, which is suitable to be
     * shown in UI.
     */
    @FlaggedApi(Flags.FLAG_VDM_PUBLIC_APIS)
    public @Nullable CharSequence getDisplayName() {
        return mDisplayName;
    }

    /**
     * Returns the IDs of all virtual displays that belong to this device, if any.
     *
@@ -156,6 +180,7 @@ public final class VirtualDevice implements Parcelable {
        dest.writeInt(mId);
        dest.writeString8(mPersistentId);
        dest.writeString8(mName);
        dest.writeCharSequence(mDisplayName);
    }

    @Override
@@ -165,6 +190,7 @@ public final class VirtualDevice implements Parcelable {
                + " mId=" + mId
                + " mPersistentId=" + mPersistentId
                + " mName=" + mName
                + " mDisplayName=" + mDisplayName
                + ")";
    }

+7 −0
Original line number Diff line number Diff line
@@ -34,3 +34,10 @@ flag {
    description: "Enable Virtual Camera"
    bug: "270352264"
}

flag {
  name: "stream_permissions"
  namespace: "virtual_devices"
  description: "Enable streaming permission dialogs to Virtual Devices"
  bug: "291737919"
}
+11 −0
Original line number Diff line number Diff line
@@ -113,6 +113,8 @@ public class GenericWindowPolicyController extends DisplayWindowPolicyController
    private final boolean mCrossTaskNavigationAllowedByDefault;
    @NonNull
    private final ArraySet<ComponentName> mCrossTaskNavigationExemptions;
    @Nullable
    private final ComponentName mPermissionDialogComponent;
    private final Object mGenericWindowPolicyControllerLock = new Object();
    @Nullable private final ActivityBlockedCallback mActivityBlockedCallback;
    private int mDisplayId = Display.INVALID_DISPLAY;
@@ -171,6 +173,7 @@ public class GenericWindowPolicyController extends DisplayWindowPolicyController
            @NonNull Set<ComponentName> activityPolicyExemptions,
            boolean crossTaskNavigationAllowedByDefault,
            @NonNull Set<ComponentName> crossTaskNavigationExemptions,
            @Nullable ComponentName permissionDialogComponent,
            @Nullable ActivityListener activityListener,
            @Nullable PipBlockedCallback pipBlockedCallback,
            @Nullable ActivityBlockedCallback activityBlockedCallback,
@@ -185,6 +188,7 @@ public class GenericWindowPolicyController extends DisplayWindowPolicyController
        mActivityPolicyExemptions = activityPolicyExemptions;
        mCrossTaskNavigationAllowedByDefault = crossTaskNavigationAllowedByDefault;
        mCrossTaskNavigationExemptions = new ArraySet<>(crossTaskNavigationExemptions);
        mPermissionDialogComponent = permissionDialogComponent;
        mActivityBlockedCallback = activityBlockedCallback;
        setInterestedWindowFlags(windowFlags, systemWindowFlags);
        mActivityListener = activityListener;
@@ -309,6 +313,13 @@ public class GenericWindowPolicyController extends DisplayWindowPolicyController
            return false;
        }

        // mPermissionDialogComponent being null means we don't want to block permission Dialogs
        // based on FLAG_STREAM_PERMISSIONS
        if (mPermissionDialogComponent != null
                && mPermissionDialogComponent.equals(activityComponent)) {
            return false;
        }

        return true;
    }

+23 −2
Original line number Diff line number Diff line
@@ -24,6 +24,7 @@ import static android.companion.virtual.VirtualDeviceParams.DEVICE_POLICY_DEFAUL
import static android.companion.virtual.VirtualDeviceParams.NAVIGATION_POLICY_DEFAULT_ALLOWED;
import static android.companion.virtual.VirtualDeviceParams.POLICY_TYPE_ACTIVITY;
import static android.companion.virtual.VirtualDeviceParams.POLICY_TYPE_RECENTS;
import static android.content.pm.PackageManager.ACTION_REQUEST_PERMISSIONS;
import static android.view.WindowManager.LayoutParams.FLAG_SECURE;
import static android.view.WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS;

@@ -204,6 +205,7 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub
    @GuardedBy("mVirtualDeviceLock")
    @NonNull
    private final Set<ComponentName> mActivityPolicyExemptions;
    private final ComponentName mPermissionDialogComponent;

    private ActivityListener createListenerAdapter() {
        return new ActivityListener() {
@@ -317,6 +319,11 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub
                mParams.getVirtualSensorCallback(), mParams.getVirtualSensorConfigs());
        mCameraAccessController = cameraAccessController;
        mCameraAccessController.startObservingIfNeeded();
        if (!Flags.streamPermissions()) {
            mPermissionDialogComponent = getPermissionDialogComponent();
        } else {
            mPermissionDialogComponent = null;
        }
        try {
            token.linkToDeath(this, 0);
        } catch (RemoteException e) {
@@ -324,8 +331,14 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub
        }
        mVirtualDeviceLog.logCreated(deviceId, mOwnerUid);

        if (Flags.vdmPublicApis()) {
            mPublicVirtualDeviceObject = new VirtualDevice(
                    this, getDeviceId(), getPersistentDeviceId(), mParams.getName(),
                    getDisplayName());
        } else {
            mPublicVirtualDeviceObject = new VirtualDevice(
                    this, getDeviceId(), getPersistentDeviceId(), mParams.getName());
        }

        if (Flags.dynamicPolicy()) {
            mActivityPolicyExemptions = new ArraySet<>(
@@ -951,6 +964,7 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub
                /*crossTaskNavigationExemptions=*/crossTaskNavigationAllowedByDefault
                        ? mParams.getBlockedCrossTaskNavigations()
                        : mParams.getAllowedCrossTaskNavigations(),
                mPermissionDialogComponent,
                createListenerAdapter(),
                this::onEnteringPipBlocked,
                this::onActivityBlocked,
@@ -963,6 +977,13 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub
        return gwpc;
    }

    private ComponentName getPermissionDialogComponent() {
        Intent intent = new Intent(ACTION_REQUEST_PERMISSIONS);
        PackageManager packageManager = mContext.getPackageManager();
        intent.setPackage(packageManager.getPermissionControllerPackageName());
        return intent.resolveActivity(packageManager);
    }

    int createVirtualDisplay(@NonNull VirtualDisplayConfig virtualDisplayConfig,
            @NonNull IVirtualDisplayCallback callback, String packageName) {
        GenericWindowPolicyController gwpc;
Loading