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

Commit 4f8b4f9e authored by Ming-Shin Lu's avatar Ming-Shin Lu
Browse files

Apply USAGE_IME_FEEDBACK to HapticFeedbackVibrationProvider

Also Remove FLAG_BYPASS_USER_VIBRATION_INTENSITY_SCALE check logic in
HapticFeedbackVibrationProvider and the flag itself introduced from
CL[1] for clean-up.

Since the current vibration and default vibration for IME feedback
are both medium level currently, means there is no additional
scaling from current settings for the keyboard vibration effect in
VibrationScaler, so scale behavior can keep applying the fixed
vibration amplititude (0.62) as before.

In the next CL, we will remove VibrationAttritubute#CATEGORY_KEYBOARD
and its logic in framework and Settings, since USAGE_IME_FEEDBACK can
fully replace the behavior with preserving scaling keyboard vibration
from settings flexibility.

[1]: I67c95718d11fb429083e1bc9dcab6e1bc85249fc

Flag: android.os.vibrator.vibration_attribute_ime_usage_api
Bug: 332661766
Test: manual as below steps
   0) Enable "Keyboard vibration" in Vibration & haptics Settings
   1) In launcher, tap google search box to show IME.
   2) typing charactors & verify keyboard is vibrating
   3) use adb command: adb dumpsys vibrator_manager, verify the
      vibration effect history shows as below
    scale:     NONE (adaptive=1.00) |flags:    0  <-- no bypass flag
    usage: IME | category=KEYBOARD ...\
    reason: performHapticFeedback(constant=3): \
    View#performHapticFeedback | \
    played: Primitive=CLICK(scale=0.62, delay=0ms) <-- same amplitudue
Test: atest VibrationSettingsTest, VibrationScalerTest
Test: atest HapticFeedbackVibrationProviderTest
Change-Id: I764aa8bd72889d4af62b30bff75af9033f22052b
parent d53c355c
Loading
Loading
Loading
Loading
+1 −21
Original line number Diff line number Diff line
@@ -184,7 +184,6 @@ public final class VibrationAttributes implements Parcelable {
            FLAG_BYPASS_USER_VIBRATION_INTENSITY_OFF,
            FLAG_INVALIDATE_SETTINGS_CACHE,
            FLAG_PIPELINED_EFFECT,
            FLAG_BYPASS_USER_VIBRATION_INTENSITY_SCALE
    })
    @Retention(RetentionPolicy.SOURCE)
    public @interface Flag{}
@@ -237,32 +236,13 @@ public final class VibrationAttributes implements Parcelable {
     */
    public static final int FLAG_PIPELINED_EFFECT = 1 << 3;

    /**
     * Flag requesting that this vibration effect to be played without applying the user
     * intensity setting to scale the vibration.
     *
     * <p>The user setting is still applied to enable/disable the vibration, but the vibration
     * effect strength will not be scaled based on the enabled setting value.
     *
     * <p>This is intended to be used on scenarios where the system needs to enforce a specific
     * strength for the vibration effect, regardless of the user preference. Only privileged apps
     * can ignore user settings, and this flag will be ignored otherwise.
     *
     * <p>If you need to bypass the user setting when it's disabling vibrations then this also
     * needs the flag {@link #FLAG_BYPASS_USER_VIBRATION_INTENSITY_OFF} to be set.
     *
     * @hide
     */
    public static final int FLAG_BYPASS_USER_VIBRATION_INTENSITY_SCALE = 1 << 4;

    /**
     * All flags supported by vibrator service, update it when adding new flag.
     * @hide
     */
    public static final int FLAG_ALL_SUPPORTED =
            FLAG_BYPASS_INTERRUPTION_POLICY | FLAG_BYPASS_USER_VIBRATION_INTENSITY_OFF
                    | FLAG_INVALIDATE_SETTINGS_CACHE | FLAG_PIPELINED_EFFECT
                    | FLAG_BYPASS_USER_VIBRATION_INTENSITY_SCALE;
                    | FLAG_INVALIDATE_SETTINGS_CACHE | FLAG_PIPELINED_EFFECT;

    /** Creates a new {@link VibrationAttributes} instance with given usage. */
    public static @NonNull VibrationAttributes createForUsage(@Usage int usage) {
+0 −17
Original line number Diff line number Diff line
@@ -107,23 +107,6 @@ final class HalVibration extends Vibration {
        mFallbacks.put(effectId, effect);
    }

    /**
     * Resolves the default vibration amplitude of {@link #getEffectToPlay()} and each fallback.
     *
     * @param defaultAmplitude An integer in [1,255] representing the device default amplitude to
     *                        replace the {@link VibrationEffect#DEFAULT_AMPLITUDE}.
     */
    public void resolveEffects(int defaultAmplitude) {
        CombinedVibration newEffect =
                mEffectToPlay.transform(VibrationEffect::resolve, defaultAmplitude);
        if (!Objects.equals(mEffectToPlay, newEffect)) {
            mEffectToPlay = newEffect;
        }
        for (int i = 0; i < mFallbacks.size(); i++) {
            mFallbacks.setValueAt(i, mFallbacks.valueAt(i).resolve(defaultAmplitude));
        }
    }

    /**
     * Scales the {@link #getEffectToPlay()} and each fallback effect based on the vibration usage.
     */
+4 −22
Original line number Diff line number Diff line
@@ -46,6 +46,8 @@ public final class HapticFeedbackVibrationProvider {
            VibrationAttributes.createForUsage(VibrationAttributes.USAGE_HARDWARE_FEEDBACK);
    private static final VibrationAttributes COMMUNICATION_REQUEST_VIBRATION_ATTRIBUTES =
            VibrationAttributes.createForUsage(VibrationAttributes.USAGE_COMMUNICATION_REQUEST);
    private static final VibrationAttributes IME_FEEDBACK_VIBRATION_ATTRIBUTES =
            VibrationAttributes.createForUsage(VibrationAttributes.USAGE_IME_FEEDBACK);

    private final VibratorInfo mVibratorInfo;
    private final boolean mHapticTextHandleEnabled;
@@ -219,8 +221,6 @@ public final class HapticFeedbackVibrationProvider {
        }

        int vibFlags = 0;
        boolean fromIme =
                (privFlags & HapticFeedbackConstants.PRIVATE_FLAG_APPLY_INPUT_METHOD_SETTINGS) != 0;
        boolean bypassVibrationIntensitySetting =
                (flags & HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING) != 0;
        if (bypassVibrationIntensitySetting) {
@@ -229,9 +229,6 @@ public final class HapticFeedbackVibrationProvider {
        if (shouldBypassInterruptionPolicy(effectId)) {
            vibFlags |= VibrationAttributes.FLAG_BYPASS_INTERRUPTION_POLICY;
        }
        if (shouldBypassIntensityScale(effectId, fromIme)) {
            vibFlags |= VibrationAttributes.FLAG_BYPASS_USER_VIBRATION_INTENSITY_SCALE;
        }

        return vibFlags == 0 ? attrs : new VibrationAttributes.Builder(attrs)
                .setFlags(vibFlags).build();
@@ -362,22 +359,6 @@ public final class HapticFeedbackVibrationProvider {
                /* fallbackForPredefinedEffect= */ predefinedEffectFallback);
    }

    private boolean shouldBypassIntensityScale(int effectId, boolean isIme) {
        if (!Flags.keyboardCategoryEnabled() || mKeyboardVibrationFixedAmplitude < 0 || !isIme) {
            // Shouldn't bypass if not support keyboard category, no fixed amplitude or not an IME.
            return false;
        }
        switch (effectId) {
            case HapticFeedbackConstants.KEYBOARD_TAP:
                return mVibratorInfo.isPrimitiveSupported(
                        VibrationEffect.Composition.PRIMITIVE_CLICK);
            case HapticFeedbackConstants.KEYBOARD_RELEASE:
                return mVibratorInfo.isPrimitiveSupported(
                        VibrationEffect.Composition.PRIMITIVE_TICK);
        }
        return false;
    }

    private VibrationAttributes createKeyboardVibrationAttributes(
            @HapticFeedbackConstants.PrivateFlags int privFlags) {
        // Use touch attribute when the keyboard category is disable.
@@ -388,7 +369,8 @@ public final class HapticFeedbackVibrationProvider {
        if ((privFlags & HapticFeedbackConstants.PRIVATE_FLAG_APPLY_INPUT_METHOD_SETTINGS) == 0) {
            return TOUCH_VIBRATION_ATTRIBUTES;
        }
        return new VibrationAttributes.Builder(TOUCH_VIBRATION_ATTRIBUTES)
        return new VibrationAttributes.Builder(IME_FEEDBACK_VIBRATION_ATTRIBUTES)
                // TODO(b/332661766): Remove CATEGORY_KEYBOARD logic
                .setCategory(VibrationAttributes.CATEGORY_KEYBOARD)
                .build();
    }
+4 −10
Original line number Diff line number Diff line
@@ -21,7 +21,6 @@ import android.annotation.Nullable;
import android.os.Build;
import android.os.CombinedVibration;
import android.os.IBinder;
import android.os.VibrationAttributes;
import android.os.VibrationEffect;
import android.os.vibrator.Flags;
import android.os.vibrator.PrebakedSegment;
@@ -177,16 +176,11 @@ final class VibrationStepConductor implements IBinder.DeathRecipient {
            expectIsVibrationThread(true);
        }

        if (!mVibration.callerInfo.attrs.isFlagSet(
                VibrationAttributes.FLAG_BYPASS_USER_VIBRATION_INTENSITY_SCALE)) {
        if (Flags.adaptiveHapticsEnabled()) {
            waitForVibrationParamsIfRequired();
        }
        // Scale resolves the default amplitudes from the effect before scaling them.
        mVibration.scaleEffects(mVibrationScaler);
        } else {
            mVibration.resolveEffects(mVibrationScaler.getDefaultVibrationAmplitude());
        }

        mVibration.adaptToDevice(mDeviceAdapter);
        CombinedVibration.Sequential sequentialEffect = toSequential(mVibration.getEffectToPlay());
+4 −11
Original line number Diff line number Diff line
@@ -103,8 +103,7 @@ public class VibratorManagerService extends IVibratorManagerService.Stub {
            new VibrationAttributes.Builder().build();
    private static final int ATTRIBUTES_ALL_BYPASS_FLAGS =
            VibrationAttributes.FLAG_BYPASS_INTERRUPTION_POLICY
                    | VibrationAttributes.FLAG_BYPASS_USER_VIBRATION_INTENSITY_OFF
                    | VibrationAttributes.FLAG_BYPASS_USER_VIBRATION_INTENSITY_SCALE;
                    | VibrationAttributes.FLAG_BYPASS_USER_VIBRATION_INTENSITY_OFF;

    /** Fixed large duration used to note repeating vibrations to {@link IBatteryStats}. */
    private static final long BATTERY_STATS_REPEATING_VIBRATION_DURATION = 5_000;
@@ -925,8 +924,7 @@ public class VibratorManagerService extends IVibratorManagerService.Stub {
    private VibrationStepConductor createVibrationStepConductor(HalVibration vib) {
        CompletableFuture<Void> requestVibrationParamsFuture = null;

        if (Flags.adaptiveHapticsEnabled() && !vib.callerInfo.attrs.isFlagSet(
                VibrationAttributes.FLAG_BYPASS_USER_VIBRATION_INTENSITY_SCALE)
        if (Flags.adaptiveHapticsEnabled()
                && mVibratorControlService.shouldRequestVibrationParams(
                vib.callerInfo.attrs.getUsage())) {
            requestVibrationParamsFuture =
@@ -940,13 +938,8 @@ public class VibratorManagerService extends IVibratorManagerService.Stub {
    }

    private Vibration.EndInfo startVibrationOnInputDevicesLocked(HalVibration vib) {
        if (!vib.callerInfo.attrs.isFlagSet(
                VibrationAttributes.FLAG_BYPASS_USER_VIBRATION_INTENSITY_SCALE)) {
        // Scale resolves the default amplitudes from the effect before scaling them.
        vib.scaleEffects(mVibrationScaler);
        } else {
            vib.resolveEffects(mVibrationScaler.getDefaultVibrationAmplitude());
        }
        mInputDeviceDelegate.vibrateIfAvailable(vib.callerInfo, vib.getEffectToPlay());

        return new Vibration.EndInfo(Vibration.Status.FORWARDED_TO_INPUT_DEVICES);
Loading