aboutsummaryrefslogtreecommitdiff
path: root/samples/SoundBoard/src/main/kotlin/com/google/oboe/samples/soundboard/MusicTileView.kt
diff options
context:
space:
mode:
Diffstat (limited to 'samples/SoundBoard/src/main/kotlin/com/google/oboe/samples/soundboard/MusicTileView.kt')
-rw-r--r--samples/SoundBoard/src/main/kotlin/com/google/oboe/samples/soundboard/MusicTileView.kt164
1 files changed, 164 insertions, 0 deletions
diff --git a/samples/SoundBoard/src/main/kotlin/com/google/oboe/samples/soundboard/MusicTileView.kt b/samples/SoundBoard/src/main/kotlin/com/google/oboe/samples/soundboard/MusicTileView.kt
new file mode 100644
index 00000000..ac813450
--- /dev/null
+++ b/samples/SoundBoard/src/main/kotlin/com/google/oboe/samples/soundboard/MusicTileView.kt
@@ -0,0 +1,164 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.oboe.samples.soundboard
+
+import android.content.Context
+import android.content.res.Configuration
+import android.graphics.*
+import android.util.SparseArray
+import android.view.MotionEvent
+import android.view.View
+
+class MusicTileView(
+ context: Context?,
+ private val mRectangles: ArrayList<Rect>,
+ tileListener: TileListener,
+ configChangeListener: ConfigChangeListener
+) : View(context) {
+ private val mIsPressedPerRectangle: BooleanArray = BooleanArray(mRectangles.size)
+ private val mPaint: Paint = Paint()
+ private val mLocationsOfFingers: SparseArray<PointF> = SparseArray()
+ private val mTileListener: TileListener
+ private val mConfigChangeListener : ConfigChangeListener
+
+ interface ConfigChangeListener {
+ fun onConfigurationChanged()
+ }
+
+ interface TileListener {
+ fun onTileOn(index: Int)
+ fun onTileOff(index: Int)
+ }
+
+ private fun getIndexFromLocation(pointF: PointF): Int {
+ for (i in mRectangles.indices) {
+ if (pointF.x > mRectangles[i].left && pointF.x < mRectangles[i].right && pointF.y > mRectangles[i].top && pointF.y < mRectangles[i].bottom) {
+ return i
+ }
+ }
+ return -1
+ }
+
+ override fun onDraw(canvas: Canvas) {
+ for (i in mRectangles.indices) {
+ mPaint.style = Paint.Style.FILL
+ if (mIsPressedPerRectangle[i]) {
+ mPaint.color = Color.rgb(128, 0, 0)
+ } else {
+ mPaint.color = Color.BLACK
+ }
+ canvas.drawRect(mRectangles[i], mPaint)
+
+ // border
+ mPaint.style = Paint.Style.STROKE
+ mPaint.strokeWidth = 10f
+ mPaint.color = Color.WHITE
+ canvas.drawRect(mRectangles[i], mPaint)
+ }
+ }
+
+ override fun onTouchEvent(event: MotionEvent): Boolean {
+ val pointerIndex = event.actionIndex
+ val pointerId = event.getPointerId(pointerIndex)
+ val maskedAction = event.actionMasked
+ var didImageChange = false
+ when (maskedAction) {
+ MotionEvent.ACTION_MOVE -> {
+
+ // Create an array to check for finger changes as multiple fingers may be on the
+ // same tile. This two-pass algorithm records the overall difference before changing
+ // the actual tiles.
+ val notesChangedBy = IntArray(mRectangles.size)
+ run {
+ val size = event.pointerCount
+ var i = 0
+ while (i < size) {
+ val point = mLocationsOfFingers[event.getPointerId(i)]
+ if (point != null) {
+ val prevIndex = getIndexFromLocation(point)
+ point.x = event.getX(i)
+ point.y = event.getY(i)
+ val newIndex = getIndexFromLocation(point)
+ if (newIndex != prevIndex) {
+ if (prevIndex != -1) {
+ notesChangedBy[prevIndex]--
+ }
+ if (newIndex != -1) {
+ notesChangedBy[newIndex]++
+ }
+ }
+ }
+ i++
+ }
+ }
+
+ // Now go through the rectangles to see if they have changed
+ var i = 0
+ while (i < mRectangles.size) {
+ if (notesChangedBy[i] > 0) {
+ mIsPressedPerRectangle[i] = true
+ mTileListener.onTileOn(i)
+ didImageChange = true
+ } else if (notesChangedBy[i] < 0) {
+ mIsPressedPerRectangle[i] = false
+ mTileListener.onTileOff(i)
+ didImageChange = true
+ }
+ i++
+ }
+ }
+ MotionEvent.ACTION_DOWN, MotionEvent.ACTION_POINTER_DOWN -> {
+ val f = PointF()
+ f.x = event.getX(pointerIndex)
+ f.y = event.getY(pointerIndex)
+ mLocationsOfFingers.put(pointerId, f)
+ val curIndex = getIndexFromLocation(f)
+ if (curIndex != -1) {
+ mIsPressedPerRectangle[curIndex] = true
+ mTileListener.onTileOn(curIndex)
+ didImageChange = true
+ }
+ }
+ MotionEvent.ACTION_UP, MotionEvent.ACTION_POINTER_UP, MotionEvent.ACTION_CANCEL -> {
+ val curIndex =
+ getIndexFromLocation(mLocationsOfFingers[event.getPointerId(pointerIndex)])
+ if (curIndex != -1) {
+ mIsPressedPerRectangle[curIndex] = false
+ mTileListener.onTileOff(curIndex)
+ didImageChange = true
+ }
+ mLocationsOfFingers.remove(pointerId)
+ }
+ }
+
+ // Calling invalidate() will force onDraw() to be called
+ if (didImageChange) {
+ invalidate()
+ }
+ return true
+ }
+
+ override fun onConfigurationChanged(newConfig: Configuration) {
+ super.onConfigurationChanged(newConfig)
+ mConfigChangeListener.onConfigurationChanged()
+ }
+
+ init {
+ mTileListener = tileListener
+ mConfigChangeListener = configChangeListener
+ }
+}