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

Commit 9d5084da authored by Vladimir Komsiyski's avatar Vladimir Komsiyski
Browse files

Refactor the VirtualSensor API.

Make the virtual sensor callback VirtualDevice-level instead of
VirtualSensor-level. This allows for clients of the API to define a
single callback that takes the sensor as an argument instead of
defining callback per sensor. Also, this allows for mimicking the
HAL APIs for direct channel support, as channel registration and
unregistration are at HAL level and not at sensor level. This is a
nicer solution because the VirtualDevice essentially acts as the
sensor HAL.

In more detail what this CL does:
 - Rename the VirtualSensorCallback and move it to its own file
 - Rename the callback method to onListenersChanged
 - Make VirtualSensor Parcelable so it can be passed to the callback
 - Move the VirtualSensor ownership to VirtualDeviceImpl
 - Make VirtualDevice id avaiable from VirtualSensor.
 - Return a boolean from the internal callbacks indicating success
 - Move the non-CTS VirtualDeviceParamsTest cases to the CTS one

Bug: 266042170
Test: atest VirtualSensorConfigTest
Test: atest SensorControllerTest
Test: atest VirtualDeviceManagerServiceTest

Change-Id: I14127f7a000d84ba41ade6ebda41c95a0c350fc9
parent 437eb02e
Loading
Loading
Loading
Loading
+9 −5
Original line number Diff line number Diff line
@@ -3176,7 +3176,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);
@@ -3231,6 +3231,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);
  }
}
@@ -3282,14 +3283,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 {
@@ -3304,7 +3309,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);
  }
+3 −9
Original line number Diff line number Diff line
@@ -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.
+9 −39
Original line number Diff line number Diff line
@@ -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();
            }
        }

        /**
@@ -940,28 +932,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.
+83 −7
Original line number Diff line number Diff line
@@ -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,13 +868,18 @@ public final class VirtualDeviceParams implements Parcelable {
         */
        @NonNull
        public VirtualDeviceParams build() {
            if (!mVirtualSensorConfigs.isEmpty()
                    && (mDevicePolicies.get(POLICY_TYPE_SENSORS, DEVICE_POLICY_DEFAULT)
                            != DEVICE_POLICY_CUSTOM)) {
            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
                    || mAudioRecordingSessionId != AUDIO_SESSION_ID_GENERATE)
@@ -837,6 +912,7 @@ public final class VirtualDeviceParams implements Parcelable {
                    mName,
                    mDevicePolicies,
                    mVirtualSensorConfigs,
                    mVirtualSensorCallback,
                    mDefaultRecentsPolicy,
                    mAudioPlaybackSessionId,
                    mAudioRecordingSessionId);
+8 −4
Original line number Diff line number Diff line
@@ -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);
}
Loading