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

Commit f132133d authored by Ahmad Khalil's avatar Ahmad Khalil Committed by Android (Google) Code Review
Browse files

Merge "Update Vibrator service with new APIS" into main

parents cc3a2cfb 05971e92
Loading
Loading
Loading
Loading
+5 −0
Original line number Diff line number Diff line
@@ -34266,9 +34266,14 @@ package android.os {
    method public final int areAllEffectsSupported(@NonNull int...);
    method public final boolean areAllPrimitivesSupported(@NonNull int...);
    method @NonNull public int[] areEffectsSupported(@NonNull int...);
    method @FlaggedApi("android.os.vibrator.normalized_pwle_effects") public boolean areEnvelopeEffectsSupported();
    method @NonNull public boolean[] arePrimitivesSupported(@NonNull int...);
    method @RequiresPermission(android.Manifest.permission.VIBRATE) public abstract void cancel();
    method public int getId();
    method @FlaggedApi("android.os.vibrator.normalized_pwle_effects") public int getMaxEnvelopeEffectControlPointDurationMillis();
    method @FlaggedApi("android.os.vibrator.normalized_pwle_effects") public int getMaxEnvelopeEffectDurationMillis();
    method @FlaggedApi("android.os.vibrator.normalized_pwle_effects") public int getMaxEnvelopeEffectSize();
    method @FlaggedApi("android.os.vibrator.normalized_pwle_effects") public int getMinEnvelopeEffectControlPointDurationMillis();
    method @NonNull public int[] getPrimitiveDurations(@NonNull int...);
    method public float getQFactor();
    method public float getResonantFrequency();
+82 −0
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
package android.os;

import android.annotation.CallbackExecutor;
import android.annotation.FlaggedApi;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -30,6 +31,7 @@ import android.content.Context;
import android.content.res.Resources;
import android.hardware.vibrator.IVibrator;
import android.media.AudioAttributes;
import android.os.vibrator.Flags;
import android.os.vibrator.VibrationConfig;
import android.os.vibrator.VibratorFrequencyProfile;
import android.util.Log;
@@ -312,6 +314,86 @@ public abstract class Vibrator {
        return getConfig().getHapticChannelMaximumAmplitude();
    }

    /**
     * Checks whether the vibrator supports the creation of envelope effects.
     *
     * Envelope effects are defined by a series of frequency-amplitude pairs with specified
     * transition times, allowing the creation of more complex vibration patterns.
     *
     * @return True if the hardware supports creating envelope effects, false otherwise.
     */
    @FlaggedApi(Flags.FLAG_NORMALIZED_PWLE_EFFECTS)
    public boolean areEnvelopeEffectsSupported() {
        return getInfo().areEnvelopeEffectsSupported();
    }

    /**
     * Retrieves the maximum duration supported for an envelope effect, in milliseconds.
     *
     * <p>If the device supports envelope effects (check {@link #areEnvelopeEffectsSupported}),
     * this value will be positive. Devices with envelope effects capabilities guarantees a
     * maximum duration equivalent to the product of {@link #getMaxEnvelopeEffectSize()} and
     * {@link #getMaxEnvelopeEffectControlPointDurationMillis()}. If the device does not support
     * envelope effects, this method will return 0.
     *
     * @return The maximum duration (in milliseconds) allowed for an envelope effect, or 0 if
     * envelope effects are not supported.
     */
    @FlaggedApi(Flags.FLAG_NORMALIZED_PWLE_EFFECTS)
    public int getMaxEnvelopeEffectDurationMillis() {
        return getInfo().getMaxEnvelopeEffectDurationMillis();
    }

    /**
     * Retrieves the maximum number of control points supported for an envelope effect.
     *
     * <p>If the device supports envelope effects (check {@link #areEnvelopeEffectsSupported}),
     * this value will be positive. Devices with envelope effects capabilities guarantee support
     * for a minimum of 16 control points. If the device does not support envelope effects,
     * this method will return 0.
     *
     * @return the maximum number of control points allowed for an envelope effect, or 0 if
     * envelope effects are not supported.
     */
    @FlaggedApi(Flags.FLAG_NORMALIZED_PWLE_EFFECTS)
    public int getMaxEnvelopeEffectSize() {
        return getInfo().getMaxEnvelopeEffectSize();
    }

    /**
     * Retrieves the minimum duration supported between two control points within an envelope
     * effect, in milliseconds.
     *
     * <p>If the device supports envelope effects (check {@link #areEnvelopeEffectsSupported}),
     * this value will be positive. Devices with envelope effects capabilities guarantee
     * support for durations down to at least 20 milliseconds. If the device does
     * not support envelope effects, this method will return 0.
     *
     * @return the minimum allowed duration between two control points in an envelope effect,
     * or 0 if envelope effects are not supported.
     */
    @FlaggedApi(Flags.FLAG_NORMALIZED_PWLE_EFFECTS)
    public int getMinEnvelopeEffectControlPointDurationMillis() {
        return getInfo().getMinEnvelopeEffectControlPointDurationMillis();
    }

    /**
     * Retrieves the maximum duration supported between two control points within an envelope
     * effect, in milliseconds.
     *
     * <p>If the device supports envelope effects (check {@link #areEnvelopeEffectsSupported}),
     * this value will be positive. Devices with envelope effects capabilities guarantee support
     * for durations up to at least 1 second. If the device does not support envelope effects,
     * this method will return 0.
     *
     * @return the maximum allowed duration between two control points in an envelope effect,
     * or 0 if envelope effects are not supported.
     */
    @FlaggedApi(Flags.FLAG_NORMALIZED_PWLE_EFFECTS)
    public int getMaxEnvelopeEffectControlPointDurationMillis() {
        return getInfo().getMaxEnvelopeEffectControlPointDurationMillis();
    }

    /**
     * Configure an always-on haptics effect.
     *
+130 −4
Original line number Diff line number Diff line
@@ -60,6 +60,9 @@ public class VibratorInfo implements Parcelable {
    private final int mPwleSizeMax;
    private final float mQFactor;
    private final FrequencyProfile mFrequencyProfile;
    private final int mMaxEnvelopeEffectSize;
    private final int mMinEnvelopeEffectControlPointDurationMillis;
    private final int mMaxEnvelopeEffectControlPointDurationMillis;

    VibratorInfo(Parcel in) {
        mId = in.readInt();
@@ -73,6 +76,9 @@ public class VibratorInfo implements Parcelable {
        mPwleSizeMax = in.readInt();
        mQFactor = in.readFloat();
        mFrequencyProfile = FrequencyProfile.CREATOR.createFromParcel(in);
        mMaxEnvelopeEffectSize = in.readInt();
        mMinEnvelopeEffectControlPointDurationMillis = in.readInt();
        mMaxEnvelopeEffectControlPointDurationMillis = in.readInt();
    }

    public VibratorInfo(int id, @NonNull VibratorInfo baseVibratorInfo) {
@@ -80,7 +86,10 @@ public class VibratorInfo implements Parcelable {
                baseVibratorInfo.mSupportedBraking, baseVibratorInfo.mSupportedPrimitives,
                baseVibratorInfo.mPrimitiveDelayMax, baseVibratorInfo.mCompositionSizeMax,
                baseVibratorInfo.mPwlePrimitiveDurationMax, baseVibratorInfo.mPwleSizeMax,
                baseVibratorInfo.mQFactor, baseVibratorInfo.mFrequencyProfile);
                baseVibratorInfo.mQFactor, baseVibratorInfo.mFrequencyProfile,
                baseVibratorInfo.mMaxEnvelopeEffectSize,
                baseVibratorInfo.mMinEnvelopeEffectControlPointDurationMillis,
                baseVibratorInfo.mMaxEnvelopeEffectControlPointDurationMillis);
    }

    /**
@@ -111,7 +120,9 @@ public class VibratorInfo implements Parcelable {
            @Nullable SparseBooleanArray supportedBraking,
            @NonNull SparseIntArray supportedPrimitives, int primitiveDelayMax,
            int compositionSizeMax, int pwlePrimitiveDurationMax, int pwleSizeMax,
            float qFactor, @NonNull FrequencyProfile frequencyProfile) {
            float qFactor, @NonNull FrequencyProfile frequencyProfile,
            int maxEnvelopeEffectSize, int minEnvelopeEffectControlPointDurationMillis,
            int maxEnvelopeEffectControlPointDurationMillis) {
        Preconditions.checkNotNull(supportedPrimitives);
        Preconditions.checkNotNull(frequencyProfile);
        mId = id;
@@ -125,6 +136,11 @@ public class VibratorInfo implements Parcelable {
        mPwleSizeMax = pwleSizeMax;
        mQFactor = qFactor;
        mFrequencyProfile = frequencyProfile;
        mMaxEnvelopeEffectSize = maxEnvelopeEffectSize;
        mMinEnvelopeEffectControlPointDurationMillis =
                minEnvelopeEffectControlPointDurationMillis;
        mMaxEnvelopeEffectControlPointDurationMillis =
                maxEnvelopeEffectControlPointDurationMillis;
    }

    @Override
@@ -140,6 +156,9 @@ public class VibratorInfo implements Parcelable {
        dest.writeInt(mPwleSizeMax);
        dest.writeFloat(mQFactor);
        mFrequencyProfile.writeToParcel(dest, flags);
        dest.writeInt(mMaxEnvelopeEffectSize);
        dest.writeInt(mMinEnvelopeEffectControlPointDurationMillis);
        dest.writeInt(mMaxEnvelopeEffectControlPointDurationMillis);
    }

    @Override
@@ -186,7 +205,12 @@ public class VibratorInfo implements Parcelable {
                && Objects.equals(mSupportedEffects, that.mSupportedEffects)
                && Objects.equals(mSupportedBraking, that.mSupportedBraking)
                && Objects.equals(mQFactor, that.mQFactor)
                && Objects.equals(mFrequencyProfile, that.mFrequencyProfile);
                && Objects.equals(mFrequencyProfile, that.mFrequencyProfile)
                && mMaxEnvelopeEffectSize == that.mMaxEnvelopeEffectSize
                && mMinEnvelopeEffectControlPointDurationMillis
                == that.mMinEnvelopeEffectControlPointDurationMillis
                && mMaxEnvelopeEffectControlPointDurationMillis
                == that.mMaxEnvelopeEffectControlPointDurationMillis;
    }

    @Override
@@ -215,6 +239,11 @@ public class VibratorInfo implements Parcelable {
                + ", mPwleSizeMax=" + mPwleSizeMax
                + ", mQFactor=" + mQFactor
                + ", mFrequencyProfile=" + mFrequencyProfile
                + ", mMaxEnvelopeEffectSize=" + mMaxEnvelopeEffectSize
                + ", mMinEnvelopeEffectControlPointDurationMillis="
                + mMinEnvelopeEffectControlPointDurationMillis
                + ", mMaxEnvelopeEffectControlPointDurationMillis="
                + mMaxEnvelopeEffectControlPointDurationMillis
                + '}';
    }

@@ -234,6 +263,11 @@ public class VibratorInfo implements Parcelable {
        pw.println("pwleSizeMax = " + mPwleSizeMax);
        pw.println("q-factor = " + mQFactor);
        pw.println("frequencyProfile = " + mFrequencyProfile);
        pw.println("mMaxEnvelopeEffectSize = " + mMaxEnvelopeEffectSize);
        pw.println("mMinEnvelopeEffectControlPointDurationMillis = "
                + mMinEnvelopeEffectControlPointDurationMillis);
        pw.println("mMaxEnvelopeEffectControlPointDurationMillis = "
                + mMaxEnvelopeEffectControlPointDurationMillis);
        pw.decreaseIndent();
    }

@@ -413,6 +447,58 @@ public class VibratorInfo implements Parcelable {
        return mPwleSizeMax;
    }

    /**
     * Check whether the vibrator supports the creation of envelope effects.
     *
     * <p>See {@link Vibrator#areEnvelopeEffectsSupported()} for more information on envelope
     * effects.
     *
     * @return True if the hardware supports creating envelope effects, false otherwise.
     */
    public boolean areEnvelopeEffectsSupported() {
        return hasCapability(IVibrator.CAP_COMPOSE_PWLE_EFFECTS_V2);
    }

    /**
     * Calculates the maximum allowed duration for an envelope effect, measured in milliseconds.
     *
     * @return The maximum duration (in milliseconds) that an envelope effect can have.
     */
    public int getMaxEnvelopeEffectDurationMillis() {
        return mMaxEnvelopeEffectSize * mMaxEnvelopeEffectControlPointDurationMillis;
    }

    /**
     * Gets the maximum number of control points supported for envelope effects on this device.
     *
     * @return The maximum number of control points that can be used to define an envelope effect.
     */
    public int getMaxEnvelopeEffectSize() {
        return mMaxEnvelopeEffectSize;
    }

    /**
     * Gets the minimum allowed duration for any individual segment within an envelope effect,
     * measured in milliseconds.
     *
     * @return The minimum duration (in milliseconds) that a segment within an envelope effect
     * can have.
     */
    public int getMinEnvelopeEffectControlPointDurationMillis() {
        return mMinEnvelopeEffectControlPointDurationMillis;
    }

    /**
     * Gets the maximum allowed duration for any individual segment within an envelope effect,
     * measured in milliseconds.
     *
     * @return The maximum duration (in milliseconds) that a segment within an envelope effect
     * can have.
     */
    public int getMaxEnvelopeEffectControlPointDurationMillis() {
        return mMaxEnvelopeEffectControlPointDurationMillis;
    }

    /**
     * Check against this vibrator capabilities.
     *
@@ -489,6 +575,9 @@ public class VibratorInfo implements Parcelable {
        if (hasCapability(IVibrator.CAP_EXTERNAL_AMPLITUDE_CONTROL)) {
            names.add("EXTERNAL_AMPLITUDE_CONTROL");
        }
        if (hasCapability(IVibrator.CAP_COMPOSE_PWLE_EFFECTS_V2)) {
            names.add("CAP_COMPOSE_PWLE_EFFECTS_V2");
        }
        return names.toArray(new String[names.size()]);
    }

@@ -745,6 +834,9 @@ public class VibratorInfo implements Parcelable {
        private float mQFactor = Float.NaN;
        private FrequencyProfile mFrequencyProfile =
                new FrequencyProfile(Float.NaN, Float.NaN, Float.NaN, null);
        private int mMaxEnvelopeEffectSize;
        private int mMinEnvelopeEffectControlPointDurationMillis;
        private int mMaxEnvelopeEffectControlPointDurationMillis;

        /** A builder class for a {@link VibratorInfo}. */
        public Builder(int id) {
@@ -821,12 +913,46 @@ public class VibratorInfo implements Parcelable {
            return this;
        }

        /**
         * Configure the maximum number of control points supported for envelope effects on this
         * device.
         */
        @NonNull
        public Builder setMaxEnvelopeEffectSize(int maxEnvelopeEffectSize) {
            mMaxEnvelopeEffectSize = maxEnvelopeEffectSize;
            return this;
        }

        /**
         * Configure the minimum supported duration for any individual segment within an
         * envelope effect in milliseconds.
         */
        @NonNull
        public Builder setMinEnvelopeEffectControlPointDurationMillis(
                int minEnvelopeEffectControlPointDuration) {
            mMinEnvelopeEffectControlPointDurationMillis = minEnvelopeEffectControlPointDuration;
            return this;
        }

        /**
         * Configure the maximum supported duration for any individual segment within an
         * envelope effect in milliseconds.
         */
        @NonNull
        public Builder setMaxEnvelopeEffectControlPointDurationMillis(
                int maxEnvelopeEffectControlPointDuration) {
            mMaxEnvelopeEffectControlPointDurationMillis = maxEnvelopeEffectControlPointDuration;
            return this;
        }

        /** Build the configured {@link VibratorInfo}. */
        @NonNull
        public VibratorInfo build() {
            return new VibratorInfo(mId, mCapabilities, mSupportedEffects, mSupportedBraking,
                    mSupportedPrimitives, mPrimitiveDelayMax, mCompositionSizeMax,
                    mPwlePrimitiveDurationMax, mPwleSizeMax, mQFactor, mFrequencyProfile);
                    mPwlePrimitiveDurationMax, mPwleSizeMax, mQFactor, mFrequencyProfile,
                    mMaxEnvelopeEffectSize, mMinEnvelopeEffectControlPointDurationMillis,
                    mMaxEnvelopeEffectControlPointDurationMillis);
        }

        /**
+7 −1
Original line number Diff line number Diff line
@@ -59,7 +59,13 @@ public final class MultiVibratorInfo extends VibratorInfo {
                integerLimitIntersection(vibrators, VibratorInfo::getPwlePrimitiveDurationMax),
                integerLimitIntersection(vibrators, VibratorInfo::getPwleSizeMax),
                floatPropertyIntersection(vibrators, VibratorInfo::getQFactor),
                mergedProfile);
                mergedProfile,
                integerLimitIntersection(vibrators,
                        VibratorInfo::getMaxEnvelopeEffectSize),
                integerLimitIntersection(vibrators,
                        VibratorInfo::getMinEnvelopeEffectControlPointDurationMillis),
                integerLimitIntersection(vibrators,
                        VibratorInfo::getMaxEnvelopeEffectControlPointDurationMillis));
    }

    private static int capabilitiesIntersection(VibratorInfo[] infos,
+42 −10
Original line number Diff line number Diff line
@@ -138,6 +138,35 @@ public class VibratorInfoTest {
        assertEquals(0, emptyInfo.getPwleSizeMax());
    }

    @Test
    public void testAreEnvelopeEffectsSupported() {
        VibratorInfo noCapabilities = new VibratorInfo.Builder(TEST_VIBRATOR_ID).build();
        assertFalse(noCapabilities.areEnvelopeEffectsSupported());
        VibratorInfo envelopeEffectCapability = new VibratorInfo.Builder(TEST_VIBRATOR_ID)
                .setCapabilities(IVibrator.CAP_COMPOSE_PWLE_EFFECTS_V2)
                .build();
        assertTrue(envelopeEffectCapability.areEnvelopeEffectsSupported());
    }

    @Test
    public void testEnvelopeEffectLimits() {
        VibratorInfo info = new VibratorInfo.Builder(TEST_VIBRATOR_ID)
                .setMaxEnvelopeEffectSize(16)
                .setMinEnvelopeEffectControlPointDurationMillis(20)
                .setMaxEnvelopeEffectControlPointDurationMillis(1_000)
                .build();
        assertEquals(16, info.getMaxEnvelopeEffectSize());
        assertEquals(20, info.getMinEnvelopeEffectControlPointDurationMillis());
        assertEquals(1_000, info.getMaxEnvelopeEffectControlPointDurationMillis());
        assertEquals(16_000, info.getMaxEnvelopeEffectDurationMillis());

        VibratorInfo emptyInfo = new VibratorInfo.Builder(TEST_VIBRATOR_ID).build();
        assertEquals(0, emptyInfo.getMaxEnvelopeEffectSize());
        assertEquals(0, emptyInfo.getMinEnvelopeEffectControlPointDurationMillis());
        assertEquals(0, emptyInfo.getMaxEnvelopeEffectControlPointDurationMillis());
        assertEquals(0, emptyInfo.getMaxEnvelopeEffectDurationMillis());
    }

    @Test
    public void testGetDefaultBraking_returnsFirstSupportedBraking() {
        assertEquals(Braking.NONE, new VibratorInfo.Builder(
@@ -272,7 +301,10 @@ public class VibratorInfoTest {
                    .setPwlePrimitiveDurationMax(50)
                    .setPwleSizeMax(20)
                    .setQFactor(2f)
                .setFrequencyProfile(TEST_FREQUENCY_PROFILE);
                    .setFrequencyProfile(TEST_FREQUENCY_PROFILE)
                    .setMaxEnvelopeEffectSize(16)
                    .setMinEnvelopeEffectControlPointDurationMillis(20)
                    .setMaxEnvelopeEffectControlPointDurationMillis(1_000);
        }
        VibratorInfo complete = completeBuilder.build();

Loading