diff --git a/.idea/gradle.xml b/.idea/gradle.xml index 526b4c2..bb80ebf 100644 --- a/.idea/gradle.xml +++ b/.idea/gradle.xml @@ -7,6 +7,7 @@ + diff --git a/.idea/jarRepositories.xml b/.idea/jarRepositories.xml index eb2873e..1e2d92c 100644 --- a/.idea/jarRepositories.xml +++ b/.idea/jarRepositories.xml @@ -26,5 +26,10 @@ + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml index 6199cc2..ef61796 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -1,6 +1,6 @@ - + diff --git a/app/build.gradle b/app/build.gradle index c989b8d..86e1d23 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -16,20 +16,21 @@ configurations.all { } android { - compileSdkVersion 30 + compileSdkVersion 32 compileOptions { - sourceCompatibility JavaVersion.VERSION_1_8 - targetCompatibility JavaVersion.VERSION_1_8 + sourceCompatibility JavaVersion.VERSION_11 + targetCompatibility JavaVersion.VERSION_11 } kotlinOptions { - jvmTarget = "1.8" + jvmTarget = "11" } defaultConfig { applicationId "fr.forum_thalie.tsumugi" minSdkVersion 16 - targetSdkVersion 30 - versionCode 120 - versionName "1.2.0" + targetSdkVersion 32 + multiDexEnabled true + versionCode 121 + versionName "1.2.1" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" vectorDrawables.useSupportLibrary = true } @@ -47,6 +48,9 @@ android { } dependencies { + def multidex_version = "2.0.1" + implementation "androidx.multidex:multidex:$multidex_version" + implementation fileTree(dir: 'libs', include: ['*.jar']) /* implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" @@ -67,15 +71,18 @@ dependencies { */ - implementation "androidx.media:media:1.1.0" + implementation "androidx.media:media:1.5.0" + + //noinspection GradleDependency implementation 'com.google.android.exoplayer:exoplayer:2.11.3' + //implementation project(':exoplayer-library') // uses local ExoPlayer clone, from dev-v2 branch (fixes ISO-8859-1 ICY metadata implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0' - implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.2.0' + implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.4.1' - implementation 'androidx.recyclerview:recyclerview:1.1.0' - implementation 'androidx.preference:preference:1.1.0' + implementation 'androidx.recyclerview:recyclerview:1.2.1' + implementation 'androidx.preference:preference-ktx:1.2.0' // jsoup HTML parser library @ https://jsoup.org/ // implementation 'org.jsoup:jsoup:1.12.1' diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 61de311..79f8a02 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -10,7 +10,8 @@ - + + @@ -22,8 +23,8 @@ android:label="@string/app_name" android:supportsRtl="true" android:theme="@style/AppTheme.Launcher" - tools:ignore="AllowBackup,GoogleAppIndexingWarning"> - + tools:ignore="AllowBackup,GoogleAppIndexingWarning" + android:name="androidx.multidex.MultiDexApplication"> + tools:targetApi="n" + android:exported="true"> @@ -47,9 +49,9 @@ + android:screenOrientation="fullUser" + android:exported="true"> @@ -63,7 +65,8 @@ android:parentActivityName=".MainActivity" android:screenOrientation="fullUser" /> - + diff --git a/app/src/main/assets/planning_example.json b/app/src/main/assets/planning_example.json index 96ac5b8..68380a9 100644 --- a/app/src/main/assets/planning_example.json +++ b/app/src/main/assets/planning_example.json @@ -7,15 +7,33 @@ "hour_end": "7:00" }, { - "title": "Jeux Vidéos Matin", - "periodicity": "1111100", + "title": "Tsumugi Rétro", + "periodicity": "1000000", "hour_begin": "09:00", - "hour_end": "10:30" + "hour_end": "12:00" }, { - "title": "Anime Matin", - "periodicity": "1111100", - "hour_begin": "10:30", + "title": "Tournant du Millénaire", + "periodicity": "0100000", + "hour_begin": "09:00", + "hour_end": "12:00" + }, + { + "title": "Tsumugi Netpop", + "periodicity": "0010000", + "hour_begin": "09:00", + "hour_end": "12:00" + }, + { + "title": "Tsumugi Moderne", + "periodicity": "0001000", + "hour_begin": "09:00", + "hour_end": "12:00" + }, + { + "title": "Tsumugi Très Récent", + "periodicity": "0000100", + "hour_begin": "09:00", "hour_end": "12:00" }, { diff --git a/app/src/main/java/fr/forum_thalie/tsumugi/BaseNotification.kt b/app/src/main/java/fr/forum_thalie/tsumugi/BaseNotification.kt index ef0bc65..6ca19dc 100644 --- a/app/src/main/java/fr/forum_thalie/tsumugi/BaseNotification.kt +++ b/app/src/main/java/fr/forum_thalie/tsumugi/BaseNotification.kt @@ -50,6 +50,7 @@ abstract class BaseNotification(private val notificationChannelId: String, notificationManager.notify(notificationId, notification) } + @RequiresApi(Build.VERSION_CODES.M) open fun create(c: Context) { notificationManager = c.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager @@ -58,7 +59,7 @@ abstract class BaseNotification(private val notificationChannelId: String, // thanks to the launchMode specified in the Manifest : android:launchMode="singleTop" val pendingIntent = PendingIntent.getActivity( c, 0, - notificationIntent, 0 + notificationIntent, PendingIntent.FLAG_IMMUTABLE ) var channelID = "" diff --git a/app/src/main/java/fr/forum_thalie/tsumugi/NowPlayingNotification.kt b/app/src/main/java/fr/forum_thalie/tsumugi/NowPlayingNotification.kt index c5c6b63..c8b4ddc 100644 --- a/app/src/main/java/fr/forum_thalie/tsumugi/NowPlayingNotification.kt +++ b/app/src/main/java/fr/forum_thalie/tsumugi/NowPlayingNotification.kt @@ -3,8 +3,10 @@ package fr.forum_thalie.tsumugi import android.app.PendingIntent import android.content.Context import android.content.Intent +import android.os.Build import android.support.v4.media.session.MediaSessionCompat import android.support.v4.media.session.PlaybackStateCompat +import androidx.annotation.RequiresApi import androidx.core.app.NotificationCompat import fr.forum_thalie.tsumugi.playerstore.PlayerStore @@ -34,7 +36,7 @@ class NowPlayingNotification( // got it right val delIntent = Intent(c, RadioService::class.java) delIntent.putExtra("action", Actions.KILL.name) - val deleteIntent = PendingIntent.getService(c, 0, delIntent, PendingIntent.FLAG_NO_CREATE) + val deleteIntent = PendingIntent.getService(c, 0, delIntent, PendingIntent.FLAG_NO_CREATE + PendingIntent.FLAG_IMMUTABLE) builder.setDeleteIntent(deleteIntent) mediaStyle = androidx.media.app.NotificationCompat.DecoratedMediaCustomViewStyle().also { @@ -46,6 +48,7 @@ class NowPlayingNotification( update(c) } + @RequiresApi(Build.VERSION_CODES.M) fun update(c: Context, isUpdatingNotificationButton: Boolean = false, isRinging: Boolean = false) { if (isUpdatingNotificationButton) @@ -72,17 +75,17 @@ class NowPlayingNotification( playPauseAction = if (PlayerStore.instance.playbackState.value == PlaybackStateCompat.STATE_PLAYING) { intent.putExtra("action", Actions.PAUSE.name) - val pendingButtonIntent = PendingIntent.getService(c, 1, intent, PendingIntent.FLAG_UPDATE_CURRENT) + val pendingButtonIntent = PendingIntent.getService(c, 1, intent, PendingIntent.FLAG_UPDATE_CURRENT + PendingIntent.FLAG_IMMUTABLE) NotificationCompat.Action.Builder(R.drawable.ic_pause, "Pause", pendingButtonIntent).build() } else { intent.putExtra("action", Actions.PLAY.name) - val pendingButtonIntent = PendingIntent.getService(c, 1, intent, PendingIntent.FLAG_UPDATE_CURRENT) + val pendingButtonIntent = PendingIntent.getService(c, 1, intent, PendingIntent.FLAG_UPDATE_CURRENT + PendingIntent.FLAG_IMMUTABLE) NotificationCompat.Action.Builder(R.drawable.ic_play,"Play", pendingButtonIntent).build() } builder.addAction(playPauseAction) val intent2 = Intent(c, RadioService::class.java) intent2.putExtra("action", Actions.KILL.name) - val pendingButtonIntent = PendingIntent.getService(c, 2, intent2, PendingIntent.FLAG_UPDATE_CURRENT) + val pendingButtonIntent = PendingIntent.getService(c, 2, intent2, PendingIntent.FLAG_UPDATE_CURRENT + PendingIntent.FLAG_IMMUTABLE) val stopAction = NotificationCompat.Action.Builder(R.drawable.ic_close,"Stop", pendingButtonIntent).build() builder.addAction(stopAction) @@ -92,7 +95,7 @@ class NowPlayingNotification( val snoozeIntent = Intent(c, RadioService::class.java) snoozeIntent.putExtra("action", Actions.SNOOZE.name) - val pendingSnoozeIntent = PendingIntent.getService(c, 5, snoozeIntent, PendingIntent.FLAG_UPDATE_CURRENT) + val pendingSnoozeIntent = PendingIntent.getService(c, 5, snoozeIntent, PendingIntent.FLAG_UPDATE_CURRENT + PendingIntent.FLAG_IMMUTABLE) val snoozeAction = NotificationCompat.Action.Builder(R.drawable.ic_alarm, "Snooze ($snoozeMinutes min.)", pendingSnoozeIntent ).build() if (snoozeMinutes > 0) builder.addAction(snoozeAction) 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 1132477..ceda78f 100644 --- a/app/src/main/java/fr/forum_thalie/tsumugi/RadioService.kt +++ b/app/src/main/java/fr/forum_thalie/tsumugi/RadioService.kt @@ -193,7 +193,8 @@ class RadioService : MediaBrowserServiceCompat() { // Define managers telephonyManager = getSystemService(Context.TELEPHONY_SERVICE) as TelephonyManager - telephonyManager?.listen(phoneStateListener, PhoneStateListener.LISTEN_CALL_STATE) + // telephonyManager?.listen(phoneStateListener, PhoneStateListener.LISTEN_CALL_STATE) + audioManager = getSystemService(Context.AUDIO_SERVICE) as AudioManager //define the audioFocusRequest diff --git a/app/src/main/java/fr/forum_thalie/tsumugi/alarm/RadioAlarm.kt b/app/src/main/java/fr/forum_thalie/tsumugi/alarm/RadioAlarm.kt index b64e8c5..80f4799 100644 --- a/app/src/main/java/fr/forum_thalie/tsumugi/alarm/RadioAlarm.kt +++ b/app/src/main/java/fr/forum_thalie/tsumugi/alarm/RadioAlarm.kt @@ -4,7 +4,9 @@ import android.app.AlarmManager import android.app.PendingIntent import android.content.Context import android.content.Intent +import android.os.Build import android.util.Log +import androidx.annotation.RequiresApi import androidx.core.app.AlarmManagerCompat import fr.forum_thalie.tsumugi.BootBroadcastReceiver import androidx.preference.PreferenceManager @@ -27,11 +29,29 @@ class RadioAlarm { { alarmIntent = Intent(c, BootBroadcastReceiver::class.java).let { intent -> intent.putExtra("action", "$tag.${Actions.PLAY_OR_FALLBACK.name}") - PendingIntent.getBroadcast(c, 0, intent, 0) + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + PendingIntent.getBroadcast( + c, + 0, + intent, + PendingIntent.FLAG_IMMUTABLE + ) + } else { + PendingIntent.getBroadcast( + c, + 0, + intent, + 0 + ) + } } showIntent = Intent(c, ParametersActivity::class.java).let { intent -> intent.putExtra("action", "alarm") - PendingIntent.getActivity(c, 0, intent, 0) + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + PendingIntent.getActivity(c, 0, intent, PendingIntent.FLAG_IMMUTABLE) + } else { + PendingIntent.getActivity(c, 0, intent, 0) + } } } @@ -43,6 +63,7 @@ class RadioAlarm { alarmManager.cancel(alarmIntent) } + @RequiresApi(Build.VERSION_CODES.M) fun setNextAlarm(c: Context, isForce: Boolean = false, forceTime: Int? = null, forceDays: Set? = null) { defineIntents(c) @@ -54,7 +75,7 @@ class RadioAlarm { val showIntent = Intent(c, ParametersActivity::class.java).let { intent -> intent.putExtra("action", ActionOpenParam.ALARM.name) - PendingIntent.getActivity(c, 0, intent, 0) + PendingIntent.getActivity(c, 0, intent, PendingIntent.FLAG_IMMUTABLE) } val time = findNextAlarmTime(c, forceTime, forceDays) if (time > 0) diff --git a/app/src/main/java/fr/forum_thalie/tsumugi/alarm/RadioSleeper.kt b/app/src/main/java/fr/forum_thalie/tsumugi/alarm/RadioSleeper.kt index fc5733c..c5ddcd8 100644 --- a/app/src/main/java/fr/forum_thalie/tsumugi/alarm/RadioSleeper.kt +++ b/app/src/main/java/fr/forum_thalie/tsumugi/alarm/RadioSleeper.kt @@ -4,7 +4,9 @@ import android.app.AlarmManager import android.app.PendingIntent import android.content.Context import android.content.Intent +import android.os.Build import android.util.Log +import androidx.annotation.RequiresApi import androidx.core.app.AlarmManagerCompat import androidx.lifecycle.MutableLiveData import androidx.preference.PreferenceManager @@ -30,18 +32,20 @@ class RadioSleeper { private lateinit var sleepIntent: PendingIntent private lateinit var fadeOutIntent: PendingIntent + @RequiresApi(Build.VERSION_CODES.M) private fun defineIntents(c: Context) { sleepIntent = Intent(c, RadioService::class.java).let { intent -> intent.putExtra("action", Actions.KILL.name) - PendingIntent.getService(c, 99, intent, 0) + PendingIntent.getService(c, 99, intent, PendingIntent.FLAG_IMMUTABLE) } fadeOutIntent = Intent(c, RadioService::class.java).let { intent -> intent.putExtra("action", Actions.FADE_OUT.name) - PendingIntent.getService(c, 98, intent, 0) + PendingIntent.getService(c, 98, intent, PendingIntent.FLAG_IMMUTABLE) } } + @RequiresApi(Build.VERSION_CODES.M) fun setSleep(c: Context, isForce: Boolean = false, forceDuration: Long? = null) { defineIntents(c) 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 ceb2a38..d51b301 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 @@ -47,7 +47,7 @@ class AlarmFragment : PreferenceFragmentCompat() { fun updateIsWakingUpSummary(preference: SwitchPreferenceCompat?, newValue: Boolean? = true, forceTime: Int? = null, forceDays: Set? = null) { - val dateLong = RadioAlarm.instance.findNextAlarmTime(context!!, forceTime, forceDays) + val dateLong = RadioAlarm.instance.findNextAlarmTime(requireContext(), forceTime, forceDays) val calendar = Calendar.getInstance() calendar.timeInMillis = dateLong if (newValue == true && calendar.timeInMillis > 0) @@ -65,14 +65,14 @@ class AlarmFragment : PreferenceFragmentCompat() { val hourOfDayDefault = 7 val minuteDefault = 0 - if (!PreferenceManager.getDefaultSharedPreferences(context!!).contains("alarmTimeFromMidnight")) + if (!PreferenceManager.getDefaultSharedPreferences(requireContext()).contains("alarmTimeFromMidnight")) { - PreferenceManager.getDefaultSharedPreferences(context!!).edit { + PreferenceManager.getDefaultSharedPreferences(requireContext()).edit { putInt("alarmTimeFromMidnight", (60*hourOfDayDefault+minuteDefault)) commit() } } - val time = PreferenceManager.getDefaultSharedPreferences(context!!).getInt("alarmTimeFromMidnight", (60*hourOfDayDefault+minuteDefault)) + val time = PreferenceManager.getDefaultSharedPreferences(requireContext()).getInt("alarmTimeFromMidnight", (60*hourOfDayDefault+minuteDefault)) val hourOfDay = time / 60 val minute = time % 60 timeSet?.summary = "${if (hourOfDay < 10) "0" else ""}$hourOfDay:${if (minute < 10) "0" else ""}$minute" @@ -80,16 +80,16 @@ class AlarmFragment : PreferenceFragmentCompat() { timeSet?.setOnPreferenceClickListener { val timePickerOnTimeSetListener = TimePickerDialog.OnTimeSetListener { _, hourOfDay, minute -> - PreferenceManager.getDefaultSharedPreferences(context!!).edit { + PreferenceManager.getDefaultSharedPreferences(requireContext()).edit { putInt("alarmTimeFromMidnight", (60*hourOfDay+minute)) commit() } timeSet.summary = "${if (hourOfDay < 10) "0" else ""}$hourOfDay:${if (minute < 10) "0" else ""}$minute" - RadioAlarm.instance.cancelAlarm(context!!) - RadioAlarm.instance.setNextAlarm(context!!, isForce = true, forceTime = hourOfDay*60+minute) + RadioAlarm.instance.cancelAlarm(requireContext()) + RadioAlarm.instance.setNextAlarm(requireContext(), isForce = true, forceTime = hourOfDay*60+minute) updateIsWakingUpSummary(isWakingUp, isWakingUp?.isChecked, forceTime = hourOfDay*60+minute) } - val timeNew = PreferenceManager.getDefaultSharedPreferences(context!!).getInt("alarmTimeFromMidnight", 7*60) + val timeNew = PreferenceManager.getDefaultSharedPreferences(requireContext()).getInt("alarmTimeFromMidnight", 7*60) val hourOfDayNew = timeNew / 60 val minuteNew = timeNew % 60 val timePicker = TimePickerDialog(context, timePickerOnTimeSetListener, hourOfDayNew, minuteNew, true) @@ -103,8 +103,8 @@ class AlarmFragment : PreferenceFragmentCompat() { val fullWeek = weekdays.toSet() val workingWeek = weekdays.toSet().minusElement(weekdays.last()).minusElement(weekdays.elementAt(weekdays.size - 2)) val listOfDays = when (newValue) { - fullWeek -> context!!.getString(R.string.every_day) - workingWeek -> context!!.getString(R.string.working_days) + fullWeek -> requireContext().getString(R.string.every_day) + workingWeek -> requireContext().getString(R.string.working_days) else -> { // build ORDERED LIST of days... I don't know why the original one is in shambles!! val fullWeekOrdered = weekdays @@ -119,12 +119,12 @@ class AlarmFragment : PreferenceFragmentCompat() { preference?.summary = listOfDays } - updateDays(alarmDays, PreferenceManager.getDefaultSharedPreferences(context).getStringSet("alarmDays", setOf())) + updateDays(alarmDays, PreferenceManager.getDefaultSharedPreferences(requireContext()).getStringSet("alarmDays", setOf())) alarmDays?.setOnPreferenceChangeListener { preference, newValue -> @Suppress("UNCHECKED_CAST") updateDays(preference as MultiSelectListPreference, newValue as Set) - RadioAlarm.instance.cancelAlarm(context!!) - RadioAlarm.instance.setNextAlarm(context!!, isForce = true, forceDays = newValue) + RadioAlarm.instance.cancelAlarm(requireContext()) + RadioAlarm.instance.setNextAlarm(requireContext(), isForce = true, forceDays = newValue) updateIsWakingUpSummary(isWakingUp, isWakingUp?.isChecked, forceDays = newValue) true } @@ -133,9 +133,9 @@ class AlarmFragment : PreferenceFragmentCompat() { isWakingUp?.setOnPreferenceChangeListener { _, newValue -> if (newValue as Boolean) - RadioAlarm.instance.setNextAlarm(context!!, isForce = true) + RadioAlarm.instance.setNextAlarm(requireContext(), isForce = true) else - RadioAlarm.instance.cancelAlarm(context!!) + RadioAlarm.instance.cancelAlarm(requireContext()) timeSet?.isEnabled = newValue alarmDays?.isEnabled = newValue snoozeDuration?.isEnabled = newValue diff --git a/build.gradle b/build.gradle index 6f110b6..9160f7a 100644 --- a/build.gradle +++ b/build.gradle @@ -1,16 +1,17 @@ // Top-level build file where you can add configuration options common to all sub-projects/modules. buildscript { - ext.kotlin_version = '1.3.72' + ext.kotlin_version = '1.6.10' repositories { google() jcenter() } dependencies { - classpath 'com.android.tools.build:gradle:7.1.1' + classpath 'com.android.tools.build:gradle:7.1.2' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files + } }