package org.mozilla.osmdroid.tileprovider.modules;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.graphics.drawable.Drawable;
import android.os.Environment;
import org.mozilla.mozstumbler.service.core.logging.ClientLog;
import org.mozilla.mozstumbler.svclocator.services.log.LoggerUtil;
import org.mozilla.osmdroid.tileprovider.IRegisterReceiver;
import org.mozilla.osmdroid.tileprovider.MapTile;
import org.mozilla.osmdroid.tileprovider.tilesource.BitmapTileSourceBase;
import org.mozilla.osmdroid.tileprovider.tilesource.ITileSource;
import org.mozilla.osmdroid.tileprovider.tilesource.TileSourceFactory;
import java.util.concurrent.atomic.AtomicReference;
/**
* This is a fork of the MapTileFilesystemProvider which provides
* etag support as well as honoring Cache-Control headers.
* <p/>
* Note that you will not see concurrency code in here as an
* ExecutorService is implemented in a superclass
* MapTileModuleProviderBase.
*
* @author Victor Ng
* @author Marc Kurtz
* @author Nicolas Gramlich
*/
public class SmartFSProvider extends MapTileModuleProviderBase {
// ===========================================================
// Constants
// ===========================================================
private static final String LOG_TAG = LoggerUtil.makeLogTag(SmartFSProvider.class);
private final IRegisterReceiver mRegisterReceiver;
private final AtomicReference<ITileSource> mTileSource = new AtomicReference<ITileSource>();
/**
* whether the sdcard is mounted read/write
*/
private boolean mSdCardAvailable = true;
// ===========================================================
// Fields
// ===========================================================
private MyBroadcastReceiver mBroadcastReceiver;
private TileDownloaderDelegate delegate;
// ===========================================================
// Constructors
// ===========================================================
public SmartFSProvider(final IRegisterReceiver pRegisterReceiver) {
this(pRegisterReceiver, TileSourceFactory.DEFAULT_TILE_SOURCE);
}
public SmartFSProvider(final IRegisterReceiver pRegisterReceiver,
final ITileSource pTileSource) {
this(pRegisterReceiver,
pTileSource,
NUMBER_OF_IO_THREADS,
TILE_FILESYSTEM_MAXIMUM_QUEUE_SIZE);
}
/**
* Provides a file system based cache tile provider. Other providers can register and store data
* in the cache.
*
* @param pRegisterReceiver
*/
public SmartFSProvider(final IRegisterReceiver pRegisterReceiver,
final ITileSource pTileSource,
int pThreadPoolSize,
int pPendingQueueSize) {
super(pThreadPoolSize, pPendingQueueSize);
checkSdCard();
mRegisterReceiver = pRegisterReceiver;
mBroadcastReceiver = new MyBroadcastReceiver();
final IntentFilter mediaFilter = new IntentFilter();
mediaFilter.addAction(Intent.ACTION_MEDIA_MOUNTED);
mediaFilter.addAction(Intent.ACTION_MEDIA_UNMOUNTED);
mediaFilter.addDataScheme("file");
pRegisterReceiver.registerReceiver(mBroadcastReceiver, mediaFilter);
setTileSource(pTileSource);
}
// ===========================================================
// Getter & Setter
// ===========================================================
public boolean hasDelegate() {
return delegate != null;
}
public Drawable downloadTile(SerializableTile serializableTile, ITileSource tileSource, MapTile tile) throws BitmapTileSourceBase.LowMemoryException {
return delegate.downloadTile(serializableTile, tileSource, tile);
}
public void configureDelegate(TileDownloaderDelegate d) {
delegate = d;
}
public ITileSource getTileSource() {
return mTileSource.get();
}
// ===========================================================
// Methods from SuperClass/Interfaces
// ===========================================================
@Override
public void setTileSource(final ITileSource pTileSource) {
mTileSource.set(pTileSource);
}
@Override
public boolean getUsesDataConnection() {
return true;
}
@Override
protected String getName() {
return "SmartFSProvider";
}
@Override
protected String getThreadGroupName() {
return "smartFsProvider";
}
@Override
protected Runnable getTileLoader() {
// @TODO vng: this is called far up the inheritance chain in super class
// MapTileModuleProviderBase::loadMapTileAsync(...). This
// whole class hierarchy should be squashed down.
return new SmartFSTileLoader(this);
}
@Override
public int getMinimumZoomLevel() {
ITileSource tileSource = mTileSource.get();
return tileSource != null ? tileSource.getMinimumZoomLevel() : MINIMUM_ZOOMLEVEL;
}
@Override
public int getMaximumZoomLevel() {
ITileSource tileSource = mTileSource.get();
return tileSource != null ? tileSource.getMaximumZoomLevel() : MAXIMUM_ZOOMLEVEL;
}
// ===========================================================
// Inner and Anonymous Classes
// ===========================================================
// Stuff from superclass
void checkSdCard() {
final String state = Environment.getExternalStorageState();
ClientLog.d(LOG_TAG, "sdcard state: " + state);
mSdCardAvailable = Environment.MEDIA_MOUNTED.equals(state);
}
protected boolean getSdCardAvailable() {
return mSdCardAvailable;
}
protected void onMediaMounted() {
// Do nothing by default. Override to handle.
}
protected void onMediaUnmounted() {
// Do nothing by default. Override to handle.
}
@Override
public void detach() {
if (mBroadcastReceiver != null) {
mRegisterReceiver.unregisterReceiver(mBroadcastReceiver);
mBroadcastReceiver = null;
}
super.detach();
}
/**
* This broadcast receiver will recheck the sd card when the mount/unmount messages happen
*/
private class MyBroadcastReceiver extends BroadcastReceiver {
@Override
public void onReceive(final Context aContext, final Intent aIntent) {
final String action = aIntent.getAction();
checkSdCard();
if (Intent.ACTION_MEDIA_MOUNTED.equals(action)) {
onMediaMounted();
} else if (Intent.ACTION_MEDIA_UNMOUNTED.equals(action)) {
onMediaUnmounted();
}
}
}
}