OSDN Git Service

Complete support for Java console (WIP)
authorjruesga <jorge@ruesga.com>
Mon, 22 Oct 2012 23:41:30 +0000 (01:41 +0200)
committerjruesga <jorge@ruesga.com>
Mon, 22 Oct 2012 23:41:30 +0000 (01:41 +0200)
* New Read and Write commands
* Remove Compress and Extract actions from ActionDialog for chrooted
mode, because this requires the use of an external library. Not
implemented for now.

src/com/cyanogenmod/explorer/commands/java/FindCommand.java
src/com/cyanogenmod/explorer/commands/java/FolderUsageCommand.java
src/com/cyanogenmod/explorer/commands/java/JavaExecutableCreator.java
src/com/cyanogenmod/explorer/commands/java/ReadCommand.java [new file with mode: 0644]
src/com/cyanogenmod/explorer/commands/java/WriteCommand.java [new file with mode: 0644]
src/com/cyanogenmod/explorer/ui/dialogs/ActionsDialog.java

index 5220323..9fbe885 100644 (file)
@@ -126,7 +126,8 @@ public class FindCommand extends Program implements FindExecutable {
 
     /**
      * Method that search files recursively
-     * @param folder
+     *
+     * @param folder The folder where to start the search
      */
     private void findRecursive(File folder) {
         // Obtains the files and folders of the folders
index 8009f75..d2e700e 100644 (file)
@@ -132,7 +132,8 @@ public class FolderUsageCommand extends Program implements FolderUsageExecutable
 
     /**
      * Method that computes the folder usage recursively
-     * @param folder
+     * 
+     * @param folder The folder where to start the computation
      */
     private void computeRecursive(File folder) {
         // Obtains the files and folders of the folders
index 66c759c..d6d06df 100644 (file)
@@ -317,12 +317,7 @@ public class JavaExecutableCreator implements ExecutableCreator {
     @Override
     public QuickFolderSearchExecutable createQuickFolderSearchExecutable(String regexp)
             throws CommandNotFoundException {
-//        try {
-//            return new QuickFolderSearchCommand(regexp);
-//        } catch (InvalidCommandDefinitionException icdEx) {
-//            throw new CommandNotFoundException("QuickFolderSearchCommand", icdEx); //$NON-NLS-1$
-//        }
-        return null;
+        throw new CommandNotFoundException("Not implemented"); //$NON-NLS-1$
     }
 
     /**
@@ -332,12 +327,7 @@ public class JavaExecutableCreator implements ExecutableCreator {
     public ReadExecutable createReadExecutable(
             String file, AsyncResultListener asyncResultListener)
             throws CommandNotFoundException {
-//        try {
-//            return new ReadCommand(file, asyncResultListener);
-//        } catch (InvalidCommandDefinitionException icdEx) {
-//            throw new CommandNotFoundException("ReadCommand", icdEx); //$NON-NLS-1$
-//        }
-        return null;
+        return new ReadCommand(file, asyncResultListener);
     }
 
     /**
@@ -374,12 +364,7 @@ public class JavaExecutableCreator implements ExecutableCreator {
     public WriteExecutable createWriteExecutable(
             String file, AsyncResultListener asyncResultListener)
             throws CommandNotFoundException {
-//        try {
-//            return new WriteCommand(file, asyncResultListener);
-//        } catch (InvalidCommandDefinitionException icdEx) {
-//            throw new CommandNotFoundException("WriteCommand", icdEx); //$NON-NLS-1$
-//        }
-        return null;
+        return new WriteCommand(file, asyncResultListener);
     }
 
     /**
@@ -390,12 +375,7 @@ public class JavaExecutableCreator implements ExecutableCreator {
             CompressionMode mode, String dst, String[] src,
             AsyncResultListener asyncResultListener)
             throws CommandNotFoundException {
-//        try {
-//            return new CompressCommand(mode, dst, src, asyncResultListener);
-//        } catch (InvalidCommandDefinitionException icdEx) {
-//            throw new CommandNotFoundException("CompressCommand", icdEx); //$NON-NLS-1$
-//        }
-        return null;
+        throw new CommandNotFoundException("Not implemented"); //$NON-NLS-1$
     }
 
     /**
@@ -406,12 +386,7 @@ public class JavaExecutableCreator implements ExecutableCreator {
             CompressionMode mode, String src,
             AsyncResultListener asyncResultListener)
             throws CommandNotFoundException {
-//        try {
-//            return new CompressCommand(mode, src, asyncResultListener);
-//        } catch (InvalidCommandDefinitionException icdEx) {
-//            throw new CommandNotFoundException("CompressCommand", icdEx); //$NON-NLS-1$
-//        }
-        return null;
+        throw new CommandNotFoundException("Not implemented"); //$NON-NLS-1$
     }
 
     /**
@@ -422,12 +397,7 @@ public class JavaExecutableCreator implements ExecutableCreator {
             String src, String dst,
             AsyncResultListener asyncResultListener)
             throws CommandNotFoundException {
-//        try {
-//            return new UncompressCommand(src, dst, asyncResultListener);
-//        } catch (InvalidCommandDefinitionException icdEx) {
-//            throw new CommandNotFoundException("UncompressCommand", icdEx); //$NON-NLS-1$
-//        }
-        return null;
+        throw new CommandNotFoundException("Not implemented"); //$NON-NLS-1$
     }
 
 }
diff --git a/src/com/cyanogenmod/explorer/commands/java/ReadCommand.java b/src/com/cyanogenmod/explorer/commands/java/ReadCommand.java
new file mode 100644 (file)
index 0000000..f8fac3d
--- /dev/null
@@ -0,0 +1,233 @@
+/*
+ * 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.commands.java;
+
+import android.util.Log;
+
+import com.cyanogenmod.explorer.commands.AsyncResultListener;
+import com.cyanogenmod.explorer.commands.ReadExecutable;
+import com.cyanogenmod.explorer.console.ExecutionException;
+import com.cyanogenmod.explorer.console.InsufficientPermissionsException;
+import com.cyanogenmod.explorer.console.NoSuchFileOrDirectory;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileReader;
+
+/**
+ * A class for read a file.
+ */
+public class ReadCommand extends Program implements ReadExecutable {
+
+    private static final String TAG = "ReadCommand"; //$NON-NLS-1$
+
+    private final String mFile;
+    private final AsyncResultListener mAsyncResultListener;
+
+    private boolean mCancelled;
+    private boolean mEnded;
+    private final Object mSync = new Object();
+
+    /**
+     * Constructor of <code>ExecCommand</code>.
+     *
+     * @param file The file to read
+     * @param asyncResultListener The partial result listener
+     */
+    public ReadCommand(
+            String file, AsyncResultListener asyncResultListener) {
+        super();
+        this.mFile = file;
+        this.mAsyncResultListener = asyncResultListener;
+        this.mCancelled = false;
+        this.mEnded = false;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean isAsynchronous() {
+        return true;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void execute()
+            throws InsufficientPermissionsException, NoSuchFileOrDirectory, ExecutionException {
+        if (isTrace()) {
+            Log.v(TAG,
+                    String.format("Reading file %s", this.mFile)); //$NON-NLS-1$
+                            
+        }
+        if (this.mAsyncResultListener != null) {
+            this.mAsyncResultListener.onAsyncStart();
+        }
+
+        File f = new File(this.mFile);
+        if (!f.exists()) {
+            if (isTrace()) {
+                Log.v(TAG, "Result: FAIL. NoSuchFileOrDirectory"); //$NON-NLS-1$
+            }
+            if (this.mAsyncResultListener != null) {
+                this.mAsyncResultListener.onException(new NoSuchFileOrDirectory(this.mFile));
+            } 
+        }
+        if (!f.isFile()) {
+            if (isTrace()) {
+                Log.v(TAG, "Result: FAIL. NoSuchFileOrDirectory"); //$NON-NLS-1$
+            }
+            if (this.mAsyncResultListener != null) {
+                this.mAsyncResultListener.onException(
+                        new ExecutionException("path exists but it's not a file")); //$NON-NLS-1$
+            } 
+        }
+
+        // Read the file
+        read(f);
+
+        if (this.mAsyncResultListener != null) {
+            this.mAsyncResultListener.onAsyncEnd(this.mCancelled);
+        }
+        if (this.mAsyncResultListener != null) {
+            this.mAsyncResultListener.onAsyncExitCode(0);
+        }
+
+        if (isTrace()) {
+            Log.v(TAG, "Result: OK"); //$NON-NLS-1$
+        }
+    }
+
+    /**
+     * Method that read the file
+     * 
+     * @param file The file to read
+     */
+    private void read(File file) {
+        // Read the file
+        BufferedReader br = null;
+        try {
+            br = new BufferedReader(new FileReader(file), getBufferSize());
+            int read = 0;
+            char[] data = new char[getBufferSize()];
+            while ((read = br.read(data, 0, getBufferSize())) != -1) {
+                if (this.mAsyncResultListener != null) {
+                    byte[] readData = new byte[read];
+                    System.arraycopy(data, 0, readData, 0, read);
+                    this.mAsyncResultListener.onPartialResult(readData);
+
+                    // Check if the process was cancelled
+                    try {
+                        synchronized (this.mSync) {
+                            if (this.mCancelled  || this.mEnded) {
+                                this.mSync.notify();
+                                break;
+                            }
+                        }
+                    } catch (Exception e) {/**NON BLOCK**/}
+                }
+            }
+
+        } catch (Exception e) {
+            if (isTrace()) {
+                Log.v(TAG, "Result: FAIL. InsufficientPermissionsException"); //$NON-NLS-1$
+            }
+            if (this.mAsyncResultListener != null) {
+                this.mAsyncResultListener.onException(new InsufficientPermissionsException());
+            } 
+
+        } finally {
+            try {
+                if (br != null) {
+                    br.close();
+                }
+            } catch (Throwable _throw) {/**NON BLOCK**/}
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean isCancelled() {
+        synchronized (this.mSync) {
+            return this.mCancelled;
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean cancel() {
+        try {
+            synchronized (this.mSync) {
+                this.mCancelled = true;
+                this.mSync.wait(5000L);
+            }
+        } catch (Exception e) {/**NON BLOCK**/}
+        return true;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean end() {
+        try {
+            synchronized (this.mSync) {
+                this.mEnded = true;
+                this.mSync.wait(5000L);
+            }
+        } catch (Exception e) {/**NON BLOCK**/}
+        return true;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void setOnEndListener(OnEndListener onEndListener) {
+        //Ignore. Java console don't use this
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void setOnCancelListener(OnCancelListener onCancelListener) {
+        //Ignore. Java console don't use this
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean isCancellable() {
+        return true;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public AsyncResultListener getAsyncResultListener() {
+        return this.mAsyncResultListener;
+    }
+}
diff --git a/src/com/cyanogenmod/explorer/commands/java/WriteCommand.java b/src/com/cyanogenmod/explorer/commands/java/WriteCommand.java
new file mode 100644 (file)
index 0000000..9d4fd40
--- /dev/null
@@ -0,0 +1,228 @@
+/*
+ * 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.commands.java;
+
+import android.util.Log;
+
+import com.cyanogenmod.explorer.commands.AsyncResultListener;
+import com.cyanogenmod.explorer.commands.WriteExecutable;
+import com.cyanogenmod.explorer.console.ExecutionException;
+import com.cyanogenmod.explorer.console.InsufficientPermissionsException;
+import com.cyanogenmod.explorer.console.NoSuchFileOrDirectory;
+
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+
+/**
+ * A class for write data to disk.<br/>
+ * <br/>
+ * User MUST call the {@link #createOutputStream()} to get the output stream where
+ * write the data.<br/>. When no more exist then user MUST call the onEnd method
+ * of the asynchronous listener.<br/>
+ */
+public class WriteCommand extends Program implements WriteExecutable {
+
+    private static final String TAG = "WriteCommand"; //$NON-NLS-1$
+
+    private final String mFile;
+    private BufferedOutputStream mBuffer;
+    private final AsyncResultListener mAsyncResultListener;
+
+    private boolean mCancelled;
+    private final Object mSync = new Object();
+
+    private static final long TIMEOUT = 1000L;
+
+    private final Object mWriteSync = new Object();
+    private boolean mReady;
+
+    /**
+     * Constructor of <code>WriteCommand</code>.
+     *
+     * @param file The file where to write the data
+     * @param asyncResultListener The partial result listener
+     */
+    public WriteCommand(
+            String file, AsyncResultListener asyncResultListener) {
+        super();
+        this.mFile = file;
+        this.mAsyncResultListener = asyncResultListener;
+        this.mCancelled = false;
+        this.mReady = false;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean isAsynchronous() {
+        return true;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public OutputStream createOutputStream() throws IOException {
+        try {
+            // Wait until command is ready
+            synchronized (this.mWriteSync) {
+                if (!this.mReady) {
+                    try {
+                        this.mWriteSync.wait(TIMEOUT);
+                    } catch (Exception e) {/**NON BLOCK**/}
+                }
+            }
+            this.mBuffer = new BufferedOutputStream(
+                            new FileOutputStream(
+                                    new File(this.mFile)), getBufferSize());
+            return this.mBuffer;
+        } catch (IOException ioEx) {
+            if (isTrace()) {
+                Log.e(TAG, "Result: FAILED. IOException", ioEx); //$NON-NLS-1$
+            }
+            throw ioEx;
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void execute()
+            throws InsufficientPermissionsException, NoSuchFileOrDirectory, ExecutionException {
+        synchronized (this.mSync) {
+            this.mReady = true;
+            this.mSync.notify();
+        }
+        
+        if (isTrace()) {
+            Log.v(TAG,
+                    String.format("Writing file %s", this.mFile)); //$NON-NLS-1$
+                            
+        }
+        if (this.mAsyncResultListener != null) {
+            this.mAsyncResultListener.onAsyncStart();
+        }
+
+        // Wait the finalization
+        try {
+            synchronized (this.mSync) {
+                this.mSync.wait();
+            }
+        } catch (Throwable _throw) {/**NON BLOCK**/}
+
+        if (this.mAsyncResultListener != null) {
+            this.mAsyncResultListener.onAsyncEnd(this.mCancelled);
+        }
+        if (this.mAsyncResultListener != null) {
+            this.mAsyncResultListener.onAsyncExitCode(0);
+        }
+
+        if (isTrace()) {
+            Log.v(TAG, "Result: OK"); //$NON-NLS-1$
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean isCancelled() {
+        synchronized (this.mSync) {
+            return this.mCancelled;
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean cancel() {
+        closeBuffer();
+        this.mCancelled = true;
+        try {
+            synchronized (this.mSync) {
+                this.mSync.notify();
+            }
+        } catch (Throwable _throw) {/**NON BLOCK**/}
+        return true;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean end() {
+        closeBuffer();
+        try {
+            synchronized (this.mSync) {
+                this.mSync.notify();
+            }
+        } catch (Throwable _throw) {/**NON BLOCK**/}
+        return true;
+    }
+
+    /**
+     * Method that close the buffer
+     */
+    private void closeBuffer() {
+        try {
+            if (this.mBuffer != null) {
+                this.mBuffer.close();
+            }
+        } catch (Exception ex) {/**NON BLOCK**/}
+        try {
+            Thread.yield();
+        } catch (Exception ex) {/**NON BLOCK**/}
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void setOnEndListener(OnEndListener onEndListener) {
+        //Ignore. Java console don't use this
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void setOnCancelListener(OnCancelListener onCancelListener) {
+        //Ignore. Java console don't use this
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean isCancellable() {
+        return true;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public AsyncResultListener getAsyncResultListener() {
+        return this.mAsyncResultListener;
+    }
+}
index df8fcd1..2a9f072 100644 (file)
@@ -642,7 +642,15 @@ public class ActionsDialog implements OnItemClickListener, OnItemLongClickListen
             menu.removeItem(R.id.mnu_actions_create_link);
             menu.removeItem(R.id.mnu_actions_create_link_global);
             menu.removeItem(R.id.mnu_actions_execute);
-            menu.removeItem(R.id.mnu_actions_execute);
+
+            // NOTE: This actions are not implemented in chrooted environments. The reason is
+            // that the main target of this application is CyanogenMod (a rooted environment).
+            // Adding this actions requires the use of commons-compress, an external Apache
+            // library that will add more size to the ending apk.
+            // For now, will maintain without implementation. Maybe, in the future.
+            menu.removeItem(R.id.mnu_actions_compress);
+            menu.removeItem(R.id.mnu_actions_compress_selection);
+            menu.removeItem(R.id.mnu_actions_extract);
         }
     }