Java tutorial
/* Open Explorer, an open source file explorer & text editor Copyright (C) 2011 Brandon Bowles <brandroid64@gmail.com> This program 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. This program 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 this program. If not, see <http://www.gnu.org/licenses/>. */ package org.brandroid.openmanager.util; import SevenZip.ArchiveExtractCallback; import SevenZip.HRESULT; import SevenZip.Handler; import SevenZip.IArchiveExtractCallback; import SevenZip.IInArchive; import SevenZip.MyRandomAccessFile; import android.os.AsyncTask; import android.os.AsyncTask.Status; import android.os.Build; import android.provider.MediaStore.Images; import android.support.v4.app.NotificationCompat; import android.annotation.SuppressLint; import android.app.AlertDialog; import android.app.Notification; import android.app.NotificationManager; import android.app.PendingIntent; import android.app.ProgressDialog; import android.view.View; import android.content.DialogInterface; import android.content.DialogInterface.OnClickListener; import android.content.Intent; import android.content.Context; import android.graphics.BitmapFactory; import android.widget.ProgressBar; import android.widget.RemoteViews; import android.widget.Toast; import android.net.Uri; import java.util.ArrayList; import java.util.Collection; import java.util.Date; import java.util.List; import java.util.Locale; import java.util.concurrent.Executor; import java.util.zip.GZIPInputStream; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; import java.util.zip.ZipInputStream; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import net.contrapunctus.lzma.LzmaInputStream; import org.brandroid.openmanager.R; import org.brandroid.openmanager.activities.BluetoothActivity; import org.brandroid.openmanager.activities.OpenExplorer; import org.brandroid.openmanager.data.OpenCursor; import org.brandroid.openmanager.data.OpenLZMA; import org.brandroid.openmanager.data.OpenLZMA.OpenLZMAEntry; import org.brandroid.openmanager.data.OpenMediaStore; import org.brandroid.openmanager.data.OpenNetworkPath; import org.brandroid.openmanager.data.OpenNetworkPath.Cancellable; import org.brandroid.openmanager.data.OpenNetworkPath.CloudDeleteListener; import org.brandroid.openmanager.data.OpenNetworkPath.CloudOpsHandler; import org.brandroid.openmanager.data.OpenPath; import org.brandroid.openmanager.data.OpenFile; import org.brandroid.openmanager.data.OpenPath.OpenStream; import org.brandroid.openmanager.data.OpenRAR; import org.brandroid.openmanager.data.OpenRAR.OpenRAREntry; import org.brandroid.openmanager.data.OpenTar.OpenTarEntry; import org.brandroid.openmanager.data.OpenSMB; import org.brandroid.openmanager.data.OpenSmartFolder; import org.brandroid.openmanager.data.OpenPath.OpenPathCopyable; import org.brandroid.openmanager.data.OpenZip; import org.brandroid.openmanager.fragments.DialogHandler; import org.brandroid.openmanager.interfaces.OpenApp; import org.brandroid.openmanager.util.FileManager.OnProgressUpdateCallback; import org.brandroid.utils.Logger; import org.brandroid.utils.Preferences; import org.brandroid.utils.Utils; import org.brandroid.utils.ViewUtils; import org.itadaki.bzip2.BZip2InputStream; import org.itadaki.bzip2.BZip2OutputStream; import org.kamranzafar.jtar.TarEntry; import org.kamranzafar.jtar.TarOutputStream; import org.kamranzafar.jtar.TarUtils; import com.github.junrar.Archive; import com.github.junrar.rarfile.FileHeader; import com.jcraft.jzlib.GZIPOutputStream; @SuppressWarnings({ "unchecked", "rawtypes" }) @SuppressLint("NewApi") public class EventHandler { public static final EventType SEARCH_TYPE = EventType.SEARCH; public static final EventType COPY_TYPE = EventType.COPY; public static final EventType ZIP_TYPE = EventType.ZIP; public static final EventType DELETE_TYPE = EventType.DELETE; public static final EventType RENAME_TYPE = EventType.RENAME; public static final EventType MKDIR_TYPE = EventType.MKDIR; public static final EventType CUT_TYPE = EventType.CUT; public static final EventType TOUCH_TYPE = EventType.TOUCH; public static final EventType ERROR_TYPE = EventType.ERROR; public static final EventType EXTRACT_TYPE = EventType.EXTRACT; public static final int BACKGROUND_NOTIFICATION_ID = 123; private static final boolean ENABLE_MULTITHREADS = false; // !OpenExplorer.BEFORE_HONEYCOMB; static final int TAR_BUFFER = 2048; public enum EventType { SEARCH, COPY, CUT, DELETE, RENAME, MKDIR, TOUCH, EXTRACT, ZIP, ERROR } public enum CompressionType { ZIP, TAR, GZ, BZ2, LZMA, RAR } public static boolean SHOW_NOTIFICATION_STATUS = !OpenExplorer.isBlackBerry() && Build.VERSION.SDK_INT >= 8; private static NotificationManager mNotifier = null; private static int EventCount = 0; public static CompressionType DefaultCompressionType = CompressionType.ZIP; private OnWorkerUpdateListener mThreadListener; private TaskChangeListener mTaskListener; private FileManager mFileMang; private static ArrayList<BackgroundWork> mTasks = new ArrayList<BackgroundWork>(); public static ArrayList<BackgroundWork> getTaskList() { return mTasks; } public static BackgroundWork[] getRunningTasks() { ArrayList<BackgroundWork> ret = new ArrayList<EventHandler.BackgroundWork>(); for (BackgroundWork bw : mTasks) if (bw.getStatus() != Status.FINISHED) ret.add(bw); return ret.toArray(new BackgroundWork[ret.size()]); } public static boolean hasRunningTasks() { for (BackgroundWork bw : mTasks) if (bw.getStatus() == Status.RUNNING) return true; return false; } public static void cancelRunningTasks() { for (BackgroundWork bw : mTasks) if (bw.getStatus() == Status.RUNNING) bw.cancel(true); if (mNotifier != null) mNotifier.cancelAll(); } public void setTaskChangeListener(TaskChangeListener l) { mTaskListener = l; } public interface TaskChangeListener { public void OnTasksChanged(int taskCount); } public interface OnWorkerUpdateListener { public void onWorkerThreadComplete(EventType type, String... results); public void onWorkerProgressUpdate(int pos, int total); /** * Occurs when an error occurs during Event * * @param type Type of requested event. * @param files List of OpenPath items. */ public void onWorkerThreadFailure(EventType type, OpenPath... files); } private synchronized void OnWorkerProgressUpdate(int pos, int total) { if (mThreadListener == null) return; mThreadListener.onWorkerProgressUpdate(pos, total); } private synchronized void OnWorkerThreadComplete(EventType type, String... results) { if (mThreadListener != null) mThreadListener.onWorkerThreadComplete(type, results); if (mTaskListener != null) mTaskListener.OnTasksChanged(getTaskList().size()); } private synchronized void OnWorkerThreadFailure(EventType type, OpenPath... files) { if (mThreadListener == null) return; mThreadListener.onWorkerThreadFailure(type, files); mThreadListener = null; if (mTaskListener != null) mTaskListener.OnTasksChanged(getTaskList().size()); } public void setUpdateListener(OnWorkerUpdateListener e) { mThreadListener = e; } public EventHandler(FileManager filemanager) { mFileMang = filemanager; } public static String getResourceString(Context mContext, int... resIds) { String ret = ""; for (int resId : resIds) ret += (ret == "" ? "" : " ") + mContext.getText(resId); return ret; } private static int binarySearch(String[] array, String key) { for (int i = 0; i < array.length; i++) if (array[i].equals(key)) return i; return -1; } public void deleteFile(final OpenPath file, final OpenApp mApp, boolean showConfirmation) { Collection<OpenPath> files = new ArrayList<OpenPath>(); files.add(file); deleteFile(files, mApp, showConfirmation); } public void deleteFile(final Collection<OpenPath> path, final OpenApp mApp, boolean showConfirmation) { final OpenPath[] files = path.toArray(new OpenPath[path.size()]); String name; final Context mContext = mApp.getContext(); if (files.length == 1) name = files[0].getName(); else name = files.length + " " + getResourceString(mContext, R.string.s_files); if (!showConfirmation) { execute(new BackgroundWork(DELETE_TYPE, mContext, null), files); return; } AlertDialog.Builder b = new AlertDialog.Builder(mContext); b.setTitle(getResourceString(mContext, R.string.s_menu_delete) + " " + name) .setMessage(mContext.getString(R.string.s_alert_confirm_delete, name)) .setIcon(R.drawable.ic_menu_delete) .setPositiveButton(getResourceString(mContext, R.string.s_menu_delete), new OnClickListener() { public void onClick(DialogInterface dialog, int which) { execute(new BackgroundWork(DELETE_TYPE, mContext, null), files); } }).setNegativeButton(getResourceString(mContext, R.string.s_cancel), new OnClickListener() { public void onClick(DialogInterface dialog, int which) { dialog.dismiss(); } }).create().show(); } public void startSearch(final OpenPath base, final Context mContext) { final InputDialog dSearch = new InputDialog(mContext).setIcon(R.drawable.search).setTitle(R.string.s_search) .setCancelable(true).setMessageTop(R.string.s_prompt_search_within).setDefaultTop(base.getPath()) .setMessage(R.string.s_prompt_search); AlertDialog alert = dSearch.setPositiveButton(R.string.s_search, new OnClickListener() { public void onClick(DialogInterface dialog, int which) { searchFile(new OpenFile(dSearch.getInputTopText()), dSearch.getInputText(), mContext); } }).setNegativeButton(R.string.s_cancel, new OnClickListener() { public void onClick(DialogInterface dialog, int which) { dialog.dismiss(); } }).create(); alert.setInverseBackgroundForced(true); alert.show(); } public void renameFile(final OpenPath path, boolean isFolder, final Context mContext) { final InputDialog dRename = new InputDialog(mContext).setIcon(R.drawable.ic_rename) .setTitle(R.string.s_menu_rename).setCancelable(true).setMessage(R.string.s_alert_rename) .setDefaultText(path.getName()); dRename.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { String newName = dRename.getInputText().toString(); BackgroundWork work = new BackgroundWork(RENAME_TYPE, mContext, path, newName); if (newName.length() > 0) { execute(work, path); } else dialog.dismiss(); } }).setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { dialog.dismiss(); } }).create().show(); } /** * @param directory directory path to create the new folder in. */ public static void createNewFolder(final OpenPath folder, final Context context, final OnWorkerUpdateListener threadListener) { final InputDialog dlg = new InputDialog(context).setTitle(R.string.s_title_newfolder) .setIcon(R.drawable.ic_menu_folder_add_dark).setMessage(R.string.s_alert_newfolder) .setMessageTop(R.string.s_alert_newfolder_folder).setDefaultTop(folder.getPath(), false) .setCancelable(true).setNegativeButton(R.string.s_cancel, DialogHandler.OnClickDismiss); dlg.setPositiveButton(R.string.s_create, new OnClickListener() { public void onClick(DialogInterface dialog, int which) { String name = dlg.getInputText(); if (name.length() > 0) { if (!folder.getChild(name).exists()) { if (!createNewFolder(folder, name, context)) { // new folder wasn't created, and since we've // already ruled out an existing folder, the folder // can't be created for another reason OpenPath path = folder.getChild(name); Logger.LogError("Unable to create folder (" + path + ")"); if (threadListener != null) threadListener.onWorkerThreadFailure(MKDIR_TYPE); Toast.makeText(context, R.string.s_msg_folder_none, Toast.LENGTH_LONG).show(); } else { if (threadListener != null) threadListener.onWorkerThreadComplete(MKDIR_TYPE); } } else { // folder exists, so let the user know Toast.makeText(context, getResourceString(context, R.string.s_msg_folder_exists), Toast.LENGTH_SHORT).show(); } } else { dialog.dismiss(); } } }); dlg.create().show(); } protected static boolean createNewFolder(OpenPath folder, String folderName, Context context) { return folder.getChild(folderName).mkdir(); } public static void createNewFile(final OpenPath folder, final Context context, final OnWorkerUpdateListener threadListener) { final InputDialog dlg = new InputDialog(context).setTitle(R.string.s_title_newfile) .setIcon(R.drawable.ic_menu_new_file).setMessage(R.string.s_alert_newfile) .setMessageTop(R.string.s_alert_newfile_folder).setDefaultTop(folder.getPath()).setCancelable(true) .setNegativeButton(R.string.s_cancel, new OnClickListener() { public void onClick(DialogInterface dialog, int which) { dialog.dismiss(); } }); dlg.setPositiveButton(R.string.s_create, new OnClickListener() { public void onClick(DialogInterface dialog, int which) { String name = dlg.getInputText(); if (name.length() > 0) { createNewFile(folder, name, threadListener); } else { dialog.dismiss(); } } }); dlg.create().show(); } public static void createNewFile(final OpenPath folder, final String filename, final OnWorkerUpdateListener threadListener) { new Thread(new Runnable() { public void run() { if (folder.getChild(filename).touch()) threadListener.onWorkerThreadComplete(TOUCH_TYPE); else threadListener.onWorkerThreadFailure(TOUCH_TYPE); } }).start(); // BackgroundWork bw = new BackgroundWork(TOUCH_TYPE, context, folder, // filename); // bw.execute(); } public void sendFile(final Collection<OpenPath> path, final Context mContext) { String name; CharSequence[] list = { "Bluetooth", "Email" }; final OpenPath[] files = new OpenPath[path.size()]; path.toArray(files); final int num = path.size(); if (num == 1) name = files[0].getName(); else name = path.size() + " " + getResourceString(mContext, R.string.s_files) + "."; AlertDialog.Builder b = new AlertDialog.Builder(mContext); b.setTitle(getResourceString(mContext, R.string.s_title_send).toString().replace("xxx", name)) .setIcon(R.drawable.bluetooth).setItems(list, new OnClickListener() { public void onClick(DialogInterface dialog, int which) { switch (which) { case 0: Intent bt = new Intent(mContext, BluetoothActivity.class); bt.putExtra("paths", files); mContext.startActivity(bt); break; case 1: ArrayList<Uri> uris = new ArrayList<Uri>(); Intent mail = new Intent(); mail.setType("application/mail"); if (num == 1) { mail.setAction(android.content.Intent.ACTION_SEND); mail.putExtra(Intent.EXTRA_STREAM, files[0].getUri()); mContext.startActivity(mail); break; } for (int i = 0; i < num; i++) uris.add(files[i].getUri()); mail.setAction(android.content.Intent.ACTION_SEND_MULTIPLE); mail.putParcelableArrayListExtra(Intent.EXTRA_STREAM, uris); mContext.startActivity(mail); break; } } }).create().show(); } public void copyFile(OpenPath source, OpenPath destPath, Context mContext) { Collection<OpenPath> files = new ArrayList<OpenPath>(); files.add(source); copyFile(files, destPath, mContext); } public void copyFile(final Collection<OpenPath> files, final OpenPath newPath, final Context mContext) { copyFile(files, newPath, mContext, true); } public void copyFile(final Collection<OpenPath> files, final OpenPath newPath, final Context mContext, final boolean copyOnly) { // for (OpenPath file : files) // copyFile(file, newPath.getChild(file.getName()), mContext); final EventType type = copyOnly ? COPY_TYPE : CUT_TYPE; for (final OpenPath file : files.toArray(new OpenPath[files.size()])) { if (checkDestinationExists(file, newPath, mContext, type)) files.remove(file); else execute(new BackgroundWork(type, mContext, newPath), file); } } private boolean checkDestinationExists(final OpenPath file, final OpenPath newPath, final Context mContext, final EventType type) { final OpenPath newFile = newPath.getChild(file.getName()); if (newFile != null && newFile.exists()) { DialogHandler.showMultiButtonDialog(mContext, getResourceString(mContext, R.string.s_alert_destination_exists), getResourceString(mContext, R.string.s_title_copying) + " " + file.getName(), new OnClickListener() { public void onClick(DialogInterface dialog, int which) { switch (which) { case R.string.s_menu_rename: OpenPath destFile = newFile; int i = 1; while (destFile.exists()) destFile = newPath.getChild(file.getName() + " (" + i++ + ")"); showRenameOnCopyDialog(file, destFile, mContext); break; case R.string.s_overwrite: execute(new BackgroundWork(type, mContext, newPath, file.getName()), file); break; } try { dialog.dismiss(); } catch (Exception e) { Logger.LogWarning("Unable to cancel copyFile dialog.", e); } } }, R.string.s_overwrite, R.string.s_skip, R.string.s_menu_rename); return true; } return false; } private void showRenameOnCopyDialog(final OpenPath sourceFile, final OpenPath destFile, final Context mContext) { final InputDialog dlg = new InputDialog(mContext).setTitle(R.string.s_menu_rename) .setDefaultText(destFile.getName()); dlg.setPositiveButton(android.R.string.ok, new OnClickListener() { public void onClick(DialogInterface dialog, int which) { OpenPath newDest = destFile.getParent().getChild(dlg.getInputText()); newDest.touch(); execute(new BackgroundWork(COPY_TYPE, mContext, newDest, newDest.getPath()), sourceFile); dialog.dismiss(); } }).setNegativeButton(android.R.string.no, new OnClickListener() { public void onClick(DialogInterface dialog, int which) { dialog.dismiss(); } }); dlg.create().show(); } public static AsyncTask execute(AsyncTask job) { if (OpenExplorer.BEFORE_HONEYCOMB) job.execute(); else job.executeOnExecutor(getExecutor()); return job; } private static Executor getExecutor() { if (ENABLE_MULTITHREADS) return AsyncTask.THREAD_POOL_EXECUTOR; else return AsyncTask.SERIAL_EXECUTOR; } public static AsyncTask execute(AsyncTask job, OpenFile... params) { if (OpenExplorer.BEFORE_HONEYCOMB) job.execute((Object[]) params); else job.executeOnExecutor(getExecutor(), (Object[]) params); return job; } public static AsyncTask<OpenPath, Integer, Integer> execute(AsyncTask<OpenPath, Integer, Integer> job, OpenPath... params) { if (OpenExplorer.BEFORE_HONEYCOMB) job.execute(params); else job.executeOnExecutor(getExecutor(), params); return job; } public static NetworkIOTask executeNetwork(NetworkIOTask job, OpenPath... params) { if (OpenExplorer.BEFORE_HONEYCOMB) job.execute(params); else job.executeOnExecutor(getExecutor(), params); return job; } public static AsyncTask execute(AsyncTask job, String... params) { if (OpenExplorer.BEFORE_HONEYCOMB) job.execute((Object[]) params); else job.executeOnExecutor(getExecutor(), (Object[]) params); return job; } public void cutFile(Collection<OpenPath> files, OpenPath newPath, Context mContext) { for (OpenPath file : files) if (!checkDestinationExists(file, newPath, mContext, CUT_TYPE)) execute(new BackgroundWork(CUT_TYPE, mContext, newPath), file); } public void searchFile(OpenPath dir, String query, Context mContext) { execute(new BackgroundWork(SEARCH_TYPE, mContext, dir, query), dir); } public BackgroundWork zipFile(OpenPath into, Collection<OpenPath> files, Context mContext) { return zipFile(into, files, mContext, DefaultCompressionType); } public BackgroundWork zipFile(OpenPath into, Collection<OpenPath> files, Context mContext, CompressionType type) { return zipFile(into, files.toArray(new OpenPath[files.size()]), mContext, type); } public BackgroundWork zipFile(OpenPath into, OpenPath[] files, Context mContext, CompressionType type) { BackgroundWork bw = new BackgroundWork(ZIP_TYPE, mContext, into); bw.setCompressionType(type); return (BackgroundWork) execute(bw, files); } public void extractSet(final OpenPath file, final OpenPath dest, final Context mContext, final String... includes) { execute(new BackgroundWork(EXTRACT_TYPE, mContext, dest, includes), file); } /* * public void unZipFileTo(OpenPath zipFile, OpenPath toDir, Context * mContext) { new BackgroundWork(UNZIPTO_TYPE, mContext, * toDir).execute(zipFile); } */ public class BackgroundWork extends AsyncTask<OpenPath, Integer, Integer> implements OnProgressUpdateCallback { private final EventType mType; private final Context mContext; private final String[] mInitParams; private final OpenPath mIntoPath; private ProgressDialog mPDialog; private Notification mNote = null; private ArrayList<String> mSearchResults = null; private boolean isDownload = false; private boolean isCancellable = true; private int taskId = -1; private final Date mStart; private long mLastRate = 0; private long mElapsed = 0l; private long mRemain = 0l; private int mTotalCount = 0; private int mCurrentIndex = 0; private OpenPath mCurrentPath; private boolean notifReady = false; private final int[] mLastProgress = new int[3]; private int notifIcon; private CompressionType mCompressType = CompressionType.ZIP; private Cancellable mCloudCancellor; private OnWorkerUpdateListener mListener; public void setWorkerUpdateListener(OnWorkerUpdateListener listener) { mListener = listener; } public void OnWorkerThreadComplete(EventType type, String... results) { if (mListener != null) mListener.onWorkerThreadComplete(type, results); EventHandler.this.OnWorkerThreadComplete(type, results); } public void OnWorkerProgressUpdate(int pos, int total) { if (mListener != null) mListener.onWorkerProgressUpdate(pos, total); EventHandler.this.OnWorkerProgressUpdate(pos, total); } public BackgroundWork(EventType type, Context context, OpenPath intoPath, String... params) { // if(OpenExplorer.IS_DEBUG_BUILD) // Logger.LogVerbose("EventHandler.BackgroundWork: " + type.toString() + ", " + intoPath.getAbsolutePath() + ", " + Utils.joinArray(params, "-")); mType = type; mContext = context; mInitParams = params; mIntoPath = intoPath; if (mNotifier == null) mNotifier = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); taskId = mTasks.size(); mStart = new Date(); mTasks.add(this); if (mTaskListener != null) mTaskListener.OnTasksChanged(getRunningTasks().length); } public void setCompressionType(CompressionType type) { mCompressType = type; } public String getOperation() { switch (mType) { case DELETE: return getResourceString(mContext, R.string.s_title_deleting).toString(); case SEARCH: return getResourceString(mContext, R.string.s_title_searching).toString(); case COPY: return getResourceString(mContext, R.string.s_title_copying).toString(); case CUT: return getResourceString(mContext, R.string.s_title_moving).toString(); case EXTRACT: return getResourceString(mContext, R.string.s_extracting).toString(); case ZIP: return getResourceString(mContext, R.string.s_title_zipping).toString(); case MKDIR: return getResourceString(mContext, R.string.s_menu_rename).toString(); case TOUCH: return getResourceString(mContext, R.string.s_create).toString(); } return getResourceString(mContext, R.string.s_title_executing); } public String getTitle() { String title = getOperation(); if (mCurrentPath != null) { title += " " + '\u2192' + " " + mCurrentPath.getName(); } return title; } public String getSubtitle() { String ret = ""; if (mTotalCount > 1) ret += "(" + (mCurrentIndex + 1) + "/" + mTotalCount + ") "; if (mIntoPath != null) ret += '\u2192' + " " + mIntoPath; return ret; } public String getLastRate() { return getLastRate(true); } public String getLastRate(Boolean auto) { if (getStatus() == Status.FINISHED) return getResourceString(mContext, R.string.s_complete); if (!auto) { if (mLastRate > 0) return getResourceString(mContext, R.string.s_status_rate) + OpenPath.formatSize(mLastRate).replace(" ", "").toLowerCase() + "/s"; else return ""; } if (getStatus() == Status.FINISHED) return getResourceString(mContext, R.string.s_complete); else if (getStatus() == Status.PENDING) return getResourceString(mContext, R.string.s_pending); if (isCancelled()) return getResourceString(mContext, R.string.s_cancelled); if (mRemain > 0) { return getTimeRemaining(); } else return getLastRate(false); } public String getTimeElapsed() { Integer min = (int) (mElapsed / 60000); Integer sec = (int) ((mElapsed / 1000) % 60); if (min > 0) return min + ":" + (sec < 10 ? "0" : "") + sec; else return sec + "s"; } public String getTimeRemaining() { return getTimeRemaining(true); } public String getTimeRemaining(boolean title) { if (mRemain <= 0) return ""; Integer min = (int) (mRemain / 60); Integer sec = (int) (mRemain % 60); return (title ? getResourceString(mContext, R.string.s_status_remaining) : "") + (min > 15 ? ">15m" : (min > 0 ? min + ":" : "") + (min > 0 && sec < 10 ? "0" : "") + sec + (min > 0 ? "" : "s")); } @Override protected void onCancelled() { if (mCloudCancellor != null) mCloudCancellor.cancel(); mNotifier.cancel(BACKGROUND_NOTIFICATION_ID); super.onCancelled(); mTasks.remove(this); } @Override protected void onCancelled(Integer result) { mNotifier.cancel(BACKGROUND_NOTIFICATION_ID); super.onCancelled(result); mTasks.remove(this); } protected void onPreExecute() { boolean showDialog = true, showNotification = false; isCancellable = true; notifIcon = R.drawable.icon; switch (mType) { case DELETE: showDialog = false; break; case SEARCH: notifIcon = android.R.drawable.ic_menu_search; break; case COPY: if (mIntoPath.requiresThread()) notifIcon = android.R.drawable.stat_sys_upload; notifIcon = R.drawable.ic_menu_copy; showDialog = false; showNotification = true; break; case CUT: notifIcon = R.drawable.ic_menu_cut; showDialog = false; showNotification = true; break; case ZIP: showDialog = true; showNotification = true; break; case EXTRACT: showDialog = true; showNotification = true; isCancellable = false; break; default: showDialog = showNotification = false; break; } if (showDialog) try { mPDialog = ProgressDialog.show(mContext, getTitle(), getResourceString(mContext, R.string.s_title_wait).toString(), false, isCancellable, new DialogInterface.OnCancelListener() { public void onCancel(DialogInterface dialog) { cancelRunningTasks(); } }); } catch (Exception e) { } if (showNotification) { prepareNotification(notifIcon, isCancellable); } } public int getNotifIconResId() { if (isCancelled()) return R.drawable.ic_action_remove_holo_dark; if (getStatus() == Status.FINISHED) return R.drawable.btn_check_on_holo_blue; return notifIcon; } public CharSequence getDetailedText() { String ret = ""; ret += "Source: " + mCurrentPath.getParent() + "\n"; ret += "Destination: " + mIntoPath + "\n"; if (mLastProgress.length > 2 && mLastProgress[0] > 0 && mLastProgress[1] > 0) { ret += "Progress: " + OpenPath.formatSize(mLastProgress[0]) + " / " + OpenPath.formatSize(mLastProgress[1]) + " "; ret += "(" + getLastRate(false) + ")\n"; } ret += getResourceString(mContext, R.string.s_status_remaining) + " "; ret += getTimeElapsed(); if (mRemain > 0) ret += " [" + getTimeRemaining(false) + "]"; return ret; } @SuppressLint("NewApi") public Notification prepareNotification(int notifIcon, boolean isCancellable, Integer... values) { boolean showProgress = true; try { NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(mContext) .setContentTitle(getTitle()).setContentText(getSubtitle()) .setLargeIcon(BitmapFactory.decodeResource(mContext.getResources(), R.drawable.icon)) .setSmallIcon(notifIcon); int progA = 0; if (showProgress) { if (mLastProgress[1] > 0) progA = (int) (((float) mLastProgress[0] / (float) mLastProgress[1]) * 1000f); if (SHOW_NOTIFICATION_STATUS) { mBuilder.setProgress(1000, progA, values.length == 0); mBuilder.setNumber(progA / 10); } } else { mBuilder.setTicker(getTitle()); } mBuilder.setContentIntent(makePendingIntent(OpenExplorer.REQ_EVENT_VIEW)); // mBuilder.setOnlyAlertOnce(true); mBuilder.setAutoCancel(true); NotificationCompat.BigTextStyle style = new NotificationCompat.BigTextStyle(); style.bigText(getDetailedText()); style.setBigContentTitle(getOperation() + " " + mCurrentPath.getName()); mBuilder.setStyle(style); mBuilder.addAction(R.drawable.ic_menu_close_clear_cancel, mContext.getResources().getText(R.string.s_cancel), makePendingIntent(OpenExplorer.REQ_EVENT_CANCEL)).addAction(R.drawable.ic_menu_info_details, mContext.getText(R.string.s_menu_info), makePendingIntent(OpenExplorer.REQ_EVENT_VIEW)); if (Build.VERSION.SDK_INT < 11) { RemoteViews noteView = new RemoteViews(mContext.getPackageName(), R.layout.notification); noteView.setTextViewText(android.R.id.title, getTitle()); noteView.setTextViewText(android.R.id.text2, getSubtitle()); noteView.setTextViewText(android.R.id.text1, getLastRate()); if (values.length == 0 && isDownload) noteView.setImageViewResource(android.R.id.icon, android.R.drawable.stat_sys_download); else noteView.setImageViewResource(android.R.id.icon, android.R.drawable.stat_notify_sync); noteView.setProgressBar(android.R.id.progress, 1000, progA, values.length == 0); mBuilder.setContent(noteView); } mNote = mBuilder.build(); notifReady = true; } catch (Exception e) { Logger.LogWarning("Couldn't post notification", e); } return mNote; } private PendingIntent makePendingIntent(int reqIntent) { Intent intent = new Intent(); intent.putExtra("TaskId", taskId); intent.putExtra("RequestId", reqIntent); return PendingIntent.getActivity(mContext, reqIntent, intent, 0); } public void searchDirectory(OpenPath dir, String pattern, ArrayList<String> aList) { try { for (OpenPath p : dir.listFiles()) if (p.getName().matches(pattern)) aList.add(p.getPath()); } catch (IOException e) { e.printStackTrace(); } try { for (OpenPath p : dir.list()) if (p.isDirectory()) searchDirectory(p, pattern, aList); } catch (IOException e) { e.printStackTrace(); } } protected Integer doInBackground(OpenPath... params) { //Logger.LogDebug("Starting Op!"); mTotalCount = params.length; int ret = 0; mCurrentPath = params[0]; switch (mType) { case DELETE: for (int i = 0; i < mTotalCount; i++) { if (checkCloudDelete(params[i])) ret++; else ret += mFileMang.deleteTarget(params[i]); } break; case SEARCH: mSearchResults = new ArrayList<String>(); searchDirectory(mIntoPath, mInitParams[0], mSearchResults); break; case RENAME: OpenPath old = mIntoPath; if (old instanceof OpenMediaStore) old = ((OpenMediaStore) mIntoPath).getFile(); if (old instanceof OpenFile) ret += FileManager.renameTarget((OpenFile) old, mInitParams[0]) ? 1 : 0; break; case MKDIR: for (OpenPath p : params) ret += p.mkdir() ? 1 : 0; break; case TOUCH: for (OpenPath p : params) ret += p.touch() ? 1 : 0; break; case COPY: for (int i = 0; i < params.length; i++) { mCurrentIndex = i; mCurrentPath = params[i]; if (OpenExplorer.IS_DEBUG_BUILD) Logger.LogVerbose("EventHandler.BackgroundWork.doInBackground: " + BackgroundWork.this.mType.toString() + ", " + mIntoPath.getAbsolutePath() + ", " + Utils.joinArray(mInitParams, "-") + " --> " + mCurrentPath.getAbsolutePath()); if (mCurrentPath.requiresThread()) isDownload = true; publishProgress(); try { if (copyToDirectory(mCurrentPath, mIntoPath, 0)) ret++; } catch (IOException e) { Logger.LogError("Couldn't copy file (" + mCurrentPath.getName() + " to " + mIntoPath.getPath() + ")", e); } } break; case CUT: for (int i = 0; i < params.length; i++) { mCurrentIndex = i; mCurrentPath = params[i]; if (mCurrentPath.requiresThread()) isDownload = true; publishProgress(); try { if (copyToDirectory(mCurrentPath, mIntoPath, 0)) { ret++; mFileMang.deleteTarget(mCurrentPath); } } catch (IOException e) { Logger.LogError("Couldn't copy file (" + mCurrentPath.getName() + " to " + mIntoPath.getPath() + ")", e); } } break; case EXTRACT: if (params[0] instanceof OpenStream) { int x = extractFiles(params[0], mIntoPath, mInitParams); if (x > 0 && new Preferences(mContext).getBoolean("global", "pref_archive_postdelete", false)) params[0].delete(); ret += x; } break; case ZIP: int x = compressFiles(mIntoPath, params); if (x > 0 && new Preferences(mContext).getBoolean("global", "pref_archive_postdelete", false)) for (OpenPath p : params) p.delete(); ret += x; break; } return ret; } protected int compressFiles(OpenPath mArchive, OpenPath... files) { switch (mCompressType) { case GZ: case BZ2: case TAR: OpenStream fs = (OpenStream) mArchive; OutputStream os = null; int ret = 0; try { mTotalCount = files.length; os = new BufferedOutputStream(fs.getOutputStream()); if (mCompressType == CompressionType.GZ) os = new GZIPOutputStream(os); else if (mCompressType == CompressionType.BZ2) os = new BZip2OutputStream(os); if (files.length > 1) os = new TarOutputStream(os); if (files.length == 1) { mTotalCount = (int) files[0].length(); InputStream is = new BufferedInputStream(((OpenStream) files[0]).getInputStream()); copyStreams(is, os, true, false); } else { mTotalCount = 0; for (OpenPath file : files) mTotalCount += file.length(); for (OpenPath file : files) { ((TarOutputStream) os) .putNextEntry(new TarEntry(((OpenFile) file).getFile(), file.getName())); InputStream is = new BufferedInputStream(((OpenStream) file).getInputStream()); copyStreams(is, os, true, false); // os.write(((OpenFile)file).readBytes()); } } } catch (IOException e) { Logger.LogError("Unable to compress files!", e); return -1; } finally { closeStream(os); } return 1; case ZIP: default: mFileMang.setProgressListener(this); publishProgress(); mFileMang.createZipFile(mIntoPath, files); return mTotalCount; } } private void copyStreams(InputStream in, OutputStream out, boolean doCloseInput, boolean doCloseOutput) throws IOException { byte[] buffer = new byte[2048]; int count = 0; int pos = 0; while ((count = in.read(buffer)) != -1) { out.write(buffer, 0, count); pos += count; onProgressUpdateCallback(pos, mTotalCount); } if (doCloseInput) try { if (in != null) in.close(); } catch (Exception e) { } if (doCloseOutput) try { if (out != null) out.close(); } catch (Exception e) { } } protected int extractFiles(OpenPath file, OpenPath into, String... includes) { int ret = 0; if (file.getMimeType().contains("rar") && (ret = extractRarFiles(new OpenRAR((OpenFile) file), into)) > 0) return ret; if ((file.getMimeType().contains("7z") || file.getMimeType().contains("lzma")) && (ret = extractLZMAFiles((OpenStream) file, into, includes)) > 0) return ret; if (file.getMimeType().contains("gz") && (ret = extractGZip(file, into)) > 0) return ret; if (file.getMimeType().contains("bz") && (ret = extractBZip2(file, into)) > 0) return ret; if (file.getMimeType().contains("zip") && (ret = extractZipFiles((OpenStream) file, into)) > 0) return ret; return 0; } private int extractBZip2(OpenPath file, OpenPath into) { InputStream input = null; OutputStream out = null; try { input = new BufferedInputStream(new BZip2InputStream(((OpenStream) file).getInputStream(), false)); mTotalCount = (int) file.length(); if (into.isDirectory()) into = into.getChild(file.getName().replace("." + file.getExtension(), "")); out = new BufferedOutputStream(((OpenStream) into).getOutputStream()); copyStreams(input, out, true, false); return 1; } catch (Exception e) { return 0; } finally { if (input != null) try { input.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } if (out != null) try { out.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } private int extractGZip(OpenPath file, OpenPath into) { InputStream input = null; OutputStream out = null; try { input = new BufferedInputStream(new GZIPInputStream(((OpenStream) file).getInputStream())); mTotalCount = (int) file.length(); if (into.isDirectory()) into = into.getChild(file.getName().replace("." + file.getExtension(), "")); out = new BufferedOutputStream(((OpenStream) into).getOutputStream()); copyStreams(input, out, true, true); return 1; } catch (Exception e) { return 0; } finally { if (input != null) try { input.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } if (out != null) try { out.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } private Boolean extractTar(OpenPath source, OpenPath into, String... includes) { if (!into.exists() && !into.mkdir()) return false; if ((source.getMimeType().contains("7z") || source.getMimeType().contains("lzma")) && extractLZMAFiles((OpenStream) source, into, includes) > -1) return true; try { TarUtils.untarTarFile(into.getPath(), source.getPath(), includes); return true; } catch (IOException e) { Logger.LogError("Unable to untar!", e); return false; } } /* * More efficient Channel based copying */ private Boolean copyFileToDirectory(final OpenFile source, OpenFile into, final int total) { Logger.LogVerbose("Using Channel copy for " + source); into.mkdir(); if (into.isDirectory()) into = into.getChild(source.getName()); if (source.getPath().equals(into.getPath())) return false; final OpenFile dest = (OpenFile) into; final boolean[] running = new boolean[] { true }; final long size = source.length(); if (size > 50000) new Thread(new Runnable() { @Override public void run() { while ((int) dest.length() < total || running[0]) { long pos = dest.length(); publish((int) pos, (int) size, total); try { Thread.sleep(500); } catch (InterruptedException e) { running[0] = false; } } } }).start(); boolean ret = dest.copyFrom(source); running[0] = false; return ret; } private Boolean checkCloudUpload(final OpenPath old, final OpenPath intoDir) { if (old instanceof OpenFile && intoDir instanceof OpenNetworkPath.CloudOpsHandler) { final CloudOpsHandler remote = ((OpenNetworkPath.CloudOpsHandler) intoDir); final OpenFile local = (OpenFile) old; final long srcLength = old.length(); mCloudCancellor = remote.uploadToCloud(local, new OpenNetworkPath.CloudProgressListener() { public void onException(Exception e) { Logger.LogError("Unable to upload to cloud", e); onPostExecute(0); mThreadListener.onWorkerThreadFailure(BackgroundWork.this.mType, old, intoDir); } @Override public void onCloudComplete(String status) { onPostExecute(1); Logger.LogDebug("Cloud Upload finished"); } @Override public void onProgress(long bytes) { onProgressUpdate((int) bytes, (int) srcLength); } }); return true; } return false; } private Boolean checkCloudDelete(final OpenPath file) { if (file instanceof OpenNetworkPath.CloudOpsHandler) { final CloudOpsHandler remote = (CloudOpsHandler) file; return remote.delete(new CloudDeleteListener() { public void onException(Exception e) { Logger.LogError("Unable to delete cloud file.", e); } public void onDeleteComplete(String status) { onPostExecute(1); } }); } return false; } private Boolean checkCloudDownload(final OpenPath from, OpenPath into) { if (into instanceof OpenFile && from instanceof OpenNetworkPath.CloudOpsHandler) { if (into.isDirectory()) into = into.getChild(from.getName()); final CloudOpsHandler remote = ((OpenNetworkPath.CloudOpsHandler) from); final OpenFile local = (OpenFile) into; final long srcLength = from.length(); mCloudCancellor = remote.downloadFromCloud(local, new OpenNetworkPath.CloudProgressListener() { public void onException(Exception e) { Logger.LogError("Unable to download from cloud", e); onPostExecute(0); mThreadListener.onWorkerThreadFailure(BackgroundWork.this.mType, from, local); } @Override public void onCloudComplete(String status) { onPostExecute(1); } @Override public void onProgress(long bytes) { onProgressUpdate((int) bytes, (int) srcLength); } }); return true; } return false; } private Boolean copyToDirectory(OpenPath old, OpenPath intoDir, int total) throws IOException { if (old.equals(intoDir)) return false; if (checkCloudDownload(old, intoDir)) return true; if (checkCloudUpload(old, intoDir)) return true; if (old instanceof OpenFile && !old.isDirectory() && intoDir instanceof OpenFile) if (copyFileToDirectory((OpenFile) old, (OpenFile) intoDir, total)) return true; if (old instanceof OpenSMB && intoDir instanceof OpenSMB) { Logger.LogVerbose("EventHandler.copyToDirectory : Using OpenSMB Channel copy"); if (((OpenSMB) old).copyTo((OpenSMB) intoDir)) return true; } /* * else if(old instanceof OpenSMB && intoDir instanceof OpenFile) * { Logger.LogVerbose( * "EventHandler.copyToDirectory : Using OpenSMB Copy"); * ((OpenSMB)old).copyTo((OpenFile)intoDir, this); * if(intoDir.length() > 0) return true; } */ if (!intoDir.canWrite()) return false; if (OpenExplorer.IS_DEBUG_BUILD) Logger.LogVerbose("EventHandler.copyToDirectory : Using Stream copy"); if (intoDir instanceof OpenCursor) { try { if (old.isImageFile() && intoDir.getName().equals("Photos")) { if (Images.Media.insertImage(mContext.getContentResolver(), old.getPath(), old.getName(), null) != null) return true; } } catch (Exception e) { return false; } } OpenPath newDir = intoDir; if (intoDir instanceof OpenSmartFolder) { newDir = ((OpenSmartFolder) intoDir).getFirstDir(); if (old instanceof OpenFile && newDir instanceof OpenFile) return copyFileToDirectory((OpenFile) old, (OpenFile) newDir, total); } Logger.LogDebug("EventHandler.copyToDirectory : Trying to copy [" + old.getPath() + "] to [" + intoDir.getPath() + "]..."); if (old.getPath().equals(intoDir.getPath())) { return false; } if (old.isDirectory()) { newDir = newDir.getChild(old.getName()); if (!newDir.exists() && !newDir.mkdir()) { Logger.LogWarning("Couldn't create initial destination file."); } } byte[] data = new byte[FileManager.BUFFER]; int read = 0; if (old.isDirectory() && newDir.isDirectory() && newDir.canWrite()) { OpenPath[] files = old.list(); for (OpenPath file : files) if (file != null) total += (int) file.length(); for (int i = 0; i < files.length; i++) if (files[i] != null && !copyToDirectory(files[i], newDir, total)) { Logger.LogWarning("Couldn't copy " + files[i].getName() + "."); return false; } return true; // } else if(old instanceof OpenSMB && newDir instanceof // OpenFile) { // ((OpenSMB)old).copyTo((OpenFile)newDir, this); } else if (old.isFile() && newDir.isDirectory() && newDir.canWrite()) { OpenPath newFile = newDir.getChild(old.getName()); if (newFile.getPath().equals(old.getPath())) { Logger.LogWarning("Old = new"); return false; } Logger.LogDebug("Creating File [" + newFile.getPath() + "]..."); if (!newDir.exists() && !newFile.mkdir()) { Logger.LogWarning("Couldn't create initial destination file."); return false; } if (old instanceof OpenPathCopyable && newFile instanceof OpenStream) { try { if (((OpenPathCopyable) old).copyTo((OpenStream) newFile)) return true; } catch (IOException e) { } } boolean success = false; if (old instanceof OpenStream && newFile instanceof OpenStream) { int size = (int) old.length(); int pos = 0; BufferedInputStream i_stream = null; BufferedOutputStream o_stream = null; try { Logger.LogDebug("Writing " + newFile.getPath()); i_stream = new BufferedInputStream(((OpenStream) old).getInputStream()); o_stream = new BufferedOutputStream(((OpenStream) newFile).getOutputStream()); while ((read = i_stream.read(data, 0, Math.min(size - pos, FileManager.BUFFER))) != -1) { o_stream.write(data, 0, read); pos += read; if (pos >= size) break; publishMyProgress(pos, size); } o_stream.flush(); i_stream.close(); o_stream.close(); success = true; } catch (NullPointerException e) { Logger.LogError("Null pointer trying to copy file.", e); } catch (FileNotFoundException e) { Logger.LogError("Couldn't find file to copy.", e); } catch (IOException e) { Logger.LogError("IOException copying file.", e); } catch (Exception e) { Logger.LogError("Unknown error copying file.", e); } finally { if (o_stream != null) o_stream.close(); if (i_stream != null) i_stream.close(); } } return success; } else if (!newDir.canWrite()) { Logger.LogWarning("Destination directory not writable."); return false; } Logger.LogWarning("Couldn't copy file for unknown reason."); return false; } private int extractRarFiles(OpenRAR rar, OpenPath directory) { if (!directory.exists() && !directory.mkdir()) return -1; int ret = 0; List<OpenRAREntry> entries = new ArrayList<OpenRAR.OpenRAREntry>(); try { entries = rar.getAllEntries(); mTotalCount = entries.size(); } catch (Exception e) { Logger.LogError("Couldn't get RAR entries!", e); return -1; } mTotalCount = (int) rar.length(); for (OpenRAREntry entry : entries) { OpenPath newFile = directory.getChild(entry.getName()); if (!newFile.getParent().exists() && !newFile.getParent().mkdir()) continue; if (!(newFile instanceof OpenStream)) continue; OutputStream out = null; try { InputStream is = new BufferedInputStream(entry.getInputStream()); out = new BufferedOutputStream(((OpenStream) newFile).getOutputStream()); copyStreams(is, out, false, true); ret++; } catch (Exception e) { Logger.LogError("Couldn't unrar!", e); } finally { closeStream(out); } } return ret; } private int extractZipFiles(OpenStream zip, OpenPath directory) { if (OpenExplorer.IS_DEBUG_BUILD) Logger.LogVerbose("Extracting ZIP: " + zip + " (into " + directory + ")"); byte[] data = new byte[FileManager.BUFFER]; ZipEntry entry; ZipInputStream zipstream = null; OutputStream out = null; int ret = -1; try { ZipFile zf = new ZipFile(((OpenFile) zip).getPath()); mTotalCount = zf.size(); zipstream = new ZipInputStream(zip.getInputStream()); while ((entry = zipstream.getNextEntry()) != null) { OpenPath newFile = directory.getChild(entry.getName()); if (!newFile.getParent().exists() && !newFile.getParent().mkdir()) { Logger.LogWarning("Unable to create parent directory while unzipping"); continue; } if (!(newFile instanceof OpenStream)) { Logger.LogWarning("ZIP: New File isn't a stream? " + newFile); continue; } int read = 0; try { out = new BufferedOutputStream(((OpenStream) newFile).getOutputStream()); copyStreams(zipstream, out, false, true); ret++; } catch (Exception e) { Logger.LogError("Unable to unzip file!", e); } finally { zipstream.closeEntry(); } } } catch (FileNotFoundException e) { ret = -1; Logger.LogError("Couldn't find zip?", e); } catch (IOException e) { ret = -1; Logger.LogError("Unable to unzip?", e); } finally { closeStream(out); closeStream(zipstream); } return ret; } private int extractLZMAFiles(OpenStream s7, final OpenPath directory, String... includes) { // Logger.LogVerbose("LZMA Trying to extract 7zip"); OpenLZMA f7 = null; int ret = 0; try { if (s7 instanceof OpenLZMA) f7 = (OpenLZMA) s7; else f7 = new OpenLZMA((OpenFile) s7); mTotalCount = f7.getListLength(); int[] indices = null; int i = 0; if (includes.length > 0) { mTotalCount = includes.length; indices = new int[includes.length]; for (OpenLZMAEntry ze : f7.getAllEntries()) { int pos = binarySearch(includes, ze.getRelativePath()); Logger.LogVerbose("LZMA " + ze.getRelativePath()); if (pos > -1) indices[i++] = pos; if (i >= indices.length) break; } } ArchiveExtractCallback extractCallbackSpec = new ArchiveExtractCallback(); String base = directory.getPath(); if (!base.endsWith("/")) base += "/"; extractCallbackSpec.setBasePath(base); // Logger.LogVerbose("LZMA Base: " + base); IArchiveExtractCallback extractCallback = extractCallbackSpec; IInArchive arch = f7.getLZMA(); extractCallbackSpec.Init(arch); int res = 0; if (indices == null) res = arch.Extract(null, -1, IInArchive.NExtract_NAskMode_kExtract, extractCallback); else res = arch.Extract(indices, indices.length, IInArchive.NExtract_NAskMode_kExtract, extractCallback); if (res == HRESULT.S_OK) { if (extractCallbackSpec.NumErrors == 0) { Logger.LogDebug("LZMA complete?"); ret = mTotalCount; return ret; } else { Logger.LogError("LZMA errors: " + extractCallbackSpec.NumErrors); } } else { Logger.LogError("Error while extracting LZMA!"); } return ret; } catch (Exception e) { Logger.LogError("Unable to extract LZMA.", e); ret = -1; } finally { } return ret; } private void closeStream(java.io.Closeable s) { try { if (s != null) s.close(); } catch (Exception e) { } } public void publish(int current, int size, int total) { publishProgress(current, size, total); // OnWorkerProgressUpdate(current, total); } private long lastPublish = 0l; public void publishMyProgress(Integer... values) { if (new Date().getTime() - lastPublish < 500) return; lastPublish = new Date().getTime(); publishProgress(values); } public int getProgressA() { return (int) (((float) mLastProgress[0] / (float) mLastProgress[1]) * 1000f); } public int getProgressB() { return (int) (((float) mLastProgress[0] / (float) mLastProgress[2]) * 1000f); } @SuppressWarnings("unused") @Override protected void onProgressUpdate(Integer... values) { int current = 0, size = 0, total = 0; if (values.length > 0) current = size = total = values[0]; if (values.length > 1) size = total = values[1]; if (values.length > 2) total = Math.max(total, values[2]); // if(mThreadListener != null) // mThreadListener.onWorkerProgressUpdate(current, size); mLastProgress[0] = current; mLastProgress[1] = size; mLastProgress[2] = total; if (size == 0) size = 1; if (total == 0) total = 1; int progA = (int) (((float) current / (float) size) * 1000f); int progB = (int) (((float) current / (float) total) * 1000f); mElapsed = new Date().getTime() - mStart.getTime(); if (mElapsed / 1000 > 0) { mLastRate = ((long) current) / (mElapsed / 1000); if (mLastRate > 0) mRemain = Utils.getAverage(mRemain, (long) (size - current) / mLastRate); } // publish(current, size, total); OnWorkerProgressUpdate(current, total); // Logger.LogInfo("onProgressUpdate(" + current + ", " + size + ", " // + total + ")-(" // + progA + "," + progB + ")-> " + mRemain + "::" + mLastRate); // mNote.setLatestEventInfo(mContext, , contentText, contentIntent) try { if (values.length == 0) mPDialog.setIndeterminate(true); else { mPDialog.setIndeterminate(false); mPDialog.setMax(1000); mPDialog.setProgress(progA); if (progB != progA) mPDialog.setSecondaryProgress(progB); else mPDialog.setSecondaryProgress(0); } } catch (Exception e) { } if (SHOW_NOTIFICATION_STATUS) { try { mNotifier.notify(BACKGROUND_NOTIFICATION_ID, prepareNotification(notifIcon, isCancellable, values)); } catch (Exception e) { Logger.LogWarning("Couldn't update notification progress.", e); } } } public void updateView(final View view) { if (view == null) return; Runnable runnable = new Runnable() { public void run() { ViewUtils.setImageResource(view, getNotifIconResId(), android.R.id.icon); ViewUtils.setText(view, getTitle(), android.R.id.title); ViewUtils.setText(view, getLastRate(), android.R.id.text1); ViewUtils.setText(view, getSubtitle(), android.R.id.text2); if (view.findViewById(android.R.id.progress) != null) { int progA = (int) (((float) mLastProgress[0] / (float) mLastProgress[1]) * 1000f); int progB = (int) (((float) mLastProgress[0] / (float) mLastProgress[2]) * 1000f); if (getStatus() != Status.RUNNING) ViewUtils.setViewsVisible(view, false, android.R.id.progress); else { ProgressBar pb = (ProgressBar) view.findViewById(android.R.id.progress); if (getStatus() == Status.PENDING || mLastRate == 0) pb.setIndeterminate(true); else { pb.setIndeterminate(false); pb.setMax(1000); pb.setProgress(progA); pb.setSecondaryProgress(progB); } } } } }; if (!Thread.currentThread().equals(OpenExplorer.UiThread)) view.post(runnable); else runnable.run(); } @Override public void onProgressUpdateCallback(Integer... vals) { publishMyProgress(vals); } protected void onPostExecute(Integer result) { // NotificationManager mNotifier = // (NotificationManager)mContext.getSystemService(Context.NOTIFICATION_SERVICE); Logger.LogDebug("EventHandler.onPostExecute(" + mIntoPath + ")"); mNotifier.cancel(BACKGROUND_NOTIFICATION_ID); if (mPDialog != null && mPDialog.isShowing()) mPDialog.dismiss(); // mTasks.remove(this); if (getRunningTasks().length == 0) mNotifier.cancelAll(); try { showToast(result); } catch (Exception e) { Logger.LogError("Unable to show EventHandle PostExecute Toast.", e); } OnWorkerThreadComplete(mType); } private void showToast(Integer result) { switch (mType) { case DELETE: if (result == 0) Toast.makeText(mContext, getResourceString(mContext, R.string.s_msg_none, R.string.s_msg_deleted), Toast.LENGTH_SHORT).show(); else if (result == -1) Toast.makeText(mContext, getResourceString(mContext, R.string.s_msg_some, R.string.s_msg_deleted), Toast.LENGTH_SHORT).show(); else Toast.makeText(mContext, getResourceString(mContext, R.string.s_msg_all, R.string.s_msg_deleted), Toast.LENGTH_SHORT).show(); break; case SEARCH: OnWorkerThreadComplete(mType, mSearchResults.toArray(new String[mSearchResults.size()])); return; case COPY: if (result == null || result == 0) Toast.makeText(mContext, getResourceString(mContext, R.string.s_msg_none, R.string.s_msg_copied), Toast.LENGTH_SHORT).show(); else if (result != null && result < 0) Toast.makeText(mContext, getResourceString(mContext, R.string.s_msg_some, R.string.s_msg_copied), Toast.LENGTH_SHORT).show(); else Toast.makeText(mContext, getResourceString(mContext, R.string.s_msg_all, R.string.s_msg_copied), Toast.LENGTH_SHORT).show(); break; case CUT: if (result == null || result == 0) Toast.makeText(mContext, getResourceString(mContext, R.string.s_msg_none, R.string.s_msg_moved), Toast.LENGTH_SHORT).show(); else if (result != null && result < 0) Toast.makeText(mContext, getResourceString(mContext, R.string.s_msg_some, R.string.s_msg_moved), Toast.LENGTH_SHORT).show(); else Toast.makeText(mContext, getResourceString(mContext, R.string.s_msg_all, R.string.s_msg_moved), Toast.LENGTH_SHORT).show(); break; case ZIP: int typeRes = R.string.s_compressed; if (result == null || result == 0) Toast.makeText(mContext, mIntoPath.getMimeType().replace("application/", "") + ": " + getResourceString(mContext, R.string.s_msg_none, typeRes), Toast.LENGTH_SHORT).show(); else if (result != null && result < 0) Toast.makeText(mContext, mIntoPath.getMimeType().replace("application/", "") + ": " + getResourceString(mContext, R.string.s_msg_some, typeRes), Toast.LENGTH_SHORT).show(); else Toast.makeText(mContext, mIntoPath.getMimeType().replace("application/", "") + ": " + getResourceString(mContext, R.string.s_msg_all, typeRes), Toast.LENGTH_SHORT).show(); break; case EXTRACT: typeRes = R.string.s_extracted; if (result == null || result == 0) Toast.makeText(mContext, mCurrentPath.getMimeType().replace("application/", "") + ": " + getResourceString(mContext, R.string.s_msg_none, typeRes), Toast.LENGTH_SHORT).show(); else if (result != null && result < 0) Toast.makeText(mContext, mCurrentPath.getMimeType().replace("application/", "") + ": " + getResourceString(mContext, R.string.s_msg_some, typeRes), Toast.LENGTH_SHORT).show(); else Toast.makeText(mContext, mCurrentPath.getMimeType().replace("application/", "") + ": " + getResourceString(mContext, R.string.s_msg_all, typeRes), Toast.LENGTH_SHORT).show(); break; } } } }