/* * This file is part of WhereYouGo. * * WhereYouGo is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * WhereYouGo is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with WhereYouGo. If not, see <http://www.gnu.org/licenses/>. * * Copyright (C) 2012 Menion <whereyougo@asamm.cz> */ package menion.android.whereyougo.gui.extension; import java.io.File; import java.io.InputStream; import java.io.StringReader; import menion.android.whereyougo.R; import menion.android.whereyougo.hardware.location.LocationState; import menion.android.whereyougo.settings.Loc; import menion.android.whereyougo.settings.Settings; import menion.android.whereyougo.utils.A; import menion.android.whereyougo.utils.FileSystem; import menion.android.whereyougo.utils.Logger; import menion.android.whereyougo.utils.Utils; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserFactory; import android.Manifest; import android.app.ActivityManager; import android.app.AlertDialog; import android.content.DialogInterface; import android.content.Intent; import android.net.Uri; import android.os.Bundle; import android.os.Debug; import android.os.StatFs; import android.view.KeyEvent; public abstract class CustomMain extends CustomActivity { private static final String TAG = "CustomMain"; // create directories during startup protected static String[] DIRS = new String[] { FileSystem.CACHE }; private static boolean callSecondInit; private static boolean callRegisterOnly; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); A.registerMain(this); callSecondInit = false; callRegisterOnly = false; if (A.getApp() == null) { // first app run //Logger.w(TAG, "onCreate() - init new"); A.registerApp((MainApplication) getApplication()); // not test some things if (testFileSystem() && testFreeSpace()) { // set last known location if (Utils.isPermissionAllowed(Manifest.permission.ACCESS_FINE_LOCATION) && Settings.getPrefBoolean(Settings.KEY_B_START_GPS_AUTOMATICALLY, Settings.DEFAULT_START_GPS_AUTOMATICALLY)) { LocationState.setGpsOn(CustomMain.this); } else { LocationState.setGpsOff(CustomMain.this); } eventFirstInit(); Settings.setScreenBasic(this); eventCreateLayout(); callSecondInit = true; } else { // do nothing, just close APP } } else { //Logger.w(TAG, "onCreate() - only register"); Settings.setScreenBasic(this); eventCreateLayout(); callRegisterOnly = true; } } public void onResumeExtra() { if (callSecondInit) { callSecondInit = false; eventSecondInit(); } if (callRegisterOnly) { callRegisterOnly = false; eventRegisterOnly(); } } private boolean testFileSystem() { if (DIRS == null || DIRS.length == 0) return true; if (FileSystem.createRoot(MainApplication.APP_NAME)) { //Logger.w(TAG, "FileSystem succesfully created!"); } else { //Logger.w(TAG, "FileSystem cannot be created!"); UtilsGUI.showDialogError(CustomMain.this, R.string.filesystem_cannot_create_root, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { showDialogFinish(FINISH_EXIT_FORCE); } }); return false; } // fileSystem created successfully for (int i = 0; i < DIRS.length; i++) { (new File(FileSystem.ROOT + DIRS[i])).mkdirs(); } return true; } private boolean testFreeSpace() { if (DIRS == null || DIRS.length == 0) return true; // check disk space (at least 5MB) StatFs stat = new StatFs(FileSystem.ROOT); long bytesFree = (long) stat.getBlockSize() *(long) stat.getAvailableBlocks(); long megFree = bytesFree / 1048576; //Logger.d(TAG, "megAvailable:" + megAvail + ", free:" + megFree); if (megFree > 0 && megFree < 5) { UtilsGUI.showDialogError(CustomMain.this, getString(R.string.not_enough_disk_space_x, FileSystem.ROOT, megFree + "MB"), new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { showDialogFinish(FINISH_EXIT_FORCE); } }); return false; } return true; } @Override public void onDestroy() { if (finish) { // stop debug if any forgotten Debug.stopMethodTracing(); // remember value before A.getApp() exist boolean clearPackageAllowed = Utils.isPermissionAllowed(Manifest.permission.KILL_BACKGROUND_PROCESSES); // call individual app close eventDestroyApp(); // disable highlight Settings.disableWakeLock(); // save last known location Settings.setLastKnownLocation(); // disable GPS modul LocationState.destroy(CustomMain.this); // destroy static references A.destroy(); // call native destroy super.onDestroy(); // remove app from memory if (clearPackageAllowed) { clearPackageFromMemory(); // XXX not work on 2.2 and higher!!! } } else { super.onDestroy(); } } public static final int FINISH_NONE = -1; public static final int FINISH_EXIT = 0; public static final int FINISH_EXIT_FORCE = 1; public static final int FINISH_RESTART = 2; public static final int FINISH_RESTART_FORCE = 3; public static final int FINISH_RESTART_FACTORY_RESET = 4; public static final int FINISH_REINSTALL = 5; private boolean finish = false; protected int finishType = FINISH_NONE; public void showDialogFinish(final int typeOfFinish) { //Logger.d(TAG, "showFinishDialog(" + typeOfFinish + ")"); if (typeOfFinish == FINISH_NONE) return; this.finishType = typeOfFinish; runOnUiThread(new Runnable() { public void run() { String title = Loc.get(R.string.question); String message = ""; boolean cancelable = ( finishType == FINISH_RESTART_FORCE || finishType == FINISH_RESTART_FACTORY_RESET || finishType == FINISH_REINSTALL || finishType == FINISH_EXIT_FORCE) ? false : true; switch (finishType) { case FINISH_EXIT: message = Loc.get(R.string.do_you_really_want_to_exit); break; case FINISH_EXIT_FORCE: title = Loc.get(R.string.info); message = Loc.get(R.string.you_have_to_exit_app_force); break; case FINISH_RESTART: message = Loc.get(R.string.you_have_to_restart_app_recommended); break; case FINISH_RESTART_FORCE: title = Loc.get(R.string.info); message = Loc.get(R.string.you_have_to_restart_app_force); break; case FINISH_RESTART_FACTORY_RESET: title = Loc.get(R.string.info); message = Loc.get(R.string.you_have_to_restart_app_force); break; case FINISH_REINSTALL: title = Loc.get(R.string.info); message = Loc.get(R.string.new_version_will_be_installed); break; } AlertDialog.Builder b = new AlertDialog.Builder(CustomMain.this); b.setCancelable(cancelable); b.setTitle(title); b.setIcon(R.drawable.ic_question_alt); b.setMessage(message); b.setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { if (finishType == FINISH_EXIT || finishType == FINISH_EXIT_FORCE) { finish = true; CustomMain.this.finish(); } else if (finishType == FINISH_RESTART || finishType == FINISH_RESTART_FORCE || finishType == FINISH_RESTART_FACTORY_RESET) { // Setup one-short alarm to restart my application in 3 seconds - TODO need use another context // AlarmManager alarmMgr = (AlarmManager) getSystemService(Context.ALARM_SERVICE); // Intent intent = new Intent(APP_INTENT_MAIN); // PendingIntent pi = PendingIntent.getBroadcast(CustomMain.this, 0, intent, PendingIntent.FLAG_ONE_SHOT); // alarmMgr.set(AlarmManager.ELAPSED_REALTIME, System.currentTimeMillis() + 3000, pi); finish = true; CustomMain.this.finish(); } else if (finishType == FINISH_REINSTALL) { Intent intent = new Intent(); intent.setAction(android.content.Intent.ACTION_VIEW); intent.setDataAndType(Uri.fromFile(new File(FileSystem.ROOT + "smartmaps.apk")), "application/vnd.android.package-archive"); startActivity(intent); showDialogFinish(FINISH_EXIT_FORCE); } } }); if (cancelable) { b.setNegativeButton(R.string.cancel, null); } b.show(); } }); } public void finishForceSilent() { finish = true; CustomMain.this.finish(); } private void clearPackageFromMemory() { new Thread(new Runnable() { public void run() { try { ActivityManager aM = (ActivityManager) getApplicationContext().getSystemService(ACTIVITY_SERVICE); Thread.sleep(1250); aM.killBackgroundProcesses(getPackageName()); } catch (Exception e) { Logger.e(TAG, "clearPackageFromMemory()", e); } } }).start(); } @Override public boolean dispatchKeyEvent(KeyEvent event) { //Logger.d(TAG, "dispatchKeyEvent(" + event.getAction() + ", " + event.getKeyCode() + ")"); if (event.getAction() == KeyEvent.ACTION_DOWN && event.getKeyCode() == KeyEvent.KEYCODE_BACK) { switch (getCloseValue()) { case CLOSE_DESTROY_APP_NO_DIALOG: finish = true; CustomMain.this.finish(); return true; case CLOSE_DESTROY_APP_DIALOG_NO_TEXT: showDialogFinish(FINISH_EXIT); return true; case CLOSE_DESTROY_APP_DIALOG_ADDITIONAL_TEXT: showDialogFinish(FINISH_EXIT); return true; case CLOSE_HIDE_APP: // no action break; } } return super.dispatchKeyEvent(event); } public static String loadAssetString(String name) { InputStream is = null; try { is = A.getMain().getAssets().open(name); int size = is.available(); byte[] buffer = new byte[size]; is.read(buffer); is.close(); return new String(buffer); } catch (Exception e) { Logger.e(TAG, "loadAssetString(" + name + ")", e); return ""; } finally { Utils.closeStream(is); } } public static String getNewsFromTo(int lastVersion, int actualVersion) { //Logger.d(TAG, "getNewsFromTo(" + lastVersion + ", " + actualVersion + "), file:" + // "news_" + (Const.isPro() ? "pro" : "free") + ".xml"); String versionInfo = "<html><head><meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" /></head><body>"; String data = CustomMain.loadAssetString("news.xml"); if (data == null || data.length() == 0) data = CustomMain.loadAssetString("news.xml"); if (data != null && data.length() > 0) { XmlPullParser parser; try { XmlPullParserFactory factory = XmlPullParserFactory.newInstance(); parser = factory.newPullParser(); parser.setInput(new StringReader(data)); int event; String tagName; boolean correct = false; while (true) { event = parser.nextToken(); if (event == XmlPullParser.START_TAG) { tagName = parser.getName(); if (tagName.equalsIgnoreCase("update")) { String name = parser.getAttributeValue(null, "name"); int id = Utils.parseInt(parser.getAttributeValue(null, "id")); if (id > lastVersion && id <= actualVersion) { correct = true; versionInfo += ("<h4>" + name + "</h4><ul>"); } else { correct = false; } } else if (tagName.equalsIgnoreCase("li")) { if (correct) { versionInfo += ("<li>" + parser.nextText() + "</li>"); } } } else if (event == XmlPullParser.END_TAG) { tagName = parser.getName(); if (tagName.equalsIgnoreCase("update")) { if (correct) { correct = false; versionInfo += "</ul>"; } } else if (tagName.equals("document")) { break; } } } } catch (Exception e) { Logger.e(TAG, "getNews()", e); } } versionInfo += "</body></html>"; return versionInfo; } /** * This is called only once after application start. It's * called in onCreate method before layout is placed */ protected abstract void eventFirstInit(); /** * Method that create layout for actual activity. This is * called everytime, onCreate method is called */ protected abstract void eventCreateLayout(); /** * This is called only once after application start. It's * called in onResume method */ protected abstract void eventSecondInit(); /** * This is called everytime except first run. It's * called in onResume method */ protected abstract void eventRegisterOnly(); /** * This is called only when application really need to be destroyed, * so in this method is suggested to clear all variables */ protected abstract void eventDestroyApp(); public static final int CLOSE_DESTROY_APP_NO_DIALOG = 0; public static final int CLOSE_DESTROY_APP_DIALOG_NO_TEXT = 1; public static final int CLOSE_DESTROY_APP_DIALOG_ADDITIONAL_TEXT = 2; public static final int CLOSE_HIDE_APP = 3; protected abstract int getCloseValue(); protected abstract String getCloseAdditionalText(); }