1 /* 2 * Copyright 2021 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.google.oboe.samples.soundboard 18 19 import android.app.Activity 20 import android.content.Context 21 import android.content.res.Configuration 22 import android.graphics.Point 23 import android.graphics.Rect 24 import android.media.AudioManager 25 import android.os.Build 26 import android.os.Bundle 27 import androidx.annotation.RequiresApi 28 import androidx.appcompat.app.AppCompatActivity 29 import kotlin.math.min 30 31 class MainActivity : AppCompatActivity() { startEnginenull32 private external fun startEngine(numSignals: Int): Long 33 private external fun stopEngine(engineHandle: Long) 34 private external fun native_setDefaultStreamValues(sampleRate: Int, framesPerBurst: Int) 35 36 companion object { 37 private const val DIMENSION_MIN_SIZE = 6 38 private const val DIMENSION_MAX_SIZE = 8 39 private var mNumColumns : Int = 0; 40 private var mNumRows : Int = 0; 41 private var mRectangles = ArrayList<Rect>() 42 43 private var mEngineHandle: Long = 0 44 45 // Used to load the 'native-lib' library on application startup. 46 init { 47 System.loadLibrary("soundboard") 48 } 49 } 50 onCreatenull51 override fun onCreate(savedInstanceState: Bundle?) { 52 super.onCreate(savedInstanceState) 53 setContentView(R.layout.activity_main) 54 } 55 onResumenull56 override fun onResume() { 57 super.onResume() 58 setup() 59 } 60 onPausenull61 override fun onPause() { 62 stopEngine(mEngineHandle) 63 super.onPause() 64 } 65 setupnull66 private fun setup() { 67 setDefaultStreamValues(this) 68 calculateAndSetRectangles(this) 69 mEngineHandle = startEngine(mNumRows * mNumColumns) 70 createMusicTiles(this) 71 } 72 setDefaultStreamValuesnull73 private fun setDefaultStreamValues(context: Context) { 74 val myAudioMgr = context.getSystemService(AUDIO_SERVICE) as AudioManager 75 val sampleRateStr = myAudioMgr.getProperty(AudioManager.PROPERTY_OUTPUT_SAMPLE_RATE) 76 val defaultSampleRate = sampleRateStr.toInt() 77 val framesPerBurstStr = 78 myAudioMgr.getProperty(AudioManager.PROPERTY_OUTPUT_FRAMES_PER_BUFFER) 79 val defaultFramesPerBurst = framesPerBurstStr.toInt() 80 native_setDefaultStreamValues(defaultSampleRate, defaultFramesPerBurst) 81 } 82 calculateAndSetRectanglesnull83 private fun calculateAndSetRectangles(context: Context) { 84 val width: Int 85 val height: Int 86 87 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { 88 width = windowManager.currentWindowMetrics.bounds.width() 89 height = windowManager.currentWindowMetrics.bounds.height() 90 } else { 91 val size = Point() 92 windowManager.defaultDisplay.getRealSize(size) 93 height = size.y 94 width = size.x 95 } 96 97 if (height > width) { 98 mNumColumns = DIMENSION_MIN_SIZE 99 mNumRows = min(DIMENSION_MIN_SIZE * height / width, DIMENSION_MAX_SIZE) 100 } else { 101 mNumRows = DIMENSION_MIN_SIZE 102 mNumColumns = min(DIMENSION_MIN_SIZE * width / height, DIMENSION_MAX_SIZE) 103 } 104 val tileLength = min(height / mNumRows, width / mNumColumns) 105 val xStartLocation = (width - tileLength * mNumColumns) / 2 106 val yStartLocation = 0 107 mRectangles = ArrayList<Rect>() 108 for (i in 0 until mNumRows) { 109 for (j in 0 until mNumColumns) { 110 val rectangle = Rect( 111 xStartLocation + j * tileLength, 112 yStartLocation + i * tileLength, 113 xStartLocation + j * tileLength + tileLength, 114 yStartLocation + i * tileLength + tileLength 115 ) 116 mRectangles.add(rectangle) 117 } 118 } 119 } 120 createMusicTilesnull121 private fun createMusicTiles(context: Context) { 122 setContentView(MusicTileView(this, mRectangles, NoteListener(mEngineHandle), 123 ScreenChangeListener { setup() })) 124 } 125 126 class ScreenChangeListener(private var mFunc: () -> Unit) : MusicTileView.ConfigChangeListener { onConfigurationChangednull127 override fun onConfigurationChanged() { 128 mFunc() 129 } 130 } 131 132 } 133