package org.emdev.common.filesystem;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.Uri;
import android.os.Bundle;
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import org.emdev.common.log.LogContext;
import org.emdev.common.log.LogManager;
import org.emdev.utils.listeners.ListenerProxy;
public class MediaManager extends BroadcastReceiver {
private static final LogContext LCTX = LogManager.root().lctx("MediaManager");
public static final ListenerProxy listeners = new ListenerProxy(Listener.class);
private static final Map<String, ExternalMedia> mountedMedia = new TreeMap<String, ExternalMedia>();
private static final MediaManager instance = new MediaManager();
private MediaManager() {
}
public static void init(final Context context) {
readMounts();
context.registerReceiver(instance, createIntentFilter());
}
static void readMounts() {
try {
final BufferedReader in = new BufferedReader(new FileReader("/proc/mounts"));
try {
for (String s = in.readLine(); s != null; s = in.readLine()) {
processMountPoint(s);
}
} catch (final IOException ex) {
LCTX.e("Reading mounting points failed: " + ex.getMessage());
} finally {
try {
in.close();
} catch (final IOException ex) {
}
}
} catch (final FileNotFoundException ex) {
LCTX.e("Reading mounting points failed: " + ex.getMessage());
}
}
static void processMountPoint(final String s) {
try {
final MountedDevice d = new MountedDevice(s);
if (filterDeviceName(d) && filterMountPath(d)) {
final boolean rw = d.params.containsKey("rw");
setMediaState(d.point, rw ? MediaState.MEDIA_MOUNTED : MediaState.MEDIA_MOUNTED_READ_ONLY);
}
} catch (final IllegalArgumentException th) {
LCTX.w(th.getMessage());
}
}
static boolean filterDeviceName(final MountedDevice d) {
return d.device.startsWith("/dev/block/vold");
}
static boolean filterMountPath(final MountedDevice d) {
return !d.point.endsWith("/secure/asec");
}
static IntentFilter createIntentFilter() {
final IntentFilter f = new IntentFilter();
f.addAction(Intent.ACTION_MEDIA_MOUNTED);
f.addAction(Intent.ACTION_MEDIA_SHARED);
f.addAction(Intent.ACTION_MEDIA_EJECT);
f.addAction(Intent.ACTION_MEDIA_BAD_REMOVAL);
f.addAction(Intent.ACTION_MEDIA_UNMOUNTABLE);
f.addAction(Intent.ACTION_MEDIA_UNMOUNTED);
f.addDataScheme("file");
return f;
}
public static void onTerminate(final Context context) {
context.unregisterReceiver(instance);
}
@Override
public void onReceive(final Context context, final Intent intent) {
final String action = intent.getAction();
if (Intent.ACTION_MEDIA_MOUNTED.equals(action)) {
final Uri data = intent.getData();
final String path = PathFromUri.retrieve(context.getContentResolver(), data);
final Bundle extras = intent.getExtras();
final boolean readOnly = extras != null ? extras.getBoolean("read-only") : false;
setMediaState(path, readOnly ? MediaState.MEDIA_MOUNTED : MediaState.MEDIA_MOUNTED_READ_ONLY);
return;
}
if (Intent.ACTION_MEDIA_SHARED.equals(action)) {
final Uri data = intent.getData();
final String path = PathFromUri.retrieve(context.getContentResolver(), data);
setMediaState(path, MediaState.MEDIA_SHARED);
return;
}
if (Intent.ACTION_MEDIA_EJECT.equals(action)) {
final Uri data = intent.getData();
final String path = PathFromUri.retrieve(context.getContentResolver(), data);
setMediaState(path, MediaState.MEDIA_REMOVED);
return;
}
if (Intent.ACTION_MEDIA_BAD_REMOVAL.equals(action)) {
final Uri data = intent.getData();
final String path = PathFromUri.retrieve(context.getContentResolver(), data);
setMediaState(path, MediaState.MEDIA_BAD_REMOVAL);
return;
}
if (Intent.ACTION_MEDIA_UNMOUNTABLE.equals(action)) {
final Uri data = intent.getData();
final String path = PathFromUri.retrieve(context.getContentResolver(), data);
setMediaState(path, MediaState.MEDIA_UNMOUNTABLE);
return;
}
if (Intent.ACTION_MEDIA_UNMOUNTED.equals(action)) {
final Uri data = intent.getData();
final String path = PathFromUri.retrieve(context.getContentResolver(), data);
setMediaState(path, MediaState.MEDIA_UNMOUNTED);
return;
}
}
public static synchronized Collection<String> getReadableMedia() {
final List<String> list = new ArrayList<String>(mountedMedia.size());
for (final ExternalMedia m : MediaManager.mountedMedia.values()) {
if (m.state.readable) {
list.add(m.path);
}
}
return list;
}
static synchronized void setMediaState(final String path, final MediaState newState) {
MediaState oldState = null;
ExternalMedia media = mountedMedia.get(path);
if (media == null) {
media = new ExternalMedia(path, newState);
mountedMedia.put(path, media);
} else {
oldState = media.state;
media.state = newState;
}
final Listener l = listeners.getListener();
LCTX.d(path + " : " + oldState + " -> " + newState);
l.onMediaStateChanged(path, oldState, media.state);
}
public static interface Listener {
void onMediaStateChanged(String path, MediaState oldState, MediaState newState);
}
private static class MountedDevice {
public final String device;
public final String point;
public final Map<String, String> params = new LinkedHashMap<String, String>();
public MountedDevice(final String s) {
final String[] fields = s.split("\\s");
if (fields.length < 4) {
throw new IllegalArgumentException("Bad moint point string: " + s);
}
device = fields[0];
point = fields[1];
final String[] pp = fields[3].split(",");
for (int i = 0; i < pp.length; i++) {
String key = pp[i];
String val = key;
final int index = key.indexOf("=");
if (index != -1) {
key = key.substring(0, index);
val = val.substring(index + 1);
}
params.put(key, val);
}
}
}
}