using UnityEngine; | |
using System.Collections; | |
public class Vibration : MonoBehaviour { | |
public static AndroidJavaClass unityPlayer; | |
public static AndroidJavaObject vibrator; | |
public static AndroidJavaObject currentActivity; | |
public static AndroidJavaClass vibrationEffectClass; | |
public static int defaultAmplitude; | |
/* | |
* "CreateOneShot": One time vibration | |
* "CreateWaveForm": Waveform vibration | |
* | |
* Vibration Effects class (Android API level 26 or higher) | |
* Milliseconds: long: milliseconds to vibrate. Must be positive. | |
* Amplitude: int: Strenght of vibration. Between 1-255. (Or default value: -1) | |
* Timings: long: If submitting a array of amplitudes, then timings are the duration of each of these amplitudes in millis. | |
* Repeat: int: index of where to repeat, -1 for no repeat | |
*/ | |
void OnEnable() { | |
#if UNITY_ANDROID && !UNITY_EDITOR | |
unityPlayer = new AndroidJavaClass("com.unity3d.player.UnityPlayer"); | |
currentActivity = unityPlayer.GetStatic<AndroidJavaObject>("currentActivity"); | |
vibrator = currentActivity.Call<AndroidJavaObject>("getSystemService", "vibrator"); | |
if (getSDKInt() >= 26) { | |
vibrationEffectClass = new AndroidJavaClass("android.os.VibrationEffect"); | |
defaultAmplitude = vibrationEffectClass.GetStatic<int>("DEFAULT_AMPLITUDE"); | |
} | |
#endif | |
} | |
//Works on API > 25 | |
public static void CreateOneShot(long milliseconds) { | |
if(isAndroid()) { | |
//If Android 8.0 (API 26+) or never use the new vibrationeffects | |
if (getSDKInt() >= 26) { | |
CreateOneShot(milliseconds, defaultAmplitude); | |
} | |
else { | |
OldVibrate(milliseconds); | |
} | |
} | |
//If not android do simple solution for now | |
else { | |
Handheld.Vibrate(); | |
} | |
} | |
public static void CreateOneShot(long milliseconds, int amplitude) { | |
if (isAndroid()) { | |
//If Android 8.0 (API 26+) or never use the new vibrationeffects | |
if (getSDKInt() >= 26) { | |
CreateVibrationEffect("createOneShot", new object[] { milliseconds, amplitude }); | |
} | |
else { | |
OldVibrate(milliseconds); | |
} | |
} | |
//If not android do simple solution for now | |
else { | |
Handheld.Vibrate(); | |
} | |
} | |
//Works on API > 25 | |
public static void CreateWaveform(long[] timings, int repeat) { | |
//Amplitude array varies between no vibration and default_vibration up to the number of timings | |
if (isAndroid()) { | |
//If Android 8.0 (API 26+) or never use the new vibrationeffects | |
if (getSDKInt() >= 26) { | |
CreateVibrationEffect("createWaveform", new object[] { timings, repeat }); | |
} | |
else { | |
OldVibrate(timings, repeat); | |
} | |
} | |
//If not android do simple solution for now | |
else { | |
Handheld.Vibrate(); | |
} | |
} | |
public static void CreateWaveform(long[] timings, int[] amplitudes, int repeat) { | |
if (isAndroid()) { | |
//If Android 8.0 (API 26+) or never use the new vibrationeffects | |
if (getSDKInt() >= 26) { | |
CreateVibrationEffect("createWaveform", new object[] { timings, amplitudes, repeat }); | |
} | |
else { | |
OldVibrate(timings, repeat); | |
} | |
} | |
//If not android do simple solution for now | |
else { | |
Handheld.Vibrate(); | |
} | |
} | |
//Handels all new vibration effects | |
private static void CreateVibrationEffect(string function, params object[] args) { | |
AndroidJavaObject vibrationEffect = vibrationEffectClass.CallStatic<AndroidJavaObject>(function, args); | |
vibrator.Call("vibrate", vibrationEffect); | |
} | |
//Handles old vibration effects | |
private static void OldVibrate(long milliseconds) { | |
vibrator.Call("vibrate", milliseconds); | |
} | |
private static void OldVibrate(long[] pattern, int repeat) { | |
vibrator.Call("vibrate", pattern, repeat); | |
} | |
public static bool HasVibrator() { | |
return vibrator.Call<bool>("hasVibrator"); | |
} | |
public static bool HasAmplituideControl() { | |
if (getSDKInt() >= 26) { | |
return vibrator.Call<bool>("hasAmplitudeControl"); //API 26+ specific | |
} | |
else { | |
return false; //If older than 26 then there is no amplitude control at all | |
} | |
} | |
public static void Cancel() { | |
if (isAndroid()) | |
vibrator.Call("cancel"); | |
} | |
private static int getSDKInt() { | |
if(isAndroid()) { | |
using (var version = new AndroidJavaClass("android.os.Build$VERSION")) { | |
return version.GetStatic<int>("SDK_INT"); | |
} | |
} | |
else { | |
return -1; | |
} | |
} | |
private static bool isAndroid() { | |
#if UNITY_ANDROID && !UNITY_EDITOR | |
return true; | |
#else | |
return false; | |
#endif | |
} | |
} |
That works great!
Thanks for the script!
if UNITY_ANDROID && !UNITY_EDITOR
unityPlayer = new AndroidJavaClass("com.unity3d.player.UnityPlayer");
currentActivity = unityPlayer.GetStatic("currentActivity");
vibrator = currentActivity.Call("getSystemService", "vibrator");
if (getSDKInt() >= 26) {
vibrationEffectClass = new AndroidJavaClass("android.os.VibrationEffect");
defaultAmplitude = vibrationEffectClass.GetStatic("DEFAULT_AMPLITUDE");
}
#endif
This area (complete code in between) becomes grey and it feels like its inaccesible or something.
This Compiles well in unity, but when i deploy and run it on my android(s), it doesn't do anything?
Tested on : Samsung S6 (Android 7.0) and Oppo Find 7a (Android 5.0)
The previous code was working fine but then that wouldn't work with later/newer APIs.
If this works for both, so this should be amazing!!!
I'm pretty sure this would work. So could you help me out? Thanks. :D
Thanks for posting this! It helped things. I do have a question though.
Do the methods with custom amplitudes work for you guys?
For me it just seems to use max power amplitude no matter what I value I pass it.
That means to say that for a vibration of lets say 500ms there is no difference in amplitude/ intensity of the vibration between lets say 10 and 255 amplitude. I tested on more devices it just feels like a maximum intensity vibration.
CreateVibrationEffect("createWaveform", new object[] { timings, amplitudes, repeat });
has the same behavior as
CreateVibrationEffect("createWaveform", new object[] { timings, repeat });
and likewise for
CreateVibrationEffect("createOneShot", new object[] { milliseconds, amplitude });
I tried to pass it value of 0 just to see if the value is getting through to the java object and indeed android monitor spits an error saying it needs a value between 1 and 255. Even if I pass 1 as value for amplitude, it seems it uses the default max amplitude.
Am I missing something or is this an android issue?
Thanks!
This code gives me an error:
NullReferenceException: Object reference not set to an instance of an object.
at Vibration.CreateVibrationEffect (System.String function, System.Object[] args) [0x00000] in <00000000000000000000000000000000>:0
I used only this line of code:
AndroidVibration.CreateOneShot((long)150);
Am I doing something wrong? (Android 9 Pie)
@Sithdown
Can you provide your class implementation for AndroidVibration?
Seems like your are missing the vibration object.
Hey, just posted a tweaked version that operates without needing to be a MonoBehaviour (all static) and a little refactored. I've changed to pure android as assuming on iOS you might want to use TapticManager etc - https://gist.github.com/handcircus/0046ce4cc8bd8cfd431c3d0375dda826
Adapted from https://gist.github.com/aVolpe/707c8cf46b1bb8dfb363 and https://gist.github.com/andyrbacon/4ff08fcdf7ab0c023118874f5339bf7a
It is a bit messy because I needed to check the SDK values on startup so I couldn't make it static. I am open for cleaner solutions.