package org.pyneo.tabulae;
import android.os.Build;
import org.pyneo.thinstore.StoreObject;
import android.app.Activity;
import android.app.FragmentManager;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.app.FragmentTransaction;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.os.StatFs;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.WindowManager;
import android.widget.Toast;
import java.io.File;
import java.io.IOException;
import java.util.Date;
import java.util.Locale;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;
import org.mapsforge.core.model.LatLong;
import org.mapsforge.map.android.graphics.AndroidGraphicFactory;
import org.mapsforge.map.android.view.MapView;
import org.pyneo.tabulae.fawlty.Fawlty;
import org.pyneo.tabulae.gui.Controller;
import org.pyneo.tabulae.gui.Dashboard;
import org.pyneo.tabulae.gui.DocumentAvtivity;
import org.pyneo.tabulae.locus.Locus;
import org.pyneo.tabulae.map.Map;
import org.pyneo.tabulae.traffic.Traffic;
import org.pyneo.tabulae.poi.Poi;
import org.pyneo.tabulae.screencapture.ScreenCaptureFragment;
import org.pyneo.tabulae.track.Track;
import org.pyneo.tabulae.poi.PoiItem;
import org.pyneo.tabulae.track.TrackItem;
import org.pyneo.tabulae.track.TrackPointItem;
import static org.pyneo.tabulae.Constants.*;
public class Tabulae extends Activity {
protected Base[] fragments;
protected Menu menu;
protected File baseStorageFile = null;
protected ExecutorService mThreadPool = Executors.newSingleThreadExecutor(new ThreadFactory() {
@Override
public Thread newThread(Runnable r) {
return new Thread(r, "inform");
}
});
SQLiteOpenHelper dbHelper;
static private String deKay(long l) {
double d = l;
final String[] fs = new String[]{"%.2fB", "%.2fKB", "%.2fMB", "%.2fGB",};
for (String f : fs) {
if (d < 1024.0) {
return String.format(Locale.US, f, d);
}
d /= 1024.0;
}
return String.format(Locale.US, "%.2fTB", d);
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (DEBUG) Log.d(TAG, "Tabulae.onCreate");
Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
@Override
public void uncaughtException(Thread thread, Throwable e) {
Log.e(TAG, "error e=" + e, e);
finish();
}
});
dbHelper = new SQLiteOpenHelper(getApplicationContext(), "tabulae.db", null, 3){
@Override public void onCreate(SQLiteDatabase db) {
if (DEBUG) Log.d(TAG, "Tabulae.onCreate.SQLiteOpenHelper.onCreate");
//Log.d(TAG, "create=" +
StoreObject.create(db, PoiItem.class);
StoreObject.create(db, TrackItem.class);
StoreObject.create(db, TrackPointItem.class);
}
@Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
if (DEBUG) Log.d(TAG, "Tabulae.onCreate.SQLiteOpenHelper.onUpgrade");
StoreObject.alter(db, PoiItem.class);
StoreObject.alter(db, TrackItem.class);
StoreObject.alter(db, TrackPointItem.class);
}
};
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
setContentView(R.layout.tabulae);
fragments = new Base[]{
new Map(),
new Track(),
new Poi(),
new Fawlty(),
new Locus(),
new Controller(),
new Dashboard(),
new ScreenCaptureFragment(),
new Traffic(),
};
//noinspection StatementWithEmptyBody
if (savedInstanceState != null) {
// .. = savedInstanceState.getString("..", null);
}
SharedPreferences preferences = getPreferences(MODE_PRIVATE);
String baseStorage = preferences.getString("baseStorage", null);
Log.d(TAG, "Tabulae.onCreate preferences baseStorage=" + baseStorage);
if (baseStorage != null) {
baseStorageFile = new File(baseStorage);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
if (!Environment.getExternalStorageState(baseStorageFile).equals(Environment.MEDIA_MOUNTED)) {
Log.e(TAG, "Tabulae.onCreate not mounted: baseStorage=" + baseStorage);
Toast.makeText(this, "Storage gone! Please reinsert SD.", Toast.LENGTH_LONG).show();
// TODO: ask for different storage
finish();
}
}
}
long baseStorageSpace = 0;
if (baseStorageFile == null) {
// look for the largest storage to begin with
for (File dir : getApplicationContext().getExternalFilesDirs(null)) {
Log.d(TAG, "Tabulae.onCreate getExternalFilesDirs baseStorage=" + baseStorage);
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP
|| dir != null && Environment.getExternalStorageState(dir).equals(Environment.MEDIA_MOUNTED)) {
long dirSpace = new StatFs(dir.getPath()).getAvailableBytes();
if (dirSpace > baseStorageSpace) {
baseStorageFile = dir;
baseStorageSpace = dirSpace;
}
}
}
Editor editor = preferences.edit();
editor.putString("baseStorage", baseStorage);
editor.apply();
} else {
baseStorageSpace = new StatFs(baseStorageFile.getPath()).getAvailableBytes();
}
Log.d(TAG, "Tabulae.onCreate using baseStorageFile=" + baseStorageFile + ", baseStorageSpace=" + deKay(baseStorageSpace));
final Intent queryIntent = getIntent();
final String queryAction = queryIntent.getAction();
if (DEBUG)
Log.d(TAG, "Tabulae.onCreate process intent=" + queryIntent + ", action=" + queryAction);
//noinspection StatementWithEmptyBody
if (Intent.ACTION_MAIN.equals(queryAction)) {
// nothing more to do
} else if (ACTION_CONVERSATIONS_REQUEST.equals(queryAction)) {
String package_ = getCallingPackage();
String activity = getCallingActivity().flattenToString();
if (DEBUG)
Log.d(TAG, "Tabulae.onCreate package_=" + package_ + ", activity=" + activity);
//Bundle extra = queryIntent.getExtras();
MapView mapView = getMapView();
if (mapView == null) {
setResult(Activity.RESULT_CANCELED, null);
} else {
LatLong location = mapView.getModel().mapViewPosition.getCenter(); // TODO defere location determination?
Intent result = new Intent();
result.putExtra(LATITUDE, location.latitude);
result.putExtra(LONGITUDE, location.longitude);
//result.putExtra(ALTITUDE, .getAltitude());
//result.putExtra(ACCURACY, .getAccuracy());
setResult(Activity.RESULT_OK, result);
}
finish();
} else if (ACTION_CONVERSATIONS_SHOW.equals(queryAction)) {
Bundle extra = queryIntent.getExtras();
if (extra.containsKey(LONGITUDE) && extra.containsKey(LATITUDE)) {
String jid = extra.getString(JID);
String name = extra.getString(NAME);
if (name == null || name.length() == 0) {
if (jid != null && jid.length() > 0) {
name = jid.split("@")[0]; // TODO avoid regex
} else {
name = "Jabber";
jid = "@xmpp";
}
}
double latitude = extra.getDouble(LATITUDE, 0);
double longitude = extra.getDouble(LONGITUDE, 0);
long id = Poi.storePointPosition(this, jid, name + ", on " + new Date(), latitude, longitude, true);
Log.w(TAG, "onCreate.ACTION_CONVERSATIONS_SHOW id=" + id);
} else
Log.w(TAG, "onCreate conversations intent recceived with no latitude/longitude");
} else if (Intent.ACTION_VIEW.equalsIgnoreCase(queryAction)) {
try {
//List<ActivityManager.RecentTaskInfo> recentTasks = ((ActivityManager)getSystemService(ACTIVITY_SERVICE)).getRecentTasks(99, ActivityManager.RECENT_WITH_EXCLUDED);
Uri uri = queryIntent.getData();
if (uri.getScheme().equalsIgnoreCase(GEO)) {
final String part = uri.getEncodedSchemeSpecificPart().split("\\?")[0];
final String[] latlon = part.split(","); // TODO avoid regex
Bundle extra = new Bundle();
extra.putDouble(LATITUDE, Double.parseDouble(latlon[0]));
extra.putDouble(LONGITUDE, Double.parseDouble(latlon[1]));
extra.putString(NAME, "poi");
extra.putString(DESCRIPTION, "shared poi");
if (DEBUG) Log.d(TAG, "Tabulae.onCreate new poi extra=" + extra);
asyncInform(R.id.event_do_poi_new, extra);
}
}
catch (Exception e) {
Log.e(TAG, "Tabulae.onCreate", e);
// Toast?
}
} else
Log.e(TAG, "Tabulae.onCreate no fit action=" + queryAction);
}
@Override
protected void onStart() {
super.onStart();
if (DEBUG) Log.d(TAG, "Tabulae.onStart");
}
@Override
protected void onRestart() {
super.onRestart();
if (DEBUG) Log.d(TAG, "Tabulae.onRestart");
}
@Override
protected void onResume() {
super.onResume();
if (DEBUG) Log.d(TAG, "Tabulae.onResume");
FragmentManager fragmentManager = getFragmentManager();
for (Base b : fragments) {
FragmentTransaction tx = fragmentManager.beginTransaction();
//if (DEBUG) Log.d(TAG, "Tabulae.onResume b=" + b.getClass().getSimpleName());
tx.add(R.id.tabulae, b, b.getClass().getSimpleName());
tx.commit();
}
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent resultData) {
if (DEBUG)
Log.d(TAG, "Tabulae.onActivityResult resultCode=" + resultCode + ", requestCode=" + requestCode);
for (Base b : fragments) {
b.onActivityResult(requestCode, resultCode, resultData);
}
}
@Override
protected void onPause() {
super.onPause();
if (DEBUG) Log.d(TAG, "Tabulae.onPause");
FragmentManager fragmentManager = getFragmentManager();
FragmentTransaction tx = fragmentManager.beginTransaction();
for (Base b : fragments) {
tx.remove(b);
}
tx.commit();
}
@Override
protected void onStop() {
super.onStop();
if (DEBUG) Log.d(TAG, "Tabulae.onStop");
}
@Override
protected void onDestroy() {
super.onDestroy();
if (DEBUG) Log.d(TAG, "Tabulae.onDestroy");
AndroidGraphicFactory.clearResourceMemoryCache();
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
getMenuInflater().inflate(R.menu.main_option_menu, menu);
this.menu = menu;
if (DEBUG) {
menu.findItem(R.id.event_do_screencapture).setVisible(true);
menu.findItem(R.id.event_do_fawlty).setVisible(true);
menu.findItem(R.id.event_do_traffic).setVisible(true);
}
for (int e: new int[]{
R.id.event_request_dashboard,
R.id.event_request_fawlty,
R.id.event_request_screencapture,
R.id.event_request_traffic,
}) {
inform(e, null);
}
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
super.onOptionsItemSelected(item);
inform(item.getItemId(), null);
return true;
}
@Override
protected void onSaveInstanceState(Bundle bundle) {
super.onSaveInstanceState(bundle);
if (DEBUG) Log.d(TAG, "Tabulae.onSaveInstanceState bundle=" + bundle);
// bundle.putString("..", ..);
}
/**
* directory for storage
*/
public File getBaseDir() {
return baseStorageFile;
}
/**
* directory for gpx exchange
*/
public File getGpxDir() {
File ret = new File(baseStorageFile, "gpx");
//noinspection ResultOfMethodCallIgnored
ret.mkdirs();
return ret;
}
/**
* directory for the tiles(cache)
*/
public File getTilesDir() {
File ret = new File(baseStorageFile, "tiles");
//noinspection ResultOfMethodCallIgnored
ret.mkdirs();
return ret;
}
/**
* directory for the mapsforge map files
*/
public File getMapsDir() {
File ret = new File(baseStorageFile, "maps");
//noinspection ResultOfMethodCallIgnored
ret.mkdirs();
return ret;
}
/**
* directory for the screen movies
*/
public File getMoviesDir() {
File ret = new File(baseStorageFile, "movies");
//noinspection ResultOfMethodCallIgnored
ret.mkdirs();
return ret;
}
public SQLiteDatabase getWritableDatabase() {
return dbHelper.getWritableDatabase();
}
public SQLiteDatabase getReadableDatabase() {
return dbHelper.getReadableDatabase();
}
public MapView getMapView() {
return ((Map) fragments[0]).getMapView();
}
public void inform(final int event, final Bundle extra) {
switch (event) {
case R.id.event_do_help:
Intent intent = new Intent(this, DocumentAvtivity.class);
String lang = getResources().getConfiguration().locale.getLanguage();
Bundle extras = new Bundle();
String path = "documents-" + lang;
try {
if (getResources().getAssets().list(path).length == 0) {
throw new IOException();
}
}
catch (IOException ignore) {
path = "documents";
}
// TODO check if exists and fallback
extras.putString("url", "file:///android_asset/" + path + "/index.html");
intent.putExtras(extras);
startActivity(intent);
break;
case R.id.event_notify_screencapture:
if (menu != null) {
menu.findItem(R.id.event_do_screencapture).setChecked(extra.getBoolean("enabled"));
}
break;
case R.id.event_notify_fawlty:
if (menu != null) {
menu.findItem(R.id.event_do_fawlty).setChecked(extra.getBoolean("enabled"));
}
break;
case R.id.event_notify_traffic:
if (menu != null) {
menu.findItem(R.id.event_do_traffic).setChecked(extra.getBoolean("enabled"));
}
break;
case R.id.event_notify_dashboard:
if (menu != null) {
menu.findItem(R.id.event_do_dashboard).setChecked(extra.getBoolean("enabled"));
}
break;
}
for (Base b : fragments) {
b.inform(event, extra);
}
}
public void asyncInform(final int event, final Bundle extra) {
this.mThreadPool.execute(new Runnable() {
public void run() {
runOnUiThread(new Runnable() {
public void run() {
inform(event, extra);
}
});
}
});
}
}