Loading core/java/android/hardware/input/IInputManager.aidl +2 −1 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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); Loading core/java/android/hardware/input/InputManager.java +1 −20 Original line number Diff line number Diff line Loading @@ -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(); } Loading services/core/java/com/android/server/input/InputManagerService.java +34 −2 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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; Loading Loading @@ -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(); } Loading @@ -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); Loading services/core/jni/com_android_server_input_InputManagerService.cpp +14 −6 Original line number Diff line number Diff line Loading @@ -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. Loading Loading @@ -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 */, Loading Loading
core/java/android/hardware/input/IInputManager.aidl +2 −1 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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); Loading
core/java/android/hardware/input/InputManager.java +1 −20 Original line number Diff line number Diff line Loading @@ -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(); } Loading
services/core/java/com/android/server/input/InputManagerService.java +34 −2 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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; Loading Loading @@ -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(); } Loading @@ -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); Loading
services/core/jni/com_android_server_input_InputManagerService.cpp +14 −6 Original line number Diff line number Diff line Loading @@ -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. Loading Loading @@ -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 */, Loading