Merge "Refactor the VirtualSensor API."
This commit is contained in:
committed by
Android (Google) Code Review
commit
0e3207ffa1
@@ -3187,7 +3187,7 @@ package android.companion.virtual {
|
||||
method @NonNull @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public android.hardware.input.VirtualTouchscreen createVirtualTouchscreen(@NonNull android.hardware.input.VirtualTouchscreenConfig);
|
||||
method @Deprecated @NonNull @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public android.hardware.input.VirtualTouchscreen createVirtualTouchscreen(@NonNull android.hardware.display.VirtualDisplay, @NonNull String, int, int);
|
||||
method public int getDeviceId();
|
||||
method @Nullable public android.companion.virtual.sensor.VirtualSensor getVirtualSensor(int, @NonNull String);
|
||||
method @NonNull public java.util.List<android.companion.virtual.sensor.VirtualSensor> getVirtualSensorList();
|
||||
method public void launchPendingIntent(int, @NonNull android.app.PendingIntent, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.IntConsumer);
|
||||
method @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public void registerIntentInterceptor(@NonNull android.content.IntentFilter, @NonNull java.util.concurrent.Executor, @NonNull android.companion.virtual.VirtualDeviceManager.IntentInterceptorCallback);
|
||||
method public void removeActivityListener(@NonNull android.companion.virtual.VirtualDeviceManager.ActivityListener);
|
||||
@@ -3242,6 +3242,7 @@ package android.companion.virtual {
|
||||
method @NonNull @RequiresPermission(value=android.Manifest.permission.ADD_ALWAYS_UNLOCKED_DISPLAY, conditional=true) public android.companion.virtual.VirtualDeviceParams.Builder setLockState(int);
|
||||
method @NonNull public android.companion.virtual.VirtualDeviceParams.Builder setName(@NonNull String);
|
||||
method @NonNull public android.companion.virtual.VirtualDeviceParams.Builder setUsersWithMatchingAccounts(@NonNull java.util.Set<android.os.UserHandle>);
|
||||
method @NonNull public android.companion.virtual.VirtualDeviceParams.Builder setVirtualSensorCallback(@NonNull java.util.concurrent.Executor, @NonNull android.companion.virtual.sensor.VirtualSensorCallback);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -3293,14 +3294,18 @@ package android.companion.virtual.audio {
|
||||
|
||||
package android.companion.virtual.sensor {
|
||||
|
||||
public class VirtualSensor {
|
||||
public final class VirtualSensor implements android.os.Parcelable {
|
||||
method public int describeContents();
|
||||
method public int getDeviceId();
|
||||
method @NonNull public String getName();
|
||||
method public int getType();
|
||||
method @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public void sendEvent(@NonNull android.companion.virtual.sensor.VirtualSensorEvent);
|
||||
method public void writeToParcel(@NonNull android.os.Parcel, int);
|
||||
field @NonNull public static final android.os.Parcelable.Creator<android.companion.virtual.sensor.VirtualSensor> CREATOR;
|
||||
}
|
||||
|
||||
public static interface VirtualSensor.SensorStateChangeCallback {
|
||||
method public void onStateChanged(boolean, @NonNull java.time.Duration, @NonNull java.time.Duration);
|
||||
public interface VirtualSensorCallback {
|
||||
method public void onConfigurationChanged(@NonNull android.companion.virtual.sensor.VirtualSensor, boolean, @NonNull java.time.Duration, @NonNull java.time.Duration);
|
||||
}
|
||||
|
||||
public final class VirtualSensorConfig implements android.os.Parcelable {
|
||||
@@ -3315,7 +3320,6 @@ package android.companion.virtual.sensor {
|
||||
public static final class VirtualSensorConfig.Builder {
|
||||
ctor public VirtualSensorConfig.Builder(int, @NonNull String);
|
||||
method @NonNull public android.companion.virtual.sensor.VirtualSensorConfig build();
|
||||
method @NonNull public android.companion.virtual.sensor.VirtualSensorConfig.Builder setStateChangeCallback(@NonNull java.util.concurrent.Executor, @NonNull android.companion.virtual.sensor.VirtualSensor.SensorStateChangeCallback);
|
||||
method @NonNull public android.companion.virtual.sensor.VirtualSensorConfig.Builder setVendor(@Nullable String);
|
||||
}
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ import android.app.PendingIntent;
|
||||
import android.companion.virtual.IVirtualDeviceIntentInterceptor;
|
||||
import android.companion.virtual.audio.IAudioConfigChangedCallback;
|
||||
import android.companion.virtual.audio.IAudioRoutingCallback;
|
||||
import android.companion.virtual.sensor.IVirtualSensorStateChangeCallback;
|
||||
import android.companion.virtual.sensor.VirtualSensor;
|
||||
import android.companion.virtual.sensor.VirtualSensorConfig;
|
||||
import android.companion.virtual.sensor.VirtualSensorEvent;
|
||||
import android.content.IntentFilter;
|
||||
@@ -112,16 +112,10 @@ interface IVirtualDevice {
|
||||
boolean sendTouchEvent(IBinder token, in VirtualTouchEvent event);
|
||||
|
||||
/**
|
||||
* Creates a virtual sensor, capable of injecting sensor events into the system.
|
||||
* Returns all virtual sensors for this device.
|
||||
*/
|
||||
@EnforcePermission("CREATE_VIRTUAL_DEVICE")
|
||||
void createVirtualSensor(IBinder tokenm, in VirtualSensorConfig config);
|
||||
|
||||
/**
|
||||
* Removes the sensor corresponding to the given token from the system.
|
||||
*/
|
||||
@EnforcePermission("CREATE_VIRTUAL_DEVICE")
|
||||
void unregisterSensor(IBinder token);
|
||||
List<VirtualSensor> getVirtualSensorList();
|
||||
|
||||
/**
|
||||
* Sends an event to the virtual sensor corresponding to the given token.
|
||||
|
||||
@@ -35,7 +35,6 @@ import android.companion.virtual.audio.VirtualAudioDevice.AudioConfigurationChan
|
||||
import android.companion.virtual.camera.VirtualCameraDevice;
|
||||
import android.companion.virtual.camera.VirtualCameraInput;
|
||||
import android.companion.virtual.sensor.VirtualSensor;
|
||||
import android.companion.virtual.sensor.VirtualSensorConfig;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
@@ -428,8 +427,6 @@ public final class VirtualDeviceManager {
|
||||
};
|
||||
@Nullable
|
||||
private VirtualCameraDevice mVirtualCameraDevice;
|
||||
@NonNull
|
||||
private final List<VirtualSensor> mVirtualSensors = new ArrayList<>();
|
||||
@Nullable
|
||||
private VirtualAudioDevice mVirtualAudioDevice;
|
||||
|
||||
@@ -448,10 +445,6 @@ public final class VirtualDeviceManager {
|
||||
params,
|
||||
mActivityListenerBinder,
|
||||
mSoundEffectListener);
|
||||
final List<VirtualSensorConfig> virtualSensorConfigs = params.getVirtualSensorConfigs();
|
||||
for (int i = 0; i < virtualSensorConfigs.size(); ++i) {
|
||||
mVirtualSensors.add(createVirtualSensor(virtualSensorConfigs.get(i)));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -478,20 +471,19 @@ public final class VirtualDeviceManager {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns this device's sensor with the given type and name, if any.
|
||||
* Returns this device's sensors.
|
||||
*
|
||||
* @see VirtualDeviceParams.Builder#addVirtualSensorConfig
|
||||
*
|
||||
* @param type The type of the sensor.
|
||||
* @param name The name of the sensor.
|
||||
* @return The matching sensor if found, {@code null} otherwise.
|
||||
* @return A list of all sensors for this device, or an empty list if no sensors exist.
|
||||
*/
|
||||
@Nullable
|
||||
public VirtualSensor getVirtualSensor(int type, @NonNull String name) {
|
||||
return mVirtualSensors.stream()
|
||||
.filter(sensor -> sensor.getType() == type && sensor.getName().equals(name))
|
||||
.findAny()
|
||||
.orElse(null);
|
||||
@NonNull
|
||||
public List<VirtualSensor> getVirtualSensorList() {
|
||||
try {
|
||||
return mVirtualDevice.getVirtualSensorList();
|
||||
} catch (RemoteException e) {
|
||||
throw e.rethrowFromSystemServer();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -937,28 +929,6 @@ public final class VirtualDeviceManager {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a virtual sensor, capable of injecting sensor events into the system. Only for
|
||||
* internal use, since device sensors must remain valid for the entire lifetime of the
|
||||
* device.
|
||||
*
|
||||
* @param config The configuration of the sensor.
|
||||
* @hide
|
||||
*/
|
||||
@RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
|
||||
@NonNull
|
||||
public VirtualSensor createVirtualSensor(@NonNull VirtualSensorConfig config) {
|
||||
Objects.requireNonNull(config);
|
||||
try {
|
||||
final IBinder token = new Binder(
|
||||
"android.hardware.sensor.VirtualSensor:" + config.getName());
|
||||
mVirtualDevice.createVirtualSensor(token, config);
|
||||
return new VirtualSensor(config.getType(), config.getName(), mVirtualDevice, token);
|
||||
} catch (RemoteException e) {
|
||||
throw e.rethrowFromSystemServer();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an activity listener to listen for events such as top activity change or virtual
|
||||
* display task stack became empty.
|
||||
|
||||
@@ -19,11 +19,18 @@ package android.companion.virtual;
|
||||
import static android.Manifest.permission.ADD_ALWAYS_UNLOCKED_DISPLAY;
|
||||
import static android.media.AudioManager.AUDIO_SESSION_ID_GENERATE;
|
||||
|
||||
import static java.util.concurrent.TimeUnit.MICROSECONDS;
|
||||
|
||||
import android.annotation.CallbackExecutor;
|
||||
import android.annotation.IntDef;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.annotation.RequiresPermission;
|
||||
import android.annotation.SuppressLint;
|
||||
import android.annotation.SystemApi;
|
||||
import android.companion.virtual.sensor.IVirtualSensorCallback;
|
||||
import android.companion.virtual.sensor.VirtualSensor;
|
||||
import android.companion.virtual.sensor.VirtualSensorCallback;
|
||||
import android.companion.virtual.sensor.VirtualSensorConfig;
|
||||
import android.content.ComponentName;
|
||||
import android.os.Parcel;
|
||||
@@ -37,11 +44,13 @@ import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
import java.time.Duration;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
/**
|
||||
* Params that can be configured when creating virtual devices.
|
||||
@@ -190,6 +199,7 @@ public final class VirtualDeviceParams implements Parcelable {
|
||||
// Mapping of @PolicyType to @DevicePolicy
|
||||
@NonNull private final SparseIntArray mDevicePolicies;
|
||||
@NonNull private final List<VirtualSensorConfig> mVirtualSensorConfigs;
|
||||
@Nullable private final IVirtualSensorCallback mVirtualSensorCallback;
|
||||
@RecentsPolicy
|
||||
private final int mDefaultRecentsPolicy;
|
||||
private final int mAudioPlaybackSessionId;
|
||||
@@ -207,6 +217,7 @@ public final class VirtualDeviceParams implements Parcelable {
|
||||
@Nullable String name,
|
||||
@NonNull SparseIntArray devicePolicies,
|
||||
@NonNull List<VirtualSensorConfig> virtualSensorConfigs,
|
||||
@Nullable IVirtualSensorCallback virtualSensorCallback,
|
||||
@RecentsPolicy int defaultRecentsPolicy,
|
||||
int audioPlaybackSessionId,
|
||||
int audioRecordingSessionId) {
|
||||
@@ -224,6 +235,7 @@ public final class VirtualDeviceParams implements Parcelable {
|
||||
mName = name;
|
||||
mDevicePolicies = Objects.requireNonNull(devicePolicies);
|
||||
mVirtualSensorConfigs = Objects.requireNonNull(virtualSensorConfigs);
|
||||
mVirtualSensorCallback = virtualSensorCallback;
|
||||
mDefaultRecentsPolicy = defaultRecentsPolicy;
|
||||
mAudioPlaybackSessionId = audioPlaybackSessionId;
|
||||
mAudioRecordingSessionId = audioRecordingSessionId;
|
||||
@@ -244,6 +256,8 @@ public final class VirtualDeviceParams implements Parcelable {
|
||||
mDevicePolicies = parcel.readSparseIntArray();
|
||||
mVirtualSensorConfigs = new ArrayList<>();
|
||||
parcel.readTypedList(mVirtualSensorConfigs, VirtualSensorConfig.CREATOR);
|
||||
mVirtualSensorCallback =
|
||||
IVirtualSensorCallback.Stub.asInterface(parcel.readStrongBinder());
|
||||
mDefaultRecentsPolicy = parcel.readInt();
|
||||
mAudioPlaybackSessionId = parcel.readInt();
|
||||
mAudioRecordingSessionId = parcel.readInt();
|
||||
@@ -371,6 +385,15 @@ public final class VirtualDeviceParams implements Parcelable {
|
||||
return mVirtualSensorConfigs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the callback to get notified about changes in the sensor listeners.
|
||||
* @hide
|
||||
*/
|
||||
@Nullable
|
||||
public IVirtualSensorCallback getVirtualSensorCallback() {
|
||||
return mVirtualSensorCallback;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the policy of how to handle activities in recents.
|
||||
*
|
||||
@@ -417,6 +440,8 @@ public final class VirtualDeviceParams implements Parcelable {
|
||||
dest.writeString8(mName);
|
||||
dest.writeSparseIntArray(mDevicePolicies);
|
||||
dest.writeTypedList(mVirtualSensorConfigs);
|
||||
dest.writeStrongBinder(
|
||||
mVirtualSensorCallback != null ? mVirtualSensorCallback.asBinder() : null);
|
||||
dest.writeInt(mDefaultRecentsPolicy);
|
||||
dest.writeInt(mAudioPlaybackSessionId);
|
||||
dest.writeInt(mAudioRecordingSessionId);
|
||||
@@ -522,11 +547,38 @@ public final class VirtualDeviceParams implements Parcelable {
|
||||
private boolean mDefaultActivityPolicyConfigured = false;
|
||||
@Nullable private String mName;
|
||||
@NonNull private SparseIntArray mDevicePolicies = new SparseIntArray();
|
||||
@NonNull private List<VirtualSensorConfig> mVirtualSensorConfigs = new ArrayList<>();
|
||||
private int mDefaultRecentsPolicy;
|
||||
private int mAudioPlaybackSessionId = AUDIO_SESSION_ID_GENERATE;
|
||||
private int mAudioRecordingSessionId = AUDIO_SESSION_ID_GENERATE;
|
||||
|
||||
@NonNull private List<VirtualSensorConfig> mVirtualSensorConfigs = new ArrayList<>();
|
||||
@Nullable
|
||||
private IVirtualSensorCallback mVirtualSensorCallback;
|
||||
|
||||
private static class VirtualSensorCallbackDelegate extends IVirtualSensorCallback.Stub {
|
||||
@NonNull
|
||||
private final Executor mExecutor;
|
||||
@NonNull
|
||||
private final VirtualSensorCallback mCallback;
|
||||
|
||||
VirtualSensorCallbackDelegate(@NonNull @CallbackExecutor Executor executor,
|
||||
@NonNull VirtualSensorCallback callback) {
|
||||
mCallback = callback;
|
||||
mExecutor = executor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onConfigurationChanged(@NonNull VirtualSensor sensor, boolean enabled,
|
||||
int samplingPeriodMicros, int batchReportLatencyMicros) {
|
||||
final Duration samplingPeriod =
|
||||
Duration.ofNanos(MICROSECONDS.toNanos(samplingPeriodMicros));
|
||||
final Duration batchReportingLatency =
|
||||
Duration.ofNanos(MICROSECONDS.toNanos(batchReportLatencyMicros));
|
||||
mExecutor.execute(() -> mCallback.onConfigurationChanged(
|
||||
sensor, enabled, samplingPeriod, batchReportingLatency));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the lock state of the device. The permission {@code ADD_ALWAYS_UNLOCKED_DISPLAY}
|
||||
* is required if this is set to {@link #LOCK_STATE_ALWAYS_UNLOCKED}.
|
||||
@@ -730,6 +782,24 @@ public final class VirtualDeviceParams implements Parcelable {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the callback to get notified about changes in the sensor listeners.
|
||||
*
|
||||
* @param executor The executor where the callback is executed on.
|
||||
* @param callback The callback to get notified when the state of the sensor
|
||||
* listeners has changed, see {@link VirtualSensorCallback}
|
||||
*/
|
||||
@SuppressLint("MissingGetterMatchingBuilder")
|
||||
@NonNull
|
||||
public Builder setVirtualSensorCallback(
|
||||
@NonNull @CallbackExecutor Executor executor,
|
||||
@NonNull VirtualSensorCallback callback) {
|
||||
mVirtualSensorCallback = new VirtualSensorCallbackDelegate(
|
||||
Objects.requireNonNull(executor),
|
||||
Objects.requireNonNull(callback));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the policy to indicate how activities are handled in recents.
|
||||
*
|
||||
@@ -798,12 +868,17 @@ public final class VirtualDeviceParams implements Parcelable {
|
||||
*/
|
||||
@NonNull
|
||||
public VirtualDeviceParams build() {
|
||||
if (!mVirtualSensorConfigs.isEmpty()
|
||||
&& (mDevicePolicies.get(POLICY_TYPE_SENSORS, DEVICE_POLICY_DEFAULT)
|
||||
!= DEVICE_POLICY_CUSTOM)) {
|
||||
throw new IllegalArgumentException(
|
||||
"DEVICE_POLICY_CUSTOM for POLICY_TYPE_SENSORS is required for creating "
|
||||
+ "virtual sensors.");
|
||||
if (!mVirtualSensorConfigs.isEmpty()) {
|
||||
if (mDevicePolicies.get(POLICY_TYPE_SENSORS, DEVICE_POLICY_DEFAULT)
|
||||
!= DEVICE_POLICY_CUSTOM) {
|
||||
throw new IllegalArgumentException(
|
||||
"DEVICE_POLICY_CUSTOM for POLICY_TYPE_SENSORS is required for creating "
|
||||
+ "virtual sensors.");
|
||||
}
|
||||
if (mVirtualSensorCallback == null) {
|
||||
throw new IllegalArgumentException(
|
||||
"VirtualSensorCallback is required for creating virtual sensors.");
|
||||
}
|
||||
}
|
||||
|
||||
if ((mAudioPlaybackSessionId != AUDIO_SESSION_ID_GENERATE
|
||||
@@ -837,6 +912,7 @@ public final class VirtualDeviceParams implements Parcelable {
|
||||
mName,
|
||||
mDevicePolicies,
|
||||
mVirtualSensorConfigs,
|
||||
mVirtualSensorCallback,
|
||||
mDefaultRecentsPolicy,
|
||||
mAudioPlaybackSessionId,
|
||||
mAudioRecordingSessionId);
|
||||
|
||||
@@ -16,20 +16,24 @@
|
||||
|
||||
package android.companion.virtual.sensor;
|
||||
|
||||
import android.companion.virtual.sensor.VirtualSensor;
|
||||
|
||||
/**
|
||||
* Interface for notification of listener registration changes for a virtual sensor.
|
||||
* Interface for notifying the sensor owner about whether and how sensor events should be injected.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
oneway interface IVirtualSensorStateChangeCallback {
|
||||
oneway interface IVirtualSensorCallback {
|
||||
|
||||
/**
|
||||
* Called when the registered listeners to a virtual sensor have changed.
|
||||
* Called when the requested sensor event injection parameters have changed.
|
||||
*
|
||||
* @param sensor The sensor whose requested injection parameters have changed.
|
||||
* @param enabled Whether the sensor is enabled.
|
||||
* @param samplingPeriodMicros The requested sensor's sampling period in microseconds.
|
||||
* @param batchReportingLatencyMicros The requested maximum time interval in microseconds
|
||||
* between the delivery of two batches of sensor events.
|
||||
*/
|
||||
void onStateChanged(boolean enabled, int samplingPeriodMicros, int batchReportLatencyMicros);
|
||||
void onConfigurationChanged(in VirtualSensor sensor, boolean enabled, int samplingPeriodMicros,
|
||||
int batchReportLatencyMicros);
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
/*
|
||||
* Copyright (C) 2023 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.companion.virtual.sensor;
|
||||
|
||||
parcelable VirtualSensor;
|
||||
@@ -22,10 +22,10 @@ import android.annotation.SystemApi;
|
||||
import android.companion.virtual.IVirtualDevice;
|
||||
import android.hardware.Sensor;
|
||||
import android.os.IBinder;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
import android.os.RemoteException;
|
||||
|
||||
import java.time.Duration;
|
||||
|
||||
/**
|
||||
* Representation of a sensor on a remote device, capable of sending events, such as an
|
||||
* accelerometer or a gyroscope.
|
||||
@@ -35,24 +35,8 @@ import java.time.Duration;
|
||||
* @hide
|
||||
*/
|
||||
@SystemApi
|
||||
public class VirtualSensor {
|
||||
|
||||
/**
|
||||
* Interface for notification of listener registration changes for a virtual sensor.
|
||||
*/
|
||||
public interface SensorStateChangeCallback {
|
||||
/**
|
||||
* Called when the registered listeners to a virtual sensor have changed.
|
||||
*
|
||||
* @param enabled Whether the sensor is enabled.
|
||||
* @param samplingPeriod The requested sampling period of the sensor.
|
||||
* @param batchReportLatency The requested maximum time interval between the delivery of two
|
||||
* batches of sensor events.
|
||||
*/
|
||||
void onStateChanged(boolean enabled, @NonNull Duration samplingPeriod,
|
||||
@NonNull Duration batchReportLatency);
|
||||
}
|
||||
|
||||
public final class VirtualSensor implements Parcelable {
|
||||
private final int mHandle;
|
||||
private final int mType;
|
||||
private final String mName;
|
||||
private final IVirtualDevice mVirtualDevice;
|
||||
@@ -61,13 +45,32 @@ public class VirtualSensor {
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public VirtualSensor(int type, String name, IVirtualDevice virtualDevice, IBinder token) {
|
||||
public VirtualSensor(int handle, int type, String name, IVirtualDevice virtualDevice,
|
||||
IBinder token) {
|
||||
mHandle = handle;
|
||||
mType = type;
|
||||
mName = name;
|
||||
mVirtualDevice = virtualDevice;
|
||||
mToken = token;
|
||||
}
|
||||
|
||||
private VirtualSensor(Parcel parcel) {
|
||||
mHandle = parcel.readInt();
|
||||
mType = parcel.readInt();
|
||||
mName = parcel.readString8();
|
||||
mVirtualDevice = IVirtualDevice.Stub.asInterface(parcel.readStrongBinder());
|
||||
mToken = parcel.readStrongBinder();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the unique handle of the sensor.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public int getHandle() {
|
||||
return mHandle;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the type of the sensor.
|
||||
*
|
||||
@@ -86,6 +89,32 @@ public class VirtualSensor {
|
||||
return mName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the identifier of the
|
||||
* {@link android.companion.virtual.VirtualDeviceManager.VirtualDevice} this sensor belongs to.
|
||||
*/
|
||||
public int getDeviceId() {
|
||||
try {
|
||||
return mVirtualDevice.getDeviceId();
|
||||
} catch (RemoteException e) {
|
||||
throw e.rethrowFromSystemServer();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(@NonNull Parcel parcel, int flags) {
|
||||
parcel.writeInt(mHandle);
|
||||
parcel.writeInt(mType);
|
||||
parcel.writeString8(mName);
|
||||
parcel.writeStrongBinder(mVirtualDevice.asBinder());
|
||||
parcel.writeStrongBinder(mToken);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a sensor event to the system.
|
||||
*/
|
||||
@@ -97,4 +126,16 @@ public class VirtualSensor {
|
||||
throw e.rethrowFromSystemServer();
|
||||
}
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public static final Parcelable.Creator<VirtualSensor> CREATOR =
|
||||
new Parcelable.Creator<VirtualSensor>() {
|
||||
public VirtualSensor createFromParcel(Parcel in) {
|
||||
return new VirtualSensor(in);
|
||||
}
|
||||
|
||||
public VirtualSensor[] newArray(int size) {
|
||||
return new VirtualSensor[size];
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright (C) 2023 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.companion.virtual.sensor;
|
||||
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.SystemApi;
|
||||
|
||||
import java.time.Duration;
|
||||
|
||||
/**
|
||||
* Interface for notifying the sensor owner about whether and how sensor events should be injected.
|
||||
*
|
||||
* <p>This callback can be used for controlling the sensor event injection - e.g. if the sensor is
|
||||
* not enabled, then no events should be injected. Similarly, the rate and delay of the injected
|
||||
* events that the registered listeners expect are specified here.
|
||||
*
|
||||
* <p>The callback is tied to the VirtualDevice's lifetime as the virtual sensors are created when
|
||||
* the device is created and destroyed when the device is destroyed.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@SystemApi
|
||||
public interface VirtualSensorCallback {
|
||||
/**
|
||||
* Called when the requested sensor event injection parameters have changed.
|
||||
*
|
||||
* <p>This is effectively called when the registered listeners to a virtual sensor have changed.
|
||||
*
|
||||
* @param sensor The sensor whose requested injection parameters have changed.
|
||||
* @param enabled Whether the sensor is enabled. True if any listeners are currently registered,
|
||||
* and false otherwise.
|
||||
* @param samplingPeriod The requested sampling period of the sensor.
|
||||
* @param batchReportLatency The requested maximum time interval between the delivery of two
|
||||
* batches of sensor events.
|
||||
*/
|
||||
void onConfigurationChanged(@NonNull VirtualSensor sensor, boolean enabled,
|
||||
@NonNull Duration samplingPeriod, @NonNull Duration batchReportLatency);
|
||||
}
|
||||
@@ -16,20 +16,15 @@
|
||||
|
||||
package android.companion.virtual.sensor;
|
||||
|
||||
import static java.util.concurrent.TimeUnit.MICROSECONDS;
|
||||
|
||||
import android.annotation.CallbackExecutor;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.annotation.SuppressLint;
|
||||
import android.annotation.SystemApi;
|
||||
import android.hardware.Sensor;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
/**
|
||||
* Configuration for creation of a virtual sensor.
|
||||
@@ -44,23 +39,17 @@ public final class VirtualSensorConfig implements Parcelable {
|
||||
private final String mName;
|
||||
@Nullable
|
||||
private final String mVendor;
|
||||
@Nullable
|
||||
private final IVirtualSensorStateChangeCallback mStateChangeCallback;
|
||||
|
||||
private VirtualSensorConfig(int type, @NonNull String name, @Nullable String vendor,
|
||||
@Nullable IVirtualSensorStateChangeCallback stateChangeCallback) {
|
||||
private VirtualSensorConfig(int type, @NonNull String name, @Nullable String vendor) {
|
||||
mType = type;
|
||||
mName = name;
|
||||
mVendor = vendor;
|
||||
mStateChangeCallback = stateChangeCallback;
|
||||
}
|
||||
|
||||
private VirtualSensorConfig(@NonNull Parcel parcel) {
|
||||
mType = parcel.readInt();
|
||||
mName = parcel.readString8();
|
||||
mVendor = parcel.readString8();
|
||||
mStateChangeCallback =
|
||||
IVirtualSensorStateChangeCallback.Stub.asInterface(parcel.readStrongBinder());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -73,8 +62,6 @@ public final class VirtualSensorConfig implements Parcelable {
|
||||
parcel.writeInt(mType);
|
||||
parcel.writeString8(mName);
|
||||
parcel.writeString8(mVendor);
|
||||
parcel.writeStrongBinder(
|
||||
mStateChangeCallback != null ? mStateChangeCallback.asBinder() : null);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -104,15 +91,6 @@ public final class VirtualSensorConfig implements Parcelable {
|
||||
return mVendor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the callback to get notified about changes in the sensor listeners.
|
||||
* @hide
|
||||
*/
|
||||
@Nullable
|
||||
public IVirtualSensorStateChangeCallback getStateChangeCallback() {
|
||||
return mStateChangeCallback;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builder for {@link VirtualSensorConfig}.
|
||||
*/
|
||||
@@ -123,32 +101,6 @@ public final class VirtualSensorConfig implements Parcelable {
|
||||
private final String mName;
|
||||
@Nullable
|
||||
private String mVendor;
|
||||
@Nullable
|
||||
private IVirtualSensorStateChangeCallback mStateChangeCallback;
|
||||
|
||||
private static class SensorStateChangeCallbackDelegate
|
||||
extends IVirtualSensorStateChangeCallback.Stub {
|
||||
@NonNull
|
||||
private final Executor mExecutor;
|
||||
@NonNull
|
||||
private final VirtualSensor.SensorStateChangeCallback mCallback;
|
||||
|
||||
SensorStateChangeCallbackDelegate(@NonNull @CallbackExecutor Executor executor,
|
||||
@NonNull VirtualSensor.SensorStateChangeCallback callback) {
|
||||
mCallback = callback;
|
||||
mExecutor = executor;
|
||||
}
|
||||
@Override
|
||||
public void onStateChanged(boolean enabled, int samplingPeriodMicros,
|
||||
int batchReportLatencyMicros) {
|
||||
final Duration samplingPeriod =
|
||||
Duration.ofNanos(MICROSECONDS.toNanos(samplingPeriodMicros));
|
||||
final Duration batchReportingLatency =
|
||||
Duration.ofNanos(MICROSECONDS.toNanos(batchReportLatencyMicros));
|
||||
mExecutor.execute(() -> mCallback.onStateChanged(
|
||||
enabled, samplingPeriod, batchReportingLatency));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new builder.
|
||||
@@ -167,7 +119,7 @@ public final class VirtualSensorConfig implements Parcelable {
|
||||
*/
|
||||
@NonNull
|
||||
public VirtualSensorConfig build() {
|
||||
return new VirtualSensorConfig(mType, mName, mVendor, mStateChangeCallback);
|
||||
return new VirtualSensorConfig(mType, mName, mVendor);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -178,24 +130,6 @@ public final class VirtualSensorConfig implements Parcelable {
|
||||
mVendor = vendor;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the callback to get notified about changes in the sensor listeners.
|
||||
*
|
||||
* @param executor The executor where the callback is executed on.
|
||||
* @param callback The callback to get notified when the state of the sensor
|
||||
* listeners has changed, see {@link VirtualSensor.SensorStateChangeCallback}
|
||||
*/
|
||||
@SuppressLint("MissingGetterMatchingBuilder")
|
||||
@NonNull
|
||||
public VirtualSensorConfig.Builder setStateChangeCallback(
|
||||
@NonNull @CallbackExecutor Executor executor,
|
||||
@NonNull VirtualSensor.SensorStateChangeCallback callback) {
|
||||
mStateChangeCallback = new SensorStateChangeCallbackDelegate(
|
||||
Objects.requireNonNull(executor),
|
||||
Objects.requireNonNull(callback));
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
@NonNull
|
||||
|
||||
@@ -20,28 +20,13 @@ import static android.hardware.Sensor.TYPE_ACCELEROMETER;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.mockito.Mockito.timeout;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
import static java.util.concurrent.TimeUnit.MILLISECONDS;
|
||||
|
||||
import android.os.Parcel;
|
||||
import android.platform.test.annotations.Presubmit;
|
||||
|
||||
import androidx.test.runner.AndroidJUnit4;
|
||||
|
||||
import com.android.internal.os.BackgroundThread;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
import org.mockito.junit.MockitoJUnit;
|
||||
import org.mockito.junit.MockitoRule;
|
||||
|
||||
import java.time.Duration;
|
||||
|
||||
@Presubmit
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
@@ -50,23 +35,11 @@ public class VirtualSensorConfigTest {
|
||||
private static final String SENSOR_NAME = "VirtualSensorName";
|
||||
private static final String SENSOR_VENDOR = "VirtualSensorVendor";
|
||||
|
||||
@Rule
|
||||
public final MockitoRule mockito = MockitoJUnit.rule();
|
||||
|
||||
@Mock
|
||||
private VirtualSensor.SensorStateChangeCallback mSensorCallback;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void parcelAndUnparcel_matches() {
|
||||
final VirtualSensorConfig originalConfig =
|
||||
new VirtualSensorConfig.Builder(TYPE_ACCELEROMETER, SENSOR_NAME)
|
||||
.setVendor(SENSOR_VENDOR)
|
||||
.setStateChangeCallback(BackgroundThread.getExecutor(), mSensorCallback)
|
||||
.build();
|
||||
final Parcel parcel = Parcel.obtain();
|
||||
originalConfig.writeToParcel(parcel, /* flags= */ 0);
|
||||
@@ -76,7 +49,6 @@ public class VirtualSensorConfigTest {
|
||||
assertThat(recreatedConfig.getType()).isEqualTo(originalConfig.getType());
|
||||
assertThat(recreatedConfig.getName()).isEqualTo(originalConfig.getName());
|
||||
assertThat(recreatedConfig.getVendor()).isEqualTo(originalConfig.getVendor());
|
||||
assertThat(recreatedConfig.getStateChangeCallback()).isNotNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -84,23 +56,5 @@ public class VirtualSensorConfigTest {
|
||||
final VirtualSensorConfig config =
|
||||
new VirtualSensorConfig.Builder(TYPE_ACCELEROMETER, SENSOR_NAME).build();
|
||||
assertThat(config.getVendor()).isNull();
|
||||
assertThat(config.getStateChangeCallback()).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void sensorConfig_sensorCallbackInvocation() throws Exception {
|
||||
final VirtualSensorConfig config =
|
||||
new VirtualSensorConfig.Builder(TYPE_ACCELEROMETER, SENSOR_NAME)
|
||||
.setStateChangeCallback(BackgroundThread.getExecutor(), mSensorCallback)
|
||||
.build();
|
||||
|
||||
final Duration samplingPeriod = Duration.ofMillis(123);
|
||||
final Duration batchLatency = Duration.ofMillis(456);
|
||||
|
||||
config.getStateChangeCallback().onStateChanged(true,
|
||||
(int) MILLISECONDS.toMicros(samplingPeriod.toMillis()),
|
||||
(int) MILLISECONDS.toMicros(batchLatency.toMillis()));
|
||||
|
||||
verify(mSensorCallback, timeout(1000)).onStateChanged(true, samplingPeriod, batchLatency);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,7 +17,9 @@
|
||||
package com.android.server.companion.virtual;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.companion.virtual.sensor.IVirtualSensorStateChangeCallback;
|
||||
import android.annotation.Nullable;
|
||||
import android.companion.virtual.sensor.IVirtualSensorCallback;
|
||||
import android.companion.virtual.sensor.VirtualSensor;
|
||||
import android.companion.virtual.sensor.VirtualSensorConfig;
|
||||
import android.companion.virtual.sensor.VirtualSensorEvent;
|
||||
import android.os.IBinder;
|
||||
@@ -40,17 +42,30 @@ public class SensorController {
|
||||
|
||||
private static final String TAG = "SensorController";
|
||||
|
||||
// See system/core/libutils/include/utils/Errors.h
|
||||
private static final int OK = 0;
|
||||
private static final int UNKNOWN_ERROR = (-2147483647 - 1); // INT32_MIN value
|
||||
private static final int BAD_VALUE = -22;
|
||||
|
||||
private final Object mLock;
|
||||
private final int mVirtualDeviceId;
|
||||
@GuardedBy("mLock")
|
||||
private final Map<IBinder, SensorDescriptor> mSensorDescriptors = new ArrayMap<>();
|
||||
|
||||
@NonNull
|
||||
private final SensorManagerInternal.RuntimeSensorCallback mRuntimeSensorCallback;
|
||||
private final SensorManagerInternal mSensorManagerInternal;
|
||||
private final VirtualDeviceManagerInternal mVdmInternal;
|
||||
|
||||
public SensorController(@NonNull Object lock, int virtualDeviceId) {
|
||||
|
||||
|
||||
public SensorController(@NonNull Object lock, int virtualDeviceId,
|
||||
@Nullable IVirtualSensorCallback virtualSensorCallback) {
|
||||
mLock = lock;
|
||||
mVirtualDeviceId = virtualDeviceId;
|
||||
mRuntimeSensorCallback = new RuntimeSensorCallbackWrapper(virtualSensorCallback);
|
||||
mSensorManagerInternal = LocalServices.getService(SensorManagerInternal.class);
|
||||
mVdmInternal = LocalServices.getService(VirtualDeviceManagerInternal.class);
|
||||
}
|
||||
|
||||
void close() {
|
||||
@@ -67,36 +82,23 @@ public class SensorController {
|
||||
}
|
||||
}
|
||||
|
||||
void createSensor(@NonNull IBinder deviceToken, @NonNull VirtualSensorConfig config) {
|
||||
Objects.requireNonNull(deviceToken);
|
||||
int createSensor(@NonNull IBinder sensorToken, @NonNull VirtualSensorConfig config) {
|
||||
Objects.requireNonNull(sensorToken);
|
||||
Objects.requireNonNull(config);
|
||||
try {
|
||||
createSensorInternal(deviceToken, config);
|
||||
return createSensorInternal(sensorToken, config);
|
||||
} catch (SensorCreationException e) {
|
||||
throw new RuntimeException(
|
||||
"Failed to create virtual sensor '" + config.getName() + "'.", e);
|
||||
}
|
||||
}
|
||||
|
||||
private void createSensorInternal(IBinder deviceToken, VirtualSensorConfig config)
|
||||
private int createSensorInternal(IBinder sensorToken, VirtualSensorConfig config)
|
||||
throws SensorCreationException {
|
||||
final SensorManagerInternal.RuntimeSensorStateChangeCallback runtimeSensorCallback =
|
||||
(enabled, samplingPeriodMicros, batchReportLatencyMicros) -> {
|
||||
IVirtualSensorStateChangeCallback callback = config.getStateChangeCallback();
|
||||
if (callback != null) {
|
||||
try {
|
||||
callback.onStateChanged(
|
||||
enabled, samplingPeriodMicros, batchReportLatencyMicros);
|
||||
} catch (RemoteException e) {
|
||||
throw new RuntimeException("Failed to call sensor callback.", e);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
final int handle = mSensorManagerInternal.createRuntimeSensor(mVirtualDeviceId,
|
||||
config.getType(), config.getName(),
|
||||
config.getVendor() == null ? "" : config.getVendor(),
|
||||
runtimeSensorCallback);
|
||||
mRuntimeSensorCallback);
|
||||
if (handle <= 0) {
|
||||
throw new SensorCreationException("Received an invalid virtual sensor handle.");
|
||||
}
|
||||
@@ -104,8 +106,8 @@ public class SensorController {
|
||||
// The handle is valid from here, so ensure that all failures clean it up.
|
||||
final BinderDeathRecipient binderDeathRecipient;
|
||||
try {
|
||||
binderDeathRecipient = new BinderDeathRecipient(deviceToken);
|
||||
deviceToken.linkToDeath(binderDeathRecipient, /* flags= */ 0);
|
||||
binderDeathRecipient = new BinderDeathRecipient(sensorToken);
|
||||
sensorToken.linkToDeath(binderDeathRecipient, /* flags= */ 0);
|
||||
} catch (RemoteException e) {
|
||||
mSensorManagerInternal.removeRuntimeSensor(handle);
|
||||
throw new SensorCreationException("Client died before sensor could be created.", e);
|
||||
@@ -114,8 +116,9 @@ public class SensorController {
|
||||
synchronized (mLock) {
|
||||
SensorDescriptor sensorDescriptor = new SensorDescriptor(
|
||||
handle, config.getType(), config.getName(), binderDeathRecipient);
|
||||
mSensorDescriptors.put(deviceToken, sensorDescriptor);
|
||||
mSensorDescriptors.put(sensorToken, sensorDescriptor);
|
||||
}
|
||||
return handle;
|
||||
}
|
||||
|
||||
boolean sendSensorEvent(@NonNull IBinder token, @NonNull VirtualSensorEvent event) {
|
||||
@@ -178,6 +181,39 @@ public class SensorController {
|
||||
}
|
||||
}
|
||||
|
||||
private final class RuntimeSensorCallbackWrapper
|
||||
implements SensorManagerInternal.RuntimeSensorCallback {
|
||||
@Nullable
|
||||
private IVirtualSensorCallback mCallback;
|
||||
|
||||
RuntimeSensorCallbackWrapper(@Nullable IVirtualSensorCallback callback) {
|
||||
mCallback = callback;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int onConfigurationChanged(int handle, boolean enabled, int samplingPeriodMicros,
|
||||
int batchReportLatencyMicros) {
|
||||
if (mCallback == null) {
|
||||
Slog.e(TAG, "No sensor callback configured for sensor handle " + handle);
|
||||
return BAD_VALUE;
|
||||
}
|
||||
VirtualSensor sensor = mVdmInternal.getVirtualSensor(mVirtualDeviceId, handle);
|
||||
if (sensor == null) {
|
||||
Slog.e(TAG, "No sensor found for deviceId=" + mVirtualDeviceId
|
||||
+ " and sensor handle=" + handle);
|
||||
return BAD_VALUE;
|
||||
}
|
||||
try {
|
||||
mCallback.onConfigurationChanged(sensor, enabled, samplingPeriodMicros,
|
||||
batchReportLatencyMicros);
|
||||
} catch (RemoteException e) {
|
||||
Slog.e(TAG, "Failed to call sensor callback: " + e);
|
||||
return UNKNOWN_ERROR;
|
||||
}
|
||||
return OK;
|
||||
}
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
static final class SensorDescriptor {
|
||||
|
||||
@@ -207,10 +243,10 @@ public class SensorController {
|
||||
}
|
||||
|
||||
private final class BinderDeathRecipient implements IBinder.DeathRecipient {
|
||||
private final IBinder mDeviceToken;
|
||||
private final IBinder mSensorToken;
|
||||
|
||||
BinderDeathRecipient(IBinder deviceToken) {
|
||||
mDeviceToken = deviceToken;
|
||||
BinderDeathRecipient(IBinder sensorToken) {
|
||||
mSensorToken = sensorToken;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -219,7 +255,7 @@ public class SensorController {
|
||||
// quitting, which removes this death recipient. If this is invoked, the remote end
|
||||
// died, or they disposed of the object without properly unregistering.
|
||||
Slog.e(TAG, "Virtual sensor controller binder died");
|
||||
unregisterSensor(mDeviceToken);
|
||||
unregisterSensor(mSensorToken);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -41,6 +41,7 @@ import android.companion.virtual.VirtualDeviceManager.ActivityListener;
|
||||
import android.companion.virtual.VirtualDeviceParams;
|
||||
import android.companion.virtual.audio.IAudioConfigChangedCallback;
|
||||
import android.companion.virtual.audio.IAudioRoutingCallback;
|
||||
import android.companion.virtual.sensor.VirtualSensor;
|
||||
import android.companion.virtual.sensor.VirtualSensorConfig;
|
||||
import android.companion.virtual.sensor.VirtualSensorEvent;
|
||||
import android.content.ComponentName;
|
||||
@@ -86,6 +87,8 @@ import com.android.server.companion.virtual.audio.VirtualAudioController;
|
||||
|
||||
import java.io.FileDescriptor;
|
||||
import java.io.PrintWriter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
@@ -131,6 +134,11 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub
|
||||
@GuardedBy("mVirtualDeviceLock")
|
||||
@Nullable
|
||||
private LocaleList mLocaleList = null;
|
||||
// This device's sensors, keyed by sensor handle.
|
||||
@GuardedBy("mVirtualDeviceLock")
|
||||
private SparseArray<VirtualSensor> mVirtualSensors = new SparseArray<>();
|
||||
@GuardedBy("mVirtualDeviceLock")
|
||||
private List<VirtualSensor> mVirtualSensorList = null;
|
||||
|
||||
private ActivityListener createListenerAdapter() {
|
||||
return new ActivityListener() {
|
||||
@@ -240,10 +248,15 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub
|
||||
mInputController = inputController;
|
||||
}
|
||||
if (sensorController == null) {
|
||||
mSensorController = new SensorController(mVirtualDeviceLock, mDeviceId);
|
||||
mSensorController = new SensorController(
|
||||
mVirtualDeviceLock, mDeviceId, mParams.getVirtualSensorCallback());
|
||||
} else {
|
||||
mSensorController = sensorController;
|
||||
}
|
||||
final List<VirtualSensorConfig> virtualSensorConfigs = mParams.getVirtualSensorConfigs();
|
||||
for (int i = 0; i < virtualSensorConfigs.size(); ++i) {
|
||||
createVirtualSensor(virtualSensorConfigs.get(i));
|
||||
}
|
||||
mCameraAccessController = cameraAccessController;
|
||||
mCameraAccessController.startObservingIfNeeded();
|
||||
mOnDeviceCloseListener = onDeviceCloseListener;
|
||||
@@ -384,6 +397,8 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub
|
||||
mVirtualAudioController = null;
|
||||
}
|
||||
mLocaleList = null;
|
||||
mVirtualSensorList = null;
|
||||
mVirtualSensors.clear();
|
||||
}
|
||||
mOnDeviceCloseListener.onClose(mDeviceId);
|
||||
mAppToken.unlinkToDeath(this, 0);
|
||||
@@ -698,17 +713,17 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub
|
||||
}
|
||||
}
|
||||
|
||||
@Override // Binder call
|
||||
@EnforcePermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
|
||||
public void createVirtualSensor(
|
||||
@NonNull IBinder deviceToken,
|
||||
@NonNull VirtualSensorConfig config) {
|
||||
super.createVirtualSensor_enforcePermission();
|
||||
Objects.requireNonNull(config);
|
||||
Objects.requireNonNull(deviceToken);
|
||||
private void createVirtualSensor(@NonNull VirtualSensorConfig config) {
|
||||
final IBinder sensorToken =
|
||||
new Binder("android.hardware.sensor.VirtualSensor:" + config.getName());
|
||||
final long ident = Binder.clearCallingIdentity();
|
||||
try {
|
||||
mSensorController.createSensor(deviceToken, config);
|
||||
int handle = mSensorController.createSensor(sensorToken, config);
|
||||
VirtualSensor sensor = new VirtualSensor(handle, config.getType(), config.getName(),
|
||||
this, sensorToken);
|
||||
synchronized (mVirtualDeviceLock) {
|
||||
mVirtualSensors.put(handle, sensor);
|
||||
}
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(ident);
|
||||
}
|
||||
@@ -716,13 +731,24 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub
|
||||
|
||||
@Override // Binder call
|
||||
@EnforcePermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
|
||||
public void unregisterSensor(@NonNull IBinder token) {
|
||||
super.unregisterSensor_enforcePermission();
|
||||
final long ident = Binder.clearCallingIdentity();
|
||||
try {
|
||||
mSensorController.unregisterSensor(token);
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(ident);
|
||||
@Nullable
|
||||
public List<VirtualSensor> getVirtualSensorList() {
|
||||
super.getVirtualSensorList_enforcePermission();
|
||||
synchronized (mVirtualDeviceLock) {
|
||||
if (mVirtualSensorList == null) {
|
||||
mVirtualSensorList = new ArrayList<>();
|
||||
for (int i = 0; i < mVirtualSensors.size(); ++i) {
|
||||
mVirtualSensorList.add(mVirtualSensors.valueAt(i));
|
||||
}
|
||||
mVirtualSensorList = Collections.unmodifiableList(mVirtualSensorList);
|
||||
}
|
||||
return mVirtualSensorList;
|
||||
}
|
||||
}
|
||||
|
||||
VirtualSensor getVirtualSensorByHandle(int handle) {
|
||||
synchronized (mVirtualDeviceLock) {
|
||||
return mVirtualSensors.get(handle);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -34,6 +34,7 @@ import android.companion.virtual.IVirtualDeviceSoundEffectListener;
|
||||
import android.companion.virtual.VirtualDevice;
|
||||
import android.companion.virtual.VirtualDeviceManager;
|
||||
import android.companion.virtual.VirtualDeviceParams;
|
||||
import android.companion.virtual.sensor.VirtualSensor;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.hardware.display.DisplayManagerInternal;
|
||||
@@ -469,6 +470,17 @@ public class VirtualDeviceManagerService extends SystemService {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable VirtualSensor getVirtualSensor(int deviceId, int handle) {
|
||||
synchronized (mVirtualDeviceManagerLock) {
|
||||
VirtualDeviceImpl virtualDevice = mVirtualDevices.get(deviceId);
|
||||
if (virtualDevice != null) {
|
||||
return virtualDevice.getVirtualSensorByHandle(handle);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull ArraySet<Integer> getDeviceIdsForUid(int uid) {
|
||||
ArraySet<Integer> result = new ArraySet<>();
|
||||
|
||||
@@ -19,6 +19,7 @@ package com.android.server.companion.virtual;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.companion.virtual.IVirtualDevice;
|
||||
import android.companion.virtual.sensor.VirtualSensor;
|
||||
import android.os.LocaleList;
|
||||
import android.util.ArraySet;
|
||||
|
||||
@@ -77,6 +78,15 @@ public abstract class VirtualDeviceManagerInternal {
|
||||
*/
|
||||
public abstract int getDeviceOwnerUid(int deviceId);
|
||||
|
||||
/**
|
||||
* Returns the VirtualSensor for the given deviceId and sensor handle, if any.
|
||||
*
|
||||
* @param deviceId the virtual device that owns the sensor
|
||||
* @param handle the sensor handle
|
||||
* @return the VirtualSensor with the given handle, or {@code null} if no such sensor exists.
|
||||
*/
|
||||
public abstract @Nullable VirtualSensor getVirtualSensor(int deviceId, int handle);
|
||||
|
||||
/**
|
||||
* Finds VirtualDevices where an app is running.
|
||||
*
|
||||
|
||||
@@ -58,7 +58,7 @@ public abstract class SensorManagerInternal {
|
||||
* @return The sensor handle.
|
||||
*/
|
||||
public abstract int createRuntimeSensor(int deviceId, int type, @NonNull String name,
|
||||
@NonNull String vendor, @NonNull RuntimeSensorStateChangeCallback callback);
|
||||
@NonNull String vendor, @NonNull RuntimeSensorCallback callback);
|
||||
|
||||
/**
|
||||
* Unregisters the sensor with the given handle from the framework.
|
||||
@@ -95,11 +95,12 @@ public abstract class SensorManagerInternal {
|
||||
* {@link #createRuntimeSensor}, i.e. the dynamic sensors created via the dynamic sensor HAL are
|
||||
* not covered.
|
||||
*/
|
||||
public interface RuntimeSensorStateChangeCallback {
|
||||
public interface RuntimeSensorCallback {
|
||||
/**
|
||||
* Invoked when the listeners of the runtime sensor have changed.
|
||||
* Returns an error code if the invocation was unsuccessful, zero otherwise.
|
||||
*/
|
||||
void onStateChanged(boolean enabled, int samplingPeriodMicros,
|
||||
int onConfigurationChanged(int handle, boolean enabled, int samplingPeriodMicros,
|
||||
int batchReportLatencyMicros);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -56,8 +56,7 @@ public class SensorService extends SystemService {
|
||||
private static native void unregisterProximityActiveListenerNative(long ptr);
|
||||
|
||||
private static native int registerRuntimeSensorNative(long ptr, int deviceId, int type,
|
||||
String name, String vendor,
|
||||
SensorManagerInternal.RuntimeSensorStateChangeCallback callback);
|
||||
String name, String vendor, SensorManagerInternal.RuntimeSensorCallback callback);
|
||||
private static native void unregisterRuntimeSensorNative(long ptr, int handle);
|
||||
private static native boolean sendRuntimeSensorEventNative(long ptr, int handle, int type,
|
||||
long timestampNanos, float[] values);
|
||||
@@ -96,7 +95,7 @@ public class SensorService extends SystemService {
|
||||
class LocalService extends SensorManagerInternal {
|
||||
@Override
|
||||
public int createRuntimeSensor(int deviceId, int type, @NonNull String name,
|
||||
@NonNull String vendor, @NonNull RuntimeSensorStateChangeCallback callback) {
|
||||
@NonNull String vendor, @NonNull RuntimeSensorCallback callback) {
|
||||
synchronized (mLock) {
|
||||
int handle = registerRuntimeSensorNative(mPtr, deviceId, type, name, vendor,
|
||||
callback);
|
||||
|
||||
@@ -32,13 +32,13 @@
|
||||
"com/android/server/sensors/SensorManagerInternal$ProximityActiveListener"
|
||||
|
||||
#define RUNTIME_SENSOR_CALLBACK_CLASS \
|
||||
"com/android/server/sensors/SensorManagerInternal$RuntimeSensorStateChangeCallback"
|
||||
"com/android/server/sensors/SensorManagerInternal$RuntimeSensorCallback"
|
||||
|
||||
namespace android {
|
||||
|
||||
static JavaVM* sJvm = nullptr;
|
||||
static jmethodID sMethodIdOnProximityActive;
|
||||
static jmethodID sMethodIdOnStateChanged;
|
||||
static jmethodID sMethodIdOnConfigurationChanged;
|
||||
|
||||
class NativeSensorService {
|
||||
public:
|
||||
@@ -67,13 +67,13 @@ private:
|
||||
};
|
||||
sp<ProximityActiveListenerDelegate> mProximityActiveListenerDelegate;
|
||||
|
||||
class RuntimeSensorCallbackDelegate : public SensorService::RuntimeSensorStateChangeCallback {
|
||||
class RuntimeSensorCallbackDelegate : public SensorService::RuntimeSensorCallback {
|
||||
public:
|
||||
RuntimeSensorCallbackDelegate(JNIEnv* env, jobject callback);
|
||||
~RuntimeSensorCallbackDelegate();
|
||||
|
||||
void onStateChanged(bool enabled, int64_t samplingPeriodNs,
|
||||
int64_t batchReportLatencyNs) override;
|
||||
status_t onConfigurationChanged(int32_t handle, bool enabled, int64_t samplingPeriodNs,
|
||||
int64_t batchReportLatencyNs) override;
|
||||
|
||||
private:
|
||||
jobject mCallback;
|
||||
@@ -231,12 +231,13 @@ NativeSensorService::RuntimeSensorCallbackDelegate::~RuntimeSensorCallbackDelega
|
||||
AndroidRuntime::getJNIEnv()->DeleteGlobalRef(mCallback);
|
||||
}
|
||||
|
||||
void NativeSensorService::RuntimeSensorCallbackDelegate::onStateChanged(
|
||||
bool enabled, int64_t samplingPeriodNs, int64_t batchReportLatencyNs) {
|
||||
status_t NativeSensorService::RuntimeSensorCallbackDelegate::onConfigurationChanged(
|
||||
int32_t handle, bool enabled, int64_t samplingPeriodNs, int64_t batchReportLatencyNs) {
|
||||
auto jniEnv = GetOrAttachJNIEnvironment(sJvm);
|
||||
jniEnv->CallVoidMethod(mCallback, sMethodIdOnStateChanged, static_cast<jboolean>(enabled),
|
||||
static_cast<jint>(ns2us(samplingPeriodNs)),
|
||||
static_cast<jint>(ns2us(batchReportLatencyNs)));
|
||||
return jniEnv->CallIntMethod(mCallback, sMethodIdOnConfigurationChanged,
|
||||
static_cast<jint>(handle), static_cast<jboolean>(enabled),
|
||||
static_cast<jint>(ns2us(samplingPeriodNs)),
|
||||
static_cast<jint>(ns2us(batchReportLatencyNs)));
|
||||
}
|
||||
|
||||
static jlong startSensorServiceNative(JNIEnv* env, jclass, jobject listener) {
|
||||
@@ -292,8 +293,8 @@ int register_android_server_sensor_SensorService(JavaVM* vm, JNIEnv* env) {
|
||||
jclass listenerClass = FindClassOrDie(env, PROXIMITY_ACTIVE_CLASS);
|
||||
sMethodIdOnProximityActive = GetMethodIDOrDie(env, listenerClass, "onProximityActive", "(Z)V");
|
||||
jclass runtimeSensorCallbackClass = FindClassOrDie(env, RUNTIME_SENSOR_CALLBACK_CLASS);
|
||||
sMethodIdOnStateChanged =
|
||||
GetMethodIDOrDie(env, runtimeSensorCallbackClass, "onStateChanged", "(ZII)V");
|
||||
sMethodIdOnConfigurationChanged =
|
||||
GetMethodIDOrDie(env, runtimeSensorCallbackClass, "onConfigurationChanged", "(IZII)I");
|
||||
return jniRegisterNativeMethods(env, "com/android/server/sensors/SensorService", methods,
|
||||
NELEM(methods));
|
||||
}
|
||||
|
||||
@@ -95,7 +95,7 @@
|
||||
-keep,allowoptimization,allowaccessmodification class com.android.server.location.gnss.GnssPowerStats { *; }
|
||||
-keep,allowoptimization,allowaccessmodification class com.android.server.location.gnss.hal.GnssNative { *; }
|
||||
-keep,allowoptimization,allowaccessmodification class com.android.server.pm.PackageManagerShellCommandDataLoader { *; }
|
||||
-keep,allowoptimization,allowaccessmodification class com.android.server.sensors.SensorManagerInternal$RuntimeSensorStateChangeCallback { *; }
|
||||
-keep,allowoptimization,allowaccessmodification class com.android.server.sensors.SensorManagerInternal$RuntimeSensorCallback { *; }
|
||||
-keep,allowoptimization,allowaccessmodification class com.android.server.sensors.SensorManagerInternal$ProximityActiveListener { *; }
|
||||
-keep,allowoptimization,allowaccessmodification class com.android.server.sensors.SensorService { *; }
|
||||
-keep,allowoptimization,allowaccessmodification class com.android.server.soundtrigger_middleware.SoundTriggerMiddlewareImpl$AudioSessionProvider$AudioSession { *; }
|
||||
|
||||
@@ -25,6 +25,7 @@ import static org.mockito.ArgumentMatchers.anyString;
|
||||
import static org.mockito.Mockito.doReturn;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
import android.companion.virtual.sensor.IVirtualSensorCallback;
|
||||
import android.companion.virtual.sensor.VirtualSensorConfig;
|
||||
import android.companion.virtual.sensor.VirtualSensorEvent;
|
||||
import android.hardware.Sensor;
|
||||
@@ -54,6 +55,8 @@ public class SensorControllerTest {
|
||||
|
||||
@Mock
|
||||
private SensorManagerInternal mSensorManagerInternalMock;
|
||||
@Mock
|
||||
private IVirtualSensorCallback mVirtualSensorCallback;
|
||||
private SensorController mSensorController;
|
||||
private VirtualSensorEvent mSensorEvent;
|
||||
private VirtualSensorConfig mVirtualSensorConfig;
|
||||
@@ -66,7 +69,8 @@ public class SensorControllerTest {
|
||||
LocalServices.removeServiceForTest(SensorManagerInternal.class);
|
||||
LocalServices.addService(SensorManagerInternal.class, mSensorManagerInternalMock);
|
||||
|
||||
mSensorController = new SensorController(new Object(), VIRTUAL_DEVICE_ID);
|
||||
mSensorController =
|
||||
new SensorController(new Object(), VIRTUAL_DEVICE_ID, mVirtualSensorCallback);
|
||||
mSensorEvent = new VirtualSensorEvent.Builder(new float[] { 1f, 2f, 3f}).build();
|
||||
mVirtualSensorConfig =
|
||||
new VirtualSensorConfig.Builder(Sensor.TYPE_ACCELEROMETER, VIRTUAL_SENSOR_NAME)
|
||||
@@ -135,6 +139,7 @@ public class SensorControllerTest {
|
||||
private void doCreateSensorSuccessfully() {
|
||||
doReturn(SENSOR_HANDLE).when(mSensorManagerInternalMock).createRuntimeSensor(
|
||||
anyInt(), anyInt(), anyString(), anyString(), any());
|
||||
mSensorController.createSensor(mSensorToken, mVirtualSensorConfig);
|
||||
assertThat(mSensorController.createSensor(mSensorToken, mVirtualSensorConfig))
|
||||
.isEqualTo(SENSOR_HANDLE);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,6 +55,9 @@ import android.companion.virtual.IVirtualDeviceSoundEffectListener;
|
||||
import android.companion.virtual.VirtualDeviceParams;
|
||||
import android.companion.virtual.audio.IAudioConfigChangedCallback;
|
||||
import android.companion.virtual.audio.IAudioRoutingCallback;
|
||||
import android.companion.virtual.sensor.IVirtualSensorCallback;
|
||||
import android.companion.virtual.sensor.VirtualSensor;
|
||||
import android.companion.virtual.sensor.VirtualSensorCallback;
|
||||
import android.companion.virtual.sensor.VirtualSensorConfig;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
@@ -102,6 +105,7 @@ import androidx.test.platform.app.InstrumentationRegistry;
|
||||
|
||||
import com.android.compatibility.common.util.AdoptShellPermissionsRule;
|
||||
import com.android.internal.app.BlockedAppStreamingActivity;
|
||||
import com.android.internal.os.BackgroundThread;
|
||||
import com.android.server.LocalServices;
|
||||
import com.android.server.input.InputManagerInternal;
|
||||
import com.android.server.sensors.SensorManagerInternal;
|
||||
@@ -225,6 +229,10 @@ public class VirtualDeviceManagerServiceTest {
|
||||
@Mock
|
||||
private SensorManagerInternal mSensorManagerInternalMock;
|
||||
@Mock
|
||||
private IVirtualSensorCallback mVirtualSensorCallback;
|
||||
@Mock
|
||||
private VirtualSensorCallback mSensorCallback;
|
||||
@Mock
|
||||
private IVirtualDeviceActivityListener mActivityListener;
|
||||
@Mock
|
||||
private IVirtualDeviceSoundEffectListener mSoundEffectListener;
|
||||
@@ -333,7 +341,8 @@ public class VirtualDeviceManagerServiceTest {
|
||||
mInputController = new InputController(new Object(), mNativeWrapperMock,
|
||||
new Handler(TestableLooper.get(this).getLooper()),
|
||||
mContext.getSystemService(WindowManager.class), threadVerifier);
|
||||
mSensorController = new SensorController(new Object(), VIRTUAL_DEVICE_ID_1);
|
||||
mSensorController =
|
||||
new SensorController(new Object(), VIRTUAL_DEVICE_ID_1, mVirtualSensorCallback);
|
||||
mCameraAccessController =
|
||||
new CameraAccessController(mContext, mLocalService, mCameraAccessBlockedCallback);
|
||||
|
||||
@@ -450,6 +459,42 @@ public class VirtualDeviceManagerServiceTest {
|
||||
assertThat(ownerUid).isEqualTo(Process.INVALID_UID);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getVirtualSensor_defaultDeviceId_returnsNull() {
|
||||
assertThat(mLocalService.getVirtualSensor(DEVICE_ID_DEFAULT, SENSOR_HANDLE)).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getVirtualSensor_invalidDeviceId_returnsNull() {
|
||||
assertThat(mLocalService.getVirtualSensor(DEVICE_ID_INVALID, SENSOR_HANDLE)).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getVirtualSensor_noSensors_returnsNull() {
|
||||
assertThat(mLocalService.getVirtualSensor(VIRTUAL_DEVICE_ID_1, SENSOR_HANDLE)).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getVirtualSensor_returnsCorrectSensor() {
|
||||
VirtualDeviceParams params = new VirtualDeviceParams.Builder()
|
||||
.setDevicePolicy(POLICY_TYPE_SENSORS, DEVICE_POLICY_CUSTOM)
|
||||
.addVirtualSensorConfig(
|
||||
new VirtualSensorConfig.Builder(Sensor.TYPE_ACCELEROMETER, DEVICE_NAME_1)
|
||||
.build())
|
||||
.setVirtualSensorCallback(BackgroundThread.getExecutor(), mSensorCallback)
|
||||
.build();
|
||||
|
||||
doReturn(SENSOR_HANDLE).when(mSensorManagerInternalMock).createRuntimeSensor(
|
||||
anyInt(), anyInt(), anyString(), anyString(), any());
|
||||
mDeviceImpl = createVirtualDevice(VIRTUAL_DEVICE_ID_1, DEVICE_OWNER_UID_1, params);
|
||||
|
||||
VirtualSensor sensor = mLocalService.getVirtualSensor(VIRTUAL_DEVICE_ID_1, SENSOR_HANDLE);
|
||||
assertThat(sensor).isNotNull();
|
||||
assertThat(sensor.getDeviceId()).isEqualTo(VIRTUAL_DEVICE_ID_1);
|
||||
assertThat(sensor.getHandle()).isEqualTo(SENSOR_HANDLE);
|
||||
assertThat(sensor.getType()).isEqualTo(Sensor.TYPE_ACCELEROMETER);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getDeviceIdsForUid_noRunningApps_returnsNull() {
|
||||
Set<Integer> deviceIds = mLocalService.getDeviceIdsForUid(UID_1);
|
||||
@@ -887,18 +932,6 @@ public class VirtualDeviceManagerServiceTest {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createVirtualSensor_noPermission_failsSecurityException() {
|
||||
try (DropShellPermissionsTemporarily drop = new DropShellPermissionsTemporarily()) {
|
||||
assertThrows(
|
||||
SecurityException.class,
|
||||
() -> mDeviceImpl.createVirtualSensor(
|
||||
BINDER,
|
||||
new VirtualSensorConfig.Builder(
|
||||
Sensor.TYPE_ACCELEROMETER, DEVICE_NAME_1).build()));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onAudioSessionStarting_noPermission_failsSecurityException() {
|
||||
mDeviceImpl.mVirtualDisplayIds.add(DISPLAY_ID_1);
|
||||
|
||||
@@ -1,85 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2021 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.server.companion.virtual;
|
||||
|
||||
import static android.companion.virtual.VirtualDeviceParams.DEVICE_POLICY_CUSTOM;
|
||||
import static android.companion.virtual.VirtualDeviceParams.POLICY_TYPE_AUDIO;
|
||||
import static android.companion.virtual.VirtualDeviceParams.POLICY_TYPE_SENSORS;
|
||||
import static android.hardware.Sensor.TYPE_ACCELEROMETER;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import android.companion.virtual.VirtualDeviceParams;
|
||||
import android.companion.virtual.sensor.VirtualSensorConfig;
|
||||
import android.os.Parcel;
|
||||
import android.os.UserHandle;
|
||||
import android.platform.test.annotations.Presubmit;
|
||||
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
@Presubmit
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class VirtualDeviceParamsTest {
|
||||
|
||||
private static final String SENSOR_NAME = "VirtualSensorName";
|
||||
private static final String SENSOR_VENDOR = "VirtualSensorVendor";
|
||||
private static final int PLAYBACK_SESSION_ID = 42;
|
||||
private static final int RECORDING_SESSION_ID = 77;
|
||||
|
||||
@Test
|
||||
public void parcelable_shouldRecreateSuccessfully() {
|
||||
VirtualDeviceParams originalParams = new VirtualDeviceParams.Builder()
|
||||
.setLockState(VirtualDeviceParams.LOCK_STATE_ALWAYS_UNLOCKED)
|
||||
.setUsersWithMatchingAccounts(Set.of(UserHandle.of(123), UserHandle.of(456)))
|
||||
.setDevicePolicy(POLICY_TYPE_SENSORS, DEVICE_POLICY_CUSTOM)
|
||||
.setDevicePolicy(POLICY_TYPE_AUDIO, DEVICE_POLICY_CUSTOM)
|
||||
.setAudioPlaybackSessionId(PLAYBACK_SESSION_ID)
|
||||
.setAudioRecordingSessionId(RECORDING_SESSION_ID)
|
||||
.addVirtualSensorConfig(
|
||||
new VirtualSensorConfig.Builder(TYPE_ACCELEROMETER, SENSOR_NAME)
|
||||
.setVendor(SENSOR_VENDOR)
|
||||
.build())
|
||||
.build();
|
||||
Parcel parcel = Parcel.obtain();
|
||||
originalParams.writeToParcel(parcel, 0);
|
||||
parcel.setDataPosition(0);
|
||||
|
||||
VirtualDeviceParams params = VirtualDeviceParams.CREATOR.createFromParcel(parcel);
|
||||
assertThat(params).isEqualTo(originalParams);
|
||||
assertThat(params.getLockState()).isEqualTo(VirtualDeviceParams.LOCK_STATE_ALWAYS_UNLOCKED);
|
||||
assertThat(params.getUsersWithMatchingAccounts())
|
||||
.containsExactly(UserHandle.of(123), UserHandle.of(456));
|
||||
assertThat(params.getDevicePolicy(POLICY_TYPE_SENSORS)).isEqualTo(DEVICE_POLICY_CUSTOM);
|
||||
assertThat(params.getDevicePolicy(POLICY_TYPE_AUDIO)).isEqualTo(DEVICE_POLICY_CUSTOM);
|
||||
assertThat(params.getAudioPlaybackSessionId()).isEqualTo(PLAYBACK_SESSION_ID);
|
||||
assertThat(params.getAudioRecordingSessionId()).isEqualTo(RECORDING_SESSION_ID);
|
||||
|
||||
List<VirtualSensorConfig> sensorConfigs = params.getVirtualSensorConfigs();
|
||||
assertThat(sensorConfigs).hasSize(1);
|
||||
VirtualSensorConfig sensorConfig = sensorConfigs.get(0);
|
||||
assertThat(sensorConfig.getType()).isEqualTo(TYPE_ACCELEROMETER);
|
||||
assertThat(sensorConfig.getName()).isEqualTo(SENSOR_NAME);
|
||||
assertThat(sensorConfig.getVendor()).isEqualTo(SENSOR_VENDOR);
|
||||
assertThat(sensorConfig.getStateChangeCallback()).isNull();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user