diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 3773df19..d6d92e24 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -4,6 +4,7 @@
+
diff --git a/app/src/main/java/com/limelight/binding/input/ControllerHandler.java b/app/src/main/java/com/limelight/binding/input/ControllerHandler.java
index b8a20829..69a2d27b 100644
--- a/app/src/main/java/com/limelight/binding/input/ControllerHandler.java
+++ b/app/src/main/java/com/limelight/binding/input/ControllerHandler.java
@@ -4,8 +4,10 @@ import android.content.Context;
import android.hardware.input.InputManager;
import android.hardware.usb.UsbDevice;
import android.hardware.usb.UsbManager;
+import android.media.AudioAttributes;
import android.os.Build;
import android.os.SystemClock;
+import android.os.VibrationEffect;
import android.os.Vibrator;
import android.util.SparseArray;
import android.view.InputDevice;
@@ -1051,7 +1053,36 @@ public class ControllerHandler implements InputManager.InputDeviceListener, UsbD
}
private void rumbleVibrator(Vibrator vibrator, short lowFreqMotor, short highFreqMotor) {
+ if (lowFreqMotor == 0 && highFreqMotor == 0) {
+ // This case is easy - just cancel and get out
+ vibrator.cancel();
+ return;
+ }
+ // Since we can only use a single amplitude value, compute the desired amplitude
+ // by taking 75% of the big motor and 25% of the small motor.
+ // NB: This value is now 0-255 as required by VibrationEffect.
+ int simulatedAmplitude = (int)(((lowFreqMotor >> 8) * 0.75) + ((highFreqMotor >> 8) * 0.25));
+
+ // Attempt to use amplitude-based control if we're on Oreo and the device
+ // supports amplitude-based vibration control.
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+ if (vibrator.hasAmplitudeControl()) {
+ VibrationEffect effect = VibrationEffect.createOneShot(Long.MAX_VALUE, simulatedAmplitude);
+ AudioAttributes audioAttributes = new AudioAttributes.Builder()
+ .setUsage(AudioAttributes.USAGE_GAME)
+ .build();
+ vibrator.vibrate(effect, audioAttributes);
+ return;
+ }
+ }
+
+ // If we reach this point, we don't have amplitude controls available, so
+ // we must emulate it by PWMing the vibration. Ick.
+ long pwmPeriod = 50;
+ long onTime = (long)((simulatedAmplitude / 255.0) * pwmPeriod);
+ long offTime = pwmPeriod - onTime;
+ vibrator.vibrate(new long[]{offTime, onTime}, 0);
}
public void handleRumble(short controllerNumber, short lowFreqMotor, short highFreqMotor) {