diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index cbc21bf..11ea536 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -17,6 +17,7 @@ + \ No newline at end of file diff --git a/app/src/main/java/de/mlte/soundboard/MainActivity.kt b/app/src/main/java/de/mlte/soundboard/MainActivity.kt index 096cb37..9a5e58b 100644 --- a/app/src/main/java/de/mlte/soundboard/MainActivity.kt +++ b/app/src/main/java/de/mlte/soundboard/MainActivity.kt @@ -1,11 +1,11 @@ package de.mlte.soundboard +import android.animation.Animator import android.animation.ValueAnimator import android.app.Activity import android.content.Context import android.content.Intent import android.content.res.Configuration.ORIENTATION_LANDSCAPE -import android.media.MediaPlayer import android.net.Uri import android.os.Bundle import android.support.v7.app.AppCompatActivity @@ -17,14 +17,35 @@ import android.view.animation.LinearInterpolator import android.widget.GridLayout import java.io.BufferedInputStream import java.io.BufferedOutputStream +import android.content.ComponentName +import android.os.IBinder +import android.content.ServiceConnection +import android.animation.AnimatorListenerAdapter +import android.util.Log class MainActivity : AppCompatActivity() { private val buttons = ArrayList() - private var player: MediaPlayer? = null - private var playing = false private var playingButton: SoundButton? = null private var playingAnimator: ValueAnimator? = null + private var playerService: PlayerService? = null + + private val playerServiceConnection = object : ServiceConnection { + + override fun onServiceConnected(className: ComponentName, + binder: IBinder) { + val binder = binder as PlayerService.PlayerServiceBinder + val service = binder.service + playerService = service + playingButton?.let{ button -> startAnimator(service, button) } + } + + override fun onServiceDisconnected(className: ComponentName) { + playerService = null + } + } + + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) @@ -37,36 +58,17 @@ class MainActivity : AppCompatActivity() { } override fun onSaveInstanceState(outState: Bundle?) { - if (playing) { - player?.let { mp -> - if (mp.isPlaying) { - outState?.putBoolean("playing", true) - outState?.putInt("playingPosition", mp.currentPosition) - val parent = findViewById(R.id.grid_layout) - val index = parent.indexOfChild(playingButton) - outState?.putInt("playingIndex", index) - } + playerService?.let { service -> + if (service.playing) { + val parent = findViewById(R.id.grid_layout) + val index = parent.indexOfChild(playingButton) + outState?.putInt("playing", index) } } super.onSaveInstanceState(outState) } - override fun onDestroy() { - if (playing) { - player?.let { mp -> - if (mp.isPlaying) { - mp.stop() - } - mp.reset() - mp.release() - } - playingAnimator?.cancel() - } - - super.onDestroy() - } - override fun onRestoreInstanceState(savedInstanceState: Bundle?) { super.onRestoreInstanceState(savedInstanceState) @@ -75,14 +77,32 @@ class MainActivity : AppCompatActivity() { } savedInstanceState?.let { state -> - if (state.getBoolean("playing")) { - val button = buttons[state.getInt("playingIndex")] - val position = state.getInt("playingPosition") - startPlaying(button, position) + val index = state.getInt("playing", -1) + if (index > -1) { + playingButton = buttons[index] } } } + override fun onStart() { + super.onStart() + + val intent = Intent(this, PlayerService::class.java) + startService(intent) + bindService(intent, playerServiceConnection, 0) + } + + override fun onStop() { + super.onStop() + + if (playerService?.playing != true) { + val intent = Intent(this, PlayerService::class.java) + stopService(intent) + } + + unbindService(playerServiceConnection) + } + override fun onCreateOptionsMenu(menu: Menu?): Boolean { val inflater = menuInflater inflater.inflate(R.menu.main, menu) @@ -108,7 +128,7 @@ class MainActivity : AppCompatActivity() { private fun saveNumButtons() { val editor = getPreferences(Context.MODE_PRIVATE).edit() editor.putInt("numButtons", buttons.size) - editor.commit() + editor.apply() } private fun organizeButtons() { @@ -135,6 +155,35 @@ class MainActivity : AppCompatActivity() { parent.columnCount = columns } + private fun playButton(soundButton: SoundButton) { + playerService?.let{ service -> + playingButton = soundButton + service.start(soundButton.soundId) + startAnimator(service, soundButton) + } + } + + private fun startAnimator(service: PlayerService, button: SoundButton) { + playingAnimator?.cancel() + if (service.playing) { + val bar = button.progressBar + val animator = ValueAnimator.ofInt(bar.max * service.currentPosition / service.duration, bar.max) + animator.interpolator = LinearInterpolator() + animator.addUpdateListener { + bar.progress = animator.animatedValue as Int + } + animator.addListener(object : AnimatorListenerAdapter() { + override fun onAnimationEnd(animation: Animator) { + bar.progress = 0 + } + }) + + animator.duration = service.duration.toLong() - service.currentPosition + animator.start() + playingAnimator = animator + } + } + private fun addButton(soundButton: SoundButton) { buttons.add(soundButton) @@ -142,21 +191,11 @@ class MainActivity : AppCompatActivity() { parent.addView(soundButton) soundButton.textView.setOnClickListener { - if (playing) { - player?.let { mp -> - if (mp.isPlaying) { - mp.stop() - } - mp.reset() - mp.release() - } - playingButton?.let { button -> - button.progressBar.progress = 0 - } - playing = false + if (playerService?.playing == true) { + playerService?.stop() playingAnimator?.cancel() } else { - startPlaying(soundButton, 0) + playButton(soundButton) } } @@ -166,36 +205,9 @@ class MainActivity : AppCompatActivity() { } } - private fun startPlaying(soundButton: SoundButton, position: Int) { - val file = getFileStreamPath("audio" + soundButton.soundId) - if (file.exists()) { - val mp = MediaPlayer.create(this, Uri.fromFile(file)) - mp.setOnCompletionListener { - playingAnimator?.cancel() - soundButton.progressBar.progress = 0 - mp.reset() - mp.release() - playing = false - } - mp.seekTo(position) - mp.start() - player = mp - playing = true - playingButton = soundButton - - val bar = soundButton.progressBar - val animator = ValueAnimator.ofInt(bar.max * position / mp.duration, bar.max) - animator.interpolator = LinearInterpolator() - animator.addUpdateListener { - bar.progress = animator.animatedValue as Int - } - animator.duration = mp.duration.toLong() - position - animator.start() - playingAnimator = animator - } - } - private fun editButton(soundButton: SoundButton) { + playerService?.stop() + playingAnimator?.cancel() val intent = Intent(baseContext, EditActivity::class.java) val parent = findViewById(R.id.grid_layout) val index = parent.indexOfChild(soundButton) @@ -262,23 +274,23 @@ class MainActivity : AppCompatActivity() { val editor = getPreferences(Context.MODE_PRIVATE).edit() editor.putString("caption" + index, textView.text.toString()) editor.putString("fileName" + index, buttons[index].fileName) - editor.commit() + editor.apply() - uri?.let { uri -> + uri?.let { u -> deleteFile("audio" + soundId) val newSoundId = System.currentTimeMillis() buttons[index].soundId = newSoundId editor.putLong("soundId" + index, newSoundId) editor.commit() - grantUriPermission(packageName, uri, Intent.FLAG_GRANT_READ_URI_PERMISSION) + grantUriPermission(packageName, u, Intent.FLAG_GRANT_READ_URI_PERMISSION) val output = BufferedOutputStream(openFileOutput("audio" + newSoundId, Context.MODE_PRIVATE)) - val input = BufferedInputStream(contentResolver.openInputStream(uri)) + val input = BufferedInputStream(contentResolver.openInputStream(u)) try { val buf = ByteArray(1024) input.read(buf) do { output.write(buf) - } while (input.read(buf) !== -1) + } while (input.read(buf) != -1) } finally { input.close() output.close() diff --git a/app/src/main/java/de/mlte/soundboard/PlayerService.kt b/app/src/main/java/de/mlte/soundboard/PlayerService.kt new file mode 100644 index 0000000..4ae4ecd --- /dev/null +++ b/app/src/main/java/de/mlte/soundboard/PlayerService.kt @@ -0,0 +1,59 @@ +package de.mlte.soundboard + +import android.app.Service +import android.content.Intent +import android.media.MediaPlayer +import android.net.Uri +import android.os.Binder +import android.os.IBinder + +class PlayerService : Service() { + private val binder = PlayerServiceBinder() + + private var player: MediaPlayer? = null + + val currentPosition: Int + get() = player?.currentPosition ?: 0 + + val duration: Int + get() = player?.duration ?: 0 + + val playing: Boolean + get() = player?.isPlaying ?: false + + inner class PlayerServiceBinder : Binder() { + internal + val service: PlayerService + get() = this@PlayerService + } + + override fun onBind(intent: Intent): IBinder = binder + + fun stop() { + player?.let { mp -> + mp.stop() + mp.reset() + mp.release() + player = null + } + } + + fun start(soundId: Long) { + stop() + val file = getFileStreamPath("audio" + soundId) + if (file.exists()) { + val mp = MediaPlayer.create(this, Uri.fromFile(file)) + mp.setOnCompletionListener { + mp.reset() + mp.release() + player = null + } + mp.start() + player = mp + } + } + + override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { + return START_STICKY + } +}