-
Notifications
You must be signed in to change notification settings - Fork 8
/
Copy pathRumble.kt
150 lines (124 loc) · 4.86 KB
/
Rumble.kt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
// TODO: Change this
package box.shoe.gameutils.rumble;
import android.content.Context
import android.os.Build
import android.os.VibrationEffect
import android.os.Vibrator
import android.util.Log
// TODO: Change this
import box.gift.gameutils.BuildConfig;
import java.util.ArrayList
import java.util.Arrays
object Rumble {
private var vibrator: Vibrator? = null
private var rumbleDisabled: Boolean = false
fun init(applicationContext: Context) {
vibrator = applicationContext.getSystemService(Context.VIBRATOR_SERVICE) as Vibrator
rumbleDisabled = vibrator == null || !vibrator!!.hasVibrator()
if (rumbleDisabled && BuildConfig.DEBUG) {
Log.w("Rumble", "System does not have a Vibrator, or the permission is disabled. " + "Rumble has been turned rest. Subsequent calls to static methods will have no effect.")
}
}
private fun apiIndependentVibrate(milliseconds: Long) {
if (rumbleDisabled) {
return
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
vibrator!!.vibrate(VibrationEffect.createOneShot(milliseconds, VibrationEffect.DEFAULT_AMPLITUDE))
} else {
vibrator!!.vibrate(milliseconds)
}
}
private fun apiIndependentVibrate(pattern: LongArray) {
if (rumbleDisabled) {
return
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
vibrator!!.vibrate(VibrationEffect.createWaveform(pattern, -1))
} else {
vibrator!!.vibrate(pattern, -1)
}
}
fun stop() {
if (rumbleDisabled) {
return
}
vibrator!!.cancel()
}
fun once(milliseconds: Long) {
apiIndependentVibrate(milliseconds)
}
fun makePattern(): RumblePattern {
return RumblePattern()
}
class RumblePattern internal constructor() {
private val internalPattern: MutableList<Long>
var isLocked: Boolean = false
private set
init {
isLocked = false
internalPattern = ArrayList()
internalPattern.add(0L)
}
fun beat(milliseconds: Long): RumblePattern {
if (isLocked) {
throw IllegalStateException("RumblePattern is locked! Cannot modify its state.")
}
if (internalPattern.size % 2 == 0) {
internalPattern[internalPattern.size - 1] = internalPattern[internalPattern.size - 1] + milliseconds
} else {
internalPattern.add(milliseconds)
}
return this
}
fun rest(milliseconds: Long): RumblePattern {
if (isLocked) {
throw IllegalStateException("RumblePattern is locked! Cannot modify its state.")
}
if (internalPattern.size % 2 == 0) {
internalPattern.add(milliseconds)
} else {
internalPattern[internalPattern.size - 1] = internalPattern[internalPattern.size - 1] + milliseconds
}
return this
}
fun lock() {
if (isLocked) {
throw IllegalStateException("RumblePattern is already locked! Use isLocked() to check.")
}
isLocked = true
}
@JvmOverloads
fun playPattern(numberOfTimes: Int = 1) {
if (numberOfTimes < 0) {
throw IllegalArgumentException("numberOfTimes must be >= 0")
}
val endsWithRest = internalPattern.size % 2 == 0
// We have a List<Long> but we need a long[]. We can't simply use toArray because that yields a Long[].
// Reserve enough space to hold the full pattern as many times as necessary to play the pattern the right number of times.
val primitiveArray = LongArray(internalPattern.size * numberOfTimes - if (endsWithRest) 0 else numberOfTimes - 1)
for (i in internalPattern.indices) {
// Auto unboxing converts each Long to a long.
primitiveArray[i] = internalPattern[i]
}
// Copy the array into itself to duplicate the pattern enough times.
// Not a simple copy - we must overlay the copies if the pattern ends in a rest.
// R B R
// [100, 300, 500]
// +
// [100, 300, 500]
for (i in 1 until numberOfTimes) {
for (j in internalPattern.indices) {
val k = j + internalPattern.size * i - if (endsWithRest) 0 else i
primitiveArray[k] += primitiveArray[j]
}
}
apiIndependentVibrate(primitiveArray)
}
override fun toString(): String {
return "RumblePattern{" +
"internalPattern=" + internalPattern +
"}"
}
}
}