Skip to content
Snippets Groups Projects
Commit 2e4b8ce9 authored by Geoffrey Métais's avatar Geoffrey Métais
Browse files

Specific broadcast receiver for storage monitoring

parent cb333466
No related branches found
No related tags found
No related merge requests found
......@@ -611,6 +611,18 @@
</intent-filter>
</receiver>
<receiver
android:name=".StoragesMonitor"
android:enabled="false"
android:exported="true" >
<intent-filter>
<action android:name="android.intent.action.MEDIA_MOUNTED"/>
<action android:name="android.intent.action.MEDIA_REMOVED"/>
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="file" />
</intent-filter>
</receiver>
<provider
android:authorities="${applicationId}.thumbprovider"
android:name=".FileProvider"
......
......@@ -45,7 +45,6 @@ import kotlinx.coroutines.channels.actor
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import org.videolan.libvlc.util.AndroidUtil
import org.videolan.vlc.gui.DialogActivity
import org.videolan.vlc.gui.helpers.UiTools
import org.videolan.vlc.gui.helpers.hf.OtgAccess
import org.videolan.vlc.util.*
......@@ -69,26 +68,12 @@ object ExternalMonitor : BroadcastReceiver(), LifecycleObserver, CoroutineScope
for (action in channel) when (action){
is MediaMounted -> {
if (TextUtils.isEmpty(action.uuid)) return@actor
if (ProcessLifecycleOwner.get().lifecycle.currentState.isAtLeast(Lifecycle.State.STARTED)) {
if (!Settings.getInstance(ctx).getBoolean("ignore_${action.uuid}", false)) {
val ml = VLCApplication.getMLInstance()
val knownDevices = ctx.getFromMl { devices }
if (!containsDevice(knownDevices, action.path) && ml.addDevice(action.uuid, action.path, true)) {
notifyStorageChanges(action.path)
}
}
} else if (AndroidDevices.watchDevices && action.path.scanAllowed()) {
val knownDevices = ctx.getFromMl { devices }
if (!Settings.getInstance(ctx).getBoolean("ignore_${action.uuid}", false)) {
val ml = VLCApplication.getMLInstance()
val scan = !containsDevice(knownDevices, action.path) && ml.addDevice(action.uuid, action.path, true)
val intent = Intent(ctx, DialogActivity::class.java).apply {
setAction(DialogActivity.KEY_DEVICE)
putExtra(DialogActivity.EXTRA_PATH, action.path)
putExtra(DialogActivity.EXTRA_UUID, action.uuid)
putExtra(DialogActivity.EXTRA_SCAN, scan)
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
val knownDevices = ctx.getFromMl { devices }
if (!containsDevice(knownDevices, action.path) && ml.addDevice(action.uuid, action.path, true)) {
notifyStorageChanges(action.path)
}
ctx.startActivity(intent)
}
}
is MediaUnmounted -> {
......@@ -122,7 +107,7 @@ object ExternalMonitor : BroadcastReceiver(), LifecycleObserver, CoroutineScope
}
}
Intent.ACTION_MEDIA_MOUNTED -> {
if (AndroidDevices.watchDevices || storageObserver != null && storageObserver!!.get() != null) {
if (storageObserver != null && storageObserver!!.get() != null) {
intent.data?.let {
actor.offer(MediaMounted(it))
storagePlugged.postValue(it)
......@@ -131,7 +116,7 @@ object ExternalMonitor : BroadcastReceiver(), LifecycleObserver, CoroutineScope
}
Intent.ACTION_MEDIA_UNMOUNTED,
Intent.ACTION_MEDIA_EJECT -> {
if (AndroidDevices.watchDevices || storageObserver != null && storageObserver!!.get() != null)
if (storageObserver != null && storageObserver!!.get() != null)
intent.data?.let {
actor.offer(MediaUnmounted(it))
storageUnplugged.postValue(it)
......@@ -217,7 +202,6 @@ object ExternalMonitor : BroadcastReceiver(), LifecycleObserver, CoroutineScope
@OnLifecycleEvent(Lifecycle.Event.ON_STOP)
internal fun unregister() {
if (AndroidDevices.watchDevices) return
val ctx = VLCApplication.getAppContext()
ctx.unregisterReceiver(this)
registered = false
......@@ -256,12 +240,12 @@ object ExternalMonitor : BroadcastReceiver(), LifecycleObserver, CoroutineScope
storageObserver = null
}
}
}
fun containsDevice(devices: Array<String>, device: String): Boolean {
if (Util.isArrayEmpty(devices)) return false
for (dev in devices) if (device.startsWith(dev.removeFileProtocole())) return true
return false
}
fun containsDevice(devices: Array<String>, device: String): Boolean {
if (Util.isArrayEmpty(devices)) return false
for (dev in devices) if (device.startsWith(dev.removeFileProtocole())) return true
return false
}
private sealed class DeviceAction
......
......@@ -254,7 +254,7 @@ class MediaParsingService : Service(), DevicesDiscoveryCb, CoroutineScope {
for (device in devices) {
val uuid = FileUtils.getFileNameFromPath(device)
if (TextUtils.isEmpty(device) || TextUtils.isEmpty(uuid) || !device.scanAllowed()) continue
if (ExternalMonitor.containsDevice(knownDevices, device)) {
if (containsDevice(knownDevices, device)) {
missingDevices.remove("file://$device")
continue
}
......
......@@ -86,7 +86,6 @@ public class StartActivity extends FragmentActivity {
final boolean firstRun = savedVersionNumber == -1;
final boolean upgrade = firstRun || savedVersionNumber != currentVersionNumber;
if (upgrade) settings.edit().putInt(Constants.PREF_FIRST_RUN, currentVersionNumber).apply();
FileUtils.copyLua(getApplicationContext(), upgrade);
final boolean tv = showTvUi();
// Route search query
if (Intent.ACTION_SEARCH.equals(action) || "com.google.android.gms.actions.SEARCH_ACTION".equals(action)) {
......@@ -110,6 +109,8 @@ public class StartActivity extends FragmentActivity {
if (target == R.id.ml_menu_last_playlist) PlaybackService.Companion.loadLastAudio(this);
else startApplication(tv, firstRun, upgrade, target);
}
FileUtils.copyLua(getApplicationContext(), upgrade);
if (AndroidDevices.watchDevices) StoragesMonitorKt.enableStorageMonitoring(this);
finish();
}
......
package org.videolan.vlc
import android.content.BroadcastReceiver
import android.content.ComponentName
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
import android.net.Uri
import android.text.TextUtils
import android.util.Log
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.ProcessLifecycleOwner
import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.channels.actor
import kotlinx.coroutines.delay
import org.videolan.medialibrary.Medialibrary
import org.videolan.vlc.gui.DialogActivity
import org.videolan.vlc.util.AppScope
import org.videolan.vlc.util.getFromMl
import org.videolan.vlc.util.scanAllowed
private const val TAG = "VLC/StoragesMonitor"
class StoragesMonitor : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
Log.d(TAG, "onReceive ${intent.action}")
val action = intent.action ?: return
if (ProcessLifecycleOwner.get().lifecycle.currentState.isAtLeast(Lifecycle.State.STARTED)) return
when (action) {
Intent.ACTION_MEDIA_MOUNTED -> intent.data?.let { actor.offer(Mount(context, it)) }
Intent.ACTION_MEDIA_UNMOUNTED -> intent.data?.let { actor.offer(Unmount(context, it)) }
else -> return
}
}
private val actor = AppScope.actor<MediaEvent>(capacity = Channel.UNLIMITED) {
for (action in channel) when (action){
is Mount -> {
if (TextUtils.isEmpty(action.uuid)) return@actor
if (action.path.scanAllowed()) {
val knownDevices = action.ctx.getFromMl { devices }
val ml = Medialibrary.getInstance()
val scan = !containsDevice(knownDevices, action.path) && ml.addDevice(action.uuid, action.path, true)
val intent = Intent(action.ctx, DialogActivity::class.java).apply {
setAction(DialogActivity.KEY_DEVICE)
putExtra(DialogActivity.EXTRA_PATH, action.path)
putExtra(DialogActivity.EXTRA_UUID, action.uuid)
putExtra(DialogActivity.EXTRA_SCAN, scan)
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
}
action.ctx.startActivity(intent)
}
}
is Unmount -> {
delay(100L)
Medialibrary.getInstance().removeDevice(action.uuid, action.path)
}
}
}
}
private sealed class MediaEvent(val ctx: Context)
private class Mount(ctx: Context, val uri : Uri, val path : String = uri.path, val uuid : String = uri.lastPathSegment) : MediaEvent(ctx)
private class Unmount(ctx: Context, val uri : Uri, val path : String = uri.path, val uuid : String = uri.lastPathSegment) : MediaEvent(ctx)
fun Context.enableStorageMonitoring() {
val componentName = ComponentName(applicationContext, StoragesMonitor::class.java)
applicationContext.packageManager.setComponentEnabledSetting(componentName,
PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
PackageManager.DONT_KILL_APP)
}
\ No newline at end of file
......@@ -44,8 +44,8 @@ public class TvReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
final String action = intent.getAction();
Log.d(TAG, "onReceive: "+action);
if (action == null || !AndroidDevices.isAndroidTv) return;
Log.d(TAG, "onReceive: "+action);
switch (action) {
case TvContract.ACTION_INITIALIZE_PROGRAMS:
Log.d(TAG, "onReceive: ACTION_INITIALIZE_PROGRAMS ");
......@@ -69,7 +69,7 @@ public class TvReceiver extends BroadcastReceiver {
case Intent.ACTION_BOOT_COMPLETED:
Log.d(TAG, "onReceive: ACTION_BOOT_COMPLETED ");
if (!AndroidUtil.isOOrLater) scheduleRecommendationUpdate(context);
if (AndroidDevices.watchDevices) ExternalMonitor.INSTANCE.register();
if (AndroidDevices.watchDevices) StoragesMonitorKt.enableStorageMonitoring(context);
break;
}
}
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment