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

Commit 557f9e05 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Expose vibration primitives durations in Vibrator" into sc-dev

parents 396ad2e2 82319601
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -32081,6 +32081,7 @@ package android.os {
    method @NonNull public boolean[] arePrimitivesSupported(@NonNull int...);
    method @RequiresPermission(android.Manifest.permission.VIBRATE) public abstract void cancel();
    method public int getId();
    method @NonNull public int[] getPrimitiveDurations(@NonNull int...);
    method public abstract boolean hasAmplitudeControl();
    method public abstract boolean hasVibrator();
    method @Deprecated @RequiresPermission(android.Manifest.permission.VIBRATE) public void vibrate(long);
+21 −0
Original line number Diff line number Diff line
@@ -551,6 +551,27 @@ public abstract class Vibrator {
        return true;
    }

    /**
     * Query the estimated durations of the given primitives.
     *
     * The returned array will be the same length as the query array and the value at a given index
     * will contain the duration in milliseconds of the effect at the same index in the querying
     * array.
     *
     * @param primitiveIds Which primitives to query for.
     * @return The duration of each primitive, with zeroes for primitives that are not supported.
     */
    @NonNull
    public int[] getPrimitiveDurations(
            @NonNull @VibrationEffect.Composition.PrimitiveType int... primitiveIds) {
        VibratorInfo info = getInfo();
        int[] durations = new int[primitiveIds.length];
        for (int i = 0; i < primitiveIds.length; i++) {
            durations[i] = info.getPrimitiveDuration(primitiveIds[i]);
        }
        return durations;
    }

    /**
     * Turn the vibrator off.
     */
+121 −18
Original line number Diff line number Diff line
@@ -25,6 +25,7 @@ import android.util.Log;
import android.util.MathUtils;
import android.util.Range;
import android.util.SparseBooleanArray;
import android.util.SparseIntArray;

import java.util.ArrayList;
import java.util.Arrays;
@@ -51,7 +52,7 @@ public class VibratorInfo implements Parcelable {
    @Nullable
    private final SparseBooleanArray mSupportedBraking;
    @Nullable
    private final SparseBooleanArray mSupportedPrimitives;
    private final SparseIntArray mSupportedPrimitives;
    private final float mQFactor;
    private final FrequencyMapping mFrequencyMapping;

@@ -60,19 +61,37 @@ public class VibratorInfo implements Parcelable {
        mCapabilities = in.readLong();
        mSupportedEffects = in.readSparseBooleanArray();
        mSupportedBraking = in.readSparseBooleanArray();
        mSupportedPrimitives = in.readSparseBooleanArray();
        mSupportedPrimitives = in.readSparseIntArray();
        mQFactor = in.readFloat();
        mFrequencyMapping = in.readParcelable(VibratorInfo.class.getClassLoader());
    }

    /** @hide */
    /**
     * Default constructor.
     *
     * @param id                  The vibrator id.
     * @param capabilities        All capability flags of the vibrator, defined in IVibrator.CAP_*.
     * @param supportedEffects    All supported predefined effects, enum values from {@link
     *                            android.hardware.vibrator.Effect}.
     * @param supportedBraking    All supported braking types, enum values from {@link Braking}.
     * @param supportedPrimitives All supported primitive effects, enum values from {@link
     *                            android.hardware.vibrator.CompositePrimitive}.
     * @param primitiveDurations  A mapping of primitive durations, where indexes are enum values
     *                            from {@link android.hardware.vibrator.CompositePrimitive} and the
     *                            values are estimated durations in milliseconds.
     * @param qFactor             The vibrator quality factor.
     * @param frequencyMapping    The description of the vibrator supported frequencies and max
     *                            amplitude mappings.
     * @hide
     */
    public VibratorInfo(int id, long capabilities, int[] supportedEffects, int[] supportedBraking,
            int[] supportedPrimitives, float qFactor, @NonNull FrequencyMapping frequencyMapping) {
            int[] supportedPrimitives, int[] primitiveDurations, float qFactor,
            @NonNull FrequencyMapping frequencyMapping) {
        mId = id;
        mCapabilities = capabilities;
        mSupportedEffects = toSparseBooleanArray(supportedEffects);
        mSupportedBraking = toSparseBooleanArray(supportedBraking);
        mSupportedPrimitives = toSparseBooleanArray(supportedPrimitives);
        mSupportedPrimitives = toSparseIntArray(supportedPrimitives, primitiveDurations);
        mQFactor = qFactor;
        mFrequencyMapping = frequencyMapping;
    }
@@ -100,7 +119,7 @@ public class VibratorInfo implements Parcelable {
        dest.writeLong(mCapabilities);
        dest.writeSparseBooleanArray(mSupportedEffects);
        dest.writeSparseBooleanArray(mSupportedBraking);
        dest.writeSparseBooleanArray(mSupportedPrimitives);
        dest.writeSparseIntArray(mSupportedPrimitives);
        dest.writeFloat(mQFactor);
        dest.writeParcelable(mFrequencyMapping, flags);
    }
@@ -119,18 +138,41 @@ public class VibratorInfo implements Parcelable {
            return false;
        }
        VibratorInfo that = (VibratorInfo) o;
        if (mSupportedPrimitives == null || that.mSupportedPrimitives == null) {
            if (mSupportedPrimitives != that.mSupportedPrimitives) {
                return false;
            }
        } else {
            if (mSupportedPrimitives.size() != that.mSupportedPrimitives.size()) {
                return false;
            }
            for (int i = 0; i < mSupportedPrimitives.size(); i++) {
                if (mSupportedPrimitives.keyAt(i) != that.mSupportedPrimitives.keyAt(i)) {
                    return false;
                }
                if (mSupportedPrimitives.valueAt(i) != that.mSupportedPrimitives.valueAt(i)) {
                    return false;
                }
            }
        }
        return mId == that.mId && mCapabilities == that.mCapabilities
                && Objects.equals(mSupportedEffects, that.mSupportedEffects)
                && Objects.equals(mSupportedBraking, that.mSupportedBraking)
                && Objects.equals(mSupportedPrimitives, that.mSupportedPrimitives)
                && Objects.equals(mQFactor, that.mQFactor)
                && Objects.equals(mFrequencyMapping, that.mFrequencyMapping);
    }

    @Override
    public int hashCode() {
        return Objects.hash(mId, mCapabilities, mSupportedEffects, mSupportedBraking,
                mSupportedPrimitives, mQFactor, mFrequencyMapping);
        int hashCode = Objects.hash(mId, mCapabilities, mSupportedEffects, mSupportedBraking,
                mQFactor, mFrequencyMapping);
        if (mSupportedPrimitives != null) {
            for (int i = 0; i < mSupportedPrimitives.size(); i++) {
                hashCode = 31 * hashCode + mSupportedPrimitives.keyAt(i);
                hashCode = 31 * hashCode + mSupportedPrimitives.valueAt(i);
            }
        }
        return hashCode;
    }

    @Override
@@ -206,7 +248,19 @@ public class VibratorInfo implements Parcelable {
    public boolean isPrimitiveSupported(
            @VibrationEffect.Composition.PrimitiveType int primitiveId) {
        return hasCapability(IVibrator.CAP_COMPOSE_EFFECTS) && mSupportedPrimitives != null
                && mSupportedPrimitives.get(primitiveId);
                && (mSupportedPrimitives.indexOfKey(primitiveId) >= 0);
    }

    /**
     * Query the estimated duration of given primitive.
     *
     * @param primitiveId Which primitives to query for.
     * @return The duration in milliseconds estimated for the primitive, or zero if primitive not
     * supported.
     */
    public int getPrimitiveDuration(
            @VibrationEffect.Composition.PrimitiveType int primitiveId) {
        return mSupportedPrimitives.get(primitiveId);
    }

    /**
@@ -364,14 +418,37 @@ public class VibratorInfo implements Parcelable {
        return names;
    }

    /**
     * Create a {@link SparseBooleanArray} from given {@code supportedKeys} where each key is mapped
     * to {@code true}.
     */
    @Nullable
    private static SparseBooleanArray toSparseBooleanArray(int[] values) {
        if (values == null) {
    private static SparseBooleanArray toSparseBooleanArray(int[] supportedKeys) {
        if (supportedKeys == null) {
            return null;
        }
        SparseBooleanArray array = new SparseBooleanArray();
        for (int value : values) {
            array.put(value, true);
        for (int key : supportedKeys) {
            array.put(key, true);
        }
        return array;
    }

    /**
     * Create a {@link SparseIntArray} from given {@code supportedKeys} where each key is mapped
     * to the value indexed by it.
     *
     * <p>If {@code values} is null or does not contain a given key as a index, then zero is stored
     * to the sparse array so it can still be used to query the supported keys.
     */
    @Nullable
    private static SparseIntArray toSparseIntArray(int[] supportedKeys, int[] values) {
        if (supportedKeys == null) {
            return null;
        }
        SparseIntArray array = new SparseIntArray();
        for (int key : supportedKeys) {
            array.put(key, (values == null || key >= values.length) ? 0 : values[key]);
        }
        return array;
    }
@@ -419,7 +496,20 @@ public class VibratorInfo implements Parcelable {
                    in.createFloatArray());
        }

        /** @hide */
        /**
         * Default constructor.
         *
         * @param minFrequencyHz        Minimum supported frequency, in hertz.
         * @param resonantFrequencyHz   The vibrator resonant frequency, in hertz.
         * @param frequencyResolutionHz The frequency resolution, in hertz, used by the max
         *                              amplitudes mapping.
         * @param suggestedSafeRangeHz  The suggested range, in hertz, for the safe relative
         *                              frequency range represented by [-1, 1].
         * @param maxAmplitudes         The max amplitude supported by each supported frequency,
         *                              starting at minimum frequency with jumps of frequency
         *                              resolution.
         * @hide
         */
        public FrequencyMapping(float minFrequencyHz, float resonantFrequencyHz,
                float frequencyResolutionHz, float suggestedSafeRangeHz, float[] maxAmplitudes) {
            mMinFrequencyHz = minFrequencyHz;
@@ -547,8 +637,10 @@ public class VibratorInfo implements Parcelable {

        @Override
        public int hashCode() {
            return Objects.hash(mMinFrequencyHz, mFrequencyResolutionHz, mFrequencyResolutionHz,
                    mSuggestedSafeRangeHz, mMaxAmplitudes);
            int hashCode = Objects.hash(mMinFrequencyHz, mFrequencyResolutionHz,
                    mFrequencyResolutionHz, mSuggestedSafeRangeHz);
            hashCode = 31 * hashCode + Arrays.hashCode(mMaxAmplitudes);
            return hashCode;
        }

        @Override
@@ -587,6 +679,7 @@ public class VibratorInfo implements Parcelable {
        private int[] mSupportedEffects = null;
        private int[] mSupportedBraking = null;
        private int[] mSupportedPrimitives = null;
        private int[] mPrimitiveDurations = new int[0];
        private float mQFactor = Float.NaN;
        private FrequencyMapping mFrequencyMapping =
                new FrequencyMapping(Float.NaN, Float.NaN, Float.NaN, Float.NaN, null);
@@ -627,6 +720,16 @@ public class VibratorInfo implements Parcelable {
            return this;
        }

        /** Configure the duration of a {@link android.hardware.vibrator.CompositePrimitive}. */
        @NonNull
        public Builder setPrimitiveDuration(int primitiveId, int duration) {
            if (mPrimitiveDurations.length <= primitiveId) {
                mPrimitiveDurations = Arrays.copyOf(mPrimitiveDurations, primitiveId + 1);
            }
            mPrimitiveDurations[primitiveId] = duration;
            return this;
        }

        /** Configure the vibrator quality factor. */
        @NonNull
        public Builder setQFactor(float qFactor) {
@@ -645,7 +748,7 @@ public class VibratorInfo implements Parcelable {
        @NonNull
        public VibratorInfo build() {
            return new VibratorInfo(mId, mCapabilities, mSupportedEffects, mSupportedBraking,
                    mSupportedPrimitives, mQFactor, mFrequencyMapping);
                    mSupportedPrimitives, mPrimitiveDurations, mQFactor, mFrequencyMapping);
        }
    }

+21 −1
Original line number Diff line number Diff line
@@ -99,6 +99,17 @@ public class VibratorInfoTest {
        assertFalse(info.isPrimitiveSupported(VibrationEffect.Composition.PRIMITIVE_CLICK));
    }

    @Test
    public void testGetPrimitiveDuration() {
        VibratorInfo info = new VibratorInfo.Builder(TEST_VIBRATOR_ID)
                .setCapabilities(IVibrator.CAP_COMPOSE_EFFECTS)
                .setSupportedPrimitives(VibrationEffect.Composition.PRIMITIVE_CLICK)
                .setPrimitiveDuration(VibrationEffect.Composition.PRIMITIVE_CLICK, 20)
                .build();
        assertEquals(20, info.getPrimitiveDuration(VibrationEffect.Composition.PRIMITIVE_CLICK));
        assertEquals(0, info.getPrimitiveDuration(VibrationEffect.Composition.PRIMITIVE_TICK));
    }

    @Test
    public void testGetDefaultBraking_returnsFirstSupportedBraking() {
        assertEquals(Braking.NONE, new VibratorInfo.Builder(
@@ -251,12 +262,14 @@ public class VibratorInfoTest {
                .setCapabilities(IVibrator.CAP_AMPLITUDE_CONTROL)
                .setSupportedEffects(VibrationEffect.EFFECT_CLICK)
                .setSupportedPrimitives(VibrationEffect.Composition.PRIMITIVE_CLICK)
                .setPrimitiveDuration(VibrationEffect.Composition.PRIMITIVE_CLICK, 20)
                .setQFactor(2f)
                .setFrequencyMapping(TEST_FREQUENCY_MAPPING);
        VibratorInfo complete = completeBuilder.build();

        assertEquals(complete, complete);
        assertEquals(complete, completeBuilder.build());
        assertEquals(complete.hashCode(), completeBuilder.build().hashCode());

        VibratorInfo completeWithComposeControl = completeBuilder
                .setCapabilities(IVibrator.CAP_COMPOSE_EFFECTS)
@@ -279,6 +292,11 @@ public class VibratorInfoTest {
                .build();
        assertNotEquals(complete, completeWithUnknownPrimitives);

        VibratorInfo completeWithDifferentPrimitiveDuration = completeBuilder
                .setPrimitiveDuration(VibrationEffect.Composition.PRIMITIVE_CLICK, 10)
                .build();
        assertNotEquals(complete, completeWithDifferentPrimitiveDuration);

        VibratorInfo completeWithDifferentFrequencyMapping = completeBuilder
                .setFrequencyMapping(new VibratorInfo.FrequencyMapping(TEST_MIN_FREQUENCY + 10,
                        TEST_RESONANT_FREQUENCY + 20, TEST_FREQUENCY_RESOLUTION + 5,
@@ -314,7 +332,8 @@ public class VibratorInfoTest {
        VibratorInfo original = new VibratorInfo.Builder(TEST_VIBRATOR_ID)
                .setCapabilities(IVibrator.CAP_COMPOSE_EFFECTS)
                .setSupportedEffects(VibrationEffect.EFFECT_CLICK)
                .setSupportedPrimitives(null)
                .setSupportedPrimitives(VibrationEffect.Composition.PRIMITIVE_CLICK)
                .setPrimitiveDuration(VibrationEffect.Composition.PRIMITIVE_CLICK, 20)
                .setQFactor(Float.NaN)
                .setFrequencyMapping(TEST_FREQUENCY_MAPPING)
                .build();
@@ -324,5 +343,6 @@ public class VibratorInfoTest {
        parcel.setDataPosition(0);
        VibratorInfo restored = VibratorInfo.CREATOR.createFromParcel(parcel);
        assertEquals(original, restored);
        assertEquals(original.hashCode(), restored.hashCode());
    }
}
+10 −0
Original line number Diff line number Diff line
@@ -79,6 +79,16 @@ public class VibratorTest {
                        VibrationEffect.Composition.PRIMITIVE_QUICK_RISE}).length);
    }

    @Test
    public void getPrimitivesDurations_returnsArrayOfSameSize() {
        assertEquals(0, mVibratorSpy.getPrimitiveDurations(new int[0]).length);
        assertEquals(1, mVibratorSpy.getPrimitiveDurations(
                new int[]{VibrationEffect.Composition.PRIMITIVE_CLICK}).length);
        assertEquals(2, mVibratorSpy.getPrimitiveDurations(
                new int[]{VibrationEffect.Composition.PRIMITIVE_CLICK,
                        VibrationEffect.Composition.PRIMITIVE_QUICK_RISE}).length);
    }

    @Test
    public void vibrate_withAudioAttributes_createsVibrationAttributesWithSameUsage() {
        VibrationEffect effect = VibrationEffect.get(VibrationEffect.EFFECT_CLICK);
Loading