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

Commit a91e94df authored by Vladimir Komsiyski's avatar Vladimir Komsiyski
Browse files

Direct connection API for runtime sensors.

The type of direct channel and highest supported rate level are
reflected in the sensor flags. Only MemoryFile channels are supported
for virtual device sensors, HardwareBuffer ones are not.

New sensor callback methods inform the VirtualDevice owner when a new
direct sensor channel has been (un-)registered or configured for a
sensor, along with the writable shared memory region and rate level.

Bug: 266042170
Test: atest SensorControllerTest
Test: atest VirtualSensorConfigTest

Change-Id: I239bdf448ce0ff1412a0bcd0a4654d70a08b3077
parent 15530467
Loading
Loading
Loading
Loading
+7 −0
Original line number Original line Diff line number Diff line
@@ -3344,10 +3344,15 @@ package android.companion.virtual.sensor {
  public interface VirtualSensorCallback {
  public interface VirtualSensorCallback {
    method public void onConfigurationChanged(@NonNull android.companion.virtual.sensor.VirtualSensor, boolean, @NonNull java.time.Duration, @NonNull java.time.Duration);
    method public void onConfigurationChanged(@NonNull android.companion.virtual.sensor.VirtualSensor, boolean, @NonNull java.time.Duration, @NonNull java.time.Duration);
    method public default void onDirectChannelConfigured(@IntRange(from=1) int, @NonNull android.companion.virtual.sensor.VirtualSensor, int, @IntRange(from=1) int);
    method public default void onDirectChannelCreated(@IntRange(from=1) int, @NonNull android.os.SharedMemory);
    method public default void onDirectChannelDestroyed(@IntRange(from=1) int);
  }
  }
  public final class VirtualSensorConfig implements android.os.Parcelable {
  public final class VirtualSensorConfig implements android.os.Parcelable {
    method public int describeContents();
    method public int describeContents();
    method public int getDirectChannelTypesSupported();
    method public int getHighestDirectReportRateLevel();
    method @NonNull public String getName();
    method @NonNull public String getName();
    method public int getType();
    method public int getType();
    method @Nullable public String getVendor();
    method @Nullable public String getVendor();
@@ -3358,6 +3363,8 @@ package android.companion.virtual.sensor {
  public static final class VirtualSensorConfig.Builder {
  public static final class VirtualSensorConfig.Builder {
    ctor public VirtualSensorConfig.Builder(int, @NonNull String);
    ctor public VirtualSensorConfig.Builder(int, @NonNull String);
    method @NonNull public android.companion.virtual.sensor.VirtualSensorConfig build();
    method @NonNull public android.companion.virtual.sensor.VirtualSensorConfig build();
    method @NonNull public android.companion.virtual.sensor.VirtualSensorConfig.Builder setDirectChannelTypesSupported(int);
    method @NonNull public android.companion.virtual.sensor.VirtualSensorConfig.Builder setHighestDirectReportRateLevel(int);
    method @NonNull public android.companion.virtual.sensor.VirtualSensorConfig.Builder setVendor(@Nullable String);
    method @NonNull public android.companion.virtual.sensor.VirtualSensorConfig.Builder setVendor(@Nullable String);
  }
  }
+20 −0
Original line number Original line Diff line number Diff line
@@ -35,6 +35,7 @@ import android.companion.virtual.sensor.VirtualSensorConfig;
import android.content.ComponentName;
import android.content.ComponentName;
import android.os.Parcel;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.Parcelable;
import android.os.SharedMemory;
import android.os.UserHandle;
import android.os.UserHandle;
import android.util.ArraySet;
import android.util.ArraySet;
import android.util.SparseArray;
import android.util.SparseArray;
@@ -577,6 +578,25 @@ public final class VirtualDeviceParams implements Parcelable {
                mExecutor.execute(() -> mCallback.onConfigurationChanged(
                mExecutor.execute(() -> mCallback.onConfigurationChanged(
                        sensor, enabled, samplingPeriod, batchReportingLatency));
                        sensor, enabled, samplingPeriod, batchReportingLatency));
            }
            }

            @Override
            public void onDirectChannelCreated(int channelHandle,
                    @NonNull SharedMemory sharedMemory) {
                mExecutor.execute(
                        () -> mCallback.onDirectChannelCreated(channelHandle, sharedMemory));
            }

            @Override
            public void onDirectChannelDestroyed(int channelHandle) {
                mExecutor.execute(() -> mCallback.onDirectChannelDestroyed(channelHandle));
            }

            @Override
            public void onDirectChannelConfigured(int channelHandle, @NonNull VirtualSensor sensor,
                    int rateLevel, int reportToken) {
                mExecutor.execute(() -> mCallback.onDirectChannelConfigured(
                        channelHandle, sensor, rateLevel, reportToken));
            }
        }
        }


        /**
        /**
+28 −0
Original line number Original line Diff line number Diff line
@@ -17,6 +17,7 @@
package android.companion.virtual.sensor;
package android.companion.virtual.sensor;


import android.companion.virtual.sensor.VirtualSensor;
import android.companion.virtual.sensor.VirtualSensor;
import android.os.SharedMemory;


/**
/**
 * Interface for notifying the sensor owner about whether and how sensor events should be injected.
 * Interface for notifying the sensor owner about whether and how sensor events should be injected.
@@ -36,4 +37,31 @@ oneway interface IVirtualSensorCallback {
     */
     */
    void onConfigurationChanged(in VirtualSensor sensor, boolean enabled, int samplingPeriodMicros,
    void onConfigurationChanged(in VirtualSensor sensor, boolean enabled, int samplingPeriodMicros,
            int batchReportLatencyMicros);
            int batchReportLatencyMicros);

    /**
     * Called when a sensor direct channel is created.
     *
     * @param channelHandle Identifier of the channel that was created.
     * @param sharedMemory The shared memory region for the direct sensor channel.
     */
    void onDirectChannelCreated(int channelHandle, in SharedMemory sharedMemory);

    /**
     * Called when a sensor direct channel is destroyed.
     *
     * @param channelHandle Identifier of the channel that was destroyed.
     */
    void onDirectChannelDestroyed(int channelHandle);

    /**
     * Called when a sensor direct channel is configured.
     *
     * @param channelHandle Identifier of the channel that was configured.
     * @param sensor The sensor, for which the channel was configured.
     * @param rateLevel The rate level used to configure the direct sensor channel.
     * @param reportToken A positive sensor report token, used to differentiate between events from
     * different sensors within the same channel.
     */
    void onDirectChannelConfigured(int channelHandle, in VirtualSensor sensor, int rateLevel,
            int reportToken);
}
}
+75 −0
Original line number Original line Diff line number Diff line
@@ -17,8 +17,13 @@
package android.companion.virtual.sensor;
package android.companion.virtual.sensor;




import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.NonNull;
import android.annotation.SystemApi;
import android.annotation.SystemApi;
import android.hardware.Sensor;
import android.hardware.SensorDirectChannel;
import android.os.MemoryFile;
import android.os.SharedMemory;


import java.time.Duration;
import java.time.Duration;


@@ -50,4 +55,74 @@ public interface VirtualSensorCallback {
     */
     */
    void onConfigurationChanged(@NonNull VirtualSensor sensor, boolean enabled,
    void onConfigurationChanged(@NonNull VirtualSensor sensor, boolean enabled,
            @NonNull Duration samplingPeriod, @NonNull Duration batchReportLatency);
            @NonNull Duration samplingPeriod, @NonNull Duration batchReportLatency);

    /**
     * Called when a {@link android.hardware.SensorDirectChannel} is created.
     *
     * <p>The {@link android.hardware.SensorManager} instance used to create the direct channel must
     * be associated with the virtual device.
     *
     * <p>A typical order of callback invocations is:
     * <ul>
     *     <li>{@code onDirectChannelCreated} - the channel handle and the associated shared memory
     *     should be stored by the virtual device</li>
     *     <li>{@code onDirectChannelConfigured} with a positive {@code rateLevel} - the virtual
     *     device should start writing to the shared memory for the associated channel with the
     *     requested parameters.</li>
     *     <li>{@code onDirectChannelConfigured} with a {@code rateLevel = RATE_STOP} - the virtual
     *     device should stop writing to the shared memory for the associated channel.</li>
     *     <li>{@code onDirectChannelDestroyed} - the shared memory associated with the channel
     *     handle should be closed.</li>
     * </ul>
     *
     * @param channelHandle Identifier of the newly created channel.
     * @param sharedMemory writable shared memory region.
     *
     * @see android.hardware.SensorManager#createDirectChannel(MemoryFile)
     * @see #onDirectChannelConfigured
     * @see #onDirectChannelDestroyed
     */
    default void onDirectChannelCreated(@IntRange(from = 1) int channelHandle,
            @NonNull SharedMemory sharedMemory) {}

    /**
     * Called when a {@link android.hardware.SensorDirectChannel} is destroyed.
     *
     * <p>The virtual device must perform any clean-up and close the shared memory that was
     * received with the {@link #onDirectChannelCreated} callback and the corresponding
     * {@code channelHandle}.
     *
     * @param channelHandle Identifier of the channel that was destroyed.
     *
     * @see SensorDirectChannel#close()
     */
    default void onDirectChannelDestroyed(@IntRange(from = 1) int channelHandle) {}

    /**
     * Called when a {@link android.hardware.SensorDirectChannel} is configured.
     *
     * <p>Sensor events for the corresponding sensor should be written at the indicated rate to the
     * shared memory region that was received with the {@link #onDirectChannelCreated} callback and
     * the corresponding {@code channelHandle}. The events should be written in the correct format
     * and with the provided {@code reportToken} until the channel is reconfigured with
     * {@link SensorDirectChannel#RATE_STOP}.
     *
     * <p>The sensor must support direct channel in order for this callback to be invoked. Only
     * {@link MemoryFile} sensor direct channels are supported for virtual sensors.
     *
     * @param channelHandle Identifier of the channel that was configured.
     * @param sensor The sensor, for which the channel was configured.
     * @param rateLevel The rate level used to configure the direct sensor channel.
     * @param reportToken A positive sensor report token, used to differentiate between events from
     * different sensors within the same channel.
     *
     * @see VirtualSensorConfig.Builder#setHighestDirectReportRateLevel(int)
     * @see VirtualSensorConfig.Builder#setDirectChannelTypesSupported(int)
     * @see android.hardware.SensorManager#createDirectChannel(MemoryFile)
     * @see #onDirectChannelCreated
     * @see SensorDirectChannel#configure(Sensor, int)
     */
    default void onDirectChannelConfigured(@IntRange(from = 1) int channelHandle,
            @NonNull VirtualSensor sensor, @SensorDirectChannel.RateLevel int rateLevel,
            @IntRange(from = 1) int reportToken) {}
}
}
+111 −3
Original line number Original line Diff line number Diff line
@@ -21,11 +21,13 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.annotation.SystemApi;
import android.hardware.Sensor;
import android.hardware.Sensor;
import android.hardware.SensorDirectChannel;
import android.os.Parcel;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.Parcelable;


import java.util.Objects;
import java.util.Objects;



/**
/**
 * Configuration for creation of a virtual sensor.
 * Configuration for creation of a virtual sensor.
 * @see VirtualSensor
 * @see VirtualSensor
@@ -33,6 +35,14 @@ import java.util.Objects;
 */
 */
@SystemApi
@SystemApi
public final class VirtualSensorConfig implements Parcelable {
public final class VirtualSensorConfig implements Parcelable {
    private static final String TAG = "VirtualSensorConfig";

    // Mask for direct mode highest rate level, bit 7, 8, 9.
    private static final int DIRECT_REPORT_MASK = 0x380;
    private static final int DIRECT_REPORT_SHIFT = 7;

    // Mask for supported direct channel, bit 10, 11
    private static final int DIRECT_CHANNEL_SHIFT = 10;


    private final int mType;
    private final int mType;
    @NonNull
    @NonNull
@@ -40,16 +50,21 @@ public final class VirtualSensorConfig implements Parcelable {
    @Nullable
    @Nullable
    private final String mVendor;
    private final String mVendor;


    private VirtualSensorConfig(int type, @NonNull String name, @Nullable String vendor) {
    private final int mFlags;

    private VirtualSensorConfig(int type, @NonNull String name, @Nullable String vendor,
            int flags) {
        mType = type;
        mType = type;
        mName = name;
        mName = name;
        mVendor = vendor;
        mVendor = vendor;
        mFlags = flags;
    }
    }


    private VirtualSensorConfig(@NonNull Parcel parcel) {
    private VirtualSensorConfig(@NonNull Parcel parcel) {
        mType = parcel.readInt();
        mType = parcel.readInt();
        mName = parcel.readString8();
        mName = parcel.readString8();
        mVendor = parcel.readString8();
        mVendor = parcel.readString8();
        mFlags = parcel.readInt();
    }
    }


    @Override
    @Override
@@ -62,6 +77,7 @@ public final class VirtualSensorConfig implements Parcelable {
        parcel.writeInt(mType);
        parcel.writeInt(mType);
        parcel.writeString8(mName);
        parcel.writeString8(mName);
        parcel.writeString8(mVendor);
        parcel.writeString8(mVendor);
        parcel.writeInt(mFlags);
    }
    }


    /**
    /**
@@ -91,16 +107,58 @@ public final class VirtualSensorConfig implements Parcelable {
        return mVendor;
        return mVendor;
    }
    }


    /**
     * Returns the highest supported direct report mode rate level of the sensor.
     *
     * @see Sensor#getHighestDirectReportRateLevel()
     */
    @SensorDirectChannel.RateLevel
    public int getHighestDirectReportRateLevel() {
        int rateLevel = ((mFlags & DIRECT_REPORT_MASK) >> DIRECT_REPORT_SHIFT);
        return rateLevel <= SensorDirectChannel.RATE_VERY_FAST
                ? rateLevel : SensorDirectChannel.RATE_VERY_FAST;
    }

    /**
     * Returns a combination of all supported direct channel types.
     *
     * @see Builder#setDirectChannelTypesSupported(int)
     * @see Sensor#isDirectChannelTypeSupported(int)
     */
    public @SensorDirectChannel.MemoryType int getDirectChannelTypesSupported() {
        int memoryTypes = 0;
        if ((mFlags & (1 << DIRECT_CHANNEL_SHIFT)) > 0) {
            memoryTypes |= SensorDirectChannel.TYPE_MEMORY_FILE;
        }
        if ((mFlags & (1 << (DIRECT_CHANNEL_SHIFT + 1))) > 0) {
            memoryTypes |= SensorDirectChannel.TYPE_HARDWARE_BUFFER;
        }
        return memoryTypes;
    }

    /**
     * Returns the sensor flags.
     * @hide
     */
    public int getFlags() {
        return mFlags;
    }

    /**
    /**
     * Builder for {@link VirtualSensorConfig}.
     * Builder for {@link VirtualSensorConfig}.
     */
     */
    public static final class Builder {
    public static final class Builder {


        private static final int FLAG_MEMORY_FILE_DIRECT_CHANNEL_SUPPORTED =
                1 << DIRECT_CHANNEL_SHIFT;
        private final int mType;
        private final int mType;
        @NonNull
        @NonNull
        private final String mName;
        private final String mName;
        @Nullable
        @Nullable
        private String mVendor;
        private String mVendor;
        private int mFlags;
        @SensorDirectChannel.RateLevel
        int mHighestDirectReportRateLevel;


        /**
        /**
         * Creates a new builder.
         * Creates a new builder.
@@ -119,7 +177,19 @@ public final class VirtualSensorConfig implements Parcelable {
         */
         */
        @NonNull
        @NonNull
        public VirtualSensorConfig build() {
        public VirtualSensorConfig build() {
            return new VirtualSensorConfig(mType, mName, mVendor);
            if (mHighestDirectReportRateLevel > 0) {
                if ((mFlags & FLAG_MEMORY_FILE_DIRECT_CHANNEL_SUPPORTED) == 0) {
                    throw new IllegalArgumentException("Setting direct channel type is required "
                            + "for sensors with direct channel support.");
                }
                mFlags |= mHighestDirectReportRateLevel << DIRECT_REPORT_SHIFT;
            }
            if ((mFlags & FLAG_MEMORY_FILE_DIRECT_CHANNEL_SUPPORTED) > 0
                    && mHighestDirectReportRateLevel == 0) {
                throw new IllegalArgumentException("Highest direct report rate level is "
                        + "required for sensors with direct channel support.");
            }
            return new VirtualSensorConfig(mType, mName, mVendor, mFlags);
        }
        }


        /**
        /**
@@ -130,6 +200,44 @@ public final class VirtualSensorConfig implements Parcelable {
            mVendor = vendor;
            mVendor = vendor;
            return this;
            return this;
        }
        }

        /**
         * Sets the highest supported rate level for direct sensor report.
         *
         * @see VirtualSensorConfig#getHighestDirectReportRateLevel()
         */
        @NonNull
        public VirtualSensorConfig.Builder setHighestDirectReportRateLevel(
                @SensorDirectChannel.RateLevel int rateLevel) {
            mHighestDirectReportRateLevel = rateLevel;
            return this;
        }

        /**
         * Sets whether direct sensor channel of the given types is supported.
         *
         * @param memoryTypes A combination of {@link SensorDirectChannel.MemoryType} flags
         * indicating the types of shared memory supported for creating direct channels. Only
         * {@link SensorDirectChannel#TYPE_MEMORY_FILE} direct channels may be supported for virtual
         * sensors.
         * @throws IllegalArgumentException if {@link SensorDirectChannel#TYPE_HARDWARE_BUFFER} is
         * set to be supported.
         */
        @NonNull
        public VirtualSensorConfig.Builder setDirectChannelTypesSupported(
                @SensorDirectChannel.MemoryType int memoryTypes) {
            if ((memoryTypes & SensorDirectChannel.TYPE_MEMORY_FILE) > 0) {
                mFlags |= FLAG_MEMORY_FILE_DIRECT_CHANNEL_SUPPORTED;
            } else {
                mFlags &= ~FLAG_MEMORY_FILE_DIRECT_CHANNEL_SUPPORTED;
            }
            if ((memoryTypes & ~SensorDirectChannel.TYPE_MEMORY_FILE) > 0) {
                throw new IllegalArgumentException(
                        "Only TYPE_MEMORY_FILE direct channels can be supported for virtual "
                                + "sensors.");
            }
            return this;
        }
    }
    }


    @NonNull
    @NonNull
Loading