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

Commit 6f0311bf authored by Chris Ye's avatar Chris Ye
Browse files

Refactor InputManager service for input rumble support.

Change aidl vibrate API to use VibrationEffect.
Handle default amplitude in InputManagerService.
Set both channels for vibration amplitudes.

Bug: 136215622
Test: Connect game controller with rumble support and play game for
force feedback effect.

Change-Id: Ib25dc4ea1b25031707c728ad947c6d8238480e30
parent 6fd5ba3a
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -23,6 +23,7 @@ import android.hardware.input.IInputDevicesChangedListener;
import android.hardware.input.ITabletModeChangedListener;
import android.hardware.input.TouchCalibration;
import android.os.IBinder;
import android.os.VibrationEffect;
import android.view.InputDevice;
import android.view.InputEvent;
import android.view.InputMonitor;
@@ -83,7 +84,7 @@ interface IInputManager {
    int isMicMuted();

    // Input device vibrator control.
    void vibrate(int deviceId, in long[] pattern, in int[] amplitudes, int repeat, IBinder token);
    void vibrate(int deviceId, in VibrationEffect effect, IBinder token);
    void cancelVibrate(int deviceId, IBinder token);

    void setPointerIconType(int typeId);
+1 −20
Original line number Diff line number Diff line
@@ -1297,27 +1297,8 @@ public final class InputManager {
        @Override
        public void vibrate(int uid, String opPkg, VibrationEffect effect,
                String reason, AudioAttributes attributes) {
            long[] pattern;
            int[] amplitudes;
            int repeat;
            if (effect instanceof VibrationEffect.OneShot) {
                VibrationEffect.OneShot oneShot = (VibrationEffect.OneShot) effect;
                pattern = new long[] { 0, oneShot.getDuration() };
                amplitudes = new int[] { 0, oneShot.getAmplitude() };
                repeat = -1;
            } else if (effect instanceof VibrationEffect.Waveform) {
                VibrationEffect.Waveform waveform = (VibrationEffect.Waveform) effect;
                pattern = waveform.getTimings();
                amplitudes = waveform.getAmplitudes();
                repeat = waveform.getRepeatIndex();
            } else {
                // TODO: Add support for prebaked effects
                Log.w(TAG, "Pre-baked effects aren't supported on input devices");
                return;
            }

            try {
                mIm.vibrate(mDeviceId, pattern, amplitudes, repeat, mToken);
                mIm.vibrate(mDeviceId, effect, mToken);
            } catch (RemoteException ex) {
                throw ex.rethrowFromSystemServer();
            }
+34 −2
Original line number Diff line number Diff line
@@ -63,6 +63,7 @@ import android.os.RemoteException;
import android.os.ResultReceiver;
import android.os.ShellCallback;
import android.os.UserHandle;
import android.os.VibrationEffect;
import android.provider.DeviceConfig;
import android.provider.Settings;
import android.provider.Settings.SettingNotFoundException;
@@ -141,6 +142,8 @@ public class InputManagerService extends IInputManager.Stub
    private static final int MSG_RELOAD_DEVICE_ALIASES = 5;
    private static final int MSG_DELIVER_TABLET_MODE_CHANGED = 6;

    private static final int DEFAULT_VIBRATION_MAGNITUDE = 192;

    // Pointer to native input manager service object.
    private final long mPtr;

@@ -1728,7 +1731,37 @@ public class InputManagerService extends IInputManager.Stub

    // Binder call
    @Override
    public void vibrate(int deviceId, long[] pattern, int[] amplitudes, int repeat, IBinder token) {
    public void vibrate(int deviceId, VibrationEffect effect, IBinder token) {
        long[] pattern;
        int[] amplitudes;
        int repeat;
        if (effect instanceof VibrationEffect.OneShot) {
            VibrationEffect.OneShot oneShot = (VibrationEffect.OneShot) effect;
            pattern = new long[] { 0, oneShot.getDuration() };
            int amplitude = oneShot.getAmplitude();
            // android framework uses DEFAULT_AMPLITUDE to signal that the vibration
            // should use some built-in default value, denoted here as DEFAULT_VIBRATION_MAGNITUDE
            if (amplitude == VibrationEffect.DEFAULT_AMPLITUDE) {
                amplitude = DEFAULT_VIBRATION_MAGNITUDE;
            }
            amplitudes = new int[] { 0, amplitude };
            repeat = -1;
        } else if (effect instanceof VibrationEffect.Waveform) {
            VibrationEffect.Waveform waveform = (VibrationEffect.Waveform) effect;
            pattern = waveform.getTimings();
            amplitudes = waveform.getAmplitudes();
            for (int i = 0; i < amplitudes.length; i++) {
                if (amplitudes[i] == VibrationEffect.DEFAULT_AMPLITUDE) {
                    amplitudes[i] = DEFAULT_VIBRATION_MAGNITUDE;
                }
            }
            repeat = waveform.getRepeatIndex();
        } else {
            // TODO: Add support for prebaked effects
            Log.w(TAG, "Pre-baked effects aren't supported on input devices");
            return;
        }

        if (repeat >= pattern.length) {
            throw new ArrayIndexOutOfBoundsException();
        }
@@ -1747,7 +1780,6 @@ public class InputManagerService extends IInputManager.Stub
                mVibratorTokens.put(token, v);
            }
        }

        synchronized (v) {
            v.mVibrating = true;
            nativeVibrate(mPtr, deviceId, pattern, amplitudes, repeat, v.mTokenValue);
+14 −6
Original line number Diff line number Diff line
@@ -75,6 +75,12 @@
using android::base::ParseUint;
using android::base::StringPrintf;

// Maximum allowable delay value in a vibration pattern before
// which the delay will be truncated.
static constexpr std::chrono::duration MAX_VIBRATE_PATTERN_DELAY = 100s;
static constexpr std::chrono::milliseconds MAX_VIBRATE_PATTERN_DELAY_MILLIS =
        std::chrono::duration_cast<std::chrono::milliseconds>(MAX_VIBRATE_PATTERN_DELAY);

namespace android {

// The exponent used to calculate the pointer speed scaling factor.
@@ -1636,17 +1642,19 @@ static void nativeVibrate(JNIEnv* env, jclass /* clazz */, jlong ptr, jint devic
            patternObj, nullptr));
    jint* amplitudes = static_cast<jint*>(env->GetPrimitiveArrayCritical(amplitudesObj, nullptr));

    std::vector<VibrationElement> pattern(patternSize);
    std::vector<VibrationElement> elements(patternSize);
    for (size_t i = 0; i < patternSize; i++) {
        jlong duration =
                max(min(patternMillis[i], (jlong)MAX_VIBRATE_PATTERN_DELAY_MSECS), (jlong)0);
        pattern[i].duration = std::chrono::milliseconds(duration);
        pattern[i].channels = {amplitudes[i]};
        // VibrationEffect.validate guarantees duration > 0.
        std::chrono::milliseconds duration(patternMillis[i]);
        elements[i].duration = std::min(duration, MAX_VIBRATE_PATTERN_DELAY_MILLIS);
        // TODO: (b/161629089) apply channel specific amplitudes from development API.
        elements[i].channels = {static_cast<uint8_t>(amplitudes[i]),
                                static_cast<uint8_t>(amplitudes[i])};
    }
    env->ReleasePrimitiveArrayCritical(patternObj, patternMillis, JNI_ABORT);
    env->ReleasePrimitiveArrayCritical(amplitudesObj, amplitudes, JNI_ABORT);

    im->getInputManager()->getReader()->vibrate(deviceId, pattern, repeat, token);
    im->getInputManager()->getReader()->vibrate(deviceId, elements, repeat, token);
}

static void nativeCancelVibrate(JNIEnv* /* env */,