package com.applang; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.nio.channels.FileChannel; import java.util.Arrays; import java.util.Enumeration; import java.util.Locale; import com.applang.Util.ValList; import dalvik.system.DexFile; import android.annotation.SuppressLint; import android.app.Activity; import android.app.ActivityManager; import android.app.AlertDialog; import android.app.Dialog; import android.app.ProgressDialog; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.content.pm.PackageManager; import android.os.AsyncTask; import android.os.Bundle; import android.os.Environment; import android.os.Handler; import android.os.Message; import android.util.Log; import android.view.View; import android.widget.Toast; import static com.applang.Util.*; public class Util2 { public static class WorkerThread extends Thread { public final static int DONE = 0, RUNNING = 1; Job<Activity> mJob; Handler mHandler; Object[] mParams; Activity mActivity; public WorkerThread(Activity activity, Job<Activity> job, Handler handler, Object... params) { mJob = job; mHandler = handler; mParams = params; mActivity = activity; } @Override public void run() { set_State(RUNNING); try { mJob.perform(mActivity, mParams); } catch (Exception e) { Log.e(TAG, "doing job", e); } while (mHandler != null && get_State() == RUNNING) { Util.delay(40); Message msg = mHandler.obtainMessage(); Bundle b = new Bundle(); b.putInt("countDown", 0); msg.setData(b); mHandler.sendMessage(msg); } } int mState; public int get_State() { return mState; } // Set current state of thread (use state=ProgressThread.DONE to stop thread) public void set_State(int state) { mState = state; } } public static WorkerThread workerThread = null; public static Dialog waitWhileWorking(final Activity activity, String text, Job<Activity> job, Object... params) { final ProgressDialog progDialog = new ProgressDialog(activity); progDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER); progDialog.setMessage(text); final Runnable followUp = param(null, 0, params); workerThread = new WorkerThread(activity, job, new Handler() { public void handleMessage(Message msg) { int countDown = msg.getData().getInt("countDown"); progDialog.setProgress(countDown); if (countDown <= 0) { activity.removeDialog(0); if (workerThread != null) { workerThread.set_State(WorkerThread.DONE); if (followUp != null) followUp.run(); } } } }, params); workerThread.start(); return progDialog; } public static boolean isExternalStorageAvailable() { return Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED); } private static int apiLevel() { return Integer.parseInt(android.os.Build.VERSION.SDK); } @SuppressLint("NewApi") public static class ImpexTask extends AsyncTask<String, Void, Boolean> { private static final String TAG = ImpexTask.class.getSimpleName(); public interface AsyncCallback{ void onTaskCompleted(); } /** * * @param export if true then export else import */ public ImpexTask(Context context, String[] fileNames, boolean export, AsyncCallback callback) { this.context = context; this.fileNames = fileNames; this.export = export; this.callback = callback; this.progress = new ProgressDialog(this.context); } Context context; String[] fileNames; boolean export; AsyncCallback callback; public static String actionString(boolean flag) { return flag ? "Export" : "Import"; } public static void doImport(Context context, String[] fileNames, AsyncCallback callback) { decision(false, context, fileNames, callback); } public static void doExport(Context context, String[] fileNames, AsyncCallback callback) { decision(true, context, fileNames, callback); } private static void decision(final boolean export, final Context context, final String[] fileNames, final AsyncCallback callback) { String action = actionString(export); if (isExternalStorageAvailable()) { areUsure(context, action + " : " + Arrays.toString(fileNames), new Job<Void>() { public void perform(Void t, Object[] params) throws Exception { if (apiLevel() < 3) { boolean success = doImpex(context, fileNames, export); message(success, context, export); } else new ImpexTask(context, fileNames, export, callback).execute(); } }); } else Toast.makeText(context, String.format("External storage is not available, unable to %s data.", action.toLowerCase(Locale.US)), Toast.LENGTH_SHORT).show(); } public static File directory(String path, boolean export) { return export ? new File(Environment.getExternalStorageDirectory(), path) : new File(Environment.getDataDirectory(), path); } public static boolean doImpex(Context context, String[] fileNames, boolean export) { boolean retval = true; try { String path = getDatabasesPath(context); for (String fileName : fileNames) { File importDir = directory(path, false); File exportDir = directory(path, true); retval &= doCopy(fileName, export, importDir, exportDir); } } catch (IOException e) { Log.e(TAG, "doImpex", e); retval = false; } return retval; } public static String getDatabasesPath(Context context) { return "data/" + context.getPackageName() + "/databases"; } public static boolean doAppex(String[] fileNames) { try { String path = "app"; for (String fileName : fileNames) { File importDir = directory(path, false); File exportDir = directory(path, true); doCopy(fileName, true, importDir, exportDir); } } catch (IOException e) { Log.e(TAG, "doAppex", e); return false; } return true; } public static boolean doCopy(String fileName, boolean export, File importDir, File exportDir) throws IOException { File source, destination; if (export) { source = new File(importDir, fileName); destination = new File(exportDir, fileName); } else { source = new File(exportDir, fileName); destination = new File(importDir, fileName); } if (!source.exists()) return false; if (export && !destination.exists()) { destination.getParentFile().mkdirs(); destination.createNewFile(); } copyFile(source, destination); Log.i(TAG, String.format(actionString(export) + "ed : '%s' to '%s'", source, destination)); return true; } public static void versionFile(File file) throws IOException { if (file.exists()) { String fileName = file.getName(); int sep = fileName.lastIndexOf('.'); if (sep < 0) sep = fileName.length(); fileName = fileName.substring(0, sep) + '.' + now() + fileName.substring(sep); file.renameTo(new File(file.getParentFile(), fileName)); } } @SuppressWarnings("resource") public static void copyFile(File src, File dst) throws IOException { FileChannel inChannel = new FileInputStream(src).getChannel(); FileChannel outChannel = new FileOutputStream(dst).getChannel(); try { inChannel.transferTo(0, inChannel.size(), outChannel); } finally { if (inChannel != null) inChannel.close(); if (outChannel != null) outChannel.close(); } } private ProgressDialog progress = null; // can use UI thread here protected void onPreExecute() { this.progress.setMessage(String.format(actionString(this.export) + "ing '%s' ...", Arrays.toString(this.fileNames))); this.progress.show(); } // automatically done on worker thread (separate from UI thread) protected Boolean doInBackground(final String... args) { return doImpex(this.context, this.fileNames, this.export); } // can use UI thread here protected void onPostExecute(final Boolean success) { if (this.progress.isShowing()) this.progress.dismiss(); message(success, this.context, this.export); if (this.callback != null) this.callback.onTaskCompleted(); } private static void message(boolean success, Context context, boolean flag) { String s = actionString(flag); if (success) Toast.makeText(context, s + " successful !", Toast.LENGTH_SHORT).show(); else Toast.makeText(context, s + " failed !", Toast.LENGTH_SHORT).show(); } } public static void alert(Context context, String message) { AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(context); alertDialogBuilder .setMessage(message) .setCancelable(false) .setNeutralButton("Close", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int id) { dialog.dismiss(); } }); AlertDialog alertDialog = alertDialogBuilder.create(); alertDialog.show(); } public static void areUsure(Context context, String message, final Job<Void> job, final Object... params) { AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(context); alertDialogBuilder .setMessage(message) .setCancelable(false) .setPositiveButton("Yes", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int id) { dialog.dismiss(); try { job.perform(null, params); } catch (Exception e) { Log.e(TAG, "areUsure", e); } } }) .setNegativeButton("No", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int id) { dialog.cancel(); } }); AlertDialog alertDialog = alertDialogBuilder.create(); alertDialog.show(); } public static void popupContextMenu(Activity activity, View view) { activity.registerForContextMenu(view); activity.openContextMenu(view); activity.unregisterForContextMenu(view); } @SuppressLint("NewApi") public static abstract class Task<Result> extends AsyncTask<Object, Intent, Result> { public Task(Activity activity, Job<Result> followUp, Object... params) { this.activity = activity; this.followUp = followUp; this.params = params; } protected Activity activity; protected Result doInBackground(Object...params) { Integer millis = param_Integer(null, 0, params); if (millis != null) delay(millis); return null; } @Override protected void onProgressUpdate(Intent... intents) { super.onProgressUpdate(intents); if (intents.length > 0 && activity != null) { Intent intent = intents[0]; if (notNullOrEmpty(intent.getAction())) activity.startActivity(intent); } } @Override protected void onPostExecute(Result result) { super.onPostExecute(result); if (followUp != null) try { followUp.perform(result, params); } catch (Exception e) { Log.e(TAG, "follow-up", e); } } private Job<Result> followUp; private Object[] params; } public static String resourcePackageName(Activity activity) { // needs : android.permission.GET_TASKS String permission = "android.permission.GET_TASKS"; int res = activity.checkCallingOrSelfPermission(permission); if (res == PackageManager.PERMISSION_GRANTED) { ActivityManager actMngr = (ActivityManager) activity.getSystemService(Context.ACTIVITY_SERVICE); return actMngr.getRunningTasks(1).get(0).topActivity.getPackageName(); } else return ""; } // NOTE there is a different method with the same signature in Util2 for Java @SuppressWarnings("rawtypes") public static Class[] getLocalClasses(String packageName, Object...params) throws Exception { Activity activity = param(null, 0, params); ValList list = vlist(); DexFile df = new DexFile(activity.getPackageCodePath()); for (Enumeration<String> iter = df.entries(); iter.hasMoreElements();) { String entry = iter.nextElement(); if (entry.startsWith(packageName)) list.add(Class.forName(entry)); } return arraycast(list.toArray(), new Class[0]); } }