OSDN Git Service

Shell improvements
authorjruesga <jorge@ruesga.com>
Mon, 1 Oct 2012 22:40:06 +0000 (00:40 +0200)
committerjruesga <jorge@ruesga.com>
Mon, 1 Oct 2012 22:40:06 +0000 (00:40 +0200)
* Change the shell console to better detect the cancel of a async
program
* Create start control command to clean buffer before start a new
command
* Add device specific buffer size
* Improve ListCommand, using Java to get the parent folder.
* Compute folder is disabled by default.
* Correct some bugs when using root directory

16 files changed:
res/values/overlay.xml
res/values/strings.xml
res/xml/command_list.xml
src/com/cyanogenmod/explorer/ExplorerApplication.java
src/com/cyanogenmod/explorer/commands/shell/Command.java
src/com/cyanogenmod/explorer/commands/shell/ListCommand.java
src/com/cyanogenmod/explorer/console/ConsoleBuilder.java
src/com/cyanogenmod/explorer/console/shell/ShellConsole.java
src/com/cyanogenmod/explorer/model/Bookmark.java
src/com/cyanogenmod/explorer/model/FileSystemObject.java
src/com/cyanogenmod/explorer/preferences/ExplorerSettings.java
src/com/cyanogenmod/explorer/ui/dialogs/FsoPropertiesDialog.java
src/com/cyanogenmod/explorer/util/FileHelper.java
src/com/cyanogenmod/explorer/util/ParseHelper.java
tests/src/com/cyanogenmod/explorer/commands/shell/AbstractConsoleTest.java
tests/src/com/cyanogenmod/explorer/console/ConsoleBuilderTest.java

index 36e1238..4f0c547 100644 (file)
 -->
 <resources xmlns:android="http://schemas.android.com/apk/res/android">
 
-  <!-- The buffer use to read files (in bytes). Default: 0.5 Mb -->
-  <integer name="read_buffer_size">512</integer>
-
-  <!-- The maximum file size that the app is able to read. Beyond this size the user will get a
-       warning message (in bytes). Default: 5 Mb
-       -->
-  <integer name="max_read_file_size">5120</integer>
+  <!-- The size of the buffers use by the console (in bytes). Default: 0.5 Mb -->
+  <integer name="buffer_size">512</integer>
 
 </resources>
\ No newline at end of file
index 0c94f61..8c66fed 100644 (file)
@@ -62,9 +62,9 @@
   <!-- Loading waiting message -->
   <string name="loading_message">Loading&#8230;</string>
   <!-- Computing message -->
-  <string name="computing_message">Computing&#8230; <xliff:g id="data">%1$s</xliff:g></string>
+  <string name="computing_message"><xliff:g id="data">%1$s</xliff:g></string>
   <!-- Computing new line message -->
-  <string name="computing_message_ln">Computing&#8230;\n<xliff:g id="data">%1$s</xliff:g></string>
+  <string name="computing_message_ln"><xliff:g id="data">%1$s</xliff:g></string>
   <!-- Cancelled message -->
   <string name="cancelled_message">Cancelled.</string>
   <!-- Error message -->
   <string name="search_terms">&lt;b>Terms:&lt;/b> <xliff:g id="terms">%1$s</xliff:g></string>
   <!-- Some terms of the search are too small. The operation can be very costly -->
   <string name="search_few_characters_msg">Some of terms of the search has few characters. In
-    this situation, the operation can be very costly in time and system resources.\n\n
+    this situation, the operation that can be very costly in time and system resources.\n\n
     Do you want to cancel the search?</string>
 
   <!-- Searching dialog title -->
   <string name="pref_compute_folder_statistics">Compute folder statistics</string>
   <!-- Preferences * General * Compute folder statistics summary on -->
   <string name="pref_compute_folder_statistics_on">Compute folder statistics in folder
-    properties dialog.</string>
+    properties dialog.\n\nWarning! Compute folder statistics is a operation very costly in time
+    and system resources.</string>
   <!-- Preferences * General * Compute folder statistics summary off -->
-  <string name="pref_compute_folder_statistics_off">Not compute folder statistics in folder
+  <string name="pref_compute_folder_statistics_off">No compute folder statistics in folder
     properties dialog.</string>
     <!-- Preferences * General * Advanced settings category -->
   <string name="pref_general_advanced_settings_category">Advanced settings</string>
index 489ea25..3115cc9 100644 (file)
@@ -26,6 +26,8 @@
      with the expected command for retrieve the exit code of the executed command
 -->
 <CommandList xmlns:androcommandId="http://schemas.android.com/apk/res/android">
+  <!-- Start code (append to commands; for retrieve the exit code) -->
+  <startcode commandId="startcode" commandPath="/system/xbin/echo %1$s0%2$s ; " />
   <!-- Exit code (append to commands; for retrieve the exit code) -->
   <exitcode commandId="exitcode" commandPath=" ; /system/xbin/echo %1$s$?%2$s" />
 
index f4a64b4..c02bde3 100644 (file)
@@ -155,7 +155,8 @@ public final class ExplorerApplication extends Application {
         try {
             sBackgroundConsole =
                     new ConsoleHolder(
-                            ConsoleBuilder.createNonPrivilegedConsole(FileHelper.ROOT_DIRECTORY));
+                            ConsoleBuilder.createNonPrivilegedConsole(
+                                    getApplicationContext(), FileHelper.ROOT_DIRECTORY));
         } catch (Exception e) {
             Log.e(TAG,
                     "Background console creation failed. " +  //$NON-NLS-1$
index 3b6ebc8..f4d4b67 100644 (file)
@@ -42,6 +42,7 @@ public abstract class Command {
     // Command list XML tags
     private static final String TAG_COMMAND_LIST = "CommandList"; //$NON-NLS-1$
     private static final String TAG_COMMAND = "command"; //$NON-NLS-1$
+    private static final String TAG_STARTCODE = "startcode"; //$NON-NLS-1$
     private static final String TAG_EXITCODE = "exitcode"; //$NON-NLS-1$
 
     private final String mId;
@@ -49,6 +50,7 @@ public abstract class Command {
     private String mArgs;   // The real arguments
     private final Object[] mCmdArgs;  //This arguments to be formatted
 
+    private static String sStartCodeCmd;
     private static String sExitCodeCmd;
 
     /**
@@ -212,6 +214,58 @@ public abstract class Command {
      * @throws InvalidCommandDefinitionException If the command is not present or has an
      * invalid definition
      */
+    public static synchronized String getStartCodeCommandInfo(
+            Resources resources) throws InvalidCommandDefinitionException {
+        //Singleton
+        if (sStartCodeCmd != null) {
+            return new String(sStartCodeCmd);
+        }
+
+        //Read the command list xml file
+        XmlResourceParser parser = resources.getXml(R.xml.command_list);
+
+        try {
+            //Find the root element
+            XmlUtils.beginDocument(parser, TAG_COMMAND_LIST);
+            while (true) {
+                XmlUtils.nextElement(parser);
+                String element = parser.getName();
+                if (element == null) {
+                    break;
+                }
+
+                if (TAG_STARTCODE.equals(element)) {
+                    CharSequence path = parser.getAttributeValue(R.styleable.Command_commandPath);
+                    if (path == null) {
+                        throw new InvalidCommandDefinitionException(
+                                TAG_STARTCODE + ": path is null"); //$NON-NLS-1$
+                    }
+
+                    //Save paths
+                    sStartCodeCmd = path.toString();
+                    return new String(sStartCodeCmd);
+                }
+            }
+        } catch (XmlPullParserException e) {
+            throw new RuntimeException(e);
+        } catch (IOException e) {
+            throw new RuntimeException(e);
+        } finally {
+            parser.close();
+        }
+
+        //Command not found
+        throw new InvalidCommandDefinitionException(TAG_STARTCODE);
+    }
+
+    /**
+     * Method that returns the exit code command info.
+     *
+     * @param resources The application resource manager
+     * @return String The exit code command info
+     * @throws InvalidCommandDefinitionException If the command is not present or has an
+     * invalid definition
+     */
     public static synchronized String getExitCodeCommandInfo(
             Resources resources) throws InvalidCommandDefinitionException {
         //Singleton
index a22767a..0a058e2 100644 (file)
@@ -97,28 +97,30 @@ public class ListCommand extends SyncResultProgram implements ListExecutable {
         //Retrieve parent directory information
         if (mode.compareTo(LIST_MODE.DIRECTORY) == 0) {
             //Resolve the parent directory
-            this.mParentDir =
-                CommandHelper.getAbsolutePath(
-                        ExplorerApplication.getInstance().getApplicationContext(), src, console);
+            if (src.compareTo(FileHelper.ROOT_DIRECTORY) == 0) {
+                this.mParentDir = null;
+            } else {
+                this.mParentDir =
+                    CommandHelper.getAbsolutePath(
+                            ExplorerApplication.
+                                getInstance().getApplicationContext(), src, console);
+            }
         } else {
             //Get the absolute path
             try {
-                // From console
+                this.mParentDir = new File(src).getCanonicalFile().getParent();
+
+            } catch (Exception e) {
+                // Try to resolve from a console
                 String abspath =
                     CommandHelper.getAbsolutePath(
-                            ExplorerApplication.getInstance().getApplicationContext(), src, console);
+                            ExplorerApplication.getInstance().
+                                getApplicationContext(), src, console);
                 //Resolve the parent directory
                 this.mParentDir =
                     CommandHelper.getParentDir(
                             ExplorerApplication.getInstance().getApplicationContext(),
                             abspath, console);
-
-            } catch (Exception e) {
-                // From Java
-                this.mParentDir = new File(src).getCanonicalFile().getParent();
-                if (this.mParentDir == null) {
-                    throw new CommandNotFoundException(ID_LS_INFO, e);
-                }
             }
         }
     }
@@ -227,7 +229,8 @@ public class ListCommand extends SyncResultProgram implements ListExecutable {
             }
 
             //Now if not is the root directory
-            if (this.mParentDir.compareTo(FileHelper.ROOT_DIRECTORY) != 0 &&
+            if (this.mParentDir != null &&
+                    this.mParentDir.compareTo(FileHelper.ROOT_DIRECTORY) != 0 &&
                     this.mMode.compareTo(LIST_MODE.DIRECTORY) == 0) {
                 this.mFiles.add(0, new ParentDirectory(new File(this.mParentDir).getParent()));
             }
index f785d9e..f958cb7 100644 (file)
@@ -115,7 +115,8 @@ public final class ConsoleBuilder {
         ConsoleHolder holder = null;
         try {
             //Create the console, destroy the current console, and marks as current
-            holder = new ConsoleHolder(createNonPrivilegedConsole(FileHelper.ROOT_DIRECTORY));
+            holder = new ConsoleHolder(
+                    createNonPrivilegedConsole(context, FileHelper.ROOT_DIRECTORY));
             destroyConsole();
             sHolder = holder;
             return true;
@@ -201,7 +202,7 @@ public final class ConsoleBuilder {
                         ? new ConsoleHolder(
                                 createPrivilegedConsole(context, FileHelper.ROOT_DIRECTORY))
                         : new ConsoleHolder(
-                                createNonPrivilegedConsole(FileHelper.ROOT_DIRECTORY));
+                                createNonPrivilegedConsole(context, FileHelper.ROOT_DIRECTORY));
             }
             return sHolder.getConsole();
         }
@@ -224,6 +225,7 @@ public final class ConsoleBuilder {
     /**
      * Method that creates a new non privileged console.
      *
+     * @param context The current context
      * @param initialDirectory The initial directory of the console
      * @return Console The non privileged console
      * @throws FileNotFoundException If the initial directory not exists
@@ -232,10 +234,11 @@ public final class ConsoleBuilder {
      * @throws ConsoleAllocException If the console can't be allocated
      * @see NonPriviledgeConsole
      */
-    public static Console createNonPrivilegedConsole(String initialDirectory)
+    public static Console createNonPrivilegedConsole(Context context, String initialDirectory)
             throws FileNotFoundException, IOException,
             InvalidCommandDefinitionException, ConsoleAllocException {
         NonPriviledgeConsole console = new NonPriviledgeConsole(initialDirectory);
+        console.setBufferSize(context.getResources().getInteger(R.integer.buffer_size));
         console.alloc();
         return console;
     }
@@ -281,6 +284,7 @@ public final class ConsoleBuilder {
             ConsoleAllocException, InsufficientPermissionsException {
         try {
             PrivilegedConsole console = new PrivilegedConsole(initialDirectory);
+            console.setBufferSize(context.getResources().getInteger(R.integer.buffer_size));
             console.alloc();
             if (console.getIdentity().getUser().getId() != ROOT_UID) {
                 //The console is not a privileged console
index d5f6884..fade848 100644 (file)
@@ -71,6 +71,8 @@ public abstract class ShellConsole extends Console {
 
     private static final long DEFAULT_TIMEOUT = 20000L;
 
+    private static final int DEFAULT_BUFFER = 512;
+
     //Shell References
     private final Shell mShell;
     private final String mInitialDirectory;
@@ -84,6 +86,7 @@ public abstract class ShellConsole extends Console {
     private Process mProc = null;
     private Program mActiveCommand = null;
     private boolean mCancelled;
+    private boolean mStarted;
 
     //Buffers
     private InputStream mIn = null;
@@ -93,7 +96,10 @@ public abstract class ShellConsole extends Console {
     private StringBuffer mSbErr = null;
 
     private final SecureRandom mRandom;
-    private String mControlPattern;
+    private String mStartControlPattern;
+    private String mEndControlPattern;
+
+    private int mBufferSize;
 
     private final ShellExecutableFactory mExecutableFactory;
 
@@ -124,6 +130,8 @@ public abstract class ShellConsole extends Console {
         this.mShell = shell;
         this.mExecutableFactory = new ShellExecutableFactory(this);
 
+        this.mBufferSize = DEFAULT_BUFFER;
+
         //Resolve and checks the initial directory
         File f = new File(initialDirectory);
         while (FileHelper.isSymlink(f)) {
@@ -162,6 +170,26 @@ public abstract class ShellConsole extends Console {
         return this.mIdentity;
     }
 
+
+
+    /**
+     * Method that returns the buffer size
+     *
+     * @return int The buffer size
+     */
+    public int getBufferSize() {
+        return this.mBufferSize;
+    }
+
+    /**
+     * Method that sets the buffer size
+     *
+     * @param bufferSize the The buffer size
+     */
+    public void setBufferSize(int bufferSize) {
+        this.mBufferSize = bufferSize;
+    }
+
     /**
      * {@inheritDoc}
      */
@@ -388,13 +416,19 @@ public abstract class ShellConsole extends Console {
             this.mActiveCommand = program;
 
             //Reset the buffers
+            this.mStarted = false;
+            this.mCancelled = false;
             this.mSbIn = new StringBuffer();
             this.mSbErr = new StringBuffer();
 
-            //Random exit identifiers
-            String exitId1 =
+            //Random start/end identifiers
+            String startId1 =
+                    String.format("/#%d#/", Long.valueOf(this.mRandom.nextLong())); //$NON-NLS-1$
+            String startId2 =
                     String.format("/#%d#/", Long.valueOf(this.mRandom.nextLong())); //$NON-NLS-1$
-            String exitId2 =
+            String endId1 =
+                    String.format("/#%d#/", Long.valueOf(this.mRandom.nextLong())); //$NON-NLS-1$
+            String endId2 =
                     String.format("/#%d#/", Long.valueOf(this.mRandom.nextLong())); //$NON-NLS-1$
 
             //Create command string
@@ -424,19 +458,28 @@ public abstract class ShellConsole extends Console {
             //This control code is unique in every invocation and is secure random
             //generated (control code 1 + exit code + control code 2)
             try {
-                this.mControlPattern = exitId1 + "\\d{1,3}" + exitId2; //$NON-NLS-1$
-                String exitCmd =
+                this.mStartControlPattern = startId1 + "\\d{1,3}" + startId2 + "\\n"; //$NON-NLS-1$ //$NON-NLS-2$
+                this.mEndControlPattern = endId1 + "\\d{1,3}" + endId2; //$NON-NLS-1$
+                String startCmd =
+                        Command.getStartCodeCommandInfo(
+                                ExplorerApplication.getInstance().getResources());
+                startCmd = String.format(
+                        startCmd, "'" + startId1 +//$NON-NLS-1$
+                        "'", "'" + startId2 + "'"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+                String endCmd =
                         Command.getExitCodeCommandInfo(
                                 ExplorerApplication.getInstance().getResources());
-                exitCmd = String.format(
-                        exitCmd, "'" + exitId1 + "'", "'" //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
-                        + exitId2 + "'"); //$NON-NLS-1$
+                endCmd = String.format(
+                        endCmd, "'" + endId1 + //$NON-NLS-1$
+                        "'", "'" + endId2 + "'"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
                 StringBuilder sb = new StringBuilder()
+                    .append(startCmd)
+                    .append(" ")  //$NON-NLS-1$
                     .append(cmd)
                     .append(" ")  //$NON-NLS-1$
                     .append(args)
                     .append(" ") //$NON-NLS-1$
-                    .append(exitCmd)
+                    .append(endCmd)
                     .append(FileHelper.NEWLINE);
                 this.mOut.write(sb.toString().getBytes());
             } catch (InvalidCommandDefinitionException icdEx) {
@@ -532,7 +575,7 @@ public abstract class ShellConsole extends Console {
             public void run() {
                 int read = 0;
                 try {
-                    //Notify the ending
+                    //Notify the start
                     if (ShellConsole.this.mActiveCommand != null
                             && ShellConsole.this.mActiveCommand instanceof AsyncResultProgram) {
                         AsyncResultProgram program =
@@ -547,15 +590,24 @@ public abstract class ShellConsole extends Console {
                             break;
                         }
                         StringBuffer sb = new StringBuffer();
-                        ShellConsole.this.mSbIn.append((char)r);
-                        sb.append((char)r);
-
-                        //Notify asynchronous partial data
-                        if (ShellConsole.this.mActiveCommand != null
-                                && ShellConsole.this.mActiveCommand instanceof AsyncResultProgram) {
-                            AsyncResultProgram program =
-                                    ((AsyncResultProgram)ShellConsole.this.mActiveCommand);
-                            program.parsePartialResult(new String(new char[]{(char)r}));
+                        if (!ShellConsole.this.mCancelled) {
+                            ShellConsole.this.mSbIn.append((char)r);
+                            if (!ShellConsole.this.mStarted) {
+                                ShellConsole.this.mStarted =
+                                        isCommandStarted(ShellConsole.this.mSbIn);
+                                sb.append(ShellConsole.this.mSbIn.toString());
+                            } else {
+                                sb.append((char)r);
+                            }
+
+                            //Notify asynchronous partial data
+                            if (ShellConsole.this.mStarted &&
+                                ShellConsole.this.mActiveCommand != null &&
+                                ShellConsole.this.mActiveCommand instanceof AsyncResultProgram) {
+                                AsyncResultProgram program =
+                                        ((AsyncResultProgram)ShellConsole.this.mActiveCommand);
+                                program.parsePartialResult(new String(new char[]{(char)r}));
+                            }
                         }
 
                         //Has more data? Read with available as more as exists
@@ -563,21 +615,32 @@ public abstract class ShellConsole extends Console {
                         int count = 0;
                         while (in.available() > 0 && count < 10) {
                             count++;
-                            byte[] data = new byte[in.available()];
+                            int available = Math.min(in.available(),
+                                                        ShellConsole.this.mBufferSize);
+                            byte[] data = new byte[available];
                             read = in.read(data);
+
+                            // Exit if active command is canceled
+                            if (ShellConsole.this.mCancelled) continue;
+
                             final String s = new String(data, 0, read);
                             ShellConsole.this.mSbIn.append(s);
-                            sb.append(s);
+                            if (!ShellConsole.this.mStarted) {
+                                ShellConsole.this.mStarted =
+                                        isCommandStarted(ShellConsole.this.mSbIn);
+                                sb.append(ShellConsole.this.mSbIn.toString());
+                            } else {
+                                sb.append(s);
+                            }
 
                             //Notify asynchronous partial data
-                            if (ShellConsole.this.mActiveCommand != null
-                               && ShellConsole.this.mActiveCommand  instanceof AsyncResultProgram) {
+                            if (ShellConsole.this.mActiveCommand != null &&
+                                ShellConsole.this.mActiveCommand  instanceof AsyncResultProgram) {
                                 AsyncResultProgram program =
                                         ((AsyncResultProgram)ShellConsole.this.mActiveCommand);
                                 program.parsePartialResult(s);
                             }
 
-
                             //Wait for buffer to be filled
                             try {
                                 Thread.sleep(50L);
@@ -586,22 +649,22 @@ public abstract class ShellConsole extends Console {
                             }
 
                             //Check if the command has finished
-                            if (isCommandFinish(sb)) {
+                            if (isCommandFinished(ShellConsole.this.mSbIn)) {
                                 //Notify the end
                                 notifyProcessFinished();
                             }
                         }
 
-                        //Audit
-                        if (isTrace()) {
+                        //Audit (if not canceled)
+                        if (!ShellConsole.this.mCancelled && isTrace()) {
                             Log.v(TAG,
                                     String.format("stdin: %s", sb.toString())); //$NON-NLS-1$
                         }
 
                         //Asynchronous programs can cause a lot of output, control buffers
                         //for a low memory footprint
-                        if (ShellConsole.this.mActiveCommand != null
-                                && ShellConsole.this.mActiveCommand instanceof AsyncResultProgram) {
+                        if (ShellConsole.this.mActiveCommand != null &&
+                                ShellConsole.this.mActiveCommand instanceof AsyncResultProgram) {
                             trimBuffer(ShellConsole.this.mSbIn);
                             trimBuffer(ShellConsole.this.mSbErr);
                         }
@@ -639,16 +702,24 @@ public abstract class ShellConsole extends Console {
                             break;
                         }
                         StringBuffer sb = new StringBuffer();
-                        ShellConsole.this.mSbErr.append((char)r);
-                        sb.append((char)r);
+                        if (!ShellConsole.this.mCancelled) {
+                            ShellConsole.this.mSbErr.append((char)r);
+                            sb.append((char)r);
+                        }
 
                         //Has more data? Read with available as more as exists
                         //or maximum loop count is rebased
                         int count = 0;
                         while (err.available() > 0 && count < 10) {
                             count++;
-                            byte[] data = new byte[err.available()];
+                            int available = Math.min(err.available(),
+                                                        ShellConsole.this.mBufferSize);
+                            byte[] data = new byte[available];
                             read = err.read(data);
+
+                            // Exit if active command is canceled
+                            if (ShellConsole.this.mCancelled) continue;
+
                             String s = new String(data, 0, read);
                             ShellConsole.this.mSbErr.append(s);
                             sb.append(s);
@@ -661,16 +732,16 @@ public abstract class ShellConsole extends Console {
                             }
                         }
 
-                        //Audit
-                        if (isTrace()) {
+                        //Audit (if not canceled)
+                        if (!ShellConsole.this.mCancelled && isTrace()) {
                             Log.v(TAG,
                                     String.format("stderr: %s", sb.toString())); //$NON-NLS-1$
                         }
 
                         //Asynchronous programs can cause a lot of output, control buffers
                         //for a low memory footprint
-                        if (ShellConsole.this.mActiveCommand != null
-                                && ShellConsole.this.mActiveCommand instanceof AsyncResultProgram) {
+                        if (ShellConsole.this.mActiveCommand != null &&
+                                ShellConsole.this.mActiveCommand instanceof AsyncResultProgram) {
                             trimBuffer(ShellConsole.this.mSbIn);
                             trimBuffer(ShellConsole.this.mSbErr);
                         }
@@ -755,14 +826,32 @@ public abstract class ShellConsole extends Console {
     }
 
     /**
+     * Method that returns if the command has started by checking the
+     * standard input buffer. This method also removes the control start command
+     * from the buffer, if it's present, leaving in the buffer the new data bytes.
+     *
+     * @param stdin The standard in buffer
+     * @return boolean If the command has started
+     */
+    private boolean isCommandStarted(StringBuffer stdin) {
+        Pattern pattern = Pattern.compile(this.mStartControlPattern);
+        Matcher matcher = pattern.matcher(stdin.toString());
+        if (matcher.find()) {
+            stdin.replace(0, matcher.end(), ""); //$NON-NLS-1$
+            return true;
+        }
+        return false;
+    }
+
+    /**
      * Method that returns if the command has finished by checking the
      * standard input buffer.
      *
      * @param stdin The standard in buffer
      * @return boolean If the command has finished
      */
-    private boolean isCommandFinish(StringBuffer stdin) {
-        Pattern pattern = Pattern.compile(this.mControlPattern);
+    private boolean isCommandFinished(StringBuffer stdin) {
+        Pattern pattern = Pattern.compile(this.mEndControlPattern);
         Matcher matcher = pattern.matcher(stdin.toString());
         return matcher.find();
     }
@@ -774,8 +863,15 @@ public abstract class ShellConsole extends Console {
      * @return int The exit code of the last executed command
      */
     private int getExitCode(StringBuffer stdin) {
+        // If process was canceled, don't expect a exit code.
+        // Returns always 143 code
+        if (this.mCancelled) {
+            return 143;
+        }
+
+        // Parse the stdin seeking exit code pattern
         String txt = stdin.toString();
-        Pattern pattern = Pattern.compile(this.mControlPattern);
+        Pattern pattern = Pattern.compile(this.mEndControlPattern);
         Matcher matcher = pattern.matcher(txt);
         if (matcher.find()) {
             this.mSbIn = new StringBuffer(txt.substring(0, matcher.start()));
@@ -785,9 +881,6 @@ public abstract class ShellConsole extends Console {
                             exitTxt.indexOf("#/") + 2,  //$NON-NLS-1$
                             exitTxt.indexOf("/#", 2))); //$NON-NLS-1$
         }
-        if (this.mCancelled) {
-            return 143;
-        }
         return 255;
     }
 
@@ -838,6 +931,7 @@ public abstract class ShellConsole extends Console {
                                 /**NON BLOCK**/
                             }
                             this.mCancelled = true;
+                            notifyProcessFinished();
                             this.mSync.notify();
                             return this.mCancelled;
                         }
index 96eb97f..c7e318f 100644 (file)
@@ -73,8 +73,7 @@ public class Bookmark implements Serializable, Comparable<Bookmark>, Parcelable
                     "%s%s/%s", //$NON-NLS-1$
                     "content://", //$NON-NLS-1$
                     BookmarksContentProvider.AUTHORITY,
-                     "/bookmarks") //$NON-NLS-1$
-                    );
+                     "/bookmarks")); //$NON-NLS-1$
 
         /**
          * The directory of the bookmark
index 4f5fa20..95a451d 100644 (file)
@@ -242,6 +242,11 @@ public abstract class FileSystemObject implements Serializable, Comparable<FileS
      */
     public String getFullPath() {
         if (FileHelper.isRootDirectory(this)) {
+            return FileHelper.ROOT_DIRECTORY;
+        } else if (FileHelper.isParentRootDirectory(this)) {
+            if (this.mParent == null) {
+                return FileHelper.ROOT_DIRECTORY + this.mName;
+            }
             return this.mParent + this.mName;
         }
         return this.mParent + File.separator + this.mName;
index fdda409..221b647 100644 (file)
@@ -88,7 +88,7 @@ public enum ExplorerSettings {
      * @hide
      */
     SETTINGS_COMPUTE_FOLDER_STATISTICS(
-            "cm_explorer_compute_folder_statistics", Boolean.TRUE), //$NON-NLS-1$
+            "cm_explorer_compute_folder_statistics", Boolean.FALSE), //$NON-NLS-1$
     /**
      * When to use case sensitive comparison in sorting of files
      * @hide
index 9c00a28..1b8522a 100644 (file)
@@ -928,8 +928,10 @@ public class FsoPropertiesDialog
 
         final Resources res = this.mContext.getResources();
         if (cancelled) {
-            FsoPropertiesDialog.this.mTvSize.setText(R.string.cancelled_message);
-            FsoPropertiesDialog.this.mTvContains.setText(R.string.cancelled_message);
+            try {
+                FsoPropertiesDialog.this.mTvSize.setText(R.string.cancelled_message);
+                FsoPropertiesDialog.this.mTvContains.setText(R.string.cancelled_message);
+            } catch (Throwable e) {/**NON BLOCK**/}
 
             // End of drawing
             this.mDrawingFolderUsage = false;
index c92b932..fb3e326 100644 (file)
@@ -186,6 +186,18 @@ public final class FileHelper {
      * @return boolean if the file system object if the root directory
      */
     public static boolean isRootDirectory(FileSystemObject fso) {
+        if (fso.getName() == null) return true;
+        return fso.getName().compareTo(FileHelper.ROOT_DIRECTORY) == 0;
+    }
+
+    /**
+     * Method that returns if the parent file system object if the root directory.
+     *
+     * @param fso The parent file system object to check
+     * @return boolean if the parent file system object if the root directory
+     */
+    public static boolean isParentRootDirectory(FileSystemObject fso) {
+        if (fso.getParent() == null) return true;
         return fso.getParent().compareTo(FileHelper.ROOT_DIRECTORY) == 0;
     }
 
index 6d7024f..2d16cb3 100644 (file)
@@ -133,6 +133,7 @@ public final class ParseHelper {
     //  Can ensure this?)
     //<name>:
     //  - if object is a symlink, the value must be "link name -> real name"
+    //  - If the name is void, then assume that it is the root directory (/)
     //
     public static FileSystemObject toFileSystemObject(
             final String parent, final String src, final boolean quick) throws ParseException {
@@ -201,6 +202,10 @@ public final class ParseHelper {
 
         //6.- Extract object name
         String szName = szEndLine;
+        if (szName.trim().length() == 0) {
+            // Assume that the object name is the root folder
+            szName = FileHelper.ROOT_DIRECTORY;
+        }
         String szLink = null;
         if (type == Symlink.UNIX_ID) {
             //"link name -> real name"
index c659de6..723d846 100644 (file)
@@ -45,7 +45,7 @@ public abstract class AbstractConsoleTest extends android.test.AndroidTestCase {
         if (isRootConsoleNeeded()) {
             this.mConsole = ConsoleBuilder.createPrivilegedConsole(getContext(), INITIAL_DIR);
         } else {
-            this.mConsole = ConsoleBuilder.createNonPrivilegedConsole(INITIAL_DIR);
+            this.mConsole = ConsoleBuilder.createNonPrivilegedConsole(getContext(), INITIAL_DIR);
         }
 
         super.setUp();
index 569854a..dd9bcca 100644 (file)
@@ -65,11 +65,10 @@ public class ConsoleBuilderTest extends android.test.AndroidTestCase {
      * Method that performs a test over creating a non privileged console.
      *
      * @throws Exception If test failed
-     * @{link {@link ConsoleBuilder#createNonPrivilegedConsole(String)}
+     * @{link {@link ConsoleBuilder#createNonPrivilegedConsole(android.content.Context, String)}
      */
-    @SuppressWarnings("static-method")
     public void testCreateNonPrivilegedConsole() throws Exception {
-        Console console = ConsoleBuilder.createNonPrivilegedConsole(PATH);
+        Console console = ConsoleBuilder.createNonPrivilegedConsole(getContext(), PATH);
         try {
             assertNotNull("console==null", console); //$NON-NLS-1$
         } finally {