1 /*
2  * Copyright (C) 2022 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.companion.virtual;
18 
19 import static android.companion.virtual.VirtualDeviceParams.DEVICE_POLICY_CUSTOM;
20 import static android.companion.virtual.VirtualDeviceParams.POLICY_TYPE_CAMERA;
21 import static android.companion.virtual.VirtualDeviceParams.POLICY_TYPE_SENSORS;
22 
23 import android.annotation.FlaggedApi;
24 import android.annotation.NonNull;
25 import android.annotation.Nullable;
26 import android.annotation.SystemApi;
27 import android.companion.virtual.flags.Flags;
28 import android.content.Context;
29 import android.os.Parcel;
30 import android.os.Parcelable;
31 import android.os.RemoteException;
32 
33 /**
34  * Details of a particular virtual device.
35  *
36  * <p>Read-only device representation exposing the properties of an existing virtual device.
37  */
38 // TODO(b/310912420): Link to VirtualDeviceManager#registerVirtualDeviceListener from the docs
39 public final class VirtualDevice implements Parcelable {
40 
41     private final @NonNull IVirtualDevice mVirtualDevice;
42     private final int mId;
43     private final @Nullable String mPersistentId;
44     private final @Nullable String mName;
45     private final @Nullable CharSequence mDisplayName;
46 
47     /**
48      * Creates a new instance of {@link VirtualDevice}.
49      * Only to be used by the VirtualDeviceManagerService.
50      *
51      * @hide
52      */
VirtualDevice(@onNull IVirtualDevice virtualDevice, int id, @Nullable String persistentId, @Nullable String name)53     public VirtualDevice(@NonNull IVirtualDevice virtualDevice, int id,
54             @Nullable String persistentId, @Nullable String name) {
55         this(virtualDevice, id, persistentId, name, null);
56     }
57 
58     /**
59      * Creates a new instance of {@link VirtualDevice}. Only to be used by the
60      * VirtualDeviceManagerService.
61      *
62      * @hide
63      */
VirtualDevice(@onNull IVirtualDevice virtualDevice, int id, @Nullable String persistentId, @Nullable String name, @Nullable CharSequence displayName)64     public VirtualDevice(@NonNull IVirtualDevice virtualDevice, int id,
65             @Nullable String persistentId, @Nullable String name,
66             @Nullable CharSequence displayName) {
67         if (id <= Context.DEVICE_ID_DEFAULT) {
68             throw new IllegalArgumentException("VirtualDevice ID must be greater than "
69                     + Context.DEVICE_ID_DEFAULT);
70         }
71         mVirtualDevice = virtualDevice;
72         mId = id;
73         mPersistentId = persistentId;
74         mName = name;
75         mDisplayName = displayName;
76     }
77 
VirtualDevice(@onNull Parcel parcel)78     private VirtualDevice(@NonNull Parcel parcel) {
79         mVirtualDevice = IVirtualDevice.Stub.asInterface(parcel.readStrongBinder());
80         mId = parcel.readInt();
81         mPersistentId = parcel.readString8();
82         mName = parcel.readString8();
83         mDisplayName = parcel.readCharSequence();
84     }
85 
86     /**
87      * Returns the unique ID of the virtual device.
88      *
89      * <p>This identifier corresponds to {@link Context#getDeviceId()} and can be used to access
90      * device-specific system capabilities.
91      *
92      * <p class="note">This identifier is ephemeral and should not be used for persisting any data
93      * per device.
94      *
95      * @see Context#createDeviceContext
96      */
97     // TODO(b/310912420): Link to #getPersistentDeviceId from the docs
getDeviceId()98     public int getDeviceId() {
99         return mId;
100     }
101 
102     /**
103      * Returns the persistent identifier of this virtual device, if any.
104      *
105      * <p> If there is no stable identifier for this virtual device, then this returns {@code null}.
106 
107      * <p>This identifier may correspond to a physical device. In that case it remains valid for as
108      * long as that physical device is associated with the host device and may be used to persist
109      * data per device.
110      *
111      * <p class="note">This identifier may not be unique across virtual devices, in case there are
112      * more than one virtual devices corresponding to the same physical device.
113      */
114     @FlaggedApi(Flags.FLAG_VDM_PUBLIC_APIS)
getPersistentDeviceId()115     public @Nullable String getPersistentDeviceId() {
116         return mPersistentId;
117     }
118 
119     /**
120      * Returns the name of the virtual device (optionally) provided during its creation.
121      */
getName()122     public @Nullable String getName() {
123         return mName;
124     }
125 
126     /**
127      * Returns the human-readable name of the virtual device, if defined, which is suitable to be
128      * shown in UI.
129      */
130     @FlaggedApi(Flags.FLAG_VDM_PUBLIC_APIS)
getDisplayName()131     public @Nullable CharSequence getDisplayName() {
132         return mDisplayName;
133     }
134 
135     /**
136      * Returns the IDs of all virtual displays that belong to this device, if any.
137      *
138      * <p>The actual {@link android.view.Display} objects can be obtained by passing the returned
139      * IDs to {@link android.hardware.display.DisplayManager#getDisplay(int)}.</p>
140      */
141     @FlaggedApi(Flags.FLAG_VDM_PUBLIC_APIS)
getDisplayIds()142     public @NonNull int[] getDisplayIds() {
143         try {
144             return mVirtualDevice.getDisplayIds();
145         } catch (RemoteException e) {
146             throw e.rethrowFromSystemServer();
147         }
148     }
149 
150     /**
151      * Returns whether this device may have custom sensors.
152      *
153      * <p>Returning {@code true} does not necessarily mean that this device has sensors, it only
154      * means that a {@link android.hardware.SensorManager} instance created from a {@link Context}
155      * associated with this device will return this device's sensors, if any.</p>
156      *
157      * @see Context#getDeviceId()
158      * @see Context#createDeviceContext(int)
159      */
160     @FlaggedApi(Flags.FLAG_VDM_PUBLIC_APIS)
hasCustomSensorSupport()161     public boolean hasCustomSensorSupport() {
162         try {
163             return mVirtualDevice.getDevicePolicy(POLICY_TYPE_SENSORS) == DEVICE_POLICY_CUSTOM;
164         } catch (RemoteException e) {
165             throw e.rethrowFromSystemServer();
166         }
167     }
168 
169     /**
170      * Returns whether this device may have custom audio input device.
171      *
172      * @hide
173      */
174     @SystemApi
175     @FlaggedApi(Flags.FLAG_VDM_PUBLIC_APIS)
hasCustomAudioInputSupport()176     public boolean hasCustomAudioInputSupport() {
177         try {
178             return mVirtualDevice.hasCustomAudioInputSupport();
179         } catch (RemoteException e) {
180             throw e.rethrowFromSystemServer();
181         }
182     }
183 
184     /**
185      * Returns whether this device may have custom cameras.
186      *
187      * <p>Returning {@code true} does not necessarily mean that this device has cameras, it only
188      * means that a {@link android.hardware.camera2.CameraManager} instance created from a
189      * {@link Context} associated with this device will return this device's cameras, if any.</p>
190      *
191      * @see Context#getDeviceId()
192      * @see Context#createDeviceContext(int)
193      *
194      * @hide
195      */
196     @SystemApi
197     @FlaggedApi(Flags.FLAG_VDM_PUBLIC_APIS)
hasCustomCameraSupport()198     public boolean hasCustomCameraSupport() {
199         try {
200             return mVirtualDevice.getDevicePolicy(POLICY_TYPE_CAMERA) == DEVICE_POLICY_CUSTOM;
201         } catch (RemoteException e) {
202             throw e.rethrowFromSystemServer();
203         }
204     }
205 
206     @Override
describeContents()207     public int describeContents() {
208         return 0;
209     }
210 
211     @Override
writeToParcel(@onNull Parcel dest, int flags)212     public void writeToParcel(@NonNull Parcel dest, int flags) {
213         dest.writeStrongBinder(mVirtualDevice.asBinder());
214         dest.writeInt(mId);
215         dest.writeString8(mPersistentId);
216         dest.writeString8(mName);
217         dest.writeCharSequence(mDisplayName);
218     }
219 
220     @Override
221     @NonNull
toString()222     public String toString() {
223         return "VirtualDevice("
224                 + " mId=" + mId
225                 + " mPersistentId=" + mPersistentId
226                 + " mName=" + mName
227                 + " mDisplayName=" + mDisplayName
228                 + ")";
229     }
230 
231     @NonNull
232     public static final Parcelable.Creator<VirtualDevice> CREATOR =
233             new Parcelable.Creator<VirtualDevice>() {
234                 public VirtualDevice createFromParcel(Parcel in) {
235                     return new VirtualDevice(in);
236                 }
237 
238                 public VirtualDevice[] newArray(int size) {
239                     return new VirtualDevice[size];
240                 }
241             };
242 }
243