fix(recordings): open last file on android
This commit is contained in:
@@ -68,6 +68,16 @@
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
|
||||
<provider
|
||||
android:name="androidx.core.content.FileProvider"
|
||||
android:authorities="${applicationId}.fileprovider"
|
||||
android:exported="false"
|
||||
android:grantUriPermissions="true">
|
||||
<meta-data
|
||||
android:name="android.support.FILE_PROVIDER_PATHS"
|
||||
android:resource="@xml/pluriwave_file_paths" />
|
||||
</provider>
|
||||
|
||||
<meta-data
|
||||
android:name="flutterEmbedding"
|
||||
android:value="2" />
|
||||
|
||||
@@ -5,13 +5,19 @@ import android.app.PendingIntent
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.os.Build
|
||||
import android.util.Log
|
||||
import androidx.core.app.NotificationManagerCompat
|
||||
|
||||
class AlarmScheduler(private val context: Context) {
|
||||
private val tag = "PluriWave"
|
||||
private val alarmManager =
|
||||
context.getSystemService(Context.ALARM_SERVICE) as AlarmManager
|
||||
|
||||
fun scheduleAlarm(id: String, title: String, triggerAtMillis: Long, preNoticeAtMillis: Long) {
|
||||
Log.d(
|
||||
tag,
|
||||
"alarm.schedule id=$id title=$title triggerAtMillis=$triggerAtMillis preNoticeAtMillis=$preNoticeAtMillis canExact=${canScheduleExactAlarms()}"
|
||||
)
|
||||
val alarmIntent = PendingIntent.getBroadcast(
|
||||
context,
|
||||
requestCode(id, 1),
|
||||
@@ -39,6 +45,7 @@ class AlarmScheduler(private val context: Context) {
|
||||
AlarmManager.AlarmClockInfo(triggerAtMillis, showIntent),
|
||||
alarmIntent
|
||||
)
|
||||
Log.d(tag, "alarm.schedule setAlarmClock OK id=$id")
|
||||
|
||||
if (preNoticeAtMillis > System.currentTimeMillis()) {
|
||||
try {
|
||||
@@ -56,13 +63,18 @@ class AlarmScheduler(private val context: Context) {
|
||||
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
|
||||
)
|
||||
)
|
||||
Log.d(tag, "alarm.schedule preNotice OK id=$id")
|
||||
} catch (_: SecurityException) {
|
||||
// The main alarm is already scheduled with setAlarmClock.
|
||||
Log.w(tag, "alarm.schedule preNotice SecurityException id=$id")
|
||||
}
|
||||
} else {
|
||||
Log.d(tag, "alarm.schedule preNotice skipped id=$id")
|
||||
}
|
||||
}
|
||||
|
||||
fun cancelAlarm(id: String) {
|
||||
Log.d(tag, "alarm.cancel id=$id")
|
||||
for (slot in 1..3) {
|
||||
alarmManager.cancel(
|
||||
PendingIntent.getBroadcast(
|
||||
|
||||
@@ -2,6 +2,7 @@ package es.freetimelab.pluriwave
|
||||
|
||||
import android.Manifest
|
||||
import android.app.ActivityNotFoundException
|
||||
import android.content.ClipData
|
||||
import android.content.Intent
|
||||
import android.content.pm.PackageManager
|
||||
import android.net.Uri
|
||||
@@ -11,13 +12,17 @@ import android.os.Environment
|
||||
import android.os.Handler
|
||||
import android.os.Looper
|
||||
import android.provider.DocumentsContract
|
||||
import android.util.Log
|
||||
import androidx.core.app.NotificationManagerCompat
|
||||
import androidx.core.content.FileProvider
|
||||
import com.ryanheise.audioservice.AudioServiceActivity
|
||||
import io.flutter.embedding.engine.FlutterEngine
|
||||
import io.flutter.plugin.common.EventChannel
|
||||
import io.flutter.plugin.common.MethodChannel
|
||||
import java.io.File
|
||||
|
||||
class MainActivity : AudioServiceActivity() {
|
||||
private val tag = "PluriWave"
|
||||
private val visualizerChannel = "pluriwave/audio_visualizer"
|
||||
private val alarmChannel = "pluriwave/alarm_scheduler"
|
||||
private val fileActionsChannel = "pluriwave/file_actions"
|
||||
@@ -59,7 +64,9 @@ class MainActivity : AudioServiceActivity() {
|
||||
val title = call.argument<String>("title") ?: "PluriWave"
|
||||
val triggerAtMillis = call.argument<Long>("triggerAtMillis")
|
||||
val preNoticeAtMillis = call.argument<Long>("preNoticeAtMillis") ?: 0L
|
||||
Log.d(tag, "alarm.channel scheduleAlarm id=$id triggerAtMillis=$triggerAtMillis preNoticeAtMillis=$preNoticeAtMillis")
|
||||
if (id == null || triggerAtMillis == null) {
|
||||
Log.w(tag, "alarm.channel scheduleAlarm invalid id=$id triggerAtMillis=$triggerAtMillis")
|
||||
result.error("INVALID_ALARM", "Missing alarm id or trigger time", null)
|
||||
} else {
|
||||
alarmScheduler.scheduleAlarm(id, title, triggerAtMillis, preNoticeAtMillis)
|
||||
@@ -68,6 +75,7 @@ class MainActivity : AudioServiceActivity() {
|
||||
}
|
||||
"cancelAlarm" -> {
|
||||
val id = call.argument<String>("id")
|
||||
Log.d(tag, "alarm.channel cancelAlarm id=$id")
|
||||
if (id == null) {
|
||||
result.error("INVALID_ALARM", "Missing alarm id", null)
|
||||
} else {
|
||||
@@ -77,6 +85,7 @@ class MainActivity : AudioServiceActivity() {
|
||||
}
|
||||
"dismissAlarmNotification" -> {
|
||||
val id = call.argument<String>("id")
|
||||
Log.d(tag, "alarm.channel dismissAlarmNotification id=$id")
|
||||
if (id == null) {
|
||||
result.error("INVALID_ALARM", "Missing alarm id", null)
|
||||
} else {
|
||||
@@ -85,6 +94,7 @@ class MainActivity : AudioServiceActivity() {
|
||||
}
|
||||
}
|
||||
"diagnostics" -> {
|
||||
Log.d(tag, "alarm.channel diagnostics")
|
||||
result.success(
|
||||
mapOf(
|
||||
"canScheduleExactAlarms" to alarmScheduler.canScheduleExactAlarms(),
|
||||
@@ -95,7 +105,9 @@ class MainActivity : AudioServiceActivity() {
|
||||
)
|
||||
}
|
||||
"getInitialAlarmIntent" -> {
|
||||
result.success(alarmPayload(intent))
|
||||
val payload = alarmPayload(intent)
|
||||
Log.d(tag, "alarm.channel getInitialAlarmIntent payload=$payload")
|
||||
result.success(payload)
|
||||
intent?.removeExtra(PluriWaveAlarmReceiver.EXTRA_ALARM_ACTION)
|
||||
}
|
||||
else -> result.notImplemented()
|
||||
@@ -109,12 +121,23 @@ class MainActivity : AudioServiceActivity() {
|
||||
when (call.method) {
|
||||
"openDirectory" -> {
|
||||
val path = call.argument<String>("path")
|
||||
Log.d(tag, "file_actions.openDirectory path=$path")
|
||||
if (path.isNullOrBlank()) {
|
||||
result.success(false)
|
||||
} else {
|
||||
result.success(openDirectory(path))
|
||||
}
|
||||
}
|
||||
"openFile" -> {
|
||||
val path = call.argument<String>("path")
|
||||
val mimeType = call.argument<String>("mimeType") ?: "audio/*"
|
||||
Log.d(tag, "file_actions.openFile path=$path mimeType=$mimeType")
|
||||
if (path.isNullOrBlank()) {
|
||||
result.success(false)
|
||||
} else {
|
||||
result.success(openFile(path, mimeType))
|
||||
}
|
||||
}
|
||||
else -> result.notImplemented()
|
||||
}
|
||||
}
|
||||
@@ -125,6 +148,7 @@ class MainActivity : AudioServiceActivity() {
|
||||
setIntent(intent)
|
||||
val payload = alarmPayload(intent)
|
||||
if (payload.isNotEmpty()) {
|
||||
Log.d(tag, "alarm.channel onNewIntent payload=$payload")
|
||||
alarmMethodChannel?.invokeMethod("alarmFired", payload)
|
||||
}
|
||||
}
|
||||
@@ -156,14 +180,46 @@ class MainActivity : AudioServiceActivity() {
|
||||
}
|
||||
return try {
|
||||
startActivity(intent)
|
||||
Log.d(tag, "file_actions.openDirectory launched path=$path")
|
||||
true
|
||||
} catch (_: ActivityNotFoundException) {
|
||||
Log.w(tag, "file_actions.openDirectory no activity for path=$path")
|
||||
false
|
||||
} catch (_: Throwable) {
|
||||
} catch (error: Throwable) {
|
||||
Log.e(tag, "file_actions.openDirectory failed path=$path", error)
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
private fun openFile(path: String, mimeType: String): Boolean {
|
||||
val file = File(path)
|
||||
if (!file.exists()) {
|
||||
Log.w(tag, "file_actions.openFile missing path=$path")
|
||||
return false
|
||||
}
|
||||
return try {
|
||||
val uri = FileProvider.getUriForFile(
|
||||
this,
|
||||
"$packageName.fileprovider",
|
||||
file
|
||||
)
|
||||
val intent = Intent(Intent.ACTION_VIEW).apply {
|
||||
setDataAndType(uri, mimeType)
|
||||
clipData = ClipData.newUri(contentResolver, "recording", uri)
|
||||
addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
|
||||
}
|
||||
startActivity(Intent.createChooser(intent, "Abrir grabación"))
|
||||
Log.d(tag, "file_actions.openFile launched path=$path")
|
||||
true
|
||||
} catch (_: ActivityNotFoundException) {
|
||||
Log.w(tag, "file_actions.openFile no viewer path=$path; opening parent")
|
||||
openDirectory(file.parentFile?.absolutePath ?: path)
|
||||
} catch (error: Throwable) {
|
||||
Log.e(tag, "file_actions.openFile failed path=$path; opening parent", error)
|
||||
openDirectory(file.parentFile?.absolutePath ?: path)
|
||||
}
|
||||
}
|
||||
|
||||
private fun directoryTreeUri(path: String): Uri? {
|
||||
val external = Environment.getExternalStorageDirectory()?.absolutePath ?: return null
|
||||
if (!path.startsWith(external)) return null
|
||||
|
||||
@@ -7,13 +7,18 @@ import android.content.BroadcastReceiver
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.os.Build
|
||||
import android.util.Log
|
||||
import androidx.core.app.NotificationCompat
|
||||
import androidx.core.app.NotificationManagerCompat
|
||||
|
||||
class PluriWaveAlarmReceiver : BroadcastReceiver() {
|
||||
override fun onReceive(context: Context, intent: Intent) {
|
||||
val alarmId = intent.getStringExtra(EXTRA_ALARM_ID) ?: return
|
||||
val alarmId = intent.getStringExtra(EXTRA_ALARM_ID) ?: run {
|
||||
Log.w(TAG, "alarm.receiver missing alarmId action=${intent.action}")
|
||||
return
|
||||
}
|
||||
val title = intent.getStringExtra(EXTRA_ALARM_TITLE) ?: "PluriWave"
|
||||
Log.d(TAG, "alarm.receiver action=${intent.action} id=$alarmId title=$title")
|
||||
|
||||
when (intent.action) {
|
||||
ACTION_FIRE -> {
|
||||
@@ -24,7 +29,12 @@ class PluriWaveAlarmReceiver : BroadcastReceiver() {
|
||||
putExtra(EXTRA_ALARM_ACTION, ACTION_FIRE)
|
||||
}
|
||||
showFireNotification(context, alarmId, title, launch)
|
||||
context.startActivity(launch)
|
||||
try {
|
||||
context.startActivity(launch)
|
||||
Log.d(TAG, "alarm.receiver fire startActivity OK id=$alarmId")
|
||||
} catch (error: Throwable) {
|
||||
Log.e(TAG, "alarm.receiver fire startActivity ERROR id=$alarmId", error)
|
||||
}
|
||||
}
|
||||
ACTION_PRE_NOTICE -> {
|
||||
showPreNoticeNotification(context, alarmId, title)
|
||||
@@ -37,8 +47,14 @@ class PluriWaveAlarmReceiver : BroadcastReceiver() {
|
||||
putExtra(EXTRA_ALARM_TITLE, title)
|
||||
putExtra(EXTRA_ALARM_ACTION, ACTION_SKIP_NEXT)
|
||||
}
|
||||
context.startActivity(launch)
|
||||
try {
|
||||
context.startActivity(launch)
|
||||
Log.d(TAG, "alarm.receiver skipNext startActivity OK id=$alarmId")
|
||||
} catch (error: Throwable) {
|
||||
Log.e(TAG, "alarm.receiver skipNext startActivity ERROR id=$alarmId", error)
|
||||
}
|
||||
}
|
||||
else -> Log.w(TAG, "alarm.receiver unknown action=${intent.action} id=$alarmId")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -72,7 +88,9 @@ class PluriWaveAlarmReceiver : BroadcastReceiver() {
|
||||
fireNotificationIdForAlarm(alarmId),
|
||||
notification,
|
||||
)
|
||||
} catch (_: SecurityException) {
|
||||
Log.d(TAG, "alarm.notification fire shown id=$alarmId")
|
||||
} catch (error: SecurityException) {
|
||||
Log.e(TAG, "alarm.notification fire SecurityException id=$alarmId", error)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -114,7 +132,12 @@ class PluriWaveAlarmReceiver : BroadcastReceiver() {
|
||||
.addAction(0, "Omitir siguiente", skipNextIntent)
|
||||
.build()
|
||||
|
||||
NotificationManagerCompat.from(context).notify(notificationIdForAlarm(alarmId), notification)
|
||||
try {
|
||||
NotificationManagerCompat.from(context).notify(notificationIdForAlarm(alarmId), notification)
|
||||
Log.d(TAG, "alarm.notification preNotice shown id=$alarmId")
|
||||
} catch (error: SecurityException) {
|
||||
Log.e(TAG, "alarm.notification preNotice SecurityException id=$alarmId", error)
|
||||
}
|
||||
}
|
||||
|
||||
private fun ensureFireChannel(context: Context) {
|
||||
@@ -155,6 +178,7 @@ class PluriWaveAlarmReceiver : BroadcastReceiver() {
|
||||
private fun requestCode(id: String, slot: Int): Int = 47 * id.hashCode() + slot
|
||||
|
||||
companion object {
|
||||
const val TAG = "PluriWave"
|
||||
const val CHANNEL_ID = "pluriwave_alarm_pre_notice"
|
||||
const val FIRE_CHANNEL_ID = "pluriwave_alarm_fire"
|
||||
const val ACTION_FIRE = "es.freetimelab.pluriwave.alarm.FIRE"
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<paths xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<files-path
|
||||
name="files"
|
||||
path="." />
|
||||
<cache-path
|
||||
name="cache"
|
||||
path="." />
|
||||
<external-files-path
|
||||
name="external_files"
|
||||
path="." />
|
||||
<external-cache-path
|
||||
name="external_cache"
|
||||
path="." />
|
||||
</paths>
|
||||
Reference in New Issue
Block a user