diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml index 45b5654..88ea3aa 100644 --- a/.idea/codeStyles/Project.xml +++ b/.idea/codeStyles/Project.xml @@ -1,8 +1,5 @@ - - diff --git a/.idea/runConfigurations.xml b/.idea/runConfigurations.xml deleted file mode 100644 index 7f68460..0000000 --- a/.idea/runConfigurations.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle index 0274953..e7ea61a 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -16,8 +16,8 @@ configurations.all { } android { - compileSdkVersion 29 - buildToolsVersion "29.0.2" + compileSdkVersion 30 + buildToolsVersion "30.0.1" compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 @@ -28,9 +28,9 @@ android { defaultConfig { applicationId "fr.forum_thalie.tsumugi" minSdkVersion 16 - targetSdkVersion 29 - versionCode 115 - versionName "1.1.5" + targetSdkVersion 30 + versionCode 120 + versionName "1.2.0" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" vectorDrawables.useSupportLibrary = true } diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 4bb94a6..61de311 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -13,6 +13,7 @@ + + android:exported="false"> @@ -60,7 +61,7 @@ android:configChanges="orientation|screenSize" android:launchMode="singleTask" android:parentActivityName=".MainActivity" - android:screenOrientation="fullSensor" /> + android:screenOrientation="fullUser" /> diff --git a/app/src/main/assets/planning_example.json b/app/src/main/assets/planning_example.json index 1ef0236..96ac5b8 100644 --- a/app/src/main/assets/planning_example.json +++ b/app/src/main/assets/planning_example.json @@ -1,7 +1,7 @@ { "planning": [ { - "title": "Musique Classique", + "title": "Le Classique du Matin", "periodicity": "1111111", "hour_begin": "6:00", "hour_end": "7:00" diff --git a/app/src/main/java/fr/forum_thalie/tsumugi/MainActivity.kt b/app/src/main/java/fr/forum_thalie/tsumugi/MainActivity.kt index 91fd2c7..c325d77 100644 --- a/app/src/main/java/fr/forum_thalie/tsumugi/MainActivity.kt +++ b/app/src/main/java/fr/forum_thalie/tsumugi/MainActivity.kt @@ -117,7 +117,7 @@ class MainActivity : BaseActivity() { } } - override fun onRestoreInstanceState(savedInstanceState: Bundle?) { + override fun onRestoreInstanceState(savedInstanceState: Bundle) { super.onRestoreInstanceState(savedInstanceState ?: Bundle()) // Now that BottomNavigationBar has restored its instance state // and its selectedItemId, we can proceed with setting up the diff --git a/app/src/main/java/fr/forum_thalie/tsumugi/RadioService.kt b/app/src/main/java/fr/forum_thalie/tsumugi/RadioService.kt index c98f641..d89e00e 100644 --- a/app/src/main/java/fr/forum_thalie/tsumugi/RadioService.kt +++ b/app/src/main/java/fr/forum_thalie/tsumugi/RadioService.kt @@ -454,12 +454,13 @@ class RadioService : MediaBrowserServiceCompat() { // this function is playing the stream if available, or a default sound if there's a problem. private fun beginPlayingOrFallback() { - PlayerStore.instance.volume.value = 100 // we set the max volume for exoPlayer to be sure it rings correctly. + PlayerStore.instance.volume.value = PreferenceManager.getDefaultSharedPreferences(this).getInt("alarmVolume", 100) + // we set the max volume for exoPlayer to be sure it rings correctly. beginPlaying(isRinging = true, isFallback = false) val wait: (Any?) -> Any = { /* Here we lower the isAlarmStopped flag and we wait for 17s. (seems like 12 could be a bit too short since I increased the buffer!!) - If the player stops the alarm (by calling an intent), the isAlarmStopped flag will be raised. + If the user stops the alarm (by calling an intent), the isAlarmStopped flag will be raised. */ isAlarmStopped = false // reset the flag var i = 0 @@ -498,6 +499,7 @@ class RadioService : MediaBrowserServiceCompat() { .setUsage(C.USAGE_ALARM) .build() } else { + isAlarmStopped = true // if we're not ringing and it tries playing, it means the user opened the app somehow audioAttributes.setUsage(AudioAttributesCompat.USAGE_MEDIA) audioFocusRequestBuilder.setAudioAttributes(audioAttributes.build()) audioFocusRequest = audioFocusRequestBuilder.build() @@ -513,8 +515,6 @@ class RadioService : MediaBrowserServiceCompat() { return } - if (mediaSession.controller.playbackState.state == PlaybackStateCompat.STATE_PLAYING && !isRinging) - return // nothing to do here PlayerStore.instance.playbackState.value = PlaybackStateCompat.STATE_PLAYING // Reinitialize media player. Otherwise the playback doesn't resume when beginPlaying. Dunno why. @@ -530,7 +530,6 @@ class RadioService : MediaBrowserServiceCompat() { } // START PLAYBACK, LET'S ROCK - player.playWhenReady = true nowPlayingNotification.update(this, isUpdatingNotificationButton = true, isRinging = isRinging) playbackStateBuilder.setState( @@ -540,6 +539,8 @@ class RadioService : MediaBrowserServiceCompat() { SystemClock.elapsedRealtime() ) mediaSession.setPlaybackState(playbackStateBuilder.build()) + player.playWhenReady = true + //[REMOVE LOG CALLS]Log.d(tag, radioTag + "begin playing") } @@ -553,7 +554,6 @@ class RadioService : MediaBrowserServiceCompat() { { if (mediaSession.controller.playbackState.state == PlaybackStateCompat.STATE_STOPPED) return // nothing to do here - if (PlayerStore.instance.playbackState.value == PlaybackStateCompat.STATE_PLAYING) isAlarmStopped = true diff --git a/app/src/main/java/fr/forum_thalie/tsumugi/preferences/AlarmAdjustVolumeFragment.kt b/app/src/main/java/fr/forum_thalie/tsumugi/preferences/AlarmAdjustVolumeFragment.kt new file mode 100644 index 0000000..aba0b8a --- /dev/null +++ b/app/src/main/java/fr/forum_thalie/tsumugi/preferences/AlarmAdjustVolumeFragment.kt @@ -0,0 +1,129 @@ +package fr.forum_thalie.tsumugi.preferences + +import android.content.Context +import android.content.Intent +import android.media.AudioManager +import android.os.Bundle +import android.view.KeyEvent +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.appcompat.app.AlertDialog +import androidx.appcompat.app.AppCompatActivity +import androidx.preference.PreferenceFragmentCompat +import androidx.preference.PreferenceManager +import androidx.preference.SeekBarPreference +import androidx.preference.SwitchPreferenceCompat +import fr.forum_thalie.tsumugi.Actions +import fr.forum_thalie.tsumugi.R +import fr.forum_thalie.tsumugi.RadioService +import fr.forum_thalie.tsumugi.playerstore.PlayerStore +import kotlinx.coroutines.* +import kotlin.coroutines.CoroutineContext +import kotlin.math.max +import kotlin.math.min + + +class AlarmAdjustVolumeFragment : PreferenceFragmentCompat() { + override fun onAttach(context: Context) { + (activity as AppCompatActivity).supportActionBar?.title = context.getString(R.string.test_alarm_volume) + super.onAttach(context) + } + + // get previous state: if it's playing, we'll resume playing as multimedia; if it was stopped, we'll stop + private var isPlayingMultimedia: Boolean = PlayerStore.instance.isPlaying.value ?: false + + override fun onStop() { + if (isPlayingMultimedia) + { + actionOnService(Actions.PLAY) + } else { + actionOnService(Actions.PAUSE) + } + PlayerStore.instance.volume.value = PreferenceManager.getDefaultSharedPreferences(requireContext()).getInt("volume", 100) + super.onStop() + } + + override fun onResume() { + + isPlayingMultimedia = PlayerStore.instance.isPlaying.value ?: false + // start as alarm + actionOnService(Actions.PLAY_OR_FALLBACK) + super.onResume() + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + fun debounce(delayMs: Long = 500L, + coroutineContext: CoroutineContext, + f: (T) -> Unit): (T) -> Unit { + var debounceJob: Job? = null + return { param: T -> + if (debounceJob?.isCompleted != false) { + debounceJob = CoroutineScope(coroutineContext).launch { + delay(delayMs) + f(param) + } + } + } + } + + val adjustAlarmVolume: (Int) -> Unit = debounce(50, GlobalScope.coroutineContext) { + android.util.Log.d(tag, "button $it pushed") + val keyCode = it + val audioManager = requireContext().getSystemService(Context.AUDIO_SERVICE) as AudioManager + audioManager.apply { + val currentVolume = this.getStreamVolume(AudioManager.STREAM_ALARM) + val minVolume = 0 // audioManager.getStreamMinVolume(AudioManager.STREAM_ALARM) <- require API28+ + val maxVolume = this.getStreamMaxVolume(AudioManager.STREAM_ALARM) + if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN) { + this.setStreamVolume(AudioManager.STREAM_ALARM, max(currentVolume - 1, minVolume), AudioManager.FLAG_SHOW_UI) + + } else if (keyCode == KeyEvent.KEYCODE_VOLUME_UP){ + this.setStreamVolume(AudioManager.STREAM_ALARM, min(currentVolume + 1, maxVolume), AudioManager.FLAG_SHOW_UI) + } else { + + } + } + + } + view.isFocusableInTouchMode = true; + view.requestFocus(); + view.setOnKeyListener { _, i, event -> + if (i == KeyEvent.KEYCODE_VOLUME_DOWN || i == KeyEvent.KEYCODE_VOLUME_UP) { + adjustAlarmVolume(i) + true + } else { + false + } + } + } + + override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { + setPreferencesFromResource(R.xml.alarm_adjust_volume_preferences, rootKey) + + val alarmVolumeSeekBar = findPreference("alarmVolume") + alarmVolumeSeekBar?.apply { + min = 0 + max = 100 + updatesContinuously = true + setOnPreferenceChangeListener { _, newValue -> + actionOnService(Actions.VOLUME, newValue as Int) + true + } + } + + } + + + private fun actionOnService(a: Actions, v: Int = 0) + { + val i = Intent(requireContext(), RadioService::class.java) + i.putExtra("action", a.name) + i.putExtra("value", v) + //[REMOVE LOG CALLS]Log.d(tag, "Sending intent ${a.name}") + requireContext().startService(i) + } + +} \ No newline at end of file diff --git a/app/src/main/java/fr/forum_thalie/tsumugi/preferences/AlarmFragment.kt b/app/src/main/java/fr/forum_thalie/tsumugi/preferences/AlarmFragment.kt index 4b07606..ceb2a38 100644 --- a/app/src/main/java/fr/forum_thalie/tsumugi/preferences/AlarmFragment.kt +++ b/app/src/main/java/fr/forum_thalie/tsumugi/preferences/AlarmFragment.kt @@ -2,15 +2,29 @@ package fr.forum_thalie.tsumugi.preferences import android.app.TimePickerDialog import android.content.Context +import android.content.Intent +import android.media.AudioManager import android.os.Bundle import android.util.Log +import android.view.KeyEvent +import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AppCompatActivity import androidx.core.content.edit import androidx.preference.* import fr.forum_thalie.tsumugi.* import fr.forum_thalie.tsumugi.R import fr.forum_thalie.tsumugi.alarm.RadioAlarm +import fr.forum_thalie.tsumugi.playerstore.PlayerStore +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.GlobalScope.coroutineContext +import kotlinx.coroutines.Job +import kotlinx.coroutines.delay +import kotlinx.coroutines.launch import java.util.* +import kotlin.coroutines.CoroutineContext +import kotlin.math.max +import kotlin.math.min + class AlarmFragment : PreferenceFragmentCompat() { @@ -129,12 +143,10 @@ class AlarmFragment : PreferenceFragmentCompat() { true } - alarmDays?.isEnabled = isWakingUp?.isChecked ?: false timeSet?.isEnabled = isWakingUp?.isChecked ?: false snoozeDuration?.isEnabled = isWakingUp?.isChecked ?: false } - } \ No newline at end of file diff --git a/app/src/main/java/fr/forum_thalie/tsumugi/ui/nowplaying/NowPlayingFragment.kt b/app/src/main/java/fr/forum_thalie/tsumugi/ui/nowplaying/NowPlayingFragment.kt index 1e306ac..fdb24c1 100644 --- a/app/src/main/java/fr/forum_thalie/tsumugi/ui/nowplaying/NowPlayingFragment.kt +++ b/app/src/main/java/fr/forum_thalie/tsumugi/ui/nowplaying/NowPlayingFragment.kt @@ -166,10 +166,10 @@ class NowPlayingFragment : Fragment() { } }) - - seekBarVolume.setOnSeekBarChangeListener(nowPlayingViewModel.seekBarChangeListener) seekBarVolume.progress = PlayerStore.instance.volume.value!! - progressBar.max = 1000 + seekBarVolume.setOnSeekBarChangeListener(nowPlayingViewModel.seekBarChangeListener) + + progressBar.max = 100 progressBar.progress = 0 syncPlayPauseButtonImage(root) diff --git a/app/src/main/res/drawable/none.xml b/app/src/main/res/drawable/none.xml new file mode 100644 index 0000000..a8b409b --- /dev/null +++ b/app/src/main/res/drawable/none.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index c2e04af..6650dd4 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -56,5 +56,13 @@ Raffraîchir les données \"Play\" au branchement de la prise casque Paramètres + Tester et ajuster le volume de l\'alarme + Touchez pour écouter et régler le volume + La radio est à présent lancée en mode alarme. Ajustez le volume avec les boutons de volume de votre appareil. Vous pouvez faire un réglage plus fin du volume avec la réglette ci-dessous. + Terminé + Ajuster le volume de l\'alarme + Régler le volume de l\'alarme + Volume de l\'alarme + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 3847fed..8fcad32 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -76,5 +76,12 @@ Refresh data Auto play when plugging headphones Settings + Test and change alarm volume + Touch this to listen to the alarm volume and set it up + The radio stream is now started in alarm mode. Adjust the volume with the volume buttons on your device. You can make a finer adjustment of the volume with the slider below. + Done + Adjust alarm volume + Set up alarm volume + Alarm volume diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml index fcdcb13..96c951a 100644 --- a/app/src/main/res/values/styles.xml +++ b/app/src/main/res/values/styles.xml @@ -11,8 +11,14 @@ @color/colorPrimaryDark -