Interhaptics SDK for Unity 1.6
Loading...
Searching...
No Matches
AndroidProvider.cs
Go to the documentation of this file.
1/* ​
2* Copyright (c) 2023 Go Touch VR SAS. All rights reserved. ​
3* ​
4*/
5
6#if !ENABLE_METAQUEST && !ENABLE_OPENXR && UNITY_ANDROID && !UNITY_EDITOR
7using UnityEngine;
9using System.Collections;
10using System.Collections.Generic;
11
12namespace Interhaptics.Platforms.Android
13{
14 public sealed class AndroidProvider : IHapticProvider
15 {
16#region HAPTIC CHARACTERISTICS FIELDS
17 private const string DISPLAY_NAME = "Android";
18 private const string DESCRIPTION = "Android device";
19 private const string MANUFACTURER = "Google";
20 private const string VERSION = "1.0";
21 private const int SAMPLERATE = 100;
22 private const int AMPLITUDE_DISTANCE = 5; //previously 0
23 private ulong lastBufferStartingTime = 0;
24 private bool hapticPlaying= false;
25 private float? expectedEndTimestamp = null;
26 private BodyPartID Hand= BodyPartID.Bp_Left_palm;
27#endregion
28
29#region HAPTIC CHARACTERISTICS GETTERS
30 [UnityEngine.Scripting.Preserve]
31 public string DisplayName()
32 {
33 return DISPLAY_NAME;
34 }
35
36 [UnityEngine.Scripting.Preserve]
37 public string Description()
38 {
39 return DESCRIPTION;
40 }
41
42 [UnityEngine.Scripting.Preserve]
43 public string Manufacturer()
44 {
45 return MANUFACTURER;
46 }
47
48 [UnityEngine.Scripting.Preserve]
49 public string Version()
50 {
51 return VERSION;
52 }
53#endregion
54
55#region PROVIDER LOOP
56
57 [UnityEngine.Scripting.Preserve]
58 public bool Init()
59 {
60#if !ENABLE_IL2CPP && UNITY_ANDROID && !UNITY_EDITOR
61 UnityEngine.Debug.LogError("Interhaptics requires IL2CPP scripting backend for Android. Please change it in Player Settings. Haptics will not play on the Mono scripting backend on the Android platform." + "Source: Android Provider");
62 HapticManager.MonoScriptingBackend = true;
63 return false;
64#endif
65
66#if !UNITY_EDITOR && UNITY_ANDROID && !ENABLE_METAQUEST && !ENABLE_OPENXR
67//Added a way to disable the provider if the device does not have haptic capabilities - TODO: Update when Android haptic controllers are available (DirectInput)
68 AndroidJavaClass UnityPlayer = new AndroidJavaClass("com.unity3d.player.UnityPlayer");
69 AndroidJavaObject currentActivity = UnityPlayer.GetStatic<AndroidJavaObject>("currentActivity");
70 AndroidJavaObject vibrator = currentActivity.Call<AndroidJavaObject>("getSystemService", "vibrator");
71 bool hasVibrator = vibrator.Call<bool>("hasVibrator");
72 if (hasVibrator)
73 {
74 Debug.Log("Haptic capabilities supported on Android.");
75 }
76 else
77 {
78 Debug.Log("Haptic capabilities not supported on this Android device.");
79 }
80 if (!SystemInfo.supportsVibration)
81 {
82 UnityEngine.Debug.LogError("The device does not have haptic capabilities. Haptics will not play on this device. ");
83 // Attempt to log Android version, API, and device model - corrected access to Android properties
84 // Note: Correct usage involves using AndroidJavaObject and AndroidJavaClass for accessing Android-specific information
85 using (var version = new AndroidJavaClass("android.os.Build$VERSION"))
86 {
87 string androidVersion = version.GetStatic<string>("RELEASE");
88 int apiLevel = version.GetStatic<int>("SDK_INT");
89 using (var build = new AndroidJavaClass("android.os.Build"))
90 {
91 string deviceModel = build.GetStatic<string>("MODEL");
92 Debug.LogError($"Android version: {androidVersion} API: {apiLevel} Device model: {deviceModel}");
93 }
94 }
95 return false;
96 }
97#endif
98
100 Core.HAR.AddBodyPart(Perception.Vibration, Hand, 1, 1, 1, SAMPLERATE, false, false, false, false);
101 if (HapticManager.DebugSwitch)
102 {
103 using (var version = new AndroidJavaClass("android.os.Build$VERSION"))
104 {
105 string androidVersion = version.GetStatic<string>("RELEASE");
106 int apiLevel = version.GetStatic<int>("SDK_INT");
107 using (var build = new AndroidJavaClass("android.os.Build"))
108 {
109 string deviceModel = build.GetStatic<string>("MODEL");
110 Debug.Log($"Android haptic provider started. Android version: {androidVersion} API: {apiLevel} Device model: {deviceModel}");
111 }
112 }
113 }
114 return true;
115 }
116
117 [UnityEngine.Scripting.Preserve]
118 public bool IsPresent()
119 {
121 }
122
123 [UnityEngine.Scripting.Preserve]
124 public bool Clean()
125 {
126 return true;
127 }
128
129 private bool IsEqual(int _amplitudeA, int _amplitudeB, int _distance = 0)
130 {
131 return Mathf.Abs(_amplitudeA - _amplitudeB) <= _distance;
132 }
133
134 [UnityEngine.Scripting.Preserve]
135 public void RenderHaptics()
136 {
137 ulong startingTime = Core.HAR.GetVectorStartingTime(Perception.Vibration, Hand, 0, 0, 0);
138 //if something to update
139 if (startingTime!= lastBufferStartingTime)
140 {
141 lastBufferStartingTime = startingTime;
142 int size = Core.HAR.GetOutputBufferSize(Perception.Vibration, Hand, 0, 0, 0, BufferDataType.Amplitude);
143 if (size > 0)
144 {
145 double[] outputBuffer = new double[size];
146 //getting haptic amplitude buffer to play
147 Core.HAR.GetOutputBuffer(outputBuffer, size, Perception.Vibration, Hand, 0, 0, 0, BufferDataType.Amplitude);
148 List<int> AndroidOutputBuffer = new List<int>();
149 List<long> timeBuffer = new List<long>();
150 long step = Mathf.RoundToInt(1000.0f / SAMPLERATE);
151 int lastAmplitude = -1;
152 int currentAmplitude = -1;
153 long currentTiming = 0;
154 //creating pattern array and casting haptic data into the correct range (0 <-> 255)
155 for (int i = 0; i < size; i++)
156 {
157 currentAmplitude = Mathf.RoundToInt((float)(outputBuffer[i] * 255));
158 if (i != 0 && IsEqual(currentAmplitude, lastAmplitude, AMPLITUDE_DISTANCE)) //compare with a distance of 0 (between 0 and 255)
159 {
160 currentTiming += step;
161 continue;
162 }
163 else
164 {
165 AndroidOutputBuffer.Add(currentAmplitude);
166 lastAmplitude = currentAmplitude;
167 if (i != 0)//we dont want to add the duration on the first iteration
168 {
169 timeBuffer.Add(currentTiming + step);
170 currentTiming = 0;
171 }
172 }
173 }
174 timeBuffer.Add(currentTiming + step);
175
176 //sending haptic data to device
177 Interhaptics.Platforms.Mobile.GenericAndroidHapticAbstraction.Vibrate(timeBuffer.ToArray(), AndroidOutputBuffer.ToArray(),-1,true);
178 hapticPlaying = true;
179 expectedEndTimestamp = UnityEngine.Time.realtimeSinceStartup+((float)size / (float)SAMPLERATE);
180 }
181 }
182 else
183 {
184 if (hapticPlaying && UnityEngine.Time.realtimeSinceStartup> expectedEndTimestamp)
185 {
186 //Stop haptic at the end of the effect
188 hapticPlaying = false;
189
190 }
191 }
192 }
193#endregion
194 }
195}
196#endif
static void Vibrate(long milliseconds, int amplitude=-1, bool cancel=false)
Vibrate for Milliseconds, with Amplitude (if available). If amplitude is -1, amplitude is Disabled....
BufferDataType
Enumeration for types of haptic buffer data.
BodyPartID
Enumeration for identifying different body parts for haptic effects.
Perception
Enumeration for different types of haptic perceptions.