diff options
Diffstat (limited to 'src')
13 files changed, 1885 insertions, 1589 deletions
diff --git a/src/com/cyanogenmod/explorer/activities/SearchActivity.java b/src/com/cyanogenmod/explorer/activities/SearchActivity.java index de653a4..20b8d93 100644 --- a/src/com/cyanogenmod/explorer/activities/SearchActivity.java +++ b/src/com/cyanogenmod/explorer/activities/SearchActivity.java @@ -68,7 +68,8 @@ import com.cyanogenmod.explorer.providers.RecentSearchesContentProvider; import com.cyanogenmod.explorer.tasks.SearchResultDrawingAsyncTask; import com.cyanogenmod.explorer.ui.dialogs.ActionsDialog; import com.cyanogenmod.explorer.ui.dialogs.MessageProgressDialog; -import com.cyanogenmod.explorer.ui.policy.ActionsPolicy; +import com.cyanogenmod.explorer.ui.policy.InfoActionPolicy; +import com.cyanogenmod.explorer.ui.policy.IntentsActionPolicy; import com.cyanogenmod.explorer.ui.widgets.ButtonItem; import com.cyanogenmod.explorer.util.CommandHelper; import com.cyanogenmod.explorer.util.DialogHelper; @@ -822,19 +823,19 @@ public class SearchActivity extends Activity // Show content description if (this.mDefaultLongClickAction.compareTo( DefaultLongClickAction.SHOW_CONTENT_DESCRIPTION) == 0) { - ActionsPolicy.showContentDescription(this, fso); + InfoActionPolicy.showContentDescription(this, fso); } // Open with else if (this.mDefaultLongClickAction.compareTo( DefaultLongClickAction.OPEN_WITH) == 0) { - ActionsPolicy.openFileSystemObject(this, fso, true); + IntentsActionPolicy.openFileSystemObject(this, fso, true); } // Show properties else if (this.mDefaultLongClickAction.compareTo( DefaultLongClickAction.SHOW_PROPERTIES) == 0) { - ActionsPolicy.showPropertiesDialog(this, fso, this); + InfoActionPolicy.showPropertiesDialog(this, fso, this); } // Show actions @@ -966,7 +967,7 @@ public class SearchActivity extends Activity } else { // Open the file here, so when focus back to the app, the search activity // its in top of the stack - ActionsPolicy.openFileSystemObject(this, fso, false); + IntentsActionPolicy.openFileSystemObject(this, fso, false); return; } } else { diff --git a/src/com/cyanogenmod/explorer/ui/dialogs/ActionsDialog.java b/src/com/cyanogenmod/explorer/ui/dialogs/ActionsDialog.java index d83f7df..2118b03 100644 --- a/src/com/cyanogenmod/explorer/ui/dialogs/ActionsDialog.java +++ b/src/com/cyanogenmod/explorer/ui/dialogs/ActionsDialog.java @@ -37,8 +37,16 @@ import com.cyanogenmod.explorer.adapters.TwoColumnsMenuListAdapter; import com.cyanogenmod.explorer.listeners.OnRequestRefreshListener; import com.cyanogenmod.explorer.listeners.OnSelectionListener; import com.cyanogenmod.explorer.model.FileSystemObject; -import com.cyanogenmod.explorer.ui.policy.ActionsPolicy; -import com.cyanogenmod.explorer.ui.policy.ActionsPolicy.LinkedResource; +import com.cyanogenmod.explorer.model.SystemFile; +import com.cyanogenmod.explorer.ui.policy.BookmarksActionPolicy; +import com.cyanogenmod.explorer.ui.policy.CompressActionPolicy; +import com.cyanogenmod.explorer.ui.policy.CopyMoveActionPolicy; +import com.cyanogenmod.explorer.ui.policy.CopyMoveActionPolicy.LinkedResource; +import com.cyanogenmod.explorer.ui.policy.DeleteActionPolicy; +import com.cyanogenmod.explorer.ui.policy.ExecutionActionPolicy; +import com.cyanogenmod.explorer.ui.policy.InfoActionPolicy; +import com.cyanogenmod.explorer.ui.policy.IntentsActionPolicy; +import com.cyanogenmod.explorer.ui.policy.NewActionPolicy; import com.cyanogenmod.explorer.util.DialogHelper; import com.cyanogenmod.explorer.util.FileHelper; import com.cyanogenmod.explorer.util.MimeTypeHelper; @@ -116,7 +124,8 @@ public class ActionsDialog implements OnItemClickListener, OnItemLongClickListen //Create the list view this.mListView = new ListView(context); LinearLayout.LayoutParams params = - new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT); + new LinearLayout.LayoutParams( + LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT); this.mListView.setLayoutParams(params); this.mListView.setAdapter(adapter); @@ -209,7 +218,7 @@ public class ActionsDialog implements OnItemClickListener, OnItemLongClickListen //- Delete case R.id.mnu_actions_delete: - ActionsPolicy.removeFileSystemObject( + DeleteActionPolicy.removeFileSystemObject( this.mContext, this.mFso, this.mOnSelectionListener, @@ -243,21 +252,21 @@ public class ActionsDialog implements OnItemClickListener, OnItemLongClickListen //- Open case R.id.mnu_actions_open: - ActionsPolicy.openFileSystemObject(this.mContext, this.mFso, false); + IntentsActionPolicy.openFileSystemObject(this.mContext, this.mFso, false); break; //- Open with case R.id.mnu_actions_open_with: - ActionsPolicy.openFileSystemObject(this.mContext, this.mFso, true); + IntentsActionPolicy.openFileSystemObject(this.mContext, this.mFso, true); break; //- Execute case R.id.mnu_actions_execute: - ActionsPolicy.execute(this.mContext, this.mFso); + ExecutionActionPolicy.execute(this.mContext, this.mFso); break; //- Send case R.id.mnu_actions_send: - ActionsPolicy.sendFileSystemObject(this.mContext, this.mFso); + IntentsActionPolicy.sendFileSystemObject(this.mContext, this.mFso); break; @@ -266,7 +275,7 @@ public class ActionsDialog implements OnItemClickListener, OnItemLongClickListen if (this.mOnSelectionListener != null) { List<FileSystemObject> selection = this.mOnSelectionListener.onRequestSelectedFiles(); - ActionsPolicy.copyFileSystemObjects( + CopyMoveActionPolicy.copyFileSystemObjects( this.mContext, createLinkedResource(selection, this.mFso), this.mOnSelectionListener, @@ -278,7 +287,7 @@ public class ActionsDialog implements OnItemClickListener, OnItemLongClickListen if (this.mOnSelectionListener != null) { List<FileSystemObject> selection = this.mOnSelectionListener.onRequestSelectedFiles(); - ActionsPolicy.moveFileSystemObjects( + CopyMoveActionPolicy.moveFileSystemObjects( this.mContext, createLinkedResource(selection, this.mFso), this.mOnSelectionListener, @@ -290,7 +299,7 @@ public class ActionsDialog implements OnItemClickListener, OnItemLongClickListen if (this.mOnSelectionListener != null) { List<FileSystemObject> selection = this.mOnSelectionListener.onRequestSelectedFiles(); - ActionsPolicy.removeFileSystemObjects( + DeleteActionPolicy.removeFileSystemObjects( this.mContext, selection, this.mOnSelectionListener, @@ -300,7 +309,7 @@ public class ActionsDialog implements OnItemClickListener, OnItemLongClickListen //- Uncompress case R.id.mnu_actions_extract: - ActionsPolicy.uncompress( + CompressActionPolicy.uncompress( this.mContext, this.mFso, this.mOnRequestRefreshListener); @@ -310,7 +319,7 @@ public class ActionsDialog implements OnItemClickListener, OnItemLongClickListen case R.id.mnu_actions_create_copy: // Create a copy of the fso if (this.mOnSelectionListener != null) { - ActionsPolicy.createCopyFileSystemObject( + CopyMoveActionPolicy.createCopyFileSystemObject( this.mContext, this.mFso, this.mOnSelectionListener, @@ -321,13 +330,13 @@ public class ActionsDialog implements OnItemClickListener, OnItemLongClickListen //- Add to bookmarks case R.id.mnu_actions_add_to_bookmarks: case R.id.mnu_actions_add_to_bookmarks_current_folder: - ActionsPolicy.addToBookmarks(this.mContext, this.mFso); + BookmarksActionPolicy.addToBookmarks(this.mContext, this.mFso); break; //- Properties case R.id.mnu_actions_properties: case R.id.mnu_actions_properties_current_folder: - ActionsPolicy.showPropertiesDialog( + InfoActionPolicy.showPropertiesDialog( this.mContext, this.mFso, this.mOnRequestRefreshListener); break; @@ -414,7 +423,7 @@ public class ActionsDialog implements OnItemClickListener, OnItemLongClickListen case R.id.mnu_actions_rename: // Rename the fso if (ActionsDialog.this.mOnSelectionListener != null) { - ActionsPolicy.renameFileSystemObject( + CopyMoveActionPolicy.renameFileSystemObject( ActionsDialog.this.mContext, inputNameDialog.mFso, name, @@ -427,7 +436,7 @@ public class ActionsDialog implements OnItemClickListener, OnItemLongClickListen case R.id.mnu_actions_create_link_global: // Create a link to the fso if (ActionsDialog.this.mOnSelectionListener != null) { - ActionsPolicy.createSymlink( + NewActionPolicy.createSymlink( ActionsDialog.this.mContext, inputNameDialog.mFso, name, @@ -471,12 +480,12 @@ public class ActionsDialog implements OnItemClickListener, OnItemLongClickListen void createNewFileSystemObject(final int menuId, final String name) { switch (menuId) { case R.id.mnu_actions_new_directory: - ActionsPolicy.createNewDirectory( + NewActionPolicy.createNewDirectory( this.mContext, name, this.mOnSelectionListener, this.mOnRequestRefreshListener); break; case R.id.mnu_actions_new_file: - ActionsPolicy.createNewFile( + NewActionPolicy.createNewFile( this.mContext, name, this.mOnSelectionListener, this.mOnRequestRefreshListener); break; @@ -560,7 +569,22 @@ public class ActionsDialog implements OnItemClickListener, OnItemLongClickListen // Compress/Uncompress (only when selection is available) if (this.mOnSelectionListener != null) { - //Uncompress + //Compress + if (this.mGlobal) { + List<FileSystemObject> selection = null; + if (this.mOnSelectionListener != null) { + selection = this.mOnSelectionListener.onRequestSelectedFiles(); + } + if (selection == null || selection.size() == 0) { + menu.removeItem(R.id.mnu_actions_compress_selection); + } + } else { + // Ignore for system files + if (this.mFso instanceof SystemFile) { + menu.removeItem(R.id.mnu_actions_compress); + } + } + //Uncompress (Only supported files) if (!this.mGlobal && !FileHelper.isSupportedUncompressedFile(this.mFso)) { menu.removeItem(R.id.mnu_actions_extract); } @@ -578,7 +602,7 @@ public class ActionsDialog implements OnItemClickListener, OnItemLongClickListen private static List<LinkedResource> createLinkedResource( List<FileSystemObject> items, FileSystemObject directory) { List<LinkedResource> resources = - new ArrayList<ActionsPolicy.LinkedResource>(items.size()); + new ArrayList<LinkedResource>(items.size()); for (int i = 0; i < items.size(); i++) { FileSystemObject fso = items.get(i); File src = new File(fso.getFullPath()); diff --git a/src/com/cyanogenmod/explorer/ui/dialogs/FsoPropertiesDialog.java b/src/com/cyanogenmod/explorer/ui/dialogs/FsoPropertiesDialog.java index efc0970..2697418 100644 --- a/src/com/cyanogenmod/explorer/ui/dialogs/FsoPropertiesDialog.java +++ b/src/com/cyanogenmod/explorer/ui/dialogs/FsoPropertiesDialog.java @@ -379,12 +379,12 @@ public class FsoPropertiesDialog try { if (this.mFso instanceof Symlink && ((Symlink) this.mFso).getLinkRef() != null) { this.mFolderUsageExecutable = - (FolderUsageExecutable)CommandHelper.getFolderUsage( + CommandHelper.getFolderUsage( this.mContext, ((Symlink) this.mFso).getLinkRef().getFullPath(), this, null); } else { this.mFolderUsageExecutable = - (FolderUsageExecutable)CommandHelper.getFolderUsage( + CommandHelper.getFolderUsage( this.mContext, this.mFso.getFullPath(), this, null); } } catch (Exception cause) { diff --git a/src/com/cyanogenmod/explorer/ui/policy/ActionsPolicy.java b/src/com/cyanogenmod/explorer/ui/policy/ActionsPolicy.java index 2fc8679..21cfb4b 100644 --- a/src/com/cyanogenmod/explorer/ui/policy/ActionsPolicy.java +++ b/src/com/cyanogenmod/explorer/ui/policy/ActionsPolicy.java @@ -16,91 +16,26 @@ package com.cyanogenmod.explorer.ui.policy; -import android.app.AlertDialog; import android.content.Context; -import android.content.DialogInterface; -import android.content.Intent; -import android.content.pm.PackageManager; -import android.content.pm.ResolveInfo; -import android.net.Uri; import android.os.AsyncTask; -import android.text.Html; import android.text.Spanned; -import android.util.Log; import android.widget.Toast; -import com.cyanogenmod.explorer.ExplorerApplication; import com.cyanogenmod.explorer.R; -import com.cyanogenmod.explorer.commands.AsyncResultListener; -import com.cyanogenmod.explorer.commands.ExecExecutable; -import com.cyanogenmod.explorer.commands.UncompressExecutable; -import com.cyanogenmod.explorer.console.ConsoleBuilder; -import com.cyanogenmod.explorer.console.ExecutionException; -import com.cyanogenmod.explorer.console.RelaunchableException; -import com.cyanogenmod.explorer.listeners.OnRequestRefreshListener; -import com.cyanogenmod.explorer.listeners.OnSelectionListener; -import com.cyanogenmod.explorer.model.Bookmark; -import com.cyanogenmod.explorer.model.Bookmark.BOOKMARK_TYPE; -import com.cyanogenmod.explorer.model.FileSystemObject; -import com.cyanogenmod.explorer.preferences.Bookmarks; -import com.cyanogenmod.explorer.ui.dialogs.AssociationsDialog; -import com.cyanogenmod.explorer.ui.dialogs.ExecutionDialog; -import com.cyanogenmod.explorer.ui.dialogs.FsoPropertiesDialog; import com.cyanogenmod.explorer.ui.dialogs.MessageProgressDialog; -import com.cyanogenmod.explorer.util.CommandHelper; -import com.cyanogenmod.explorer.util.DialogHelper; import com.cyanogenmod.explorer.util.ExceptionUtil; -import com.cyanogenmod.explorer.util.ExceptionUtil.OnRelaunchCommandResult; -import com.cyanogenmod.explorer.util.FileHelper; -import com.cyanogenmod.explorer.util.FixedQueue; -import com.cyanogenmod.explorer.util.MimeTypeHelper; - -import java.io.File; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Comparator; -import java.util.List; /** * A class with the convenience methods for resolve actions */ -public final class ActionsPolicy { - - /** - * A class that holds a relationship between a source {@link File} and - * his destination {@link File} - */ - public static class LinkedResource implements Comparable<LinkedResource> { - final File mSrc; - final File mDst; - - /** - * Constructor of <code>LinkedResource</code> - * - * @param src The source file system object - * @param dst The destination file system object - */ - public LinkedResource(File src, File dst) { - super(); - this.mSrc = src; - this.mDst = dst; - } - - /** - * {@inheritDoc} - */ - @Override - public int compareTo(LinkedResource another) { - return this.mSrc.compareTo(another.mSrc); - } - } +public abstract class ActionsPolicy { /** * An interface for using in conjunction with AsyncTask for have * a */ - private interface BackgroundCallable { + protected interface BackgroundCallable { /** * Method that returns the resource identifier of the icon of the dialog * @@ -142,7 +77,7 @@ public final class ActionsPolicy { * * @see BackgroundCallable */ - private static class BackgroundAsyncTask + protected static class BackgroundAsyncTask extends AsyncTask<Object, Spanned, Throwable> { private final Context mCtx; @@ -217,1499 +152,13 @@ public final class ActionsPolicy { } } - - /** - * A class that holds a listener of the execution of a program - */ - private static class ExecutionListener implements AsyncResultListener { - - private final ExecutionDialog mDialog; - - /** - * Constructor of <code>ExecutionListener</code> - * - * @param dialog The console dialog - */ - public ExecutionListener(ExecutionDialog dialog) { - super(); - this.mDialog = dialog; - } - - @Override - public void onPartialResult(Object result) { - this.mDialog.onAppendData((String)result); - } - - @Override - public void onException(Exception cause) { - this.mDialog.onAppendData(ExceptionUtil.toStackTrace(cause)); - } - - @Override - public void onAsyncStart() { - this.mDialog.onStart(); - } - - @Override - public void onAsyncEnd(boolean canceled) {/**NON BLOCK**/} - - @Override - public void onAsyncExitCode(int exitCode) { - this.mDialog.onEnd(exitCode); - } - } - - /** - * A class that holds a listener for compression/uncompression operations - */ - private static class CompressListener implements AsyncResultListener { - - Object mSync; - final FixedQueue<String> mQueue; - boolean mEnd; - Throwable mCause; - - /** - * Constructor of <code>CompressListener</code> - */ - public CompressListener() { - super(); - this.mEnd = false; - this.mSync = new Object(); - this.mQueue = new FixedQueue<String>(2); //Holds only one item - this.mCause = null; - } - - @Override - public void onPartialResult(Object result) { - synchronized (this.mSync) { - this.mQueue.insert((String)result); - } - } - - @Override - public void onException(Exception cause) { - synchronized (this.mSync) { - this.mCause = cause; - } - } - - @Override - public void onAsyncStart() {/**NON BLOCK**/} - - @Override - public void onAsyncEnd(boolean canceled) {/**NON BLOCK**/} - - @Override - public void onAsyncExitCode(int exitCode) { - synchronized (this.mSync) { - this.mEnd = true; - } - } - } - - /** - * @hide - */ - private enum COPY_MOVE_OPERATION { - COPY, - MOVE, - RENAME, - CREATE_COPY, - } - - - private static final String TAG = "ActionPolicy"; //$NON-NLS-1$ - - private static boolean DEBUG = false; - - /** - * Constructor of <code>ActionsPolicy</code>. - */ - private ActionsPolicy() { - super(); - } - - /** - * Method that show a {@link Toast} with the content description of a {@link FileSystemObject}. - * - * @param ctx The current context - * @param fso The file system object - */ - public static void showContentDescription(final Context ctx, final FileSystemObject fso) { - String contentDescription = fso.getFullPath(); - Toast.makeText(ctx, contentDescription, Toast.LENGTH_SHORT).show(); - } - - /** - * Method that show a new dialog for show {@link FileSystemObject} properties. - * - * @param ctx The current context - * @param fso The file system object - * @param onRequestRefreshListener The listener for request a refresh after properties - * of the {@link FileSystemObject} were changed (optional) - */ - public static void showPropertiesDialog( - final Context ctx, final FileSystemObject fso, - final OnRequestRefreshListener onRequestRefreshListener) { - //Show a the filesystem info dialog - final FsoPropertiesDialog dialog = new FsoPropertiesDialog(ctx, fso); - dialog.setOnDismissListener(new DialogInterface.OnDismissListener() { - @Override - public void onDismiss(DialogInterface dlg) { - // Any change? - if (dialog.isHasChanged()) { - if (onRequestRefreshListener != null) { - onRequestRefreshListener.onRequestRefresh(dialog.getFso()); - } - } - } - }); - dialog.show(); - } - - /** - * Method that opens a {@link FileSystemObject} with the default registered application - * by the system, or ask the user for select a registered application. - * - * @param ctx The current context - * @param fso The file system object - * @param choose If allow the user to select the application to open with - */ - public static void openFileSystemObject( - final Context ctx, final FileSystemObject fso, final boolean choose) { - try { - // Create the intent to - Intent intent = new Intent(); - intent.setAction(android.content.Intent.ACTION_VIEW); - - // Obtain the mime/type and passed it to intent - String mime = MimeTypeHelper.getMimeType(ctx, fso); - File file = new File(fso.getFullPath()); - if (mime != null) { - intent.setDataAndType(Uri.fromFile(file), mime); - } else { - intent.setData(Uri.fromFile(file)); - } - - // Resolve the intent - resolveIntent( - ctx, - intent, - choose, - R.drawable.ic_holo_light_open, - R.string.associations_dialog_openwith_title, - R.string.associations_dialog_openwith_action, - true); - - } catch (Exception e) { - ExceptionUtil.translateException(ctx, e); - } - } - - /** - * Method that sends a {@link FileSystemObject} with the default registered application - * by the system, or ask the user for select a registered application. - * - * @param ctx The current context - * @param fso The file system object - */ - public static void sendFileSystemObject( - final Context ctx, final FileSystemObject fso) { - try { - // Create the intent to - Intent intent = new Intent(); - intent.setAction(android.content.Intent.ACTION_SEND); - intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); - intent.setType(MimeTypeHelper.getMimeType(ctx, fso)); - Uri uri = Uri.fromFile(new File(fso.getFullPath())); - intent.putExtra(Intent.EXTRA_STREAM, uri); - - // Resolve the intent - resolveIntent( - ctx, - intent, - false, - R.drawable.ic_holo_light_send, - R.string.associations_dialog_sendwith_title, - R.string.associations_dialog_sendwith_action, - false); - - } catch (Exception e) { - ExceptionUtil.translateException(ctx, e); - } - } - - /** - * Method that resolve - * - * @param ctx The current context - * @param intent The intent to resolve - * @param choose If allow the user to select the application to select the registered - * application. If no preferred app or more than one exists the dialog is shown. - * @param icon The icon of the dialog - * @param title The title of the dialog - * @param action The button title of the dialog - * @param allowPreferred If allow the user to mark the selected app as preferred - */ - private static void resolveIntent( - Context ctx, Intent intent, boolean choose, - int icon, int title, int action, boolean allowPreferred) { - //Retrieve the activities that can handle the file - final PackageManager packageManager = ctx.getPackageManager(); - if (DEBUG) { - intent.addFlags(Intent.FLAG_DEBUG_LOG_RESOLUTION); - } - List<ResolveInfo> info = - packageManager. - queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY); - - // Retrieve the preferred activity that can handle the file - final ResolveInfo mPreferredInfo = packageManager.resolveActivity(intent, 0); - - // No registered application - if (info.size() == 0) { - Toast.makeText(ctx, R.string.msgs_not_registered_app, Toast.LENGTH_SHORT).show(); - return; - } - - // Is a simple open and we have an application that can handle the file? - if (!choose && - ((mPreferredInfo != null && mPreferredInfo.match != 0) || info.size() == 1)) { - ctx.startActivity(intent); - return; - } - - // Otherwise, we have to show the open with dialog - AssociationsDialog dialog = - new AssociationsDialog( - ctx, - icon, - ctx.getString(title), - ctx.getString(action), - intent, - info, - mPreferredInfo, - allowPreferred); - dialog.show(); - } - - /** - * Method that adds the {@link FileSystemObject} to the bookmarks database. - * - * @param ctx The current context - * @param fso The file system object - */ - public static void addToBookmarks(final Context ctx, final FileSystemObject fso) { - try { - // Create the bookmark - Bookmark bookmark = - new Bookmark(BOOKMARK_TYPE.USER_DEFINED, fso.getName(), fso.getFullPath()); - bookmark = Bookmarks.addBookmark(ctx, bookmark); - if (bookmark == null) { - // The operation fails - Toast.makeText( - ctx, - R.string.msgs_operation_failure, - Toast.LENGTH_SHORT).show(); - } else { - // Success - Toast.makeText( - ctx, - R.string.bookmarks_msgs_add_success, - Toast.LENGTH_SHORT).show(); - } - - } catch (Exception e) { - ExceptionUtil.translateException(ctx, e); - } - } - - /** - * Method that executes a {@link FileSystemObject} and show the output in the console - * dialog. - * - * @param ctx The current context - * @param fso The file system object - */ - public static void execute( - final Context ctx, final FileSystemObject fso) { - try { - // Create a console dialog for display the script output - final ExecutionDialog dialog = new ExecutionDialog(ctx, fso); - dialog.show(); - - Thread t = new Thread() { - @Override - public void run() { - final ExecutionListener listener = new ExecutionListener(dialog); - try { - Thread.sleep(250L); - - // Execute the script - ExecExecutable cmd = - CommandHelper.exec( - ctx, fso.getFullPath(), listener, null); - dialog.setCmd(cmd); - } catch (Exception e) { - listener.onException(e); - } - } - }; - t.start(); - - } catch (Exception e) { - ExceptionUtil.translateException(ctx, e); - } - } - - /** - * Method that create the a new file system object. - * - * @param ctx The current context - * @param name The name of the file to be created - * @param onSelectionListener The selection listener (required) - * @param onRequestRefreshListener The listener for request a refresh after the new - * file was created (option) - */ - public static void createNewFile( - final Context ctx, final String name, - final OnSelectionListener onSelectionListener, - final OnRequestRefreshListener onRequestRefreshListener) { - createNewFileSystemObject(ctx, name, false, onSelectionListener, onRequestRefreshListener); - } - - /** - * Method that create the a new folder system object. - * - * @param ctx The current context - * @param name The name of the file to be created - * @param onSelectionListener The selection listener (required) - * @param onRequestRefreshListener The listener for request a refresh after the new - * folder was created (option) - */ - public static void createNewDirectory( - final Context ctx, final String name, - final OnSelectionListener onSelectionListener, - final OnRequestRefreshListener onRequestRefreshListener) { - createNewFileSystemObject(ctx, name, true, onSelectionListener, onRequestRefreshListener); - } - - /** - * Method that create the a new file system object. - * - * @param ctx The current context - * @param name The name of the file to be created - * @param folder If the new {@link FileSystemObject} to create is a folder (true) or a - * file (false). - * @param onSelectionListener The selection listener (required) - * @param onRequestRefreshListener The listener for request a refresh after the new - * folder was created (option) - */ - private static void createNewFileSystemObject( - final Context ctx, final String name, final boolean folder, - final OnSelectionListener onSelectionListener, - final OnRequestRefreshListener onRequestRefreshListener) { - - //Create the absolute file name - File newFso = new File( - onSelectionListener.onRequestCurrentDir(), name); - final String newName = newFso.getAbsolutePath(); - - try { - if (folder) { - if (DEBUG) { - Log.d(TAG, String.format("Creating new directory: %s", newName)); //$NON-NLS-1$ - } - CommandHelper.createDirectory(ctx, newName, null); - } else { - if (DEBUG) { - Log.d(TAG, String.format("Creating new file: %s", newName)); //$NON-NLS-1$ - } - CommandHelper.createFile(ctx, newName, null); - } - - //Operation complete. Show refresh - if (onRequestRefreshListener != null) { - FileSystemObject fso = null; - try { - fso = CommandHelper.getFileInfo(ctx, newName, false, null); - } catch (Throwable ex2) { - /**NON BLOCK**/ - } - onRequestRefreshListener.onRequestRefresh(fso); - } - showOperationSuccessMsg(ctx); - - } catch (Throwable ex) { - //Capture the exception - if (ex instanceof RelaunchableException) { - ExceptionUtil.attachAsyncTask(ex, new AsyncTask<Object, Integer, Boolean>() { - /** - * {@inheritDoc} - */ - @Override - protected Boolean doInBackground(Object... params) { - //Operation complete. Show refresh - if (onRequestRefreshListener != null) { - FileSystemObject fso = null; - try { - fso = - CommandHelper.getFileInfo(ctx, newName, false, null); - } catch (Throwable ex2) { - /**NON BLOCK**/ - } - onRequestRefreshListener.onRequestRefresh(fso); - } - return Boolean.TRUE; - } - - /** - * {@inheritDoc} - */ - @Override - protected void onPostExecute(Boolean result) { - if (result != null && result.booleanValue()) { - showOperationSuccessMsg(ctx); - } - } - }); - } - ExceptionUtil.translateException(ctx, ex); - } - } - - /** - * Method that remove an existing file system object. - * - * @param ctx The current context - * @param src The source file system object - * @param lnkName The new name of the link - * @param onSelectionListener The listener for obtain selection information (required) - * @param onRequestRefreshListener The listener for request a refresh (optional) - */ - public static void createSymlink( - final Context ctx, - final FileSystemObject src, - final String lnkName, - final OnSelectionListener onSelectionListener, - final OnRequestRefreshListener onRequestRefreshListener) { - - //Create the absolute file name - File newFso = new File( - onSelectionListener.onRequestCurrentDir(), lnkName); - final String link = newFso.getAbsolutePath(); - - try { - if (DEBUG) { - Log.d(TAG, String.format( - "Creating new symlink: %s -> %s", src.getFullPath(), link)); //$NON-NLS-1$ - } - CommandHelper.createLink(ctx, src.getFullPath(), link, null); - - //Operation complete. Show refresh - if (onRequestRefreshListener != null) { - FileSystemObject fso = null; - try { - fso = CommandHelper.getFileInfo(ctx, link, false, null); - } catch (Throwable ex2) { - /**NON BLOCK**/ - } - onRequestRefreshListener.onRequestRefresh(fso); - } - showOperationSuccessMsg(ctx); - - } catch (Throwable ex) { - //Capture the exception - if (ex instanceof RelaunchableException) { - ExceptionUtil.attachAsyncTask(ex, new AsyncTask<Object, Integer, Boolean>() { - /** - * {@inheritDoc} - */ - @Override - protected Boolean doInBackground(Object... params) { - //Operation complete. Show refresh - if (onRequestRefreshListener != null) { - FileSystemObject fso = null; - try { - fso = CommandHelper.getFileInfo(ctx, link, false, null); - } catch (Throwable ex2) { - /**NON BLOCK**/ - } - onRequestRefreshListener.onRequestRefresh(fso); - } - return Boolean.TRUE; - } - - /** - * {@inheritDoc} - */ - @Override - protected void onPostExecute(Boolean result) { - if (result != null && result.booleanValue()) { - showOperationSuccessMsg(ctx); - } - } - - }); - } - ExceptionUtil.translateException(ctx, ex); - } - } - - /** - * Method that remove an existing file system object. - * - * @param ctx The current context - * @param fso The file system object to remove - * @param onSelectionListener The listener for obtain selection information (required) - * @param onRequestRefreshListener The listener for request a refresh (optional) - */ - public static void removeFileSystemObject( - final Context ctx, final FileSystemObject fso, - final OnSelectionListener onSelectionListener, - final OnRequestRefreshListener onRequestRefreshListener) { - // Generate an array and invoke internal method - List<FileSystemObject> files = new ArrayList<FileSystemObject>(1); - files.add(fso); - removeFileSystemObjects(ctx, files, onSelectionListener, onRequestRefreshListener); - } - - /** - * Method that remove an existing file system object. - * - * @param ctx The current context - * @param files The list of files to remove - * @param onSelectionListener The listener for obtain selection information (required) - * @param onRequestRefreshListener The listener for request a refresh (optional) - */ - public static void removeFileSystemObjects( - final Context ctx, final List<FileSystemObject> files, - final OnSelectionListener onSelectionListener, - final OnRequestRefreshListener onRequestRefreshListener) { - - // Ask the user before remove - AlertDialog dialog =DialogHelper.createYesNoDialog( - ctx, R.string.actions_ask_undone_operation, - new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface alertDialog, int which) { - if (which == DialogInterface.BUTTON_POSITIVE) { - // Remove the items - removeFileSystemObjectsInBackground( - ctx, - files, - onSelectionListener, - onRequestRefreshListener); - } - } - }); - dialog.show(); - } - - /** - * Method that remove an existing file system object in background. - * - * @param ctx The current context - * @param files The list of files to remove - * @param onSelectionListener The listener for obtain selection information (optional) - * @param onRequestRefreshListener The listener for request a refresh (optional) - * @hide - */ - static void removeFileSystemObjectsInBackground( - final Context ctx, final List<FileSystemObject> files, - final OnSelectionListener onSelectionListener, - final OnRequestRefreshListener onRequestRefreshListener) { - - // Some previous checks prior to execute - // 1.- Check the operation consistency (only if it is viable) - if (onSelectionListener != null) { - final String currentDirectory = onSelectionListener.onRequestCurrentDir(); - if (!checkRemoveConsistency(ctx, files, currentDirectory)) { - return; - } - } - // 2.- Sort the items by path to avoid delete parents fso prior to child fso - final List<FileSystemObject> sortedFsos = new ArrayList<FileSystemObject>(files); - Collections.sort(sortedFsos, new Comparator<FileSystemObject>() { - @Override - public int compare(FileSystemObject lhs, FileSystemObject rhs) { - return lhs.compareTo(rhs) * -1; //Reverse - } - }); - - // The callable interface - final BackgroundCallable callable = new BackgroundCallable() { - // The current items - private int mCurrent = 0; - final Context mCtx = ctx; - final List<FileSystemObject> mFiles = sortedFsos; - final OnRequestRefreshListener mOnRequestRefreshListener = onRequestRefreshListener; - - final Object mSync = new Object(); - Throwable mCause; - - @Override - public int getDialogTitle() { - return R.string.waiting_dialog_deleting_title; - } - @Override - public int getDialogIcon() { - return R.drawable.ic_holo_light_operation; - } - - @Override - public Spanned requestProgress() { - FileSystemObject fso = this.mFiles.get(this.mCurrent); - - // Return the current operation - String progress = - this.mCtx.getResources(). - getString( - R.string.waiting_dialog_deleting_msg, - fso.getFullPath()); - return Html.fromHtml(progress); - } - - @Override - public void onSuccess() { - //Operation complete. Refresh - if (this.mOnRequestRefreshListener != null) { - // The reference is not the same, so refresh the complete navigation view - this.mOnRequestRefreshListener.onRequestRefresh(null); - } - ActionsPolicy.showOperationSuccessMsg(ctx); - } - - @Override - public void doInBackground(Object... params) throws Throwable { - this.mCause = null; - - // This method expect to receive - // 1.- BackgroundAsyncTask - BackgroundAsyncTask task = (BackgroundAsyncTask)params[0]; - - for (int i = 0; i < this.mFiles.size(); i++) { - FileSystemObject fso = this.mFiles.get(i); - - doOperation(this.mCtx, fso); - - // Next file - this.mCurrent++; - if (this.mCurrent < this.mFiles.size()) { - task.onRequestProgress(); - } - } - } - - /** - * Method that deletes the file or directory - * - * @param ctx The current context - * @param fso The file or folder to be deleted - */ - @SuppressWarnings("hiding") - private void doOperation( - final Context ctx, final FileSystemObject fso) throws Throwable { - try { - // Remove the item - if (FileHelper.isDirectory(fso)) { - CommandHelper.deleteDirectory(ctx, fso.getFullPath(), null); - } else { - CommandHelper.deleteFile(ctx, fso.getFullPath(), null); - } - } catch (Exception e) { - // Need to be relaunched? - if (e instanceof RelaunchableException) { - OnRelaunchCommandResult rl = new OnRelaunchCommandResult() { - @Override - @SuppressWarnings("unqualified-field-access") - public void onSuccess() { - synchronized (mSync) { - mSync.notify(); - } - } - - @Override - @SuppressWarnings("unqualified-field-access") - public void onFailed(Throwable cause) { - mCause = cause; - synchronized (mSync) { - mSync.notify(); - } - } - @Override - @SuppressWarnings("unqualified-field-access") - public void onCanceled() { - synchronized (mSync) { - mSync.notify(); - } - } - }; - - // Translate the exception (and wait for the result) - ExceptionUtil.translateException(ctx, e, false, true, rl); - synchronized (this.mSync) { - this.mSync.wait(); - } - - // Persist the exception? - if (this.mCause != null) { - // The exception must be elevated - throw this.mCause; - } - - } else { - // The exception must be elevated - throw e; - } - } - - // Check that the operation was completed retrieving the deleted fso - boolean failed = false; - try { - CommandHelper.getFileInfo(ctx, fso.getFullPath(), false, null); - - // Failed. The file still exists - failed = true; - - } catch (Throwable e) { - // Operation complete successfully - } - if (failed) { - throw new ExecutionException( - String.format( - "Failed to delete file: %s", fso.getFullPath())); //$NON-NLS-1$ - } - } - }; - final BackgroundAsyncTask task = new BackgroundAsyncTask(ctx, callable); - - // Execute background task - task.execute(task); - } - - /** - * Method that remove an existing file system object. - * - * @param ctx The current context - * @param fso The file system object - * @param newName The new name of the object - * @param onSelectionListener The listener for obtain selection information (required) - * @param onRequestRefreshListener The listener for request a refresh (optional) - */ - public static void renameFileSystemObject( - final Context ctx, - final FileSystemObject fso, - final String newName, - final OnSelectionListener onSelectionListener, - final OnRequestRefreshListener onRequestRefreshListener) { - - // Create the destination filename - File dst = new File(fso.getParent(), newName); - File src = new File(fso.getFullPath()); - - // Create arguments - LinkedResource linkRes = new LinkedResource(src, dst); - List<LinkedResource> files = new ArrayList<ActionsPolicy.LinkedResource>(1); - files.add(linkRes); - - // Internal copy - copyOrMoveFileSystemObjects( - ctx, - COPY_MOVE_OPERATION.RENAME, - files, - onSelectionListener, - onRequestRefreshListener); - } - - /** - * Method that copy an existing file system object. - * - * @param ctx The current context - * @param fso The file system object - * @param onSelectionListener The listener for obtain selection information (required) - * @param onRequestRefreshListener The listener for request a refresh (optional) - */ - public static void createCopyFileSystemObject( - final Context ctx, - final FileSystemObject fso, - final OnSelectionListener onSelectionListener, - final OnRequestRefreshListener onRequestRefreshListener) { - - // Create a non-existing name - List<FileSystemObject> curFiles = onSelectionListener.onRequestCurrentItems(); - String newName = FileHelper.createNonExistingName(ctx, curFiles, fso); - final File dst = new File(fso.getParent(), newName); - File src = new File(fso.getFullPath()); - - // Create arguments - LinkedResource linkRes = new LinkedResource(src, dst); - List<LinkedResource> files = new ArrayList<ActionsPolicy.LinkedResource>(1); - files.add(linkRes); - - // Internal copy - copyOrMoveFileSystemObjects( - ctx, - COPY_MOVE_OPERATION.CREATE_COPY, - files, - onSelectionListener, - onRequestRefreshListener); - } - - /** - * Method that copy an existing file system object. - * - * @param ctx The current context - * @param files The list of files to copy - * @param onSelectionListener The listener for obtain selection information (required) - * @param onRequestRefreshListener The listener for request a refresh (optional) - */ - public static void copyFileSystemObjects( - final Context ctx, - final List<LinkedResource> files, - final OnSelectionListener onSelectionListener, - final OnRequestRefreshListener onRequestRefreshListener) { - // Internal copy - copyOrMoveFileSystemObjects( - ctx, - COPY_MOVE_OPERATION.COPY, - files, - onSelectionListener, - onRequestRefreshListener); - } - - /** - * Method that copy an existing file system object. - * - * @param ctx The current context - * @param files The list of files to move - * @param onSelectionListener The listener for obtain selection information (required) - * @param onRequestRefreshListener The listener for request a refresh (optional) - */ - public static void moveFileSystemObjects( - final Context ctx, - final List<LinkedResource> files, - final OnSelectionListener onSelectionListener, - final OnRequestRefreshListener onRequestRefreshListener) { - // Internal move - copyOrMoveFileSystemObjects( - ctx, - COPY_MOVE_OPERATION.MOVE, - files, - onSelectionListener, - onRequestRefreshListener); - } - - /** - * Method that copy an existing file system object. - * - * @param ctx The current context - * @param operation Indicates the operation to do - * @param files The list of source/destination files to copy - * @param onSelectionListener The listener for obtain selection information (required) - * @param onRequestRefreshListener The listener for request a refresh (optional) - */ - private static void copyOrMoveFileSystemObjects( - final Context ctx, - final COPY_MOVE_OPERATION operation, - final List<LinkedResource> files, - final OnSelectionListener onSelectionListener, - final OnRequestRefreshListener onRequestRefreshListener) { - - // Some previous checks prior to execute - // 1.- Listener can't not be null - if (onSelectionListener == null) { - AlertDialog dialog = - DialogHelper.createErrorDialog(ctx, R.string.msgs_illegal_argument); - dialog.show(); - return; - } - // 2.- All the destination files must have the same parent and it must be currentDirectory, - // and not be null - final String currentDirectory = onSelectionListener.onRequestCurrentDir(); - for (int i = 0; i < files.size(); i++) { - LinkedResource linkedRes = files.get(i); - if (linkedRes.mSrc == null || linkedRes.mDst == null) { - AlertDialog dialog = - DialogHelper.createErrorDialog(ctx, R.string.msgs_illegal_argument); - dialog.show(); - return; - } - if (linkedRes.mDst.getParent() == null || - linkedRes.mDst.getParent().compareTo(currentDirectory) != 0) { - AlertDialog dialog = - DialogHelper.createErrorDialog(ctx, R.string.msgs_illegal_argument); - dialog.show(); - return; - } - } - // 3.- Check the operation consistency - if (operation.compareTo(COPY_MOVE_OPERATION.MOVE) == 0) { - if (!checkMoveConsistency(ctx, files, currentDirectory)) { - return; - } - } - - // The callable interface - final BackgroundCallable callable = new BackgroundCallable() { - // The current items - private int mCurrent = 0; - final Context mCtx = ctx; - final COPY_MOVE_OPERATION mOperation = operation; - final List<LinkedResource> mFiles = files; - final OnRequestRefreshListener mOnRequestRefreshListener = onRequestRefreshListener; - - final Object mSync = new Object(); - Throwable mCause; - - @Override - public int getDialogTitle() { - return this.mOperation.compareTo(COPY_MOVE_OPERATION.MOVE) == 0 || - this.mOperation.compareTo(COPY_MOVE_OPERATION.RENAME) == 0 ? - R.string.waiting_dialog_moving_title : - R.string.waiting_dialog_copying_title; - } - @Override - public int getDialogIcon() { - return R.drawable.ic_holo_light_operation; - } - - @Override - public Spanned requestProgress() { - File src = this.mFiles.get(this.mCurrent).mSrc; - File dst = this.mFiles.get(this.mCurrent).mDst; - - // Return the current operation - String progress = - this.mCtx.getResources(). - getString( - this.mOperation.compareTo(COPY_MOVE_OPERATION.MOVE) == 0 || - this.mOperation.compareTo(COPY_MOVE_OPERATION.RENAME) == 0 ? - R.string.waiting_dialog_moving_msg : - R.string.waiting_dialog_copying_msg, - src.getAbsolutePath(), - dst.getAbsolutePath()); - return Html.fromHtml(progress); - } - - @Override - public void onSuccess() { - //Operation complete. Refresh - if (this.mOnRequestRefreshListener != null) { - // The reference is not the same, so refresh the complete navigation view - this.mOnRequestRefreshListener.onRequestRefresh(null); - } - ActionsPolicy.showOperationSuccessMsg(ctx); - } - - @Override - public void doInBackground(Object... params) throws Throwable { - this.mCause = null; - - // This method expect to receive - // 1.- BackgroundAsyncTask - BackgroundAsyncTask task = (BackgroundAsyncTask)params[0]; - - for (int i = 0; i < this.mFiles.size(); i++) { - File src = this.mFiles.get(i).mSrc; - File dst = this.mFiles.get(i).mDst; - - doOperation(this.mCtx, src, dst, this.mOperation); - - // Next file - this.mCurrent++; - if (this.mCurrent < this.mFiles.size()) { - task.onRequestProgress(); - } - } - } - - /** - * Method that copy or move the file to another location - * - * @param ctx The current context - * @param src The source file - * @param dst The destination file - * @param operation Indicates the operation to do - */ - @SuppressWarnings("hiding") - private void doOperation( - Context ctx, File src, File dst, COPY_MOVE_OPERATION operation) - throws Throwable { - // If the source is the same as destiny then don't do the operation - if (src.compareTo(dst) == 0) return; - - try { - // Copy or move? - if (operation.compareTo(COPY_MOVE_OPERATION.MOVE) == 0 || - operation.compareTo(COPY_MOVE_OPERATION.RENAME) == 0) { - CommandHelper.move( - ctx, - src.getAbsolutePath(), - dst.getAbsolutePath(), - null); - } else { - CommandHelper.copy( - ctx, - src.getAbsolutePath(), - dst.getAbsolutePath(), - null); - } - } catch (Exception e) { - // Need to be relaunched? - if (e instanceof RelaunchableException) { - OnRelaunchCommandResult rl = new OnRelaunchCommandResult() { - @Override - @SuppressWarnings("unqualified-field-access") - public void onSuccess() { - synchronized (mSync) { - mSync.notify(); - } - } - - @Override - @SuppressWarnings("unqualified-field-access") - public void onFailed(Throwable cause) { - mCause = cause; - synchronized (mSync) { - mSync.notify(); - } - } - @Override - @SuppressWarnings("unqualified-field-access") - public void onCanceled() { - synchronized (mSync) { - mSync.notify(); - } - } - }; - - // Translate the exception (and wait for the result) - ExceptionUtil.translateException(ctx, e, false, true, rl); - synchronized (this.mSync) { - this.mSync.wait(); - } - - // Persist the exception? - if (this.mCause != null) { - // The exception must be elevated - throw this.mCause; - } - - } else { - // The exception must be elevated - throw e; - } - } - - // Check that the operation was completed retrieving the fso modified - CommandHelper.getFileInfo(ctx, dst.getAbsolutePath(), false, null); - } - }; - final BackgroundAsyncTask task = new BackgroundAsyncTask(ctx, callable); - - // Prior to execute, we need to check if some of the files will be overwritten - List<FileSystemObject> curFiles = onSelectionListener.onRequestCurrentItems(); - if (curFiles != null) { - // Is necessary to ask the user? - if (isOverwriteNeeded(files, curFiles)) { - //Show a dialog asking the user for overwrite the files - AlertDialog dialog = - DialogHelper.createTwoButtonsQuestionDialog( - ctx, - android.R.string.cancel, - R.string.overwrite, - ctx.getString(R.string.msgs_overwrite_files), - new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface alertDialog, int which) { - // NEGATIVE (overwrite) POSITIVE (cancel) - if (which == DialogInterface.BUTTON_NEGATIVE) { - // Execute background task - task.execute(task); - } - } - }); - dialog.show(); - return; - } - } - - // Execute background task - task.execute(task); - } - - /** - * Method that uncompress a compressed file. - * - * @param ctx The current context - * @param fso The compressed file - * @param onRequestRefreshListener The listener for request a refresh (optional) - * @hide - */ - public static void uncompress( - final Context ctx, final FileSystemObject fso, - final OnRequestRefreshListener onRequestRefreshListener) { - - // The callable interface - final BackgroundCallable callable = new BackgroundCallable() { - // The current items - final Context mCtx = ctx; - final FileSystemObject mFso = fso; - final OnRequestRefreshListener mOnRequestRefreshListener = onRequestRefreshListener; - - final Object mSync = new Object(); - Throwable mCause; - - final CompressListener mListener = - new CompressListener(); - private String mMsg; - private boolean mStarted = false; - - @Override - public int getDialogTitle() { - return R.string.waiting_dialog_extracting_title; - } - @Override - public int getDialogIcon() { - return R.drawable.ic_holo_light_operation; - } - - @Override - public Spanned requestProgress() { - // Initializing the dialog - if (!this.mStarted) { - String progress = - this.mCtx.getResources(). - getString( - R.string.waiting_dialog_extracting_analizing_msg); - return Html.fromHtml(progress); - } - - // Return the current operation - String msg = (this.mMsg == null) ? "" : this.mMsg; //$NON-NLS-1$ - String progress = - this.mCtx.getResources(). - getString( - R.string.waiting_dialog_extracting_msg, - msg); - return Html.fromHtml(progress); - } - - @Override - public void onSuccess() { - //Operation complete. Refresh - if (this.mOnRequestRefreshListener != null) { - // The reference is not the same, so refresh the complete navigation view - this.mOnRequestRefreshListener.onRequestRefresh(null); - } - ActionsPolicy.showOperationSuccessMsg(ctx); - } - - @Override - public void doInBackground(Object... params) throws Throwable { - this.mCause = null; - this.mStarted = true; - - // This method expect to receive - // 1.- BackgroundAsyncTask - BackgroundAsyncTask task = (BackgroundAsyncTask)params[0]; - String out = null; - try { - UncompressExecutable cmd = - CommandHelper.uncompress( - ctx, - this.mFso.getFullPath(), - this.mListener, null); - out = cmd.getOutUncompressedFile(); - - // Request paint the - this.mListener.mQueue.insert(out); - task.onRequestProgress(); - - // Don't use an active blocking because this suppose that all message - // will be processed by the UI. Instead, refresh with a delay and - // display the active file - while (!this.mListener.mEnd) { - // Sleep to don't saturate the UI thread - Thread.sleep(50L); - - List<String> msgs = this.mListener.mQueue.peekAll(); - if (msgs.size() > 0) { - this.mMsg = msgs.get(msgs.size()-1); - task.onRequestProgress(); - } - } - - // Dialog is ended. Force the last redraw - List<String> msgs = this.mListener.mQueue.peekAll(); - if (msgs.size() > 0) { - this.mMsg = msgs.get(msgs.size()-1); - task.onRequestProgress(); - } - - } catch (Exception e) { - // Need to be relaunched? - if (e instanceof RelaunchableException) { - OnRelaunchCommandResult rl = new OnRelaunchCommandResult() { - @Override - @SuppressWarnings("unqualified-field-access") - public void onSuccess() { - synchronized (mSync) { - mSync.notify(); - } - } - - @Override - @SuppressWarnings("unqualified-field-access") - public void onFailed(Throwable cause) { - mCause = cause; - synchronized (mSync) { - mSync.notify(); - } - } - @Override - @SuppressWarnings("unqualified-field-access") - public void onCanceled() { - synchronized (mSync) { - mSync.notify(); - } - } - }; - - // Translate the exception (and wait for the result) - ExceptionUtil.translateException(ctx, e, false, true, rl); - synchronized (this.mSync) { - this.mSync.wait(); - } - - // Persist the exception? - if (this.mCause != null) { - // The exception must be elevated - throw this.mCause; - } - - } else { - // The exception must be elevated - throw e; - } - } - - - // Any exception? - if (this.mListener.mCause != null) { - throw this.mListener.mCause; - } - - // Check that the operation was completed retrieving the extracted file or folder - boolean failed = true; - try { - CommandHelper.getFileInfo(ctx, out, false, null); - - // Failed. The file exists - failed = false; - - } catch (Throwable e) { - // Operation complete successfully - } - if (failed) { - throw new ExecutionException( - String.format( - "Failed to extract file: %s", //$NON-NLS-1$ - this.mFso.getFullPath())); - } - } - }; - final BackgroundAsyncTask task = new BackgroundAsyncTask(ctx, callable); - - // Check if the output exists - boolean askUser = false; - try { - UncompressExecutable ucmd = - ExplorerApplication.getBackgroundConsole(). - getExecutableFactory().newCreator(). - createUncompressExecutable(fso.getFullPath(), null); - String dst = ucmd.getOutUncompressedFile(); - FileSystemObject info = CommandHelper.getFileInfo(ctx, dst, null); - if (info != null) { - askUser = true; - } - } catch (Exception e) {/**NON BLOCK**/} - - // Ask the user because the destination file or folder exists - if (askUser) { - //Show a dialog asking the user for overwrite the files - AlertDialog dialog = - DialogHelper.createTwoButtonsQuestionDialog( - ctx, - android.R.string.cancel, - R.string.overwrite, - ctx.getString(R.string.msgs_overwrite_files), - new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface alertDialog, int which) { - // NEGATIVE (overwrite) POSITIVE (cancel) - if (which == DialogInterface.BUTTON_NEGATIVE) { - // Check if the necessary to display a warning because - // security issues - checkZipSecurityWarning(ctx, task, fso); - } - } - }); - dialog.show(); - } else { - // Execute background task - task.execute(task); - } - } - - /** - * Method that checks if it is necessary to display a warning dialog because - * the privileged extraction of a zip file. - * - * @param ctx The current context - * @param task The task - * @param fso The zip file - * @hide - */ - static void checkZipSecurityWarning( - final Context ctx, final BackgroundAsyncTask task, FileSystemObject fso) { - // WARNING! Extracting a ZIP file with relatives or absolutes path could break - // the system and is need a security alert that the user can confirm prior to - // make the extraction - String ext = FileHelper.getExtension(fso); - if (ConsoleBuilder.isPrivileged() && ext.compareTo("zip") == 0) { //$NON-NLS-1$ - AlertDialog dialog =DialogHelper.createYesNoDialog( - ctx, R.string.security_warning_extract, - new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface alertDialog, int which) { - if (which == DialogInterface.BUTTON_POSITIVE) { - // Execute background task - task.execute(task); - } - } - }); - dialog.show(); - } else { - // Execute background task - task.execute(task); - } - } - - /** - * Method that check if is needed to prompt the user for overwrite prior to do - * the operation. - * - * @param files The list of source/destination files. - * @param currentFiles The list of the current files in the destination directory. - * @return boolean If is needed to prompt the user for overwrite - */ - private static boolean isOverwriteNeeded( - List<LinkedResource> files, List<FileSystemObject> currentFiles) { - boolean askUser = false; - for (int i = 0; i < currentFiles.size(); i++) { - for (int j = 0; j < files.size(); j++) { - FileSystemObject dst1 = currentFiles.get(i); - File dst2 = files.get(j).mDst; - - // The file exists in the destination directory - if (dst1.getFullPath().compareTo(dst2.getAbsolutePath()) == 0) { - askUser = true; - break; - } - } - if (askUser) break; - } - return askUser; - } - - /** - * Method that check the consistency of move operations.<br/> - * <br/> - * The method checks the following rules:<br/> - * <ul> - * <li>Any of the files of the move operation can not include the - * current directory.</li> - * <li>Any of the files of the move operation can not include the - * current directory.</li> - * </ul> - * - * @param ctx The current context - * @param files The list of source/destination files - * @param currentDirectory The current directory - * @return boolean If the consistency is validate successfully - */ - private static boolean checkMoveConsistency( - Context ctx, List<LinkedResource> files, String currentDirectory) { - for (int i = 0; i < files.size(); i++) { - LinkedResource linkRes = files.get(i); - String src = linkRes.mSrc.getAbsolutePath(); - String dst = linkRes.mDst.getAbsolutePath(); - - // 1.- Current directory can't be moved - if (currentDirectory != null && currentDirectory.startsWith(src)) { - // Operation not allowed - AlertDialog dialog = - DialogHelper.createErrorDialog( - ctx, R.string.msgs_unresolved_inconsistencies); - dialog.show(); - return false; - } - - // 2.- Destination can't be a child of source - if (dst.startsWith(src)) { - // Operation not allowed - AlertDialog dialog = - DialogHelper.createErrorDialog( - ctx, R.string.msgs_operation_not_allowed_in_current_directory); - dialog.show(); - return false; - } - } - return true; - } - - /** - * Method that check the consistency of delete operations.<br/> - * <br/> - * The method checks the following rules:<br/> - * <ul> - * <li>Any of the files of the move or delete operation can not include the - * current directory.</li> - * </ul> - * - * @param ctx The current context - * @param files The list of source/destination files - * @param currentDirectory The current directory - * @return boolean If the consistency is validate successfully - */ - private static boolean checkRemoveConsistency( - Context ctx, List<FileSystemObject> files, String currentDirectory) { - for (int i = 0; i < files.size(); i++) { - FileSystemObject fso = files.get(i); - - // 1.- Current directory can't be deleted - if (currentDirectory.startsWith(fso.getFullPath())) { - // Operation not allowed - AlertDialog dialog = - DialogHelper.createErrorDialog( - ctx, R.string.msgs_unresolved_inconsistencies); - dialog.show(); - return false; - } - } - return true; - } - /** * Method that shows a message when the operation is complete successfully * * @param ctx The current context * @hide */ - static void showOperationSuccessMsg(Context ctx) { + protected static void showOperationSuccessMsg(Context ctx) { Toast.makeText(ctx, R.string.msgs_success, Toast.LENGTH_SHORT).show(); } }
\ No newline at end of file diff --git a/src/com/cyanogenmod/explorer/ui/policy/BookmarksActionPolicy.java b/src/com/cyanogenmod/explorer/ui/policy/BookmarksActionPolicy.java new file mode 100644 index 0000000..6afe0df --- /dev/null +++ b/src/com/cyanogenmod/explorer/ui/policy/BookmarksActionPolicy.java @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2012 The CyanogenMod Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.cyanogenmod.explorer.ui.policy; + +import android.content.Context; +import android.widget.Toast; + +import com.cyanogenmod.explorer.R; +import com.cyanogenmod.explorer.model.Bookmark; +import com.cyanogenmod.explorer.model.Bookmark.BOOKMARK_TYPE; +import com.cyanogenmod.explorer.model.FileSystemObject; +import com.cyanogenmod.explorer.preferences.Bookmarks; +import com.cyanogenmod.explorer.util.ExceptionUtil; + +/** + * A class with the convenience methods for resolve bookmarks related actions + */ +public final class BookmarksActionPolicy extends ActionsPolicy { + + /** + * Method that adds the {@link FileSystemObject} to the bookmarks database. + * + * @param ctx The current context + * @param fso The file system object + */ + public static void addToBookmarks(final Context ctx, final FileSystemObject fso) { + try { + // Create the bookmark + Bookmark bookmark = + new Bookmark(BOOKMARK_TYPE.USER_DEFINED, fso.getName(), fso.getFullPath()); + bookmark = Bookmarks.addBookmark(ctx, bookmark); + if (bookmark == null) { + // The operation fails + Toast.makeText( + ctx, + R.string.msgs_operation_failure, + Toast.LENGTH_SHORT).show(); + } else { + // Success + Toast.makeText( + ctx, + R.string.bookmarks_msgs_add_success, + Toast.LENGTH_SHORT).show(); + } + + } catch (Exception e) { + ExceptionUtil.translateException(ctx, e); + } + } + +}
\ No newline at end of file diff --git a/src/com/cyanogenmod/explorer/ui/policy/CompressActionPolicy.java b/src/com/cyanogenmod/explorer/ui/policy/CompressActionPolicy.java new file mode 100644 index 0000000..b41ed3d --- /dev/null +++ b/src/com/cyanogenmod/explorer/ui/policy/CompressActionPolicy.java @@ -0,0 +1,354 @@ +/* + * Copyright (C) 2012 The CyanogenMod Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.cyanogenmod.explorer.ui.policy; + +import android.app.AlertDialog; +import android.content.Context; +import android.content.DialogInterface; +import android.text.Html; +import android.text.Spanned; + +import com.cyanogenmod.explorer.ExplorerApplication; +import com.cyanogenmod.explorer.R; +import com.cyanogenmod.explorer.commands.AsyncResultListener; +import com.cyanogenmod.explorer.commands.UncompressExecutable; +import com.cyanogenmod.explorer.console.ConsoleBuilder; +import com.cyanogenmod.explorer.console.ExecutionException; +import com.cyanogenmod.explorer.console.RelaunchableException; +import com.cyanogenmod.explorer.listeners.OnRequestRefreshListener; +import com.cyanogenmod.explorer.model.FileSystemObject; +import com.cyanogenmod.explorer.util.CommandHelper; +import com.cyanogenmod.explorer.util.DialogHelper; +import com.cyanogenmod.explorer.util.ExceptionUtil; +import com.cyanogenmod.explorer.util.ExceptionUtil.OnRelaunchCommandResult; +import com.cyanogenmod.explorer.util.FileHelper; +import com.cyanogenmod.explorer.util.FixedQueue; + +import java.util.List; + +/** + * A class with the convenience methods for resolve compress/uncompress related actions + */ +public final class CompressActionPolicy extends ActionsPolicy { + + /** + * A class that holds a listener for compression/uncompression operations + */ + private static class CompressListener implements AsyncResultListener { + + Object mSync; + final FixedQueue<String> mQueue; + boolean mEnd; + Throwable mCause; + + /** + * Constructor of <code>CompressListener</code> + */ + public CompressListener() { + super(); + this.mEnd = false; + this.mSync = new Object(); + this.mQueue = new FixedQueue<String>(2); //Holds only one item + this.mCause = null; + } + + @Override + public void onPartialResult(Object result) { + synchronized (this.mSync) { + this.mQueue.insert((String)result); + } + } + + @Override + public void onException(Exception cause) { + synchronized (this.mSync) { + this.mCause = cause; + } + } + + @Override + public void onAsyncStart() {/**NON BLOCK**/} + + @Override + public void onAsyncEnd(boolean canceled) {/**NON BLOCK**/} + + @Override + public void onAsyncExitCode(int exitCode) { + synchronized (this.mSync) { + this.mEnd = true; + } + } + } + + /** + * Method that uncompress a compressed file. + * + * @param ctx The current context + * @param fso The compressed file + * @param onRequestRefreshListener The listener for request a refresh (optional) + * @hide + */ + public static void uncompress( + final Context ctx, final FileSystemObject fso, + final OnRequestRefreshListener onRequestRefreshListener) { + + // The callable interface + final BackgroundCallable callable = new BackgroundCallable() { + // The current items + final Context mCtx = ctx; + final FileSystemObject mFso = fso; + final OnRequestRefreshListener mOnRequestRefreshListener = onRequestRefreshListener; + + final Object mSync = new Object(); + Throwable mCause; + + final CompressListener mListener = + new CompressListener(); + private String mMsg; + private boolean mStarted = false; + + @Override + public int getDialogTitle() { + return R.string.waiting_dialog_extracting_title; + } + @Override + public int getDialogIcon() { + return R.drawable.ic_holo_light_operation; + } + + @Override + public Spanned requestProgress() { + // Initializing the dialog + if (!this.mStarted) { + String progress = + this.mCtx.getResources(). + getString( + R.string.waiting_dialog_extracting_analizing_msg); + return Html.fromHtml(progress); + } + + // Return the current operation + String msg = (this.mMsg == null) ? "" : this.mMsg; //$NON-NLS-1$ + String progress = + this.mCtx.getResources(). + getString( + R.string.waiting_dialog_extracting_msg, + msg); + return Html.fromHtml(progress); + } + + @Override + public void onSuccess() { + //Operation complete. Refresh + if (this.mOnRequestRefreshListener != null) { + // The reference is not the same, so refresh the complete navigation view + this.mOnRequestRefreshListener.onRequestRefresh(null); + } + ActionsPolicy.showOperationSuccessMsg(ctx); + } + + @Override + public void doInBackground(Object... params) throws Throwable { + this.mCause = null; + this.mStarted = true; + + // This method expect to receive + // 1.- BackgroundAsyncTask + BackgroundAsyncTask task = (BackgroundAsyncTask)params[0]; + String out = null; + try { + UncompressExecutable cmd = + CommandHelper.uncompress( + ctx, + this.mFso.getFullPath(), + this.mListener, null); + out = cmd.getOutUncompressedFile(); + + // Request paint the + this.mListener.mQueue.insert(out); + task.onRequestProgress(); + + // Don't use an active blocking because this suppose that all message + // will be processed by the UI. Instead, refresh with a delay and + // display the active file + while (!this.mListener.mEnd) { + // Sleep to don't saturate the UI thread + Thread.sleep(50L); + + List<String> msgs = this.mListener.mQueue.peekAll(); + if (msgs.size() > 0) { + this.mMsg = msgs.get(msgs.size()-1); + task.onRequestProgress(); + } + } + + // Dialog is ended. Force the last redraw + List<String> msgs = this.mListener.mQueue.peekAll(); + if (msgs.size() > 0) { + this.mMsg = msgs.get(msgs.size()-1); + task.onRequestProgress(); + } + + } catch (Exception e) { + // Need to be relaunched? + if (e instanceof RelaunchableException) { + OnRelaunchCommandResult rl = new OnRelaunchCommandResult() { + @Override + @SuppressWarnings("unqualified-field-access") + public void onSuccess() { + synchronized (mSync) { + mSync.notify(); + } + } + + @Override + @SuppressWarnings("unqualified-field-access") + public void onFailed(Throwable cause) { + mCause = cause; + synchronized (mSync) { + mSync.notify(); + } + } + @Override + @SuppressWarnings("unqualified-field-access") + public void onCanceled() { + synchronized (mSync) { + mSync.notify(); + } + } + }; + + // Translate the exception (and wait for the result) + ExceptionUtil.translateException(ctx, e, false, true, rl); + synchronized (this.mSync) { + this.mSync.wait(); + } + + // Persist the exception? + if (this.mCause != null) { + // The exception must be elevated + throw this.mCause; + } + + } else { + // The exception must be elevated + throw e; + } + } + + + // Any exception? + if (this.mListener.mCause != null) { + throw this.mListener.mCause; + } + + // Check that the operation was completed retrieving the extracted file or folder + boolean failed = true; + try { + CommandHelper.getFileInfo(ctx, out, false, null); + + // Failed. The file exists + failed = false; + + } catch (Throwable e) { + // Operation complete successfully + } + if (failed) { + throw new ExecutionException( + String.format( + "Failed to extract file: %s", //$NON-NLS-1$ + this.mFso.getFullPath())); + } + } + }; + final BackgroundAsyncTask task = new BackgroundAsyncTask(ctx, callable); + + // Check if the output exists + boolean askUser = false; + try { + UncompressExecutable ucmd = + ExplorerApplication.getBackgroundConsole(). + getExecutableFactory().newCreator(). + createUncompressExecutable(fso.getFullPath(), null); + String dst = ucmd.getOutUncompressedFile(); + FileSystemObject info = CommandHelper.getFileInfo(ctx, dst, null); + if (info != null) { + askUser = true; + } + } catch (Exception e) {/**NON BLOCK**/} + + // Ask the user because the destination file or folder exists + if (askUser) { + //Show a dialog asking the user for overwrite the files + AlertDialog dialog = + DialogHelper.createTwoButtonsQuestionDialog( + ctx, + android.R.string.cancel, + R.string.overwrite, + ctx.getString(R.string.msgs_overwrite_files), + new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface alertDialog, int which) { + // NEGATIVE (overwrite) POSITIVE (cancel) + if (which == DialogInterface.BUTTON_NEGATIVE) { + // Check if the necessary to display a warning because + // security issues + checkZipSecurityWarning(ctx, task, fso); + } + } + }); + dialog.show(); + } else { + // Execute background task + task.execute(task); + } + } + + /** + * Method that checks if it is necessary to display a warning dialog because + * the privileged extraction of a zip file. + * + * @param ctx The current context + * @param task The task + * @param fso The zip file + * @hide + */ + static void checkZipSecurityWarning( + final Context ctx, final BackgroundAsyncTask task, FileSystemObject fso) { + // WARNING! Extracting a ZIP file with relatives or absolutes path could break + // the system and is need a security alert that the user can confirm prior to + // make the extraction + String ext = FileHelper.getExtension(fso); + if (ConsoleBuilder.isPrivileged() && ext.compareTo("zip") == 0) { //$NON-NLS-1$ + AlertDialog dialog =DialogHelper.createYesNoDialog( + ctx, R.string.security_warning_extract, + new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface alertDialog, int which) { + if (which == DialogInterface.BUTTON_POSITIVE) { + // Execute background task + task.execute(task); + } + } + }); + dialog.show(); + } else { + // Execute background task + task.execute(task); + } + } +}
\ No newline at end of file diff --git a/src/com/cyanogenmod/explorer/ui/policy/CopyMoveActionPolicy.java b/src/com/cyanogenmod/explorer/ui/policy/CopyMoveActionPolicy.java new file mode 100644 index 0000000..3a49c1f --- /dev/null +++ b/src/com/cyanogenmod/explorer/ui/policy/CopyMoveActionPolicy.java @@ -0,0 +1,509 @@ +/* + * Copyright (C) 2012 The CyanogenMod Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.cyanogenmod.explorer.ui.policy; + +import android.app.AlertDialog; +import android.content.Context; +import android.content.DialogInterface; +import android.text.Html; +import android.text.Spanned; + +import com.cyanogenmod.explorer.R; +import com.cyanogenmod.explorer.console.RelaunchableException; +import com.cyanogenmod.explorer.listeners.OnRequestRefreshListener; +import com.cyanogenmod.explorer.listeners.OnSelectionListener; +import com.cyanogenmod.explorer.model.FileSystemObject; +import com.cyanogenmod.explorer.util.CommandHelper; +import com.cyanogenmod.explorer.util.DialogHelper; +import com.cyanogenmod.explorer.util.ExceptionUtil; +import com.cyanogenmod.explorer.util.ExceptionUtil.OnRelaunchCommandResult; +import com.cyanogenmod.explorer.util.FileHelper; + +import java.io.File; +import java.util.ArrayList; +import java.util.List; + +/** + * A class with the convenience methods for resolve copy/move related actions + */ +public final class CopyMoveActionPolicy extends ActionsPolicy { + + /** + * @hide + */ + private enum COPY_MOVE_OPERATION { + COPY, + MOVE, + RENAME, + CREATE_COPY, + } + + + /** + * A class that holds a relationship between a source {@link File} and + * his destination {@link File} + */ + public static class LinkedResource implements Comparable<LinkedResource> { + final File mSrc; + final File mDst; + + /** + * Constructor of <code>LinkedResource</code> + * + * @param src The source file system object + * @param dst The destination file system object + */ + public LinkedResource(File src, File dst) { + super(); + this.mSrc = src; + this.mDst = dst; + } + + /** + * {@inheritDoc} + */ + @Override + public int compareTo(LinkedResource another) { + return this.mSrc.compareTo(another.mSrc); + } + } + + /** + * Method that remove an existing file system object. + * + * @param ctx The current context + * @param fso The file system object + * @param newName The new name of the object + * @param onSelectionListener The listener for obtain selection information (required) + * @param onRequestRefreshListener The listener for request a refresh (optional) + */ + public static void renameFileSystemObject( + final Context ctx, + final FileSystemObject fso, + final String newName, + final OnSelectionListener onSelectionListener, + final OnRequestRefreshListener onRequestRefreshListener) { + + // Create the destination filename + File dst = new File(fso.getParent(), newName); + File src = new File(fso.getFullPath()); + + // Create arguments + LinkedResource linkRes = new LinkedResource(src, dst); + List<LinkedResource> files = new ArrayList<LinkedResource>(1); + files.add(linkRes); + + // Internal copy + copyOrMoveFileSystemObjects( + ctx, + COPY_MOVE_OPERATION.RENAME, + files, + onSelectionListener, + onRequestRefreshListener); + } + + /** + * Method that copy an existing file system object. + * + * @param ctx The current context + * @param fso The file system object + * @param onSelectionListener The listener for obtain selection information (required) + * @param onRequestRefreshListener The listener for request a refresh (optional) + */ + public static void createCopyFileSystemObject( + final Context ctx, + final FileSystemObject fso, + final OnSelectionListener onSelectionListener, + final OnRequestRefreshListener onRequestRefreshListener) { + + // Create a non-existing name + List<FileSystemObject> curFiles = onSelectionListener.onRequestCurrentItems(); + String newName = FileHelper.createNonExistingName(ctx, curFiles, fso); + final File dst = new File(fso.getParent(), newName); + File src = new File(fso.getFullPath()); + + // Create arguments + LinkedResource linkRes = new LinkedResource(src, dst); + List<LinkedResource> files = new ArrayList<LinkedResource>(1); + files.add(linkRes); + + // Internal copy + copyOrMoveFileSystemObjects( + ctx, + COPY_MOVE_OPERATION.CREATE_COPY, + files, + onSelectionListener, + onRequestRefreshListener); + } + + /** + * Method that copy an existing file system object. + * + * @param ctx The current context + * @param files The list of files to copy + * @param onSelectionListener The listener for obtain selection information (required) + * @param onRequestRefreshListener The listener for request a refresh (optional) + */ + public static void copyFileSystemObjects( + final Context ctx, + final List<LinkedResource> files, + final OnSelectionListener onSelectionListener, + final OnRequestRefreshListener onRequestRefreshListener) { + // Internal copy + copyOrMoveFileSystemObjects( + ctx, + COPY_MOVE_OPERATION.COPY, + files, + onSelectionListener, + onRequestRefreshListener); + } + + /** + * Method that copy an existing file system object. + * + * @param ctx The current context + * @param files The list of files to move + * @param onSelectionListener The listener for obtain selection information (required) + * @param onRequestRefreshListener The listener for request a refresh (optional) + */ + public static void moveFileSystemObjects( + final Context ctx, + final List<LinkedResource> files, + final OnSelectionListener onSelectionListener, + final OnRequestRefreshListener onRequestRefreshListener) { + // Internal move + copyOrMoveFileSystemObjects( + ctx, + COPY_MOVE_OPERATION.MOVE, + files, + onSelectionListener, + onRequestRefreshListener); + } + + /** + * Method that copy an existing file system object. + * + * @param ctx The current context + * @param operation Indicates the operation to do + * @param files The list of source/destination files to copy + * @param onSelectionListener The listener for obtain selection information (required) + * @param onRequestRefreshListener The listener for request a refresh (optional) + */ + private static void copyOrMoveFileSystemObjects( + final Context ctx, + final COPY_MOVE_OPERATION operation, + final List<LinkedResource> files, + final OnSelectionListener onSelectionListener, + final OnRequestRefreshListener onRequestRefreshListener) { + + // Some previous checks prior to execute + // 1.- Listener can't not be null + if (onSelectionListener == null) { + AlertDialog dialog = + DialogHelper.createErrorDialog(ctx, R.string.msgs_illegal_argument); + dialog.show(); + return; + } + // 2.- All the destination files must have the same parent and it must be currentDirectory, + // and not be null + final String currentDirectory = onSelectionListener.onRequestCurrentDir(); + for (int i = 0; i < files.size(); i++) { + LinkedResource linkedRes = files.get(i); + if (linkedRes.mSrc == null || linkedRes.mDst == null) { + AlertDialog dialog = + DialogHelper.createErrorDialog(ctx, R.string.msgs_illegal_argument); + dialog.show(); + return; + } + if (linkedRes.mDst.getParent() == null || + linkedRes.mDst.getParent().compareTo(currentDirectory) != 0) { + AlertDialog dialog = + DialogHelper.createErrorDialog(ctx, R.string.msgs_illegal_argument); + dialog.show(); + return; + } + } + // 3.- Check the operation consistency + if (operation.compareTo(COPY_MOVE_OPERATION.MOVE) == 0) { + if (!checkMoveConsistency(ctx, files, currentDirectory)) { + return; + } + } + + // The callable interface + final BackgroundCallable callable = new BackgroundCallable() { + // The current items + private int mCurrent = 0; + final Context mCtx = ctx; + final COPY_MOVE_OPERATION mOperation = operation; + final List<LinkedResource> mFiles = files; + final OnRequestRefreshListener mOnRequestRefreshListener = onRequestRefreshListener; + + final Object mSync = new Object(); + Throwable mCause; + + @Override + public int getDialogTitle() { + return this.mOperation.compareTo(COPY_MOVE_OPERATION.MOVE) == 0 || + this.mOperation.compareTo(COPY_MOVE_OPERATION.RENAME) == 0 ? + R.string.waiting_dialog_moving_title : + R.string.waiting_dialog_copying_title; + } + @Override + public int getDialogIcon() { + return R.drawable.ic_holo_light_operation; + } + + @Override + public Spanned requestProgress() { + File src = this.mFiles.get(this.mCurrent).mSrc; + File dst = this.mFiles.get(this.mCurrent).mDst; + + // Return the current operation + String progress = + this.mCtx.getResources(). + getString( + this.mOperation.compareTo(COPY_MOVE_OPERATION.MOVE) == 0 || + this.mOperation.compareTo(COPY_MOVE_OPERATION.RENAME) == 0 ? + R.string.waiting_dialog_moving_msg : + R.string.waiting_dialog_copying_msg, + src.getAbsolutePath(), + dst.getAbsolutePath()); + return Html.fromHtml(progress); + } + + @Override + public void onSuccess() { + //Operation complete. Refresh + if (this.mOnRequestRefreshListener != null) { + // The reference is not the same, so refresh the complete navigation view + this.mOnRequestRefreshListener.onRequestRefresh(null); + } + ActionsPolicy.showOperationSuccessMsg(ctx); + } + + @Override + public void doInBackground(Object... params) throws Throwable { + this.mCause = null; + + // This method expect to receive + // 1.- BackgroundAsyncTask + BackgroundAsyncTask task = (BackgroundAsyncTask)params[0]; + + for (int i = 0; i < this.mFiles.size(); i++) { + File src = this.mFiles.get(i).mSrc; + File dst = this.mFiles.get(i).mDst; + + doOperation(this.mCtx, src, dst, this.mOperation); + + // Next file + this.mCurrent++; + if (this.mCurrent < this.mFiles.size()) { + task.onRequestProgress(); + } + } + } + + /** + * Method that copy or move the file to another location + * + * @param ctx The current context + * @param src The source file + * @param dst The destination file + * @param operation Indicates the operation to do + */ + @SuppressWarnings("hiding") + private void doOperation( + Context ctx, File src, File dst, COPY_MOVE_OPERATION operation) + throws Throwable { + // If the source is the same as destiny then don't do the operation + if (src.compareTo(dst) == 0) return; + + try { + // Copy or move? + if (operation.compareTo(COPY_MOVE_OPERATION.MOVE) == 0 || + operation.compareTo(COPY_MOVE_OPERATION.RENAME) == 0) { + CommandHelper.move( + ctx, + src.getAbsolutePath(), + dst.getAbsolutePath(), + null); + } else { + CommandHelper.copy( + ctx, + src.getAbsolutePath(), + dst.getAbsolutePath(), + null); + } + } catch (Exception e) { + // Need to be relaunched? + if (e instanceof RelaunchableException) { + OnRelaunchCommandResult rl = new OnRelaunchCommandResult() { + @Override + @SuppressWarnings("unqualified-field-access") + public void onSuccess() { + synchronized (mSync) { + mSync.notify(); + } + } + + @Override + @SuppressWarnings("unqualified-field-access") + public void onFailed(Throwable cause) { + mCause = cause; + synchronized (mSync) { + mSync.notify(); + } + } + @Override + @SuppressWarnings("unqualified-field-access") + public void onCanceled() { + synchronized (mSync) { + mSync.notify(); + } + } + }; + + // Translate the exception (and wait for the result) + ExceptionUtil.translateException(ctx, e, false, true, rl); + synchronized (this.mSync) { + this.mSync.wait(); + } + + // Persist the exception? + if (this.mCause != null) { + // The exception must be elevated + throw this.mCause; + } + + } else { + // The exception must be elevated + throw e; + } + } + + // Check that the operation was completed retrieving the fso modified + CommandHelper.getFileInfo(ctx, dst.getAbsolutePath(), false, null); + } + }; + final BackgroundAsyncTask task = new BackgroundAsyncTask(ctx, callable); + + // Prior to execute, we need to check if some of the files will be overwritten + List<FileSystemObject> curFiles = onSelectionListener.onRequestCurrentItems(); + if (curFiles != null) { + // Is necessary to ask the user? + if (isOverwriteNeeded(files, curFiles)) { + //Show a dialog asking the user for overwrite the files + AlertDialog dialog = + DialogHelper.createTwoButtonsQuestionDialog( + ctx, + android.R.string.cancel, + R.string.overwrite, + ctx.getString(R.string.msgs_overwrite_files), + new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface alertDialog, int which) { + // NEGATIVE (overwrite) POSITIVE (cancel) + if (which == DialogInterface.BUTTON_NEGATIVE) { + // Execute background task + task.execute(task); + } + } + }); + dialog.show(); + return; + } + } + + // Execute background task + task.execute(task); + } + + /** + * Method that check if is needed to prompt the user for overwrite prior to do + * the operation. + * + * @param files The list of source/destination files. + * @param currentFiles The list of the current files in the destination directory. + * @return boolean If is needed to prompt the user for overwrite + */ + private static boolean isOverwriteNeeded( + List<LinkedResource> files, List<FileSystemObject> currentFiles) { + boolean askUser = false; + for (int i = 0; i < currentFiles.size(); i++) { + for (int j = 0; j < files.size(); j++) { + FileSystemObject dst1 = currentFiles.get(i); + File dst2 = files.get(j).mDst; + + // The file exists in the destination directory + if (dst1.getFullPath().compareTo(dst2.getAbsolutePath()) == 0) { + askUser = true; + break; + } + } + if (askUser) break; + } + return askUser; + } + + + /** + * Method that check the consistency of move operations.<br/> + * <br/> + * The method checks the following rules:<br/> + * <ul> + * <li>Any of the files of the move operation can not include the + * current directory.</li> + * <li>Any of the files of the move operation can not include the + * current directory.</li> + * </ul> + * + * @param ctx The current context + * @param files The list of source/destination files + * @param currentDirectory The current directory + * @return boolean If the consistency is validate successfully + */ + private static boolean checkMoveConsistency( + Context ctx, List<LinkedResource> files, String currentDirectory) { + for (int i = 0; i < files.size(); i++) { + LinkedResource linkRes = files.get(i); + String src = linkRes.mSrc.getAbsolutePath(); + String dst = linkRes.mDst.getAbsolutePath(); + + // 1.- Current directory can't be moved + if (currentDirectory != null && currentDirectory.startsWith(src)) { + // Operation not allowed + AlertDialog dialog = + DialogHelper.createErrorDialog( + ctx, R.string.msgs_unresolved_inconsistencies); + dialog.show(); + return false; + } + + // 2.- Destination can't be a child of source + if (dst.startsWith(src)) { + // Operation not allowed + AlertDialog dialog = + DialogHelper.createErrorDialog( + ctx, R.string.msgs_operation_not_allowed_in_current_directory); + dialog.show(); + return false; + } + } + return true; + } +}
\ No newline at end of file diff --git a/src/com/cyanogenmod/explorer/ui/policy/DeleteActionPolicy.java b/src/com/cyanogenmod/explorer/ui/policy/DeleteActionPolicy.java new file mode 100644 index 0000000..d66cb95 --- /dev/null +++ b/src/com/cyanogenmod/explorer/ui/policy/DeleteActionPolicy.java @@ -0,0 +1,311 @@ +/* + * Copyright (C) 2012 The CyanogenMod Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.cyanogenmod.explorer.ui.policy; + +import android.app.AlertDialog; +import android.content.Context; +import android.content.DialogInterface; +import android.text.Html; +import android.text.Spanned; + +import com.cyanogenmod.explorer.R; +import com.cyanogenmod.explorer.console.ExecutionException; +import com.cyanogenmod.explorer.console.RelaunchableException; +import com.cyanogenmod.explorer.listeners.OnRequestRefreshListener; +import com.cyanogenmod.explorer.listeners.OnSelectionListener; +import com.cyanogenmod.explorer.model.FileSystemObject; +import com.cyanogenmod.explorer.util.CommandHelper; +import com.cyanogenmod.explorer.util.DialogHelper; +import com.cyanogenmod.explorer.util.ExceptionUtil; +import com.cyanogenmod.explorer.util.ExceptionUtil.OnRelaunchCommandResult; +import com.cyanogenmod.explorer.util.FileHelper; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; + + +/** + * A class with the convenience methods for resolve delete related actions + */ +public final class DeleteActionPolicy extends ActionsPolicy { + + /** + * Method that remove an existing file system object. + * + * @param ctx The current context + * @param fso The file system object to remove + * @param onSelectionListener The listener for obtain selection information (required) + * @param onRequestRefreshListener The listener for request a refresh (optional) + */ + public static void removeFileSystemObject( + final Context ctx, final FileSystemObject fso, + final OnSelectionListener onSelectionListener, + final OnRequestRefreshListener onRequestRefreshListener) { + // Generate an array and invoke internal method + List<FileSystemObject> files = new ArrayList<FileSystemObject>(1); + files.add(fso); + removeFileSystemObjects(ctx, files, onSelectionListener, onRequestRefreshListener); + } + + /** + * Method that remove an existing file system object. + * + * @param ctx The current context + * @param files The list of files to remove + * @param onSelectionListener The listener for obtain selection information (required) + * @param onRequestRefreshListener The listener for request a refresh (optional) + */ + public static void removeFileSystemObjects( + final Context ctx, final List<FileSystemObject> files, + final OnSelectionListener onSelectionListener, + final OnRequestRefreshListener onRequestRefreshListener) { + + // Ask the user before remove + AlertDialog dialog =DialogHelper.createYesNoDialog( + ctx, R.string.actions_ask_undone_operation, + new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface alertDialog, int which) { + if (which == DialogInterface.BUTTON_POSITIVE) { + // Remove the items + removeFileSystemObjectsInBackground( + ctx, + files, + onSelectionListener, + onRequestRefreshListener); + } + } + }); + dialog.show(); + } + + /** + * Method that remove an existing file system object in background. + * + * @param ctx The current context + * @param files The list of files to remove + * @param onSelectionListener The listener for obtain selection information (optional) + * @param onRequestRefreshListener The listener for request a refresh (optional) + * @hide + */ + static void removeFileSystemObjectsInBackground( + final Context ctx, final List<FileSystemObject> files, + final OnSelectionListener onSelectionListener, + final OnRequestRefreshListener onRequestRefreshListener) { + + // Some previous checks prior to execute + // 1.- Check the operation consistency (only if it is viable) + if (onSelectionListener != null) { + final String currentDirectory = onSelectionListener.onRequestCurrentDir(); + if (!checkRemoveConsistency(ctx, files, currentDirectory)) { + return; + } + } + // 2.- Sort the items by path to avoid delete parents fso prior to child fso + final List<FileSystemObject> sortedFsos = new ArrayList<FileSystemObject>(files); + Collections.sort(sortedFsos, new Comparator<FileSystemObject>() { + @Override + public int compare(FileSystemObject lhs, FileSystemObject rhs) { + return lhs.compareTo(rhs) * -1; //Reverse + } + }); + + // The callable interface + final BackgroundCallable callable = new BackgroundCallable() { + // The current items + private int mCurrent = 0; + final Context mCtx = ctx; + final List<FileSystemObject> mFiles = sortedFsos; + final OnRequestRefreshListener mOnRequestRefreshListener = onRequestRefreshListener; + + final Object mSync = new Object(); + Throwable mCause; + + @Override + public int getDialogTitle() { + return R.string.waiting_dialog_deleting_title; + } + @Override + public int getDialogIcon() { + return R.drawable.ic_holo_light_operation; + } + + @Override + public Spanned requestProgress() { + FileSystemObject fso = this.mFiles.get(this.mCurrent); + + // Return the current operation + String progress = + this.mCtx.getResources(). + getString( + R.string.waiting_dialog_deleting_msg, + fso.getFullPath()); + return Html.fromHtml(progress); + } + + @Override + public void onSuccess() { + //Operation complete. Refresh + if (this.mOnRequestRefreshListener != null) { + // The reference is not the same, so refresh the complete navigation view + this.mOnRequestRefreshListener.onRequestRefresh(null); + } + ActionsPolicy.showOperationSuccessMsg(ctx); + } + + @Override + public void doInBackground(Object... params) throws Throwable { + this.mCause = null; + + // This method expect to receive + // 1.- BackgroundAsyncTask + BackgroundAsyncTask task = (BackgroundAsyncTask)params[0]; + + for (int i = 0; i < this.mFiles.size(); i++) { + FileSystemObject fso = this.mFiles.get(i); + + doOperation(this.mCtx, fso); + + // Next file + this.mCurrent++; + if (this.mCurrent < this.mFiles.size()) { + task.onRequestProgress(); + } + } + } + + /** + * Method that deletes the file or directory + * + * @param ctx The current context + * @param fso The file or folder to be deleted + */ + @SuppressWarnings("hiding") + private void doOperation( + final Context ctx, final FileSystemObject fso) throws Throwable { + try { + // Remove the item + if (FileHelper.isDirectory(fso)) { + CommandHelper.deleteDirectory(ctx, fso.getFullPath(), null); + } else { + CommandHelper.deleteFile(ctx, fso.getFullPath(), null); + } + } catch (Exception e) { + // Need to be relaunched? + if (e instanceof RelaunchableException) { + OnRelaunchCommandResult rl = new OnRelaunchCommandResult() { + @Override + @SuppressWarnings("unqualified-field-access") + public void onSuccess() { + synchronized (mSync) { + mSync.notify(); + } + } + + @Override + @SuppressWarnings("unqualified-field-access") + public void onFailed(Throwable cause) { + mCause = cause; + synchronized (mSync) { + mSync.notify(); + } + } + @Override + @SuppressWarnings("unqualified-field-access") + public void onCanceled() { + synchronized (mSync) { + mSync.notify(); + } + } + }; + + // Translate the exception (and wait for the result) + ExceptionUtil.translateException(ctx, e, false, true, rl); + synchronized (this.mSync) { + this.mSync.wait(); + } + + // Persist the exception? + if (this.mCause != null) { + // The exception must be elevated + throw this.mCause; + } + + } else { + // The exception must be elevated + throw e; + } + } + + // Check that the operation was completed retrieving the deleted fso + boolean failed = false; + try { + CommandHelper.getFileInfo(ctx, fso.getFullPath(), false, null); + + // Failed. The file still exists + failed = true; + + } catch (Throwable e) { + // Operation complete successfully + } + if (failed) { + throw new ExecutionException( + String.format( + "Failed to delete file: %s", fso.getFullPath())); //$NON-NLS-1$ + } + } + }; + final BackgroundAsyncTask task = new BackgroundAsyncTask(ctx, callable); + + // Execute background task + task.execute(task); + } + + /** + * Method that check the consistency of delete operations.<br/> + * <br/> + * The method checks the following rules:<br/> + * <ul> + * <li>Any of the files of the move or delete operation can not include the + * current directory.</li> + * </ul> + * + * @param ctx The current context + * @param files The list of source/destination files + * @param currentDirectory The current directory + * @return boolean If the consistency is validate successfully + */ + private static boolean checkRemoveConsistency( + Context ctx, List<FileSystemObject> files, String currentDirectory) { + for (int i = 0; i < files.size(); i++) { + FileSystemObject fso = files.get(i); + + // 1.- Current directory can't be deleted + if (currentDirectory.startsWith(fso.getFullPath())) { + // Operation not allowed + AlertDialog dialog = + DialogHelper.createErrorDialog( + ctx, R.string.msgs_unresolved_inconsistencies); + dialog.show(); + return false; + } + } + return true; + } +}
\ No newline at end of file diff --git a/src/com/cyanogenmod/explorer/ui/policy/ExecutionActionPolicy.java b/src/com/cyanogenmod/explorer/ui/policy/ExecutionActionPolicy.java new file mode 100644 index 0000000..05f6ed3 --- /dev/null +++ b/src/com/cyanogenmod/explorer/ui/policy/ExecutionActionPolicy.java @@ -0,0 +1,111 @@ +/* + * Copyright (C) 2012 The CyanogenMod Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.cyanogenmod.explorer.ui.policy; + +import android.content.Context; + +import com.cyanogenmod.explorer.commands.AsyncResultListener; +import com.cyanogenmod.explorer.commands.ExecExecutable; +import com.cyanogenmod.explorer.model.FileSystemObject; +import com.cyanogenmod.explorer.ui.dialogs.ExecutionDialog; +import com.cyanogenmod.explorer.util.CommandHelper; +import com.cyanogenmod.explorer.util.ExceptionUtil; + +/** + * A class with the convenience methods for resolve executions related actions + */ +public final class ExecutionActionPolicy extends ActionsPolicy { + + /** + * A class that holds a listener of the execution of a program + */ + private static class ExecutionListener implements AsyncResultListener { + + private final ExecutionDialog mDialog; + + /** + * Constructor of <code>ExecutionListener</code> + * + * @param dialog The console dialog + */ + public ExecutionListener(ExecutionDialog dialog) { + super(); + this.mDialog = dialog; + } + + @Override + public void onPartialResult(Object result) { + this.mDialog.onAppendData((String)result); + } + + @Override + public void onException(Exception cause) { + this.mDialog.onAppendData(ExceptionUtil.toStackTrace(cause)); + } + + @Override + public void onAsyncStart() { + this.mDialog.onStart(); + } + + @Override + public void onAsyncEnd(boolean canceled) {/**NON BLOCK**/} + + @Override + public void onAsyncExitCode(int exitCode) { + this.mDialog.onEnd(exitCode); + } + } + + /** + * Method that executes a {@link FileSystemObject} and show the output in the console + * dialog. + * + * @param ctx The current context + * @param fso The file system object + */ + public static void execute( + final Context ctx, final FileSystemObject fso) { + try { + // Create a console dialog for display the script output + final ExecutionDialog dialog = new ExecutionDialog(ctx, fso); + dialog.show(); + + Thread t = new Thread() { + @Override + public void run() { + final ExecutionListener listener = new ExecutionListener(dialog); + try { + Thread.sleep(250L); + + // Execute the script + ExecExecutable cmd = + CommandHelper.exec( + ctx, fso.getFullPath(), listener, null); + dialog.setCmd(cmd); + } catch (Exception e) { + listener.onException(e); + } + } + }; + t.start(); + + } catch (Exception e) { + ExceptionUtil.translateException(ctx, e); + } + } +}
\ No newline at end of file diff --git a/src/com/cyanogenmod/explorer/ui/policy/InfoActionPolicy.java b/src/com/cyanogenmod/explorer/ui/policy/InfoActionPolicy.java new file mode 100644 index 0000000..8168015 --- /dev/null +++ b/src/com/cyanogenmod/explorer/ui/policy/InfoActionPolicy.java @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2012 The CyanogenMod Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.cyanogenmod.explorer.ui.policy; + +import android.content.Context; +import android.content.DialogInterface; +import android.widget.Toast; + +import com.cyanogenmod.explorer.listeners.OnRequestRefreshListener; +import com.cyanogenmod.explorer.model.FileSystemObject; +import com.cyanogenmod.explorer.ui.dialogs.FsoPropertiesDialog; + +/** + * A class with the convenience methods for resolve the display of info actions + */ +public final class InfoActionPolicy extends ActionsPolicy { + + /** + * Method that show a {@link Toast} with the content description of a {@link FileSystemObject}. + * + * @param ctx The current context + * @param fso The file system object + */ + public static void showContentDescription(final Context ctx, final FileSystemObject fso) { + String contentDescription = fso.getFullPath(); + Toast.makeText(ctx, contentDescription, Toast.LENGTH_SHORT).show(); + } + + /** + * Method that show a new dialog for show {@link FileSystemObject} properties. + * + * @param ctx The current context + * @param fso The file system object + * @param onRequestRefreshListener The listener for request a refresh after properties + * of the {@link FileSystemObject} were changed (optional) + */ + public static void showPropertiesDialog( + final Context ctx, final FileSystemObject fso, + final OnRequestRefreshListener onRequestRefreshListener) { + //Show a the filesystem info dialog + final FsoPropertiesDialog dialog = new FsoPropertiesDialog(ctx, fso); + dialog.setOnDismissListener(new DialogInterface.OnDismissListener() { + @Override + public void onDismiss(DialogInterface dlg) { + // Any change? + if (dialog.isHasChanged()) { + if (onRequestRefreshListener != null) { + onRequestRefreshListener.onRequestRefresh(dialog.getFso()); + } + } + } + }); + dialog.show(); + } + +}
\ No newline at end of file diff --git a/src/com/cyanogenmod/explorer/ui/policy/IntentsActionPolicy.java b/src/com/cyanogenmod/explorer/ui/policy/IntentsActionPolicy.java new file mode 100644 index 0000000..1d43a8c --- /dev/null +++ b/src/com/cyanogenmod/explorer/ui/policy/IntentsActionPolicy.java @@ -0,0 +1,167 @@ +/* + * Copyright (C) 2012 The CyanogenMod Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.cyanogenmod.explorer.ui.policy; + +import android.content.Context; +import android.content.Intent; +import android.content.pm.PackageManager; +import android.content.pm.ResolveInfo; +import android.net.Uri; +import android.widget.Toast; + +import com.cyanogenmod.explorer.R; +import com.cyanogenmod.explorer.model.FileSystemObject; +import com.cyanogenmod.explorer.ui.dialogs.AssociationsDialog; +import com.cyanogenmod.explorer.util.ExceptionUtil; +import com.cyanogenmod.explorer.util.MimeTypeHelper; + +import java.io.File; +import java.util.List; + +/** + * A class with the convenience methods for resolve intents related actions + */ +public final class IntentsActionPolicy extends ActionsPolicy { + + private static boolean DEBUG = false; + + /** + * Method that opens a {@link FileSystemObject} with the default registered application + * by the system, or ask the user for select a registered application. + * + * @param ctx The current context + * @param fso The file system object + * @param choose If allow the user to select the application to open with + */ + public static void openFileSystemObject( + final Context ctx, final FileSystemObject fso, final boolean choose) { + try { + // Create the intent to + Intent intent = new Intent(); + intent.setAction(android.content.Intent.ACTION_VIEW); + + // Obtain the mime/type and passed it to intent + String mime = MimeTypeHelper.getMimeType(ctx, fso); + File file = new File(fso.getFullPath()); + if (mime != null) { + intent.setDataAndType(Uri.fromFile(file), mime); + } else { + intent.setData(Uri.fromFile(file)); + } + + // Resolve the intent + resolveIntent( + ctx, + intent, + choose, + R.drawable.ic_holo_light_open, + R.string.associations_dialog_openwith_title, + R.string.associations_dialog_openwith_action, + true); + + } catch (Exception e) { + ExceptionUtil.translateException(ctx, e); + } + } + + /** + * Method that sends a {@link FileSystemObject} with the default registered application + * by the system, or ask the user for select a registered application. + * + * @param ctx The current context + * @param fso The file system object + */ + public static void sendFileSystemObject( + final Context ctx, final FileSystemObject fso) { + try { + // Create the intent to + Intent intent = new Intent(); + intent.setAction(android.content.Intent.ACTION_SEND); + intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); + intent.setType(MimeTypeHelper.getMimeType(ctx, fso)); + Uri uri = Uri.fromFile(new File(fso.getFullPath())); + intent.putExtra(Intent.EXTRA_STREAM, uri); + + // Resolve the intent + resolveIntent( + ctx, + intent, + false, + R.drawable.ic_holo_light_send, + R.string.associations_dialog_sendwith_title, + R.string.associations_dialog_sendwith_action, + false); + + } catch (Exception e) { + ExceptionUtil.translateException(ctx, e); + } + } + + /** + * Method that resolve + * + * @param ctx The current context + * @param intent The intent to resolve + * @param choose If allow the user to select the application to select the registered + * application. If no preferred app or more than one exists the dialog is shown. + * @param icon The icon of the dialog + * @param title The title of the dialog + * @param action The button title of the dialog + * @param allowPreferred If allow the user to mark the selected app as preferred + */ + private static void resolveIntent( + Context ctx, Intent intent, boolean choose, + int icon, int title, int action, boolean allowPreferred) { + //Retrieve the activities that can handle the file + final PackageManager packageManager = ctx.getPackageManager(); + if (DEBUG) { + intent.addFlags(Intent.FLAG_DEBUG_LOG_RESOLUTION); + } + List<ResolveInfo> info = + packageManager. + queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY); + + // Retrieve the preferred activity that can handle the file + final ResolveInfo mPreferredInfo = packageManager.resolveActivity(intent, 0); + + // No registered application + if (info.size() == 0) { + Toast.makeText(ctx, R.string.msgs_not_registered_app, Toast.LENGTH_SHORT).show(); + return; + } + + // Is a simple open and we have an application that can handle the file? + if (!choose && + ((mPreferredInfo != null && mPreferredInfo.match != 0) || info.size() == 1)) { + ctx.startActivity(intent); + return; + } + + // Otherwise, we have to show the open with dialog + AssociationsDialog dialog = + new AssociationsDialog( + ctx, + icon, + ctx.getString(title), + ctx.getString(action), + intent, + info, + mPreferredInfo, + allowPreferred); + dialog.show(); + } +}
\ No newline at end of file diff --git a/src/com/cyanogenmod/explorer/ui/policy/NewActionPolicy.java b/src/com/cyanogenmod/explorer/ui/policy/NewActionPolicy.java new file mode 100644 index 0000000..fd29fbe --- /dev/null +++ b/src/com/cyanogenmod/explorer/ui/policy/NewActionPolicy.java @@ -0,0 +1,234 @@ +/* + * Copyright (C) 2012 The CyanogenMod Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.cyanogenmod.explorer.ui.policy; + +import android.content.Context; +import android.os.AsyncTask; +import android.util.Log; + +import com.cyanogenmod.explorer.console.RelaunchableException; +import com.cyanogenmod.explorer.listeners.OnRequestRefreshListener; +import com.cyanogenmod.explorer.listeners.OnSelectionListener; +import com.cyanogenmod.explorer.model.FileSystemObject; +import com.cyanogenmod.explorer.util.CommandHelper; +import com.cyanogenmod.explorer.util.ExceptionUtil; + +import java.io.File; + +/** + * A class with the convenience methods for resolve new related actions + */ +public final class NewActionPolicy extends ActionsPolicy { + + private static final String TAG = "NewActionPolicy"; //$NON-NLS-1$ + + private static boolean DEBUG = false; + + /** + * Method that create the a new file system object. + * + * @param ctx The current context + * @param name The name of the file to be created + * @param onSelectionListener The selection listener (required) + * @param onRequestRefreshListener The listener for request a refresh after the new + * file was created (option) + */ + public static void createNewFile( + final Context ctx, final String name, + final OnSelectionListener onSelectionListener, + final OnRequestRefreshListener onRequestRefreshListener) { + createNewFileSystemObject(ctx, name, false, onSelectionListener, onRequestRefreshListener); + } + + /** + * Method that create the a new folder system object. + * + * @param ctx The current context + * @param name The name of the file to be created + * @param onSelectionListener The selection listener (required) + * @param onRequestRefreshListener The listener for request a refresh after the new + * folder was created (option) + */ + public static void createNewDirectory( + final Context ctx, final String name, + final OnSelectionListener onSelectionListener, + final OnRequestRefreshListener onRequestRefreshListener) { + createNewFileSystemObject(ctx, name, true, onSelectionListener, onRequestRefreshListener); + } + + /** + * Method that create the a new file system object. + * + * @param ctx The current context + * @param name The name of the file to be created + * @param folder If the new {@link FileSystemObject} to create is a folder (true) or a + * file (false). + * @param onSelectionListener The selection listener (required) + * @param onRequestRefreshListener The listener for request a refresh after the new + * folder was created (option) + */ + private static void createNewFileSystemObject( + final Context ctx, final String name, final boolean folder, + final OnSelectionListener onSelectionListener, + final OnRequestRefreshListener onRequestRefreshListener) { + + //Create the absolute file name + File newFso = new File( + onSelectionListener.onRequestCurrentDir(), name); + final String newName = newFso.getAbsolutePath(); + + try { + if (folder) { + if (DEBUG) { + Log.d(TAG, String.format("Creating new directory: %s", newName)); //$NON-NLS-1$ + } + CommandHelper.createDirectory(ctx, newName, null); + } else { + if (DEBUG) { + Log.d(TAG, String.format("Creating new file: %s", newName)); //$NON-NLS-1$ + } + CommandHelper.createFile(ctx, newName, null); + } + + //Operation complete. Show refresh + if (onRequestRefreshListener != null) { + FileSystemObject fso = null; + try { + fso = CommandHelper.getFileInfo(ctx, newName, false, null); + } catch (Throwable ex2) { + /**NON BLOCK**/ + } + onRequestRefreshListener.onRequestRefresh(fso); + } + showOperationSuccessMsg(ctx); + + } catch (Throwable ex) { + //Capture the exception + if (ex instanceof RelaunchableException) { + ExceptionUtil.attachAsyncTask(ex, new AsyncTask<Object, Integer, Boolean>() { + /** + * {@inheritDoc} + */ + @Override + protected Boolean doInBackground(Object... params) { + //Operation complete. Show refresh + if (onRequestRefreshListener != null) { + FileSystemObject fso = null; + try { + fso = + CommandHelper.getFileInfo(ctx, newName, false, null); + } catch (Throwable ex2) { + /**NON BLOCK**/ + } + onRequestRefreshListener.onRequestRefresh(fso); + } + return Boolean.TRUE; + } + + /** + * {@inheritDoc} + */ + @Override + protected void onPostExecute(Boolean result) { + if (result != null && result.booleanValue()) { + showOperationSuccessMsg(ctx); + } + } + }); + } + ExceptionUtil.translateException(ctx, ex); + } + } + + /** + * Method that remove an existing file system object. + * + * @param ctx The current context + * @param src The source file system object + * @param lnkName The new name of the link + * @param onSelectionListener The listener for obtain selection information (required) + * @param onRequestRefreshListener The listener for request a refresh (optional) + */ + public static void createSymlink( + final Context ctx, + final FileSystemObject src, + final String lnkName, + final OnSelectionListener onSelectionListener, + final OnRequestRefreshListener onRequestRefreshListener) { + + //Create the absolute file name + File newFso = new File( + onSelectionListener.onRequestCurrentDir(), lnkName); + final String link = newFso.getAbsolutePath(); + + try { + if (DEBUG) { + Log.d(TAG, String.format( + "Creating new symlink: %s -> %s", src.getFullPath(), link)); //$NON-NLS-1$ + } + CommandHelper.createLink(ctx, src.getFullPath(), link, null); + + //Operation complete. Show refresh + if (onRequestRefreshListener != null) { + FileSystemObject fso = null; + try { + fso = CommandHelper.getFileInfo(ctx, link, false, null); + } catch (Throwable ex2) { + /**NON BLOCK**/ + } + onRequestRefreshListener.onRequestRefresh(fso); + } + showOperationSuccessMsg(ctx); + + } catch (Throwable ex) { + //Capture the exception + if (ex instanceof RelaunchableException) { + ExceptionUtil.attachAsyncTask(ex, new AsyncTask<Object, Integer, Boolean>() { + /** + * {@inheritDoc} + */ + @Override + protected Boolean doInBackground(Object... params) { + //Operation complete. Show refresh + if (onRequestRefreshListener != null) { + FileSystemObject fso = null; + try { + fso = CommandHelper.getFileInfo(ctx, link, false, null); + } catch (Throwable ex2) { + /**NON BLOCK**/ + } + onRequestRefreshListener.onRequestRefresh(fso); + } + return Boolean.TRUE; + } + + /** + * {@inheritDoc} + */ + @Override + protected void onPostExecute(Boolean result) { + if (result != null && result.booleanValue()) { + showOperationSuccessMsg(ctx); + } + } + + }); + } + ExceptionUtil.translateException(ctx, ex); + } + } +}
\ No newline at end of file diff --git a/src/com/cyanogenmod/explorer/ui/widgets/NavigationView.java b/src/com/cyanogenmod/explorer/ui/widgets/NavigationView.java index 66d0007..7ef697e 100644 --- a/src/com/cyanogenmod/explorer/ui/widgets/NavigationView.java +++ b/src/com/cyanogenmod/explorer/ui/widgets/NavigationView.java @@ -48,7 +48,8 @@ import com.cyanogenmod.explorer.preferences.NavigationLayoutMode; import com.cyanogenmod.explorer.preferences.ObjectIdentifier; import com.cyanogenmod.explorer.preferences.ObjectStringIdentifier; import com.cyanogenmod.explorer.preferences.Preferences; -import com.cyanogenmod.explorer.ui.policy.ActionsPolicy; +import com.cyanogenmod.explorer.ui.policy.InfoActionPolicy; +import com.cyanogenmod.explorer.ui.policy.IntentsActionPolicy; import com.cyanogenmod.explorer.util.CommandHelper; import com.cyanogenmod.explorer.util.DialogHelper; import com.cyanogenmod.explorer.util.ExceptionUtil; @@ -753,19 +754,19 @@ public class NavigationView extends RelativeLayout implements // Show content description else if (this.mDefaultLongClickAction.compareTo( DefaultLongClickAction.SHOW_CONTENT_DESCRIPTION) == 0) { - ActionsPolicy.showContentDescription(getContext(), fso); + InfoActionPolicy.showContentDescription(getContext(), fso); } // Open with else if (this.mDefaultLongClickAction.compareTo( DefaultLongClickAction.OPEN_WITH) == 0) { - ActionsPolicy.openFileSystemObject(getContext(), fso, true); + IntentsActionPolicy.openFileSystemObject(getContext(), fso, true); } // Show properties else if (this.mDefaultLongClickAction.compareTo( DefaultLongClickAction.SHOW_PROPERTIES) == 0) { - ActionsPolicy.showPropertiesDialog(getContext(), fso, this); + InfoActionPolicy.showPropertiesDialog(getContext(), fso, this); } // Show actions @@ -798,7 +799,7 @@ public class NavigationView extends RelativeLayout implements changeCurrentDir(fso.getFullPath(), searchInfo); } else { // Open the file with the preferred registered app - ActionsPolicy.openFileSystemObject(getContext(), fso, false); + IntentsActionPolicy.openFileSystemObject(getContext(), fso, false); } } @@ -821,7 +822,7 @@ public class NavigationView extends RelativeLayout implements } } else { // Open the file with the preferred registered app - ActionsPolicy.openFileSystemObject(getContext(), fso, false); + IntentsActionPolicy.openFileSystemObject(getContext(), fso, false); } } catch (Throwable ex) { ExceptionUtil.translateException(getContext(), ex); |
