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
This commit is contained in:
@@ -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);
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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 */,
|
||||
|
||||
Reference in New Issue
Block a user