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

Commit f8b0192d authored by Yeabkal Wubshit's avatar Yeabkal Wubshit
Browse files

Create API to Check if Vibrator Supports VibrationEffect

This allows clients to check if a VibrationEffect can be played as
defined by a given Vibrator.

Bug: 241732519
Test: unit tests
Change-Id: Ida31edd46d7ff2106c4c8800cb47d21db94db029
parent c6346aa1
Loading
Loading
Loading
Loading
+22 −0
Original line number Diff line number Diff line
@@ -28,6 +28,7 @@ import android.content.Context;
import android.hardware.vibrator.V1_0.EffectStrength;
import android.hardware.vibrator.V1_3.Effect;
import android.net.Uri;
import android.os.Vibrator;
import android.os.vibrator.PrebakedSegment;
import android.os.vibrator.PrimitiveSegment;
import android.os.vibrator.RampSegment;
@@ -514,6 +515,16 @@ public abstract class VibrationEffect implements Parcelable {
    @TestApi
    public abstract long getDuration();

    /**
     * Checks if a given {@link Vibrator} can play this effect as intended.
     *
     * <p>See @link Vibrator#areVibrationFeaturesSupported(VibrationEffect)} for more information
     * about what counts as supported by a vibrator, and what counts as not.
     *
     * @hide
     */
    public abstract boolean areVibrationFeaturesSupported(@NonNull Vibrator vibrator);

    /**
     * Returns true if this effect could represent a touch haptic feedback.
     *
@@ -756,6 +767,17 @@ public abstract class VibrationEffect implements Parcelable {
            return totalDuration;
        }

        /** @hide */
        @Override
        public boolean areVibrationFeaturesSupported(@NonNull Vibrator vibrator) {
            for (VibrationEffectSegment segment : mSegments) {
                if (!segment.areVibrationFeaturesSupported(vibrator)) {
                    return false;
                }
            }
            return true;
        }

        /** @hide */
        @Override
        public boolean isHapticFeedbackCandidate() {
+22 −0
Original line number Diff line number Diff line
@@ -221,6 +221,28 @@ public abstract class Vibrator {
                IVibrator.CAP_FREQUENCY_CONTROL | IVibrator.CAP_COMPOSE_PWLE_EFFECTS);
    }

    /**
     * Checks whether or not the vibrator supports all components of a given {@link VibrationEffect}
     * (i.e. the vibrator can play the given effect as intended).
     *
     * <p>If this method returns {@code true}, then the VibrationEffect should play as expected.
     * If {@code false}, playing the VibrationEffect might still make a vibration, but the vibration
     * may be significantly degraded from the intention.
     *
     * <p>This method aggregates the results of feature check methods such as
     * {@link #hasAmplitudeControl}, {@link #areAllPrimitivesSupported(int...)}, etc, depending
     * on the features that are actually used by the VibrationEffect.
     *
     * @param effect the {@link VibrationEffect} to check if it is supported
     * @return {@code true} if the vibrator can play the given {@code effect} as intended,
     *         {@code false} otherwise.
     *
     * @hide
     */
    public boolean areVibrationFeaturesSupported(@NonNull VibrationEffect effect) {
        return effect.areVibrationFeaturesSupported(this);
    }

    /**
     * Check whether the vibrator can be controlled by an external service with the
     * {@link IExternalVibratorService}.
+26 −0
Original line number Diff line number Diff line
@@ -22,6 +22,7 @@ import android.annotation.TestApi;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.VibrationEffect;
import android.os.Vibrator;

import java.util.Objects;

@@ -67,6 +68,31 @@ public final class PrebakedSegment extends VibrationEffectSegment {
        return -1;
    }

    /** @hide */
    @Override
    public boolean areVibrationFeaturesSupported(@NonNull Vibrator vibrator) {
        if (vibrator.areAllEffectsSupported(mEffectId) == Vibrator.VIBRATION_EFFECT_SUPPORT_YES) {
            return true;
        }
        if (!mFallback) {
            // If the Vibrator's support is not `VIBRATION_EFFECT_SUPPORT_YES`, and this effect does
            // not support fallbacks, the effect is considered not supported by the vibrator.
            return false;
        }
        // The vibrator does not have hardware support for the effect, but the effect has fallback
        // support. Check if a fallback will be available for the effect ID.
        switch (mEffectId) {
            case VibrationEffect.EFFECT_CLICK:
            case VibrationEffect.EFFECT_DOUBLE_CLICK:
            case VibrationEffect.EFFECT_HEAVY_CLICK:
            case VibrationEffect.EFFECT_TICK:
                // Any of these effects are always supported via some form of fallback.
                return true;
            default:
                return false;
        }
    }

    /** @hide */
    @Override
    public boolean isHapticFeedbackCandidate() {
+7 −0
Original line number Diff line number Diff line
@@ -22,6 +22,7 @@ import android.annotation.TestApi;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.VibrationEffect;
import android.os.Vibrator;

import com.android.internal.util.Preconditions;

@@ -67,6 +68,12 @@ public final class PrimitiveSegment extends VibrationEffectSegment {
        return -1;
    }

    /** @hide */
    @Override
    public boolean areVibrationFeaturesSupported(@NonNull Vibrator vibrator) {
        return vibrator.areAllPrimitivesSupported(mPrimitiveId);
    }

    /** @hide */
    @Override
    public boolean isHapticFeedbackCandidate() {
+24 −0
Original line number Diff line number Diff line
@@ -20,6 +20,7 @@ import android.annotation.NonNull;
import android.annotation.TestApi;
import android.os.Parcel;
import android.os.VibrationEffect;
import android.os.Vibrator;

import com.android.internal.util.Preconditions;

@@ -93,6 +94,29 @@ public final class RampSegment extends VibrationEffectSegment {
        return mDuration;
    }

    /** @hide */
    @Override
    public boolean areVibrationFeaturesSupported(@NonNull Vibrator vibrator) {
        boolean areFeaturesSupported = true;
        // If the start/end frequencies are not the same, require frequency control since we need to
        // ramp up/down the frequency.
        if ((mStartFrequencyHz != mEndFrequencyHz)
                // If there is no frequency ramping, make sure that the one frequency used does not
                // require frequency control.
                || frequencyRequiresFrequencyControl(mStartFrequencyHz)) {
            areFeaturesSupported &= vibrator.hasFrequencyControl();
        }
        // If the start/end amplitudes are not the same, require amplitude control since we need to
        // ramp up/down the amplitude.
        if ((mStartAmplitude != mEndAmplitude)
                // If there is no amplitude ramping, make sure that the amplitude used does not
                // require amplitude control.
                || amplitudeRequiresAmplitudeControl(mStartAmplitude)) {
            areFeaturesSupported &= vibrator.hasAmplitudeControl();
        }
        return areFeaturesSupported;
    }

    /** @hide */
    @Override
    public boolean isHapticFeedbackCandidate() {
Loading