diff options
78 files changed, 1616 insertions, 1169 deletions
diff --git a/res/layout-sw600dp/theme_view.xml b/res/layout-sw600dp/theme_view.xml new file mode 100644 index 00000000..356d1070 --- /dev/null +++ b/res/layout-sw600dp/theme_view.xml @@ -0,0 +1,64 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2011 The Android Open Source 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. +--> + +<com.cyanogenmod.filemanager.ui.preferences.ThemeView + xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="1dp" + android:layout_height="match_parent"> + + <TextView + android:id="@+id/theme_name" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_alignParentTop="true" + android:gravity="center" + android:ellipsize="end" + android:singleLine="true" + android:textAppearance="@style/primary_text_appearance" /> + + <TextView + android:id="@+id/theme_author" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_below="@id/theme_name" + android:gravity="center" + android:ellipsize="end" + android:singleLine="true" + android:textAppearance="@style/primary_text_appearance_nohighlight" /> + + <TextView + android:id="@+id/theme_desc" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_alignParentBottom="true" + android:gravity="center" + android:ellipsize="end" + android:singleLine="false" + android:maxLines="2" + android:textAppearance="@style/secondary_text_appearance" /> + + <ImageView + android:id="@+id/theme_preview" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:layout_above="@id/theme_desc" + android:layout_below="@id/theme_author" + android:padding="@dimen/extra_large_margin" + android:layout_gravity="center" + android:scaleType="centerInside" + android:contentDescription="@null" /> + +</com.cyanogenmod.filemanager.ui.preferences.ThemeView> diff --git a/res/layout-sw720dp/theme_view.xml b/res/layout-sw720dp/theme_view.xml new file mode 100644 index 00000000..356d1070 --- /dev/null +++ b/res/layout-sw720dp/theme_view.xml @@ -0,0 +1,64 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2011 The Android Open Source 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. +--> + +<com.cyanogenmod.filemanager.ui.preferences.ThemeView + xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="1dp" + android:layout_height="match_parent"> + + <TextView + android:id="@+id/theme_name" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_alignParentTop="true" + android:gravity="center" + android:ellipsize="end" + android:singleLine="true" + android:textAppearance="@style/primary_text_appearance" /> + + <TextView + android:id="@+id/theme_author" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_below="@id/theme_name" + android:gravity="center" + android:ellipsize="end" + android:singleLine="true" + android:textAppearance="@style/primary_text_appearance_nohighlight" /> + + <TextView + android:id="@+id/theme_desc" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_alignParentBottom="true" + android:gravity="center" + android:ellipsize="end" + android:singleLine="false" + android:maxLines="2" + android:textAppearance="@style/secondary_text_appearance" /> + + <ImageView + android:id="@+id/theme_preview" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:layout_above="@id/theme_desc" + android:layout_below="@id/theme_author" + android:padding="@dimen/extra_large_margin" + android:layout_gravity="center" + android:scaleType="centerInside" + android:contentDescription="@null" /> + +</com.cyanogenmod.filemanager.ui.preferences.ThemeView> diff --git a/res/layout/bookmarks_item.xml b/res/layout/bookmarks_item.xml index f1c7acca..fc8e4be5 100644 --- a/res/layout/bookmarks_item.xml +++ b/res/layout/bookmarks_item.xml @@ -17,7 +17,7 @@ <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="wrap_content" android:layout_height="@dimen/default_row_height" - android:background="@drawable/holo_selector" > + android:background="@drawable/holo_list_selector_deselected" > <ImageView android:id="@+id/bookmarks_item_icon" diff --git a/res/layout/editor.xml b/res/layout/editor.xml index af78d622..177d377e 100644 --- a/res/layout/editor.xml +++ b/res/layout/editor.xml @@ -46,6 +46,7 @@ android:gravity="top|left" android:cursorVisible="true" android:background="@null" + android:imeOptions="actionDone|flagNoFullscreen" android:inputType="textMultiLine|textImeMultiLine" android:text="@null" android:textAppearance="@style/secondary_text_appearance" /> diff --git a/res/layout/history_item.xml b/res/layout/history_item.xml index 4fca6ff1..2ef5fe97 100644 --- a/res/layout/history_item.xml +++ b/res/layout/history_item.xml @@ -17,7 +17,7 @@ <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="wrap_content" android:layout_height="@dimen/default_row_height" - android:background="@drawable/holo_selector" > + android:background="@drawable/holo_list_selector_deselected" > <ImageView android:id="@+id/history_item_icon" diff --git a/res/layout/inline_autocomplete.xml b/res/layout/inline_autocomplete.xml index 3938cb40..e6d1c518 100644 --- a/res/layout/inline_autocomplete.xml +++ b/res/layout/inline_autocomplete.xml @@ -27,6 +27,7 @@ android:gravity="top" android:hint="@null" android:inputType="none" + android:imeOptions="actionDone|flagNoFullscreen" android:paddingLeft="@dimen/small_buttom_width" android:singleLine="false" android:textColor="@android:color/darker_gray" @@ -46,7 +47,7 @@ android:gravity="top" android:hint="@null" android:inputType="textNoSuggestions|textImeMultiLine" - android:imeOptions="actionDone" + android:imeOptions="actionDone|flagNoFullscreen" android:paddingLeft="@dimen/small_buttom_width" android:singleLine="false" android:textColor="@color/black_transparent" diff --git a/res/layout/input_name_dialog.xml b/res/layout/input_name_dialog.xml index 3ff195f2..2ec64d78 100644 --- a/res/layout/input_name_dialog.xml +++ b/res/layout/input_name_dialog.xml @@ -40,7 +40,7 @@ android:layout_marginLeft="@dimen/extra_large_margin" android:layout_marginRight="@dimen/extra_large_margin" android:ems="@integer/default_edit_text_ems" - android:imeOptions="actionDone" + android:imeOptions="actionDone|flagNoFullscreen" android:scrollHorizontally="true" android:selectAllOnFocus="true" android:inputType="textNoSuggestions"> diff --git a/res/layout/navigation.xml b/res/layout/navigation.xml index f77033c7..68df9c4f 100644 --- a/res/layout/navigation.xml +++ b/res/layout/navigation.xml @@ -17,6 +17,7 @@ <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:filemanager="http://schemas.android.com/apk/res/com.cyanogenmod.filemanager" + android:id="@+id/navigation_layout" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> diff --git a/res/values-es/strings.xml b/res/values-es/strings.xml index 40f2ada4..757534b0 100644 --- a/res/values-es/strings.xml +++ b/res/values-es/strings.xml @@ -85,7 +85,7 @@ <string name="cm_filemanager_show_symlinks">Ver accesos directos</string> <string name="filesystem_info_warning_title">Sin información</string> <string name="filesystem_info_warning_msg">No hay información disponible para el sistema de archivos.</string> - <string name="filesystem_info_cant_be_mounted_msg">El sistema de archivos no ha podido ser montado/desmontado.</string> + <string name="filesystem_info_cant_be_mounted_msg">El sistema de archivos no puede ser montado/desmontado.</string> <string name="filesystem_info_mount_not_allowed_msg">La operación de montaje del sistema de archivos no está permitida en modo seguro. Tocar aquà para cambiar a modo superusuario.</string> <string name="filesystem_info_mount_failed_msg">La operación de montaje del sistema de archivos ha fallado. Algunos sistemas de archivos, como las tarjetas SD, no pueden ser montados o desmontados porque están diseñados como sistemas de solo-lectura.</string> <string name="filesystem_info_dialog_title">Información del sistema de archivos</string> @@ -281,7 +281,7 @@ <string name="pref_about_summary">File Manager v<xliff:g id="version">%1$s</xliff:g> \nCopyright \u00A9 2012 The CyanogenMod Project</string> <string name="pref_general_behaviour_category">General</string> - <string name="pref_case_sensitive_sort">Distinción mayúsc. y minúsc.</string> + <string name="pref_case_sensitive_sort">Ordenación sensible</string> <string name="pref_disk_usage_warning_level">Aviso de uso de disco</string> <string name="pref_disk_usage_warning_level_summary" formatted="false">Mostrar un color diferente para los widgets de uso de disco, cuando el espacio ocupado supere el <xliff:g id="level">%1$s</xliff:g> por ciento del total</string> <string name="pref_compute_folder_statistics">EstadÃsticas de carpetas</string> @@ -297,7 +297,7 @@ <string name="pref_access_mode_root">Modo superusuario</string> <string name="pref_access_mode_root_summary">Modo superusuario\n\n¡Aviso! Este modo permite operaciones que pueden bloquear el dispositivo. Será su responsabilidad asegurarse de que la operación sea segura</string> <string name="pref_search_results_category">Resultados</string> - <string name="pref_show_relevance_widget">Mostrar widget de relevancia</string> + <string name="pref_show_relevance_widget">Mostrar relevancia</string> <string name="pref_highlight_terms">Resaltar términos de búsqueda</string> <string name="pref_sort_search_results_mode">Ordenación de resultados</string> <string name="pref_sort_search_results_mode_none">Sin ordenar</string> @@ -315,7 +315,7 @@ <string name="pref_themes_no_preview">Vista previa\nno disponible</string> <string name="pref_themes_confirmation">Tema aplicado satisfactoriamente.</string> <string name="pref_themes_not_found">Tema no encontrado.</string> - <string name="pref_debug_traces">Habilitar registro de depuración</string> + <string name="pref_debug_traces">Habilitar depuración</string> <string name="theme_default_name">Tema claro</string> <string name="theme_default_description">Un tema en colores claros para File Manager.</string> <string name="security_warning_extract">¡Aviso!\n\nExtraer archivos comprimidos que contienen rutas absolutas o relativas puede causar daños en su dispositivo por la posible sobrescritura de archivos de sistema.\n\n¿Continuar?</string> diff --git a/res/values/dimen.xml b/res/values/dimen.xml index 0278d310..fe85edb3 100644 --- a/res/values/dimen.xml +++ b/res/values/dimen.xml @@ -106,7 +106,8 @@ <!-- Theme button min width --> <dimen name="themes_min_width_button">300dp</dimen> - <!-- Theme width --> + <!-- Theme width/height --> <dimen name="theme_max_width">300dip</dimen> + <dimen name="theme_max_height">600dip</dimen> </resources> diff --git a/res/values/overlay.xml b/res/values/overlay.xml index 1a68d534..8d591964 100644 --- a/res/values/overlay.xml +++ b/res/values/overlay.xml @@ -60,6 +60,7 @@ /system/xbin/gunzip, /system/xbin/pwd, /system/xbin/readlink, + /system/xbin/stat, /system/xbin/su, /system/xbin/tar, /system/xbin/uncompress, diff --git a/res/xml/command_list.xml b/res/xml/command_list.xml index caa288ac..c473c284 100644 --- a/res/xml/command_list.xml +++ b/res/xml/command_list.xml @@ -31,9 +31,9 @@ --> <CommandList xmlns="http://schemas.android.com/apk/res/com.cyanogenmod.filemanager"> <!-- Start code (append to commands; for retrieve the exit code) --> - <startcode commandId="startcode" commandPath="/system/xbin/echo %1$s0%2$s ; " /> + <startcode commandId="startcode" commandPath="/system/xbin/echo -n %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" /> + <exitcode commandId="exitcode" commandPath=" ; /system/xbin/echo -n %1$s$?%2$s" /> <!-- Shell commands --> <command commandId="bash" commandPath="/system/bin/sh" commandArgs="" /> @@ -49,14 +49,14 @@ <!-- FileSystem --> <command commandId="mount" commandPath="/system/bin/mount" commandArgs="-o %1$s,remount -t auto %2$s %3$s" /> - <command commandId="mountpointinfo" commandPath="/system/bin/cat" commandArgs="/proc/mounts" /> + <command commandId="mountpointinfo" commandPath="/system/bin/mount" commandArgs="" /> <!-- List/Find/Info --> - <command commandId="ls" commandPath="cd" commandArgs="%1$s && /system/bin/ls -al %1$s | { /system/xbin/grep -v -e '^l' || true; } && /system/xbin/echo '>SIMLINKS>' && /system/bin/ls -al %1$s | { /system/xbin/grep -e '^l' || true; } && /system/xbin/echo '>SIMLINKS_DATA>' && /system/bin/ls -aF %1$s | /system/xbin/grep -e '^l' | /system/xbin/cut -d ' ' -f2- && /system/bin/ls -aF %1$s | /system/xbin/grep -e '^l' | /system/xbin/cut -d ' ' -f2- | /system/xbin/awk '{print "\\""$0"\\""}' | /system/xbin/xargs -r -n1 /system/xbin/readlink -f && /system/bin/ls -F %1$s | /system/xbin/grep -e '^l' | /system/xbin/cut -d ' ' -f2- | /system/xbin/awk '{print "\\""$0"\\""}' | /system/xbin/xargs -r -n1 /system/xbin/readlink -f | /system/xbin/awk '{print "\\""$0"\\""}' | { /system/xbin/xargs -r /system/bin/ls -ald || /system/xbin/echo; }" /> - <command commandId="fileinfo" commandPath="/system/bin/ls" commandArgs="-ald %1$s" /> - <command commandId="find" commandPath="/system/xbin/find" commandArgs="%1$s \\( -name %2$s -o -name %3$s -o -name %4$s -o -name %5$s -o -name %6$s \\) -exec /system/xbin/echo {} \\; -exec /system/bin/ls -ald {} \\;" /> + <command commandId="ls" commandPath="/system/bin/ls" commandArgs="%1$s 1> /dev/null && /system/xbin/stat -t %1$s* 2>&1" /> + <command commandId="fileinfo" commandPath="/system/xbin/stat" commandArgs="-t %1$s 2>&1" /> + <command commandId="find" commandPath="/system/xbin/find" commandArgs="%1$s \\( -name %2$s -o -name %3$s -o -name %4$s -o -name %5$s -o -name %6$s \\) -exec /system/xbin/stat -t {} 2>&1 \\;" /> <command commandId="quickfoldersearch" commandPath="/system/bin/ls" commandArgs="-aFd %1$s.* %1$s* 2> /dev/null | /system/xbin/grep -e '^d' -e '^ld' | /system/xbin/cut -d" " -f2-" /> - <command commandId="readlink" commandPath="cd" commandArgs="%2$s && /system/xbin/readlink -f %1$s | /system/xbin/awk -F// '{print "\\""$1"\\""}' | /system/xbin/xargs -n1 /system/xbin/dirname && /system/xbin/readlink -f %1$s | /system/xbin/awk -F// '{print "\\""$1"\\""}' | /system/xbin/xargs -n1 /system/bin/ls -ald" /> + <command commandId="readlink" commandPath="/system/bin/ls" commandArgs="%1$s 1> /dev/null && /system/xbin/stat -tL %1$s 2>&1" /> <!-- Operational --> <command commandId="chmod" commandPath="/system/bin/chmod" commandArgs="%1$s %2$s" /> @@ -71,7 +71,7 @@ <!-- Usage --> <command commandId="diskusage" commandPath="/system/bin/df" commandArgs="%1$s" /> <command commandId="diskusageall" commandPath="/system/bin/df" commandArgs="" /> - <command commandId="folderusage" commandPath="/system/bin/ls" commandArgs="-alR %1$s" /> + <command commandId="folderusage" commandPath="/system/bin/ls" commandArgs="-alR %1$s 2> /dev/null" /> <!-- I/O --> <command commandId="read" commandPath="/system/bin/cat" commandArgs="%1$s" /> diff --git a/src/com/cyanogenmod/filemanager/FileManagerApplication.java b/src/com/cyanogenmod/filemanager/FileManagerApplication.java index c765ee35..cc1ff941 100644 --- a/src/com/cyanogenmod/filemanager/FileManagerApplication.java +++ b/src/com/cyanogenmod/filemanager/FileManagerApplication.java @@ -35,6 +35,7 @@ import com.cyanogenmod.filemanager.preferences.ObjectStringIdentifier; import com.cyanogenmod.filemanager.preferences.Preferences; import com.cyanogenmod.filemanager.ui.ThemeManager; import com.cyanogenmod.filemanager.ui.ThemeManager.Theme; +import com.cyanogenmod.filemanager.util.AIDHelper; import com.cyanogenmod.filemanager.util.FileHelper; import com.cyanogenmod.filemanager.util.MimeTypeHelper; @@ -100,7 +101,7 @@ public final class FileManagerApplication extends Application { } }; - // A broadcast receiver for detect the uninstall of apk with themes + // A broadcast receiver for detect the install/uninstall of apps (for themes, AIDs, ...) private final BroadcastReceiver mUninstallReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { @@ -109,34 +110,46 @@ public final class FileManagerApplication extends Application { intent.getAction().compareTo(Intent.ACTION_PACKAGE_FULLY_REMOVED) == 0) { // Check that the remove package is not the current theme if (intent.getData() != null) { - // Get the package name and remove the schema - String apkPackage = intent.getData().toString(); - apkPackage = apkPackage.substring("package:".length()); //$NON-NLS-1$ - - Theme currentTheme = ThemeManager.getCurrentTheme(context); - if (currentTheme.getPackage().compareTo(apkPackage) == 0) { - // The apk that contains the current theme was remove, change - // to default theme - String composedId = - (String)FileManagerSettings.SETTINGS_THEME.getDefaultValue(); - ThemeManager.setCurrentTheme(getApplicationContext(), composedId); - try { - Preferences.savePreference( - FileManagerSettings.SETTINGS_THEME, composedId, true); - } catch (Throwable ex) { - Log.w(TAG, "can't save theme preference", ex); //$NON-NLS-1$ - } + // --- AIDs + try { + AIDHelper.getAIDs(getApplicationContext(), true); + } catch (Exception e) { + Log.w(TAG, "Failed to reload AIDs", e); //$NON-NLS-1$ + } - // Notify the changes to activities - try { - Intent broadcastIntent = - new Intent(FileManagerSettings.INTENT_THEME_CHANGED); - broadcastIntent.putExtra( - FileManagerSettings.EXTRA_THEME_ID, composedId); - sendBroadcast(broadcastIntent); - } catch (Throwable ex) { - Log.w(TAG, "notify of theme change failed", ex); //$NON-NLS-1$ + // --- Themes + try { + // Get the package name and remove the schema + String apkPackage = intent.getData().toString(); + apkPackage = apkPackage.substring("package:".length()); //$NON-NLS-1$ + + Theme currentTheme = ThemeManager.getCurrentTheme(context); + if (currentTheme.getPackage().compareTo(apkPackage) == 0) { + // The apk that contains the current theme was remove, change + // to default theme + String composedId = + (String)FileManagerSettings.SETTINGS_THEME.getDefaultValue(); + ThemeManager.setCurrentTheme(getApplicationContext(), composedId); + try { + Preferences.savePreference( + FileManagerSettings.SETTINGS_THEME, composedId, true); + } catch (Throwable ex) { + Log.w(TAG, "can't save theme preference", ex); //$NON-NLS-1$ + } + + // Notify the changes to activities + try { + Intent broadcastIntent = + new Intent(FileManagerSettings.INTENT_THEME_CHANGED); + broadcastIntent.putExtra( + FileManagerSettings.EXTRA_THEME_ID, composedId); + sendBroadcast(broadcastIntent); + } catch (Throwable ex) { + Log.w(TAG, "notify of theme change failed", ex); //$NON-NLS-1$ + } } + } catch (Exception e) { + Log.w(TAG, "Failed to reload themes", e); //$NON-NLS-1$ } } } @@ -153,8 +166,8 @@ public final class FileManagerApplication extends Application { if (DEBUG) { Log.d(TAG, "FileManagerApplication.onCreate"); //$NON-NLS-1$ } - register(); init(); + register(); } /** @@ -192,19 +205,6 @@ public final class FileManagerApplication extends Application { * Method that register the application context. */ private void register() { - //Save the static application reference - sApp = this; - - // Read the system properties - sSystemProperties = new Properties(); - readSystemProperties(); - - // Check if the application is debuggable - sIsDebuggable = (0 != (getApplicationInfo().flags &= ApplicationInfo.FLAG_DEBUGGABLE)); - - // Check if the device is rooted - sIsDeviceRooted = areShellCommandsPresent(); - // Register the notify broadcast receiver IntentFilter filter = new IntentFilter(); filter.addAction(FileManagerSettings.INTENT_SETTING_CHANGED); @@ -222,10 +222,26 @@ public final class FileManagerApplication extends Application { * Method that initializes the application. */ private void init() { + //Save the static application reference + sApp = this; + + // Read the system properties + sSystemProperties = new Properties(); + readSystemProperties(); + + // Check if the application is debuggable + sIsDebuggable = (0 != (getApplicationInfo().flags &= ApplicationInfo.FLAG_DEBUGGABLE)); + + // Check if the device is rooted + sIsDeviceRooted = areShellCommandsPresent(); + //Sets the default preferences if no value is set yet FileHelper.ROOT_DIRECTORY = getString(R.string.root_dir); Preferences.loadDefaults(); + // Read AIDs + AIDHelper.getAIDs(getApplicationContext(), true); + // Allocate the default and current themes String defaultValue = ((String)FileManagerSettings. SETTINGS_THEME.getDefaultValue()); @@ -243,6 +259,9 @@ public final class FileManagerApplication extends Application { Log.w(TAG, "can't save theme preference", ex); //$NON-NLS-1$ } } + // Set the base theme + Theme theme = ThemeManager.getCurrentTheme(getApplicationContext()); + theme.setBaseTheme(getApplicationContext(), false); //Create a console for background tasks allocBackgroundConsole(getApplicationContext()); diff --git a/src/com/cyanogenmod/filemanager/activities/BookmarksActivity.java b/src/com/cyanogenmod/filemanager/activities/BookmarksActivity.java index d14988c8..317c8a4c 100644 --- a/src/com/cyanogenmod/filemanager/activities/BookmarksActivity.java +++ b/src/com/cyanogenmod/filemanager/activities/BookmarksActivity.java @@ -587,15 +587,22 @@ public class BookmarksActivity extends Activity implements OnItemClickListener, private List<Bookmark> loadUserBookmarks() { List<Bookmark> bookmarks = new ArrayList<Bookmark>(); Cursor cursor = Bookmarks.getAllBookmarks(this.getContentResolver()); - if (cursor != null && cursor.moveToFirst()) { - do { - Bookmark bm = new Bookmark(cursor); - if (this.mChRooted && !StorageHelper.isPathInStorageVolume(bm.mPath)) { - continue; + try { + if (cursor != null && cursor.moveToFirst()) { + do { + Bookmark bm = new Bookmark(cursor); + if (this.mChRooted && !StorageHelper.isPathInStorageVolume(bm.mPath)) { + continue; + } + bookmarks.add(bm); + } while (cursor.moveToNext()); + } + } finally { + try { + if (cursor != null) { + cursor.close(); } - bookmarks.add(bm); - } while (cursor.moveToNext()); - cursor.close(); + } catch (Exception e) {/**NON BLOCK**/} } return bookmarks; } diff --git a/src/com/cyanogenmod/filemanager/activities/EditorActivity.java b/src/com/cyanogenmod/filemanager/activities/EditorActivity.java index 6b682ad2..4a922121 100644 --- a/src/com/cyanogenmod/filemanager/activities/EditorActivity.java +++ b/src/com/cyanogenmod/filemanager/activities/EditorActivity.java @@ -602,9 +602,9 @@ public class EditorActivity extends Activity implements TextWatcher { } } else { // Now we have the buffer, set the text of the editor - if (!EditorActivity.this.mBinary && EditorActivity.this.mFso.getSize() == 0) { - // Clean the document - EditorActivity.this.mEditor.setText(""); //$NON-NLS-1$ + if (EditorActivity.this.mBinary) { + EditorActivity.this.mEditor.setText( + this.mReader.mBuffer, BufferType.NORMAL); } else { EditorActivity.this.mEditor.setText( this.mReader.mBuffer, BufferType.EDITABLE); diff --git a/src/com/cyanogenmod/filemanager/activities/NavigationActivity.java b/src/com/cyanogenmod/filemanager/activities/NavigationActivity.java index 56b7ec90..1ecd3be5 100644 --- a/src/com/cyanogenmod/filemanager/activities/NavigationActivity.java +++ b/src/com/cyanogenmod/filemanager/activities/NavigationActivity.java @@ -617,9 +617,7 @@ public class NavigationActivity extends Activity //Ensure initial is an absolute directory try { - initialDir = - CommandHelper.getAbsolutePath( - NavigationActivity.this, initialDir, null); + initialDir = new File(initialDir).getAbsolutePath(); } catch (Throwable e) { Log.e(TAG, "Resolve of initital directory fails", e); //$NON-NLS-1$ String msg = @@ -916,7 +914,7 @@ public class NavigationActivity extends Activity * {@inheritDoc} */ @Override - public void onRequestRefresh(Object o) { + public void onRequestRefresh(Object o, boolean clearSelection) { if (o instanceof FileSystemObject) { // Refresh only the item this.getCurrentNavigationView().refresh((FileSystemObject)o); @@ -924,14 +922,16 @@ public class NavigationActivity extends Activity // Refresh all getCurrentNavigationView().refresh(); } - this.getCurrentNavigationView().onDeselectAll(); + if (clearSelection) { + this.getCurrentNavigationView().onDeselectAll(); + } } /** * {@inheritDoc} */ @Override - public void onRequestRemove(Object o) { + public void onRequestRemove(Object o, boolean clearSelection) { if (o instanceof FileSystemObject) { // Remove from view this.getCurrentNavigationView().removeItem((FileSystemObject)o); @@ -939,9 +939,11 @@ public class NavigationActivity extends Activity //Remove from history removeFromHistory((FileSystemObject)o); } else { - onRequestRefresh(null); + onRequestRefresh(null, clearSelection); + } + if (clearSelection) { + this.getCurrentNavigationView().onDeselectAll(); } - this.getCurrentNavigationView().onDeselectAll(); } /** @@ -1187,7 +1189,6 @@ public class NavigationActivity extends Activity bundle.putString( SearchActivity.EXTRA_SEARCH_DIRECTORY, getCurrentNavigationView().getCurrentDir()); - // TODO VoiceSearch icon is not shown. This must be a bug of CM. Verify with a test app. startSearch(Preferences.getLastSearch(), true, bundle, false); return true; } @@ -1596,10 +1597,13 @@ public class NavigationActivity extends Activity Theme theme = ThemeManager.getCurrentTheme(this); theme.setBaseTheme(this, false); + //- Layout + View v = findViewById(R.id.navigation_layout); + theme.setBackgroundDrawable(this, v, "background_drawable"); //$NON-NLS-1$ //- ActionBar theme.setTitlebarDrawable(this, getActionBar(), "titlebar_drawable"); //$NON-NLS-1$ //- StatusBar - View v = findViewById(R.id.navigation_statusbar); + v = findViewById(R.id.navigation_statusbar); if (orientation == Configuration.ORIENTATION_LANDSCAPE) { theme.setBackgroundDrawable(this, v, "titlebar_drawable"); //$NON-NLS-1$ } else { diff --git a/src/com/cyanogenmod/filemanager/activities/SearchActivity.java b/src/com/cyanogenmod/filemanager/activities/SearchActivity.java index 2c706fc6..60d043c8 100644 --- a/src/com/cyanogenmod/filemanager/activities/SearchActivity.java +++ b/src/com/cyanogenmod/filemanager/activities/SearchActivity.java @@ -54,6 +54,7 @@ import com.cyanogenmod.filemanager.adapters.SearchResultAdapter; import com.cyanogenmod.filemanager.commands.AsyncResultExecutable; import com.cyanogenmod.filemanager.commands.AsyncResultListener; import com.cyanogenmod.filemanager.console.NoSuchFileOrDirectory; +import com.cyanogenmod.filemanager.console.RelaunchableException; import com.cyanogenmod.filemanager.listeners.OnRequestRefreshListener; import com.cyanogenmod.filemanager.model.Directory; import com.cyanogenmod.filemanager.model.FileSystemObject; @@ -80,6 +81,7 @@ import com.cyanogenmod.filemanager.ui.widgets.FlingerListView.OnItemFlingerRespo import com.cyanogenmod.filemanager.util.CommandHelper; import com.cyanogenmod.filemanager.util.DialogHelper; import com.cyanogenmod.filemanager.util.ExceptionUtil; +import com.cyanogenmod.filemanager.util.ExceptionUtil.OnRelaunchCommandResult; import com.cyanogenmod.filemanager.util.FileHelper; import com.cyanogenmod.filemanager.util.StorageHelper; @@ -868,15 +870,19 @@ public class SearchActivity extends Activity FileSystemObject fso = result.getFso(); if (fso instanceof Directory) { back(false, fso, false); + return; } else if (fso instanceof Symlink) { Symlink symlink = (Symlink)fso; if (symlink.getLinkRef() != null && symlink.getLinkRef() instanceof Directory) { back(false, symlink.getLinkRef(), false); + return; } - } else { - // Open the file with the preferred registered app - back(false, fso, false); + fso = symlink.getLinkRef(); } + + // Open the file with the preferred registered app + back(false, fso, false); + } catch (Throwable ex) { ExceptionUtil.translateException(this.mSearchListView.getContext(), ex); } @@ -955,7 +961,7 @@ public class SearchActivity extends Activity * {@inheritDoc} */ @Override - public void onRequestRefresh(Object o) { + public void onRequestRefresh(Object o, boolean clearSelection) { // Refresh only the item SearchResultAdapter adapter = (SearchResultAdapter)this.mSearchListView.getAdapter(); @@ -985,7 +991,7 @@ public class SearchActivity extends Activity * {@inheritDoc} */ @Override - public void onRequestRemove(Object o) { + public void onRequestRemove(Object o, boolean clearSelection) { if (o instanceof FileSystemObject) { removeItem((FileSystemObject)o); } @@ -1006,10 +1012,14 @@ public class SearchActivity extends Activity * * @param cancelled Indicates if the activity was cancelled * @param item The fso + * @param isChecked If the fso was fully retrieve previously to this call. Otherwise, a + * getFileInfo call is done to complete the fso information * @hide */ void back(final boolean cancelled, FileSystemObject item, boolean isChecked) { - Intent intent = new Intent(); + final Context ctx = SearchActivity.this; + final Intent intent = new Intent(); + boolean finish = true; if (cancelled) { if (SearchActivity.this.mDrawingSearchResultTask != null && SearchActivity.this.mDrawingSearchResultTask.isRunning()) { @@ -1023,44 +1033,77 @@ public class SearchActivity extends Activity setResult(RESULT_CANCELED, intent); } else { // Check that the bookmark exists + FileSystemObject fso = item; try { - FileSystemObject fso = item; if (!isChecked) { - fso = CommandHelper.getFileInfo(this, item.getFullPath(), null); - } - if (fso != null) { - if (FileHelper.isDirectory(fso)) { - intent.putExtra(NavigationActivity.EXTRA_SEARCH_ENTRY_SELECTION, fso); - intent.putExtra( - NavigationActivity.EXTRA_SEARCH_LAST_SEARCH_DATA, - (Parcelable)createSearchInfo()); - setResult(RESULT_OK, intent); - } else { - // Open the file here, so when focus back to the app, the search activity - // its in top of the stack - IntentsActionPolicy.openFileSystemObject(this, fso, false, null, null); - return; - } - } else { - // The fso not exists, delete the fso from the search - try { - removeItem(item); - } catch (Exception ex) {/**NON BLOCK**/} + fso = CommandHelper.getFileInfo(ctx, item.getFullPath(), null); } + finish = navigateTo(fso, intent); } catch (Exception e) { // Capture the exception - ExceptionUtil.translateException(this, e); - if (e instanceof NoSuchFileOrDirectory || e instanceof FileNotFoundException) { - // The fso not exists, delete the fso from the search - try { - removeItem(item); - } catch (Exception ex) {/**NON BLOCK**/} + final FileSystemObject fFso = fso; + final OnRelaunchCommandResult relaunchListener = new OnRelaunchCommandResult() { + @Override + public void onSuccess() { + if (navigateTo(fFso, intent)) { + finish(); + } + } + @Override + public void onFailed(Throwable cause) { + ExceptionUtil.translateException(ctx, cause, false, false); + } + @Override + public void onCancelled() { /** NON BLOCK**/} + }; + ExceptionUtil.translateException(ctx, e, false, true, relaunchListener); + if (!(e instanceof RelaunchableException)) { + if (e instanceof NoSuchFileOrDirectory || e instanceof FileNotFoundException) { + // The fso not exists, delete the fso from the search + try { + removeItem(fso); + } catch (Exception ex) {/**NON BLOCK**/} + } } return; } } - finish(); + + // End this activity + if (finish) { + finish(); + } + } + + /** + * Method that navigate to the file system used the intent (NavigationActivity) + * + * @param fso The file system object to navigate to + * @param intent The intent used to navigate to + * @return boolean If the action implies finish this activity + */ + boolean navigateTo(FileSystemObject fso, Intent intent) { + if (fso != null) { + if (FileHelper.isDirectory(fso)) { + intent.putExtra(NavigationActivity.EXTRA_SEARCH_ENTRY_SELECTION, fso); + intent.putExtra( + NavigationActivity.EXTRA_SEARCH_LAST_SEARCH_DATA, + (Parcelable)createSearchInfo()); + setResult(RESULT_OK, intent); + return true; + } + + // Open the file here, so when focus back to the app, the search activity + // its in top of the stack + IntentsActionPolicy.openFileSystemObject(this, fso, false, null, null); + } else { + // The fso not exists, delete the fso from the search + try { + removeItem(fso); + } catch (Exception ex) {/**NON BLOCK**/} + } + return false; } /** diff --git a/src/com/cyanogenmod/filemanager/adapters/AssociationsAdapter.java b/src/com/cyanogenmod/filemanager/adapters/AssociationsAdapter.java index 1daaf715..22f6c3c9 100644 --- a/src/com/cyanogenmod/filemanager/adapters/AssociationsAdapter.java +++ b/src/com/cyanogenmod/filemanager/adapters/AssociationsAdapter.java @@ -95,7 +95,7 @@ public class AssociationsAdapter this.mOnItemClickListener = onItemClickListener; //Do cache of the data for better performance - processData(); + processData(intents); } /** @@ -103,7 +103,7 @@ public class AssociationsAdapter */ @Override public void notifyDataSetChanged() { - processData(); + processData(null); super.notifyDataSetChanged(); } @@ -117,13 +117,15 @@ public class AssociationsAdapter /** * Method that process the data before use {@link #getView} method. + * + * @param intents The list of intents (to better performance) or null. */ - private void processData() { + private void processData(List<ResolveInfo> intents) { this.mData = new DataHolder[getCount()]; - int cc = getCount(); + int cc = (intents == null) ? getCount() : intents.size(); for (int i = 0; i < cc; i++) { //Intent info - ResolveInfo intentInfo = getItem(i); + ResolveInfo intentInfo = (intents == null) ? getItem(i) : intents.get(i); //Build the data holder this.mData[i] = new AssociationsAdapter.DataHolder(); diff --git a/src/com/cyanogenmod/filemanager/adapters/BookmarksAdapter.java b/src/com/cyanogenmod/filemanager/adapters/BookmarksAdapter.java index a60ccd3b..cbe63a49 100644 --- a/src/com/cyanogenmod/filemanager/adapters/BookmarksAdapter.java +++ b/src/com/cyanogenmod/filemanager/adapters/BookmarksAdapter.java @@ -108,7 +108,7 @@ public class BookmarksAdapter extends ArrayAdapter<Bookmark> { this.mOnActionClickListener = onActionClickListener; //Do cache of the data for better performance - processData(); + processData(bookmarks); } /** @@ -116,7 +116,7 @@ public class BookmarksAdapter extends ArrayAdapter<Bookmark> { */ @Override public void notifyDataSetChanged() { - processData(); + processData(null); super.notifyDataSetChanged(); } @@ -131,13 +131,15 @@ public class BookmarksAdapter extends ArrayAdapter<Bookmark> { /** * Method that process the data before use {@link #getView} method. + * + * @param bookmarks The list of bookmarks (to better performance) or null. */ - private void processData() { + private void processData(List<Bookmark> bookmarks) { this.mData = new DataHolder[getCount()]; - int cc = getCount(); + int cc = (bookmarks == null) ? getCount() : bookmarks.size(); for (int i = 0; i < cc; i++) { //Bookmark info - Bookmark bookmark = getItem(i); + Bookmark bookmark = (bookmarks == null) ? getItem(i) : bookmarks.get(i); //Build the data holder this.mData[i] = new BookmarksAdapter.DataHolder(); @@ -187,7 +189,7 @@ public class BookmarksAdapter extends ArrayAdapter<Bookmark> { // Apply the current theme Theme theme = ThemeManager.getCurrentTheme(getContext()); theme.setBackgroundDrawable( - getContext(), v, "background_drawable"); //$NON-NLS-1$ + getContext(), v, "selectors_deselected_drawable"); //$NON-NLS-1$ theme.setTextColor( getContext(), viewHolder.mTvName, "text_color"); //$NON-NLS-1$ theme.setTextColor( diff --git a/src/com/cyanogenmod/filemanager/adapters/CheckableListAdapter.java b/src/com/cyanogenmod/filemanager/adapters/CheckableListAdapter.java index befac79b..be28711f 100644 --- a/src/com/cyanogenmod/filemanager/adapters/CheckableListAdapter.java +++ b/src/com/cyanogenmod/filemanager/adapters/CheckableListAdapter.java @@ -176,8 +176,8 @@ public class CheckableListAdapter extends ArrayAdapter<CheckableListAdapter.Chec int cc = getCount(); for (int i = 0; i < cc; i++) { getItem(i).mChecked = (i == position); - notifyDataSetChanged(); } + notifyDataSetChanged(); } } diff --git a/src/com/cyanogenmod/filemanager/adapters/FileSystemObjectAdapter.java b/src/com/cyanogenmod/filemanager/adapters/FileSystemObjectAdapter.java index c0f5facb..740dde41 100644 --- a/src/com/cyanogenmod/filemanager/adapters/FileSystemObjectAdapter.java +++ b/src/com/cyanogenmod/filemanager/adapters/FileSystemObjectAdapter.java @@ -135,7 +135,7 @@ public class FileSystemObjectAdapter //Do cache of the data for better performance loadDefaultIcons(); - processData(); + processData(files); } /** @@ -161,7 +161,7 @@ public class FileSystemObjectAdapter */ @Override public void notifyDataSetChanged() { - processData(); + processData(null); super.notifyDataSetChanged(); } @@ -195,16 +195,18 @@ public class FileSystemObjectAdapter /** * Method that process the data before use {@link #getView} method. + * + * @param files The list of files (to better performance) or null. */ - private void processData() { + private void processData(List<FileSystemObject> files) { Theme theme = ThemeManager.getCurrentTheme(getContext()); Resources res = getContext().getResources(); DateFormat df = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT); this.mData = new DataHolder[getCount()]; - int cc = getCount(); + int cc = (files == null) ? getCount() : files.size(); for (int i = 0; i < cc; i++) { //File system object info - FileSystemObject fso = getItem(i); + FileSystemObject fso = (files == null) ? getItem(i) : files.get(i); //Parse the last modification time and permissions StringBuilder sbSummary = new StringBuilder(); @@ -213,7 +215,7 @@ public class FileSystemObjectAdapter } else { sbSummary.append(df.format(fso.getLastModifiedTime())); sbSummary.append(" "); //$NON-NLS-1$ - sbSummary.append(fso.toRawString()); + sbSummary.append(fso.toRawPermissionString()); } //Build the data holder @@ -457,7 +459,6 @@ public class FileSystemObjectAdapter theme.getDrawable( getContext(), "checkbox_deselected_drawable"); //$NON-NLS-1$ } - notifyDataSetChanged(); //Add or remove from the global selected items FileSystemObject fso = getItem(i); @@ -477,6 +478,9 @@ public class FileSystemObjectAdapter FileSystemObjectAdapter.this.mSelectedItems); this.mOnSelectionChangedListener.onSelectionChanged(selection); } + + // The internal structure was update, only super adapter need to be notified + super.notifyDataSetChanged(); } } diff --git a/src/com/cyanogenmod/filemanager/adapters/HistoryAdapter.java b/src/com/cyanogenmod/filemanager/adapters/HistoryAdapter.java index 0a604ca6..4582410f 100644 --- a/src/com/cyanogenmod/filemanager/adapters/HistoryAdapter.java +++ b/src/com/cyanogenmod/filemanager/adapters/HistoryAdapter.java @@ -101,7 +101,7 @@ public class HistoryAdapter extends ArrayAdapter<History> { this.mIconHolder = new IconHolder(); //Do cache of the data for better performance - processData(); + processData(history); } /** @@ -109,7 +109,7 @@ public class HistoryAdapter extends ArrayAdapter<History> { */ @Override public void notifyDataSetChanged() { - processData(); + processData(null); super.notifyDataSetChanged(); } @@ -123,14 +123,16 @@ public class HistoryAdapter extends ArrayAdapter<History> { } /** - * Method that process the data before use {@link #getView} method . + * Method that process the data before use {@link #getView} method. + * + * @param historyData The list of histories (to better performance) or null. */ - private void processData() { + private void processData(List<History> historyData) { this.mData = new DataHolder[getCount()]; - int cc = getCount(); + int cc = (historyData == null) ? getCount() : historyData.size(); for (int i = 0; i < cc; i++) { //History info - History history = getItem(i); + History history = (historyData == null) ? getItem(i) : historyData.get(i); //Build the data holder this.mData[i] = new HistoryAdapter.DataHolder(); @@ -176,7 +178,7 @@ public class HistoryAdapter extends ArrayAdapter<History> { // Apply the current theme Theme theme = ThemeManager.getCurrentTheme(getContext()); theme.setBackgroundDrawable( - getContext(), v, "background_drawable"); //$NON-NLS-1$ + getContext(), v, "selectors_deselected_drawable"); //$NON-NLS-1$ theme.setTextColor( getContext(), viewHolder.mTvName, "text_color"); //$NON-NLS-1$ theme.setTextColor( diff --git a/src/com/cyanogenmod/filemanager/adapters/SearchResultAdapter.java b/src/com/cyanogenmod/filemanager/adapters/SearchResultAdapter.java index 7a8027e9..0561a647 100644 --- a/src/com/cyanogenmod/filemanager/adapters/SearchResultAdapter.java +++ b/src/com/cyanogenmod/filemanager/adapters/SearchResultAdapter.java @@ -127,7 +127,7 @@ public class SearchResultAdapter extends ArrayAdapter<SearchResult> { //Do cache of the data for better performance loadDefaultIcons(); - processData(); + processData(files); } /** @@ -143,7 +143,7 @@ public class SearchResultAdapter extends ArrayAdapter<SearchResult> { */ @Override public void notifyDataSetChanged() { - processData(); + processData(null); super.notifyDataSetChanged(); } @@ -158,17 +158,19 @@ public class SearchResultAdapter extends ArrayAdapter<SearchResult> { /** * Method that process the data before use {@link #getView} method. + * + * @param files The list of files (to better performance) or null. */ - private void processData() { + private void processData(List<SearchResult> files) { Theme theme = ThemeManager.getCurrentTheme(getContext()); int highlightedColor = theme.getColor(getContext(), "search_highlight_color"); //$NON-NLS-1$ this.mData = new DataHolder[getCount()]; - int cc = getCount(); + int cc = (files == null) ? getCount() : files.size(); for (int i = 0; i < cc; i++) { //File system object info - SearchResult result = getItem(i); + SearchResult result = (files == null) ? getItem(i) : files.get(i); //Build the data holder this.mData[i] = new SearchResultAdapter.DataHolder(); diff --git a/src/com/cyanogenmod/filemanager/commands/ExecutableCreator.java b/src/com/cyanogenmod/filemanager/commands/ExecutableCreator.java index 630546f8..a0fd6f94 100644 --- a/src/com/cyanogenmod/filemanager/commands/ExecutableCreator.java +++ b/src/com/cyanogenmod/filemanager/commands/ExecutableCreator.java @@ -18,6 +18,8 @@ package com.cyanogenmod.filemanager.commands; import com.cyanogenmod.filemanager.commands.ListExecutable.LIST_MODE; import com.cyanogenmod.filemanager.console.CommandNotFoundException; +import com.cyanogenmod.filemanager.console.InsufficientPermissionsException; +import com.cyanogenmod.filemanager.console.NoSuchFileOrDirectory; import com.cyanogenmod.filemanager.model.Group; import com.cyanogenmod.filemanager.model.MountPoint; import com.cyanogenmod.filemanager.model.Permissions; @@ -37,9 +39,12 @@ public interface ExecutableCreator { * @return ChangeCurrentDirExecutable A {@link ChangeCurrentDirExecutable} executable * implementation reference * @throws CommandNotFoundException If the executable can't be created + * @throws NoSuchFileOrDirectory If the file or directory was not found + * @throws InsufficientPermissionsException If an operation requires elevated permissions */ ChangeCurrentDirExecutable createChangeCurrentDirExecutable( - String dir) throws CommandNotFoundException; + String dir) throws CommandNotFoundException, + NoSuchFileOrDirectory, InsufficientPermissionsException; /** * Method that creates an executable for change the owner of a file system object. @@ -50,9 +55,12 @@ public interface ExecutableCreator { * @return ChangeOwnerExecutable A {@link ChangeOwnerExecutable} executable * implementation reference * @throws CommandNotFoundException If the executable can't be created + * @throws NoSuchFileOrDirectory If the file or directory was not found + * @throws InsufficientPermissionsException If an operation requires elevated permissions */ ChangeOwnerExecutable createChangeOwnerExecutable( - String fso, User newUser, Group newGroup) throws CommandNotFoundException; + String fso, User newUser, Group newGroup) throws CommandNotFoundException, + NoSuchFileOrDirectory, InsufficientPermissionsException; /** * Method that creates an executable for change the permissions of a file system object. @@ -62,9 +70,12 @@ public interface ExecutableCreator { * @return ChangePermissionsExecutable A {@link ChangePermissionsExecutable} executable * implementation reference * @throws CommandNotFoundException If the executable can't be created + * @throws NoSuchFileOrDirectory If the file or directory was not found + * @throws InsufficientPermissionsException If an operation requires elevated permissions */ ChangePermissionsExecutable createChangePermissionsExecutable( - String fso, Permissions newPermissions) throws CommandNotFoundException; + String fso, Permissions newPermissions) throws CommandNotFoundException, + NoSuchFileOrDirectory, InsufficientPermissionsException; /** * Method that creates an executable for copy a file system object to @@ -74,8 +85,11 @@ public interface ExecutableCreator { * @param dst The absolute path to the destination file system object * @return CopyExecutable A {@link CopyExecutable} executable implementation reference * @throws CommandNotFoundException If the executable can't be created + * @throws NoSuchFileOrDirectory If the file or directory was not found + * @throws InsufficientPermissionsException If an operation requires elevated permissions */ - CopyExecutable createCopyExecutable(String src, String dst) throws CommandNotFoundException; + CopyExecutable createCopyExecutable(String src, String dst) throws CommandNotFoundException, + NoSuchFileOrDirectory, InsufficientPermissionsException; /** * Method that creates an executable for create a new directory. @@ -84,9 +98,12 @@ public interface ExecutableCreator { * @return CreateDirExecutable A {@link CreateDirExecutable} executable implementation * reference * @throws CommandNotFoundException If the executable can't be created + * @throws NoSuchFileOrDirectory If the file or directory was not found + * @throws InsufficientPermissionsException If an operation requires elevated permissions */ CreateDirExecutable createCreateDirectoryExecutable(String dir) - throws CommandNotFoundException; + throws CommandNotFoundException, + NoSuchFileOrDirectory, InsufficientPermissionsException; /** * Method that creates an executable for create a new file. @@ -95,8 +112,11 @@ public interface ExecutableCreator { * @return CreateFileExecutable A {@link CreateFileExecutable} executable * implementation reference * @throws CommandNotFoundException If the executable can't be created + * @throws NoSuchFileOrDirectory If the file or directory was not found + * @throws InsufficientPermissionsException If an operation requires elevated permissions */ - CreateFileExecutable createCreateFileExecutable(String file) throws CommandNotFoundException; + CreateFileExecutable createCreateFileExecutable(String file) throws CommandNotFoundException, + NoSuchFileOrDirectory, InsufficientPermissionsException; /** * Method that creates an executable for retrieve the current directory. @@ -104,8 +124,11 @@ public interface ExecutableCreator { * @return CurrentDirExecutable A {@link CurrentDirExecutable} executable * implementation reference * @throws CommandNotFoundException If the executable can't be created + * @throws NoSuchFileOrDirectory If the file or directory was not found + * @throws InsufficientPermissionsException If an operation requires elevated permissions */ - CurrentDirExecutable createCurrentDirExecutable() throws CommandNotFoundException; + CurrentDirExecutable createCurrentDirExecutable() throws CommandNotFoundException, + NoSuchFileOrDirectory, InsufficientPermissionsException; /** * Method that creates an executable for delete a directory. @@ -114,8 +137,11 @@ public interface ExecutableCreator { * @return DeleteDirExecutable A {@link DeleteDirExecutable} executable implementation * reference * @throws CommandNotFoundException If the executable can't be created + * @throws NoSuchFileOrDirectory If the file or directory was not found + * @throws InsufficientPermissionsException If an operation requires elevated permissions */ - DeleteDirExecutable createDeleteDirExecutable(String dir) throws CommandNotFoundException; + DeleteDirExecutable createDeleteDirExecutable(String dir) throws CommandNotFoundException, + NoSuchFileOrDirectory, InsufficientPermissionsException; /** * Method that creates an executable for delete a file. @@ -124,8 +150,11 @@ public interface ExecutableCreator { * @return DeleteFileExecutable A {@link DeleteFileExecutable} executable * implementation reference * @throws CommandNotFoundException If the executable can't be created + * @throws NoSuchFileOrDirectory If the file or directory was not found + * @throws InsufficientPermissionsException If an operation requires elevated permissions */ - DeleteFileExecutable createDeleteFileExecutable(String file) throws CommandNotFoundException; + DeleteFileExecutable createDeleteFileExecutable(String file) throws CommandNotFoundException, + NoSuchFileOrDirectory, InsufficientPermissionsException; /** * Method that creates an executable for retrieve the disk usage. @@ -134,8 +163,11 @@ public interface ExecutableCreator { * @return DiskUsageExecutable A {@link DiskUsageExecutable} executable implementation * reference * @throws CommandNotFoundException If the executable can't be created + * @throws NoSuchFileOrDirectory If the file or directory was not found + * @throws InsufficientPermissionsException If an operation requires elevated permissions */ - DiskUsageExecutable createDiskUsageExecutable() throws CommandNotFoundException; + DiskUsageExecutable createDiskUsageExecutable() throws CommandNotFoundException, + NoSuchFileOrDirectory, InsufficientPermissionsException; /** * Method that creates an executable for retrieve the disk usage. @@ -145,8 +177,11 @@ public interface ExecutableCreator { * @return DiskUsageExecutable A {@link DiskUsageExecutable} executable implementation * reference * @throws CommandNotFoundException If the executable can't be created + * @throws NoSuchFileOrDirectory If the file or directory was not found + * @throws InsufficientPermissionsException If an operation requires elevated permissions */ - DiskUsageExecutable createDiskUsageExecutable(String dir) throws CommandNotFoundException; + DiskUsageExecutable createDiskUsageExecutable(String dir) throws CommandNotFoundException, + NoSuchFileOrDirectory, InsufficientPermissionsException; /** * Method that creates an executable for expanding environment variables. @@ -155,8 +190,11 @@ public interface ExecutableCreator { * @param msg The message to expand * @return EchoExecutable A {@link EchoExecutable} executable implementation reference * @throws CommandNotFoundException If the executable can't be created + * @throws NoSuchFileOrDirectory If the file or directory was not found + * @throws InsufficientPermissionsException If an operation requires elevated permissions */ - EchoExecutable createEchoExecutable(String msg) throws CommandNotFoundException; + EchoExecutable createEchoExecutable(String msg) throws CommandNotFoundException, + NoSuchFileOrDirectory, InsufficientPermissionsException; /** * Method that execute a command @@ -165,9 +203,12 @@ public interface ExecutableCreator { * @param asyncResultListener The listener where to return partial results * @return ExecExecutable A {@link ExecExecutable} executable implementation reference * @throws CommandNotFoundException If the executable can't be created + * @throws NoSuchFileOrDirectory If the file or directory was not found + * @throws InsufficientPermissionsException If an operation requires elevated permissions */ ExecExecutable createExecExecutable( - String cmd, AsyncResultListener asyncResultListener) throws CommandNotFoundException; + String cmd, AsyncResultListener asyncResultListener) throws CommandNotFoundException, + NoSuchFileOrDirectory, InsufficientPermissionsException; /** * Method that creates an executable for make searches over the filesystem. @@ -177,10 +218,13 @@ public interface ExecutableCreator { * @param asyncResultListener The listener where to return partial results * @return FindExecutable A {@link FindExecutable} executable implementation reference * @throws CommandNotFoundException If the executable can't be created + * @throws NoSuchFileOrDirectory If the file or directory was not found + * @throws InsufficientPermissionsException If an operation requires elevated permissions */ FindExecutable createFindExecutable( String directory, Query query, AsyncResultListener asyncResultListener) - throws CommandNotFoundException; + throws CommandNotFoundException, + NoSuchFileOrDirectory, InsufficientPermissionsException; /** * Method that creates an executable for compute the disk usage of a folder. @@ -190,27 +234,36 @@ public interface ExecutableCreator { * @return FolderUsageExecutable A {@link FolderUsageExecutable} executable * implementation reference * @throws CommandNotFoundException If the executable can't be created + * @throws NoSuchFileOrDirectory If the file or directory was not found + * @throws InsufficientPermissionsException If an operation requires elevated permissions */ FolderUsageExecutable createFolderUsageExecutable( String directory, AsyncResultListener asyncResultListener) - throws CommandNotFoundException; + throws CommandNotFoundException, + NoSuchFileOrDirectory, InsufficientPermissionsException; /** * Method that creates an executable for retrieve the groups of the current user. * * @return GroupsExecutable A {@link GroupsExecutable} executable implementation reference * @throws CommandNotFoundException If the executable can't be created + * @throws NoSuchFileOrDirectory If the file or directory was not found + * @throws InsufficientPermissionsException If an operation requires elevated permissions */ GroupsExecutable createGroupsExecutable() - throws com.cyanogenmod.filemanager.console.CommandNotFoundException; + throws com.cyanogenmod.filemanager.console.CommandNotFoundException, + NoSuchFileOrDirectory, InsufficientPermissionsException; /** * Method that creates an executable for retrieve identity information of the current user. * * @return IdentityExecutable A {@link IdentityExecutable} executable implementation reference * @throws CommandNotFoundException If the executable can't be created + * @throws NoSuchFileOrDirectory If the file or directory was not found + * @throws InsufficientPermissionsException If an operation requires elevated permissions */ - IdentityExecutable createIdentityExecutable() throws CommandNotFoundException; + IdentityExecutable createIdentityExecutable() throws CommandNotFoundException, + NoSuchFileOrDirectory, InsufficientPermissionsException; /** * Method that creates a symlink of an other file system object. @@ -219,9 +272,12 @@ public interface ExecutableCreator { * @param link The absolute path to the link fso * @return LinkExecutable A {@link LinkExecutable} executable implementation reference * @throws CommandNotFoundException If the executable can't be created + * @throws NoSuchFileOrDirectory If the file or directory was not found + * @throws InsufficientPermissionsException If an operation requires elevated permissions */ LinkExecutable createLinkExecutable( - String src, String link) throws CommandNotFoundException; + String src, String link) throws CommandNotFoundException, + NoSuchFileOrDirectory, InsufficientPermissionsException; /** * Method that creates an executable for list files of a directory. @@ -229,10 +285,13 @@ public interface ExecutableCreator { * @param src The directory where to do the listing * @return ListExecutable A {@link ListExecutable} executable implementation reference * @throws CommandNotFoundException If the executable can't be created - * @see LIST_MODE + * @throws NoSuchFileOrDirectory If the file or directory was not found + * @throws InsufficientPermissionsException If an operation requires elevated permissions + * @see LIST_MODE#DIRECTORY */ ListExecutable createListExecutable(String src) - throws CommandNotFoundException; + throws CommandNotFoundException, + NoSuchFileOrDirectory, InsufficientPermissionsException; /** * Method that creates an executable for retrieve information of a file @@ -241,10 +300,13 @@ public interface ExecutableCreator { * @param followSymlinks If follow the symlink * @return ListExecutable A {@link ListExecutable} executable implementation reference * @throws CommandNotFoundException If the executable can't be created - * @see LIST_MODE + * @throws NoSuchFileOrDirectory If the file or directory was not found + * @throws InsufficientPermissionsException If an operation requires elevated permissions + * @see LIST_MODE#FILEINFO */ ListExecutable createFileInfoExecutable(String src, boolean followSymlinks) - throws CommandNotFoundException; + throws CommandNotFoundException, + NoSuchFileOrDirectory, InsufficientPermissionsException; /** * Method that creates an executable for retrieve identity information of the current user. @@ -253,9 +315,12 @@ public interface ExecutableCreator { * @param rw Indicates if the operation mount the device as read-write * @return MountExecutable A {@link MountExecutable} executable implementation reference * @throws CommandNotFoundException If the executable can't be created + * @throws NoSuchFileOrDirectory If the file or directory was not found + * @throws InsufficientPermissionsException If an operation requires elevated permissions */ MountExecutable createMountExecutable( - MountPoint mp, boolean rw) throws CommandNotFoundException; + MountPoint mp, boolean rw) throws CommandNotFoundException, + NoSuchFileOrDirectory, InsufficientPermissionsException; /** * Method that creates an executable for retrieve identity information of the current user. @@ -263,8 +328,11 @@ public interface ExecutableCreator { * @return MountPointInfoExecutable A {@link MountPointInfoExecutable} executable * implementation reference * @throws CommandNotFoundException If the executable can't be created + * @throws NoSuchFileOrDirectory If the file or directory was not found + * @throws InsufficientPermissionsException If an operation requires elevated permissions */ - MountPointInfoExecutable createMountPointInfoExecutable() throws CommandNotFoundException; + MountPointInfoExecutable createMountPointInfoExecutable() throws CommandNotFoundException, + NoSuchFileOrDirectory, InsufficientPermissionsException; /** * Method that creates an executable for move a file system object to @@ -274,8 +342,11 @@ public interface ExecutableCreator { * @param dst The absolute path to the destination file system object * @return MoveExecutable A {@link MoveExecutable} executable implementation reference * @throws CommandNotFoundException If the executable can't be created + * @throws NoSuchFileOrDirectory If the file or directory was not found + * @throws InsufficientPermissionsException If an operation requires elevated permissions */ - MoveExecutable createMoveExecutable(String src, String dst) throws CommandNotFoundException; + MoveExecutable createMoveExecutable(String src, String dst) throws CommandNotFoundException, + NoSuchFileOrDirectory, InsufficientPermissionsException; /** * Method that creates an executable for retrieve the parent directory @@ -285,8 +356,11 @@ public interface ExecutableCreator { * @return ParentDirExecutable A {@link ParentDirExecutable} executable implementation * reference * @throws CommandNotFoundException If the executable can't be created + * @throws NoSuchFileOrDirectory If the file or directory was not found + * @throws InsufficientPermissionsException If an operation requires elevated permissions */ - ParentDirExecutable createParentDirExecutable(String fso) throws CommandNotFoundException; + ParentDirExecutable createParentDirExecutable(String fso) throws CommandNotFoundException, + NoSuchFileOrDirectory, InsufficientPermissionsException; /** * Method that creates an executable for retrieve operating system process identifier of a @@ -295,8 +369,11 @@ public interface ExecutableCreator { * @return ProcessIdExecutable A {@link ProcessIdExecutable} executable implementation * reference * @throws CommandNotFoundException If the executable can't be created + * @throws NoSuchFileOrDirectory If the file or directory was not found + * @throws InsufficientPermissionsException If an operation requires elevated permissions */ - ProcessIdExecutable createShellProcessIdExecutable() throws CommandNotFoundException; + ProcessIdExecutable createShellProcessIdExecutable() throws CommandNotFoundException, + NoSuchFileOrDirectory, InsufficientPermissionsException; /** * Method that creates an executable for retrieve operating system process identifier of a @@ -307,9 +384,12 @@ public interface ExecutableCreator { * @return ProcessIdExecutable A {@link ProcessIdExecutable} executable implementation * reference * @throws CommandNotFoundException If the executable can't be created + * @throws NoSuchFileOrDirectory If the file or directory was not found + * @throws InsufficientPermissionsException If an operation requires elevated permissions */ ProcessIdExecutable createProcessIdExecutable( - int pid, String processName) throws CommandNotFoundException; + int pid, String processName) throws CommandNotFoundException, + NoSuchFileOrDirectory, InsufficientPermissionsException; /** * Method that creates an executable for quickly retrieve the name of directories @@ -319,9 +399,12 @@ public interface ExecutableCreator { * @return ProcessIdExecutable A {@link ProcessIdExecutable} executable implementation * reference * @throws CommandNotFoundException If the executable can't be created + * @throws NoSuchFileOrDirectory If the file or directory was not found + * @throws InsufficientPermissionsException If an operation requires elevated permissions */ QuickFolderSearchExecutable createQuickFolderSearchExecutable( - String regexp) throws CommandNotFoundException; + String regexp) throws CommandNotFoundException, + NoSuchFileOrDirectory, InsufficientPermissionsException; /** * Method that creates an executable for read data from disk. @@ -330,10 +413,13 @@ public interface ExecutableCreator { * @param asyncResultListener The listener where to return partial results * @return ReadExecutable A {@link ReadExecutable} executable implementation reference * @throws CommandNotFoundException If the executable can't be created + * @throws NoSuchFileOrDirectory If the file or directory was not found + * @throws InsufficientPermissionsException If an operation requires elevated permissions */ ReadExecutable createReadExecutable( String file, AsyncResultListener asyncResultListener) - throws CommandNotFoundException; + throws CommandNotFoundException, + NoSuchFileOrDirectory, InsufficientPermissionsException; /** * Method that creates an executable for resolves the real @@ -343,8 +429,11 @@ public interface ExecutableCreator { * @return ResolveLinkExecutable A {@link ResolveLinkExecutable} executable * implementation reference * @throws CommandNotFoundException If the executable can't be created + * @throws NoSuchFileOrDirectory If the file or directory was not found + * @throws InsufficientPermissionsException If an operation requires elevated permissions */ - ResolveLinkExecutable createResolveLinkExecutable(String fso) throws CommandNotFoundException; + ResolveLinkExecutable createResolveLinkExecutable(String fso) throws CommandNotFoundException, + NoSuchFileOrDirectory, InsufficientPermissionsException; /** * Method that creates an executable for send a signal to the current process. @@ -353,9 +442,12 @@ public interface ExecutableCreator { * @param signal The signal to send * @return SendSignalExecutable A {@link SendSignalExecutable} executable implementation reference * @throws CommandNotFoundException If the executable can't be created + * @throws NoSuchFileOrDirectory If the file or directory was not found + * @throws InsufficientPermissionsException If an operation requires elevated permissions */ SendSignalExecutable createSendSignalExecutable( - int process, SIGNAL signal) throws CommandNotFoundException; + int process, SIGNAL signal) throws CommandNotFoundException, + NoSuchFileOrDirectory, InsufficientPermissionsException; /** * Method that creates an executable for send a kill signal to the current process. @@ -364,9 +456,12 @@ public interface ExecutableCreator { * @param signal The signal to send * @return SendSignalExecutable A {@link SendSignalExecutable} executable implementation reference * @throws CommandNotFoundException If the executable can't be created + * @throws NoSuchFileOrDirectory If the file or directory was not found + * @throws InsufficientPermissionsException If an operation requires elevated permissions */ SendSignalExecutable createKillExecutable( - int process) throws CommandNotFoundException; + int process) throws CommandNotFoundException, + NoSuchFileOrDirectory, InsufficientPermissionsException; /** * Method that creates an executable for write data to disk. @@ -375,10 +470,13 @@ public interface ExecutableCreator { * @param asyncResultListener The listener where to return partial results * @return WriteExecutable A {@link WriteExecutable} executable implementation reference * @throws CommandNotFoundException If the executable can't be created + * @throws NoSuchFileOrDirectory If the file or directory was not found + * @throws InsufficientPermissionsException If an operation requires elevated permissions */ WriteExecutable createWriteExecutable( String file, AsyncResultListener asyncResultListener) - throws CommandNotFoundException; + throws CommandNotFoundException, + NoSuchFileOrDirectory, InsufficientPermissionsException; /** * Method that creates an executable for archive-compress file system objects. @@ -389,11 +487,14 @@ public interface ExecutableCreator { * @param asyncResultListener The listener where to return partial results * @return CompressExecutable A {@link CompressExecutable} executable implementation reference * @throws CommandNotFoundException If the executable can't be created + * @throws NoSuchFileOrDirectory If the file or directory was not found + * @throws InsufficientPermissionsException If an operation requires elevated permissions */ CompressExecutable createCompressExecutable( CompressionMode mode, String dst, String[] src, AsyncResultListener asyncResultListener) - throws CommandNotFoundException; + throws CommandNotFoundException, + NoSuchFileOrDirectory, InsufficientPermissionsException; /** * Method that creates an executable for compress a file system object. @@ -403,10 +504,13 @@ public interface ExecutableCreator { * @param asyncResultListener The listener where to return partial results * @return CompressExecutable A {@link CompressExecutable} executable implementation reference * @throws CommandNotFoundException If the executable can't be created + * @throws NoSuchFileOrDirectory If the file or directory was not found + * @throws InsufficientPermissionsException If an operation requires elevated permissions */ CompressExecutable createCompressExecutable( CompressionMode mode, String src, AsyncResultListener asyncResultListener) - throws CommandNotFoundException; + throws CommandNotFoundException, + NoSuchFileOrDirectory, InsufficientPermissionsException; /** * Method that creates an executable for uncompress file system objects. @@ -417,9 +521,12 @@ public interface ExecutableCreator { * @param asyncResultListener The listener where to return partial results * @return UncompressExecutable A {@link UncompressExecutable} executable implementation reference * @throws CommandNotFoundException If the executable can't be created + * @throws NoSuchFileOrDirectory If the file or directory was not found + * @throws InsufficientPermissionsException If an operation requires elevated permissions */ UncompressExecutable createUncompressExecutable( String src, String dst, AsyncResultListener asyncResultListener) - throws CommandNotFoundException; + throws CommandNotFoundException, + NoSuchFileOrDirectory, InsufficientPermissionsException; } diff --git a/src/com/cyanogenmod/filemanager/commands/java/DiskUsageCommand.java b/src/com/cyanogenmod/filemanager/commands/java/DiskUsageCommand.java index 133de0d4..b0bd1243 100644 --- a/src/com/cyanogenmod/filemanager/commands/java/DiskUsageCommand.java +++ b/src/com/cyanogenmod/filemanager/commands/java/DiskUsageCommand.java @@ -78,13 +78,6 @@ public class DiskUsageCommand extends Program implements DiskUsageExecutable { public void execute() throws InsufficientPermissionsException, NoSuchFileOrDirectory, ExecutionException { - //Retrieve the mount points - MountPointInfoCommand cmd = new MountPointInfoCommand(this.mMountsFile); - cmd.setBufferSize(getBufferSize()); - cmd.setTrace(isTrace()); - cmd.execute(); - List<MountPoint> mp = cmd.getResult(); - if (isTrace()) { Log.v(TAG, String.format("Getting usage for: %s", //$NON-NLS-1$ @@ -92,19 +85,20 @@ public class DiskUsageCommand extends Program implements DiskUsageExecutable { } if (this.mSrc == null) { + // Retrieve the mount points + MountPointInfoCommand cmd = new MountPointInfoCommand(this.mMountsFile); + cmd.setBufferSize(getBufferSize()); + cmd.setTrace(isTrace()); + cmd.execute(); + List<MountPoint> mp = cmd.getResult(); + + // Get every disk usage for (int i = 0; i < mp.size(); i++) { File root = new File(mp.get(i).getMountPoint()); this.mDisksUsage.add(createDiskUsuage(root)); } } else { - // Search the root of file - for (int i = 0; i < mp.size(); i++) { - File root = new File(mp.get(i).getMountPoint()); - if (this.mSrc.startsWith(root.getAbsolutePath())) { - this.mDisksUsage.add(createDiskUsuage(root)); - break; - } - } + this.mDisksUsage.add(createDiskUsuage(new File(this.mSrc))); } if (isTrace()) { @@ -118,12 +112,12 @@ public class DiskUsageCommand extends Program implements DiskUsageExecutable { * @param root The root file * @return DiskUsage The disk usage */ - private DiskUsage createDiskUsuage(File root) { + private DiskUsage createDiskUsuage(File file) { DiskUsage du = new DiskUsage( - root.getAbsolutePath(), - root.getTotalSpace(), - root.getTotalSpace() - root.getFreeSpace(), - root.getFreeSpace()); + file.getAbsolutePath(), + file.getTotalSpace(), + file.getTotalSpace() - file.getFreeSpace(), + file.getFreeSpace()); if (isTrace()) { Log.v(TAG, du.toString()); } diff --git a/src/com/cyanogenmod/filemanager/commands/java/FindCommand.java b/src/com/cyanogenmod/filemanager/commands/java/FindCommand.java index 17e011e8..793dc616 100644 --- a/src/com/cyanogenmod/filemanager/commands/java/FindCommand.java +++ b/src/com/cyanogenmod/filemanager/commands/java/FindCommand.java @@ -16,7 +16,6 @@ package com.cyanogenmod.filemanager.commands.java; -import android.content.Context; import android.util.Log; import com.cyanogenmod.filemanager.commands.AsyncResultListener; @@ -39,7 +38,6 @@ public class FindCommand extends Program implements FindExecutable { private static final String TAG = "FindCommand"; //$NON-NLS-1$ - private final Context mCtx; private final String mDirectory; private final String[] mQueryRegExp; private final AsyncResultListener mAsyncResultListener; @@ -51,15 +49,12 @@ public class FindCommand extends Program implements FindExecutable { /** * Constructor of <code>FindCommand</code>. * - * @param ctx The current context * @param directory The absolute directory where start the search * @param query The terms to be searched * @param asyncResultListener The partial result listener */ - public FindCommand( - Context ctx, String directory, Query query, AsyncResultListener asyncResultListener) { + public FindCommand(String directory, Query query, AsyncResultListener asyncResultListener) { super(); - this.mCtx = ctx; this.mDirectory = directory; this.mQueryRegExp = createRegexp(directory, query); this.mAsyncResultListener = asyncResultListener; @@ -145,7 +140,7 @@ public class FindCommand extends Program implements FindExecutable { for (int j = 0; j < ccc; j++) { if (files[i].getName().matches(this.mQueryRegExp[j])) { FileSystemObject fso = - FileHelper.createFileSystemObject(this.mCtx, files[i]); + FileHelper.createFileSystemObject(files[i]); if (fso != null) { if (isTrace()) { Log.v(TAG, String.valueOf(fso)); diff --git a/src/com/cyanogenmod/filemanager/commands/java/JavaExecutableCreator.java b/src/com/cyanogenmod/filemanager/commands/java/JavaExecutableCreator.java index b43fe7a1..875544ef 100644 --- a/src/com/cyanogenmod/filemanager/commands/java/JavaExecutableCreator.java +++ b/src/com/cyanogenmod/filemanager/commands/java/JavaExecutableCreator.java @@ -200,7 +200,7 @@ public class JavaExecutableCreator implements ExecutableCreator { public FindExecutable createFindExecutable( String directory, Query query, AsyncResultListener asyncResultListener) throws CommandNotFoundException { - return new FindCommand(this.mConsole.getCtx(), directory, query, asyncResultListener); + return new FindCommand(directory, query, asyncResultListener); } /** @@ -245,7 +245,7 @@ public class JavaExecutableCreator implements ExecutableCreator { @Override public ListExecutable createListExecutable(String src) throws CommandNotFoundException { - return new ListCommand(this.mConsole.getCtx(), src, LIST_MODE.DIRECTORY); + return new ListCommand(src, LIST_MODE.DIRECTORY); } /** @@ -254,7 +254,7 @@ public class JavaExecutableCreator implements ExecutableCreator { @Override public ListExecutable createFileInfoExecutable(String src, boolean followSymlinks) throws CommandNotFoundException { - return new ListCommand(this.mConsole.getCtx(), src, LIST_MODE.FILEINFO); + return new ListCommand(src, LIST_MODE.FILEINFO); } /** @@ -336,7 +336,7 @@ public class JavaExecutableCreator implements ExecutableCreator { @Override public ResolveLinkExecutable createResolveLinkExecutable(String fso) throws CommandNotFoundException { - return new ResolveLinkCommand(this.mConsole.getCtx(), fso); + return new ResolveLinkCommand(fso); } /** diff --git a/src/com/cyanogenmod/filemanager/commands/java/ListCommand.java b/src/com/cyanogenmod/filemanager/commands/java/ListCommand.java index 8f1a766e..45e35081 100644 --- a/src/com/cyanogenmod/filemanager/commands/java/ListCommand.java +++ b/src/com/cyanogenmod/filemanager/commands/java/ListCommand.java @@ -16,7 +16,6 @@ package com.cyanogenmod.filemanager.commands.java; -import android.content.Context; import android.util.Log; import com.cyanogenmod.filemanager.commands.ListExecutable; @@ -39,7 +38,6 @@ public class ListCommand extends Program implements ListExecutable { private static final String TAG = "ListCommand"; //$NON-NLS-1$ - private final Context mCtx; private final String mSrc; private final LIST_MODE mMode; private final List<FileSystemObject> mFiles; @@ -47,13 +45,11 @@ public class ListCommand extends Program implements ListExecutable { /** * Constructor of <code>ListCommand</code>. List mode. * - * @param ctx The current context * @param src The file system object to be listed * @param mode The mode of listing */ - public ListCommand(Context ctx, String src, LIST_MODE mode) { + public ListCommand(String src, LIST_MODE mode) { super(); - this.mCtx = ctx; this.mSrc = src; this.mMode = mode; this.mFiles = new ArrayList<FileSystemObject>(); @@ -100,7 +96,7 @@ public class ListCommand extends Program implements ListExecutable { File[] files = f.listFiles(); if (files != null) { for (int i = 0; i < files.length; i++) { - FileSystemObject fso = FileHelper.createFileSystemObject(this.mCtx, files[i]); + FileSystemObject fso = FileHelper.createFileSystemObject(files[i]); if (fso != null) { if (isTrace()) { Log.v(TAG, String.valueOf(fso)); @@ -119,7 +115,7 @@ public class ListCommand extends Program implements ListExecutable { } else { // Build the parent information - FileSystemObject fso = FileHelper.createFileSystemObject(this.mCtx, f); + FileSystemObject fso = FileHelper.createFileSystemObject(f); if (fso != null) { if (isTrace()) { Log.v(TAG, String.valueOf(fso)); diff --git a/src/com/cyanogenmod/filemanager/commands/java/ResolveLinkCommand.java b/src/com/cyanogenmod/filemanager/commands/java/ResolveLinkCommand.java index fe94243e..1cbc1330 100644 --- a/src/com/cyanogenmod/filemanager/commands/java/ResolveLinkCommand.java +++ b/src/com/cyanogenmod/filemanager/commands/java/ResolveLinkCommand.java @@ -16,7 +16,6 @@ package com.cyanogenmod.filemanager.commands.java; -import android.content.Context; import android.util.Log; import com.cyanogenmod.filemanager.commands.ListExecutable.LIST_MODE; @@ -37,19 +36,16 @@ public class ResolveLinkCommand extends Program implements ResolveLinkExecutable private static final String TAG = "ResolveLinkCommand"; //$NON-NLS-1$ - private final Context mCtx; private final String mSrc; private FileSystemObject mFso; /** * Constructor of <code>ResolveLinkCommand</code>. * - * @param ctx The current context * @param src The file system object to read */ - public ResolveLinkCommand(Context ctx, String src) { + public ResolveLinkCommand(String src) { super(); - this.mCtx = ctx; this.mSrc = src; } @@ -82,7 +78,7 @@ public class ResolveLinkCommand extends Program implements ResolveLinkExecutable } try { String absPath = f.getCanonicalPath(); - ListCommand cmd = new ListCommand(this.mCtx, absPath, LIST_MODE.FILEINFO); + ListCommand cmd = new ListCommand(absPath, LIST_MODE.FILEINFO); cmd.execute(); this.mFso = cmd.getSingleResult(); } catch (Exception e) { diff --git a/src/com/cyanogenmod/filemanager/commands/shell/AsyncResultProgram.java b/src/com/cyanogenmod/filemanager/commands/shell/AsyncResultProgram.java index 1b1f07d7..64dc0e53 100644 --- a/src/com/cyanogenmod/filemanager/commands/shell/AsyncResultProgram.java +++ b/src/com/cyanogenmod/filemanager/commands/shell/AsyncResultProgram.java @@ -176,6 +176,7 @@ public abstract class AsyncResultProgram public final void onRequestParsePartialResult(String partialIn) { synchronized (this.mSync) { String data = partialIn; + String rest = ""; //$NON-NLS-1$ if (parseOnlyCompleteLines()) { int pos = partialIn.lastIndexOf(FileHelper.NEWLINE); if (pos == -1) { @@ -186,11 +187,12 @@ public abstract class AsyncResultProgram //Retrieve the data data = this.mTempBuffer.append(partialIn.substring(0, pos + 1)).toString(); + rest = partialIn.substring(pos + 1); } this.mPartialDataType.add(STDIN); this.mPartialData.add(data); - this.mTempBuffer = new StringBuffer(); + this.mTempBuffer = new StringBuffer(rest); this.mSync.notify(); } } @@ -204,6 +206,7 @@ public abstract class AsyncResultProgram public final void parsePartialErrResult(String partialErr) { synchronized (this.mSync) { String data = partialErr; + String rest = ""; //$NON-NLS-1$ if (parseOnlyCompleteLines()) { int pos = partialErr.lastIndexOf(FileHelper.NEWLINE); if (pos == -1) { @@ -214,11 +217,12 @@ public abstract class AsyncResultProgram //Retrieve the data data = this.mTempBuffer.append(partialErr.substring(0, pos + 1)).toString(); + rest = partialErr.substring(pos + 1); } this.mPartialDataType.add(STDERR); this.mPartialData.add(data); - this.mTempBuffer = new StringBuffer(); + this.mTempBuffer = new StringBuffer(rest); this.mSync.notify(); } } diff --git a/src/com/cyanogenmod/filemanager/commands/shell/FindCommand.java b/src/com/cyanogenmod/filemanager/commands/shell/FindCommand.java index 033d5e02..4857a3e3 100644 --- a/src/com/cyanogenmod/filemanager/commands/shell/FindCommand.java +++ b/src/com/cyanogenmod/filemanager/commands/shell/FindCommand.java @@ -43,27 +43,16 @@ import java.util.List; */ public class FindCommand extends AsyncResultProgram implements FindExecutable { - //IMP!! This command must returns in the same command a line with the - //full path of the file, and a list style line of the find file in - //the next line - //xe: - // - // /mnt/emmc/test79.txt - // ----rwxr-x system sdcard_rw 0 2012-05-15 12:15 test79.txt - // - private static final String TAG = "FindCommand"; //$NON-NLS-1$ private static final String ID = "find"; //$NON-NLS-1$ - private final String mDirectory; - private final List<FileSystemObject> mFiles; - private String mPartial; + private final File mDirectory; /** * Constructor of <code>FindCommand</code>. * - * @param directory The absolute directory where start the search + * @param directory The absolute path of the directory where do the search * @param query The terms to be searched * @param asyncResultListener The partial result listener * @throws InvalidCommandDefinitionException If the command has an invalid definition @@ -71,10 +60,8 @@ public class FindCommand extends AsyncResultProgram implements FindExecutable { public FindCommand( String directory, Query query, AsyncResultListener asyncResultListener) throws InvalidCommandDefinitionException { - super(ID, asyncResultListener, createArgs(directory, query)); - this.mFiles = new ArrayList<FileSystemObject>(); - this.mPartial = ""; //$NON-NLS-1$ - this.mDirectory = directory; + super(ID, asyncResultListener, createArgs(FileHelper.addTrailingSlash(directory), query)); + this.mDirectory = new File(directory); } /** @@ -82,8 +69,7 @@ public class FindCommand extends AsyncResultProgram implements FindExecutable { */ @Override public void onStartParsePartialResult() { - this.mFiles.clear(); - this.mPartial = ""; //$NON-NLS-1$ + //$NON-NLS-1$ } /** @@ -91,7 +77,7 @@ public class FindCommand extends AsyncResultProgram implements FindExecutable { */ @Override public void onEndParsePartialResult(boolean cancelled) { - this.mPartial = ""; //$NON-NLS-1$ + //$NON-NLS-1$ } /** @@ -105,70 +91,34 @@ public class FindCommand extends AsyncResultProgram implements FindExecutable { BufferedReader br = null; try { //Read the partial + previous partial and clean partial - br = new BufferedReader(new StringReader(this.mPartial + partialIn)); - this.mPartial = ""; //$NON-NLS-1$ + br = new BufferedReader(new StringReader(partialIn)); //Add all lines to an array - List<String> lines = new ArrayList<String>(); String line = null; while ((line = br.readLine()) != null) { + //Checks that there is some text in the line. Otherwise ignore it if (line.trim().length() == 0) { - continue; + break; } - lines.add(line); - } - //2 lines per file system object translation - while (lines.size() >= 2) { + // Add to the list try { - //Data is synchronized?? Have two valid lines? - if (!lines.get(0).startsWith(File.separator)) { - //Discard line. The data is no synchronized (some wrong in the output) - lines.remove(0); - continue; - } - if (lines.get(1).startsWith(File.separator)) { - //Discard line. The data is no synchronized (some wrong in the output) - lines.remove(1); - continue; - } + FileSystemObject fso = ParseHelper.parseStatOutput(line); - //Extract the parent directory - String parentDir = new File(lines.get(0)).getParent(); - if (parentDir == null || parentDir.trim().length() == 0) { - parentDir = FileHelper.ROOT_DIRECTORY; + // Search directory is not part of the search + if (fso.getFullPath().compareTo(this.mDirectory.getAbsolutePath()) != 0) { + partialFiles.add(fso); } - //Retrieve the file system object and calculate relevance - FileSystemObject fso = ParseHelper.toFileSystemObject(parentDir, lines.get(1)); - if (fso.getName() != null && fso.getName().length() > 0) { - // Don't return the directory of the search. Only files under this - // directory - if (this.mDirectory.compareTo(fso.getFullPath()) != 0) { - String name = new File(lines.get(0)).getName(); - // In some situations, xe when the name has a -> the name is - // incorrect resolved, but src name should by fine in this case - fso.setName(name); - // The symlink is not resolved here - - this.mFiles.add(fso); - partialFiles.add(fso); - } + } catch (Exception e) { + // Log the parsing error + if (isTrace()) { + Log.w(TAG, + String.format( + "Failed to parse output: %s", //$NON-NLS-1$ + String.valueOf(line))); } - - } catch (Exception ex) { - Log.w(TAG, "Partial result fails", ex); //$NON-NLS-1$ } - - //Remove the pair of lines - lines.remove(0); - lines.remove(0); - } - - //Saves the lines for the next partial read (At this point only one line - //can exists in the buffer. The rest was processed or discarded) - if (lines.size() > 0) { - this.mPartial = lines.get(0).concat(FileHelper.NEWLINE); } //If a listener is defined, then send the partial result diff --git a/src/com/cyanogenmod/filemanager/commands/shell/FolderUsageCommand.java b/src/com/cyanogenmod/filemanager/commands/shell/FolderUsageCommand.java index 807e883c..b969018c 100644 --- a/src/com/cyanogenmod/filemanager/commands/shell/FolderUsageCommand.java +++ b/src/com/cyanogenmod/filemanager/commands/shell/FolderUsageCommand.java @@ -24,14 +24,16 @@ import com.cyanogenmod.filemanager.commands.SIGNAL; import com.cyanogenmod.filemanager.console.CommandNotFoundException; import com.cyanogenmod.filemanager.console.ExecutionException; import com.cyanogenmod.filemanager.console.InsufficientPermissionsException; +import com.cyanogenmod.filemanager.model.BlockDevice; +import com.cyanogenmod.filemanager.model.CharacterDevice; import com.cyanogenmod.filemanager.model.Directory; -import com.cyanogenmod.filemanager.model.FileSystemObject; +import com.cyanogenmod.filemanager.model.DomainSocket; import com.cyanogenmod.filemanager.model.FolderUsage; +import com.cyanogenmod.filemanager.model.NamedPipe; import com.cyanogenmod.filemanager.model.Symlink; import com.cyanogenmod.filemanager.util.FileHelper; import com.cyanogenmod.filemanager.util.MimeTypeHelper; import com.cyanogenmod.filemanager.util.MimeTypeHelper.MimeTypeCategory; -import com.cyanogenmod.filemanager.util.ParseHelper; import java.io.BufferedReader; import java.io.StringReader; @@ -51,7 +53,6 @@ public class FolderUsageCommand extends AsyncResultProgram implements FolderUsag private final String mDirectory; private FolderUsage mFolderUsage; - private String mPartial; /** * Constructor of <code>FolderUsageCommand</code>. @@ -65,7 +66,6 @@ public class FolderUsageCommand extends AsyncResultProgram implements FolderUsag throws InvalidCommandDefinitionException { super(ID, asyncResultListener, new String[]{directory}); this.mFolderUsage = new FolderUsage(directory); - this.mPartial = ""; //$NON-NLS-1$ this.mDirectory = directory; } @@ -75,7 +75,6 @@ public class FolderUsageCommand extends AsyncResultProgram implements FolderUsag @Override public void onStartParsePartialResult() { this.mFolderUsage = new FolderUsage(this.mDirectory); - this.mPartial = ""; //$NON-NLS-1$ } /** @@ -83,7 +82,7 @@ public class FolderUsageCommand extends AsyncResultProgram implements FolderUsag */ @Override public void onEndParsePartialResult(boolean cancelled) { - this.mPartial = ""; //$NON-NLS-1$ + //$NON-NLS-1$ } /** @@ -95,76 +94,100 @@ public class FolderUsageCommand extends AsyncResultProgram implements FolderUsag // Check the in buffer to extract information BufferedReader br = null; try { - //Read the partial + previous partial and clean partial - br = new BufferedReader(new StringReader(this.mPartial + partialIn)); - this.mPartial = ""; //$NON-NLS-1$ + // Parse the line. We expect a ls -l output line + // -rw-r--r-- root root 7 2012-12-30 00:49 test.txt + // + // (1) permissions + // (2) owner + // (3) group + // (4) size + // (5) date + // (6) name + + //Partial contains full lines + br = new BufferedReader(new StringReader(partialIn)); //Add all lines to an array List<String> lines = new ArrayList<String>(); String line = null; while ((line = br.readLine()) != null) { - if (line.trim().length() == 0) { + // Discard empty, paths, and folder links + if (line.length() == 0 || + line.startsWith(FileHelper.ROOT_DIRECTORY) || + line.startsWith(FileHelper.CURRENT_DIRECTORY) || + line.startsWith(FileHelper.PARENT_DIRECTORY)) { continue; } lines.add(line); } - //2 lines per file system object translation - boolean newData = false; int c = 0; - while (lines.size() > 0) { - try { + try { + while (lines.size() > 0) { // Retrieve the info - String szLine = lines.get(0).trim(); - - // Parent folder is not necessary here. Only the information relative to - // type and size - FileSystemObject fso = - ParseHelper.toFileSystemObject( - FileHelper.ROOT_DIRECTORY, szLine, true); - - // Only regular files or directories. No compute Symlinks - if (fso instanceof Symlink) { - - // Directory - } else if (fso instanceof Directory) { - // Folder - this.mFolderUsage.addFolder(); - newData = true; - - // Regular File, Block device, ... - } else { - this.mFolderUsage.addFile(); - // Compute statistics and size - MimeTypeCategory category = - MimeTypeHelper.getCategory(null, fso); - this.mFolderUsage.addFileToCategory(category); - this.mFolderUsage.addSize(fso.getSize()); - newData = true; + String szLine = lines.remove(0).trim(); + try { + // Clean the line (we don't care about names, only need the extension) + // so remove spaces is safe here + while (szLine.indexOf(" ") != -1) { //$NON-NLS-1$ + szLine = szLine.replaceAll(" ", " "); //$NON-NLS-1$ //$NON-NLS-2$ + } + + char type = szLine.charAt(0); + if (type == Symlink.UNIX_ID || + type == BlockDevice.UNIX_ID || + type == CharacterDevice.UNIX_ID || + type == DomainSocket.UNIX_ID || + type == NamedPipe.UNIX_ID) { + // File + Category + this.mFolderUsage.addFile(); + if (type == Symlink.UNIX_ID) { + this.mFolderUsage.addFileToCategory(MimeTypeCategory.NONE); + } else { + this.mFolderUsage.addFileToCategory(MimeTypeCategory.SYSTEM); + } + + } else if (type == Directory.UNIX_ID) { + // Folder + this.mFolderUsage.addFolder(); + + } else { + // File + Category + Size + try { + // we need a valid line + String[] fields = szLine.split(" "); //$NON-NLS-1$ + if (fields.length < 7) { + continue; + } + + long size = Long.parseLong(fields[3]); + String name = fields[fields.length-1];// We only need the extension + String ext = FileHelper.getExtension(name); + MimeTypeCategory category = + MimeTypeHelper.getCategoryFromExt(null, ext); + this.mFolderUsage.addFile(); + this.mFolderUsage.addFileToCategory(category); + this.mFolderUsage.addSize(size); + } catch (Exception e) {/**NON BLOCK**/} + } + c++; + + } catch (Exception e) { + // Ignore. } // Partial notification if (c % 5 == 0) { //If a listener is defined, then send the partial result - if (getAsyncResultListener() != null && newData) { + if (getAsyncResultListener() != null) { getAsyncResultListener().onPartialResult(this.mFolderUsage); } } - - } catch (Exception ex) { /**NON BLOCK **/ } - - //Remove the the line - lines.remove(0); - } - - //Saves the lines for the next partial read (At this point only one line - //can exists in the buffer. The rest was processed or discarded) - if (lines.size() > 0) { - this.mPartial = lines.get(0).concat(FileHelper.NEWLINE); - } + } + } catch (Exception ex) { /**NON BLOCK **/ } //If a listener is defined, then send the partial result - if (getAsyncResultListener() != null && newData) { + if (getAsyncResultListener() != null) { getAsyncResultListener().onPartialResult(this.mFolderUsage); } diff --git a/src/com/cyanogenmod/filemanager/commands/shell/ListCommand.java b/src/com/cyanogenmod/filemanager/commands/shell/ListCommand.java index bb05da82..c6228d18 100644 --- a/src/com/cyanogenmod/filemanager/commands/shell/ListCommand.java +++ b/src/com/cyanogenmod/filemanager/commands/shell/ListCommand.java @@ -16,19 +16,15 @@ package com.cyanogenmod.filemanager.commands.shell; -import com.cyanogenmod.filemanager.FileManagerApplication; +import android.util.Log; + import com.cyanogenmod.filemanager.commands.ListExecutable; import com.cyanogenmod.filemanager.console.CommandNotFoundException; -import com.cyanogenmod.filemanager.console.ConsoleAllocException; import com.cyanogenmod.filemanager.console.ExecutionException; import com.cyanogenmod.filemanager.console.InsufficientPermissionsException; -import com.cyanogenmod.filemanager.console.NoSuchFileOrDirectory; -import com.cyanogenmod.filemanager.console.OperationTimeoutException; import com.cyanogenmod.filemanager.console.shell.ShellConsole; import com.cyanogenmod.filemanager.model.FileSystemObject; import com.cyanogenmod.filemanager.model.ParentDirectory; -import com.cyanogenmod.filemanager.model.Symlink; -import com.cyanogenmod.filemanager.util.CommandHelper; import com.cyanogenmod.filemanager.util.FileHelper; import com.cyanogenmod.filemanager.util.ParseHelper; @@ -45,17 +41,15 @@ import java.util.List; /** * A class for list information about files and directories. * - * {@link "http://unixhelp.ed.ac.uk/CGI/man-cgi?ls"} + * {@link "http://unixhelp.ed.ac.uk/CGI/man-cgi?stat"} */ public class ListCommand extends SyncResultProgram implements ListExecutable { - private static final String ID_LS_DIRECTORY = "ls"; //$NON-NLS-1$ - private static final String ID_LS_INFO = "fileinfo"; //$NON-NLS-1$ + private static final String TAG = "ListCommand"; //$NON-NLS-1$ - private static final String SYMLINK_REF = ">SIMLINKS>"; //$NON-NLS-1$ - private static final String SYMLINK_DATA_REF = ">SIMLINKS_DATA>"; //$NON-NLS-1$ + private static final String ID_LS = "ls"; //$NON-NLS-1$ + private static final String ID_FILEINFO = "fileinfo"; //$NON-NLS-1$ - private final String mSrc; private final LIST_MODE mMode; private final List<FileSystemObject> mFiles; private String mParentDir; @@ -67,37 +61,22 @@ public class ListCommand extends SyncResultProgram implements ListExecutable { * @param console The console in which retrieve the parent directory information. * <code>null</code> to attach to the default console * @throws InvalidCommandDefinitionException If the command has an invalid definition - * @throws FileNotFoundException If the initial directory not exists - * @throws NoSuchFileOrDirectory If the file or directory was not found - * @throws IOException If initial directory couldn't be checked - * @throws ConsoleAllocException If the console can't be allocated - * @throws InsufficientPermissionsException If an operation requires elevated permissions - * @throws CommandNotFoundException If the command was not found - * @throws OperationTimeoutException If the operation exceeded the maximum time of wait - * @throws ExecutionException If the operation returns a invalid exit code */ public ListCommand(String src, ShellConsole console) - throws InvalidCommandDefinitionException, FileNotFoundException, - NoSuchFileOrDirectory, IOException, ConsoleAllocException, - InsufficientPermissionsException, CommandNotFoundException, - OperationTimeoutException, ExecutionException { - //If the mode is listing directory, for avoid problems with symlink, - //always append a / to the end of the path (if not exists) - super(ID_LS_DIRECTORY, new String[]{ FileHelper.addTrailingSlash(src) }); + throws InvalidCommandDefinitionException { + // Always add backslash for list the files of the directory, instead of + // the directory. + super(ID_LS, new String[]{ FileHelper.addTrailingSlash(src) }); //Initialize files to something distinct of null this.mFiles = new ArrayList<FileSystemObject>(); this.mMode = LIST_MODE.DIRECTORY; - this.mSrc = src; //Retrieve parent directory information if (src.compareTo(FileHelper.ROOT_DIRECTORY) == 0) { this.mParentDir = null; } else { - this.mParentDir = - CommandHelper.getAbsolutePath( - FileManagerApplication. - getInstance().getApplicationContext(), src, console); + this.mParentDir = new File(src).getAbsolutePath(); } } @@ -110,22 +89,13 @@ public class ListCommand extends SyncResultProgram implements ListExecutable { * <code>null</code> to attach to the default console * @throws InvalidCommandDefinitionException If the command has an invalid definition * @throws FileNotFoundException If the initial directory not exists - * @throws NoSuchFileOrDirectory If the file or directory was not found * @throws IOException If initial directory couldn't be checked - * @throws ConsoleAllocException If the console can't be allocated - * @throws InsufficientPermissionsException If an operation requires elevated permissions - * @throws CommandNotFoundException If the command was not found - * @throws OperationTimeoutException If the operation exceeded the maximum time of wait - * @throws ExecutionException If the operation returns a invalid exit code */ public ListCommand(String src, boolean followSymlinks, ShellConsole console) - throws InvalidCommandDefinitionException, FileNotFoundException, - NoSuchFileOrDirectory, IOException, ConsoleAllocException, - InsufficientPermissionsException, CommandNotFoundException, - OperationTimeoutException, ExecutionException { - //If the mode is listing directory, for avoid problems with symlink, - //always append a / to the end of the path (if not exists) - super(ID_LS_INFO, + throws InvalidCommandDefinitionException, FileNotFoundException, IOException { + // Always remove backslash for avoid listing the files of the directory, instead of + // the directory. + super(ID_FILEINFO, new String[]{ FileHelper.removeTrailingSlash( followSymlinks ? @@ -135,31 +105,16 @@ public class ListCommand extends SyncResultProgram implements ListExecutable { //Initialize files to something distinct of null this.mFiles = new ArrayList<FileSystemObject>(); this.mMode = LIST_MODE.FILEINFO; - this.mSrc = src; //Get the absolute path - try { - if (followSymlinks) { - this.mParentDir = - FileHelper.removeTrailingSlash( - new File(src).getCanonicalFile().getParent()); - } else { - this.mParentDir = - FileHelper.removeTrailingSlash( - new File(src).getAbsoluteFile().getParent()); - } - - } catch (Exception e) { - // Try to resolve from a console - String abspath = - CommandHelper.getAbsolutePath( - FileManagerApplication.getInstance(). - getApplicationContext(), src, console); - //Resolve the parent directory + if (followSymlinks) { this.mParentDir = - CommandHelper.getParentDir( - FileManagerApplication.getInstance().getApplicationContext(), - abspath, console); + FileHelper.removeTrailingSlash( + new File(src).getCanonicalFile().getParent()); + } else { + this.mParentDir = + FileHelper.removeTrailingSlash( + new File(src).getAbsoluteFile().getParent()); } } @@ -171,150 +126,29 @@ public class ListCommand extends SyncResultProgram implements ListExecutable { //Release the array this.mFiles.clear(); - // Check the in buffer to extract information + // Read every line and parse it BufferedReader br = null; - int line = 0; try { br = new BufferedReader(new StringReader(in)); - String szLine = null; - boolean symlinks = false; - int symlinksCount = 0; - while ((szLine = br.readLine()) != null) { + String line = null; + while ((line = br.readLine()) != null) { //Checks that there is some text in the line. Otherwise ignore it - if (szLine.trim().length() == 0) { + if (line.trim().length() == 0) { break; } - //For a fast recovery, command return non symlink first and - //symlinks files, the resolution and the his info - //Is now symlinks? - if (szLine.startsWith(SYMLINK_REF)) { - //Ignore the control line - szLine = br.readLine(); - line++; - symlinks = true; - } - - //Parse the line into a FileSystemObject reference - if (!symlinks) { - try { - FileSystemObject fso = - ParseHelper.toFileSystemObject(this.mParentDir, szLine); - if (this.mMode.compareTo(LIST_MODE.FILEINFO) == 0 && - fso instanceof Symlink) { - // In some situations, xe when the name has a -> the name is - // incorrect resolved, but src name should by fine in this case - fso.setName(new File(this.mSrc).getName()); - // The symlink is not resolved here - } - this.mFiles.add(fso); - } catch (ParseException pEx) { - throw new ParseException(pEx.getMessage(), line); - } - } else { - //Is ending symlink reference - if (szLine.startsWith(SYMLINK_DATA_REF)) { - if (symlinksCount == 0) { - //No more data - break; - } - //Ignore the control line - szLine = br.readLine(); - line++; - - //The next information is known: symlinksCount * 3 - String[] name = new String[symlinksCount]; - String[] absPath = new String[symlinksCount]; - String[] refPath = new String[symlinksCount]; - for (int i = 0; i < symlinksCount; i++) { - if (szLine == null || szLine.trim().length() == 0) { - name[i] = null; - szLine = br.readLine(); - line++; - continue; - } - name[i] = szLine; - szLine = br.readLine(); - line++; - } - for (int i = 0; i < symlinksCount; i++) { - if (szLine == null || szLine.trim().length() == 0) { - absPath[i] = null; - szLine = br.readLine(); - line++; - continue; - } - absPath[i] = szLine; - szLine = br.readLine(); - line++; - } - for (int i = 0; i < symlinksCount; i++) { - if (szLine == null || szLine.trim().length() == 0) { - refPath[i] = null; - szLine = br.readLine(); - line++; - continue; - } - refPath[i] = szLine; - szLine = br.readLine(); - line++; - } - - //Fill the parent if is null - for (int i = 0; i < symlinksCount; i++) { - Symlink symLink = - ((Symlink)this.mFiles.get( - this.mFiles.size() - symlinksCount + i)); - if (symLink.getParent() == null) { - symLink.setParent(FileHelper.ROOT_DIRECTORY); - } - } - - // Symlink can cause incoherences in the name because "->" string - // Now, we have the real name of the symlink - for (int i = 0; i < symlinksCount; i++) { - if (name[i] != null) { - Symlink symLink = - ((Symlink)this.mFiles.get( - this.mFiles.size() - symlinksCount + i)); - symLink.setName(name[i]); - } - } - - //Fill the data - for (int i = 0; i < symlinksCount; i++) { - try { - if (absPath[i] != null && absPath[i].length() > 0) { - Symlink symLink = - ((Symlink)this.mFiles.get( - this.mFiles.size() - symlinksCount + i)); - String parentLink = new File(absPath[i]).getParent(); - if (parentLink == null) { - parentLink = FileHelper.ROOT_DIRECTORY; - } - String info = refPath[i]; - FileSystemObject fsoRef = - ParseHelper.toFileSystemObject(parentLink, info); - symLink.setLinkRef(fsoRef); - } - } catch (Throwable ex) { - //If parsing the file failed, ignore it and threat as a regular - //file (the destination file not exists or can't be resolved) - } - } - break; - } - - //Add the symlink - try { - this.mFiles.add(ParseHelper.toFileSystemObject(this.mParentDir, szLine)); - symlinksCount++; - } catch (ParseException pEx) { - throw new ParseException(pEx.getMessage(), line); + // Parse and add to result files + try { + this.mFiles.add(ParseHelper.parseStatOutput(line)); + } catch (Exception e) { + // Log the parsing error + if (isTrace()) { + Log.w(TAG, + String.format( + "Failed to parse output: %s", //$NON-NLS-1$ + String.valueOf(line))); } } - - line++; } // Add the parent directory @@ -325,13 +159,10 @@ public class ListCommand extends SyncResultProgram implements ListExecutable { } } catch (IOException ioEx) { - throw new ParseException(ioEx.getMessage(), line); - - } catch (ParseException pEx) { - throw pEx; + throw new ParseException(ioEx.getMessage(), 0); } catch (Exception ex) { - throw new ParseException(ex.getMessage(), line); + throw new ParseException(ex.getMessage(), 0); } finally { try { diff --git a/src/com/cyanogenmod/filemanager/commands/shell/ReadCommand.java b/src/com/cyanogenmod/filemanager/commands/shell/ReadCommand.java index d6617f48..cd2232ba 100644 --- a/src/com/cyanogenmod/filemanager/commands/shell/ReadCommand.java +++ b/src/com/cyanogenmod/filemanager/commands/shell/ReadCommand.java @@ -96,6 +96,14 @@ public class ReadCommand extends AsyncResultProgram implements ReadExecutable { * {@inheritDoc} */ @Override + public boolean parseOnlyCompleteLines() { + return false; + } + + /** + * {@inheritDoc} + */ + @Override public void checkExitCode(int exitCode) throws InsufficientPermissionsException, CommandNotFoundException, ExecutionException { // We have not privileges to read the file diff --git a/src/com/cyanogenmod/filemanager/commands/shell/ResolveLinkCommand.java b/src/com/cyanogenmod/filemanager/commands/shell/ResolveLinkCommand.java index f3d764f1..575144a1 100644 --- a/src/com/cyanogenmod/filemanager/commands/shell/ResolveLinkCommand.java +++ b/src/com/cyanogenmod/filemanager/commands/shell/ResolveLinkCommand.java @@ -63,9 +63,10 @@ public class ResolveLinkCommand extends SyncResultProgram implements ResolveLink BufferedReader br = null; try { br = new BufferedReader(new StringReader(in)); - String szParentDir = br.readLine(); - String szFileInfo = br.readLine(); - this.mFso = ParseHelper.toFileSystemObject(szParentDir, szFileInfo); + + // Extract and parse the stat output + String line = br.readLine(); + this.mFso = ParseHelper.parseStatOutput(line); } catch (Exception ex) { throw new ParseException(ex.getMessage(), 0); @@ -95,6 +96,6 @@ public class ResolveLinkCommand extends SyncResultProgram implements ResolveLink @Override public void checkExitCode(int exitCode) throws InsufficientPermissionsException, CommandNotFoundException, ExecutionException { - //Safely ignore + /**NON BLOCK**/ } } diff --git a/src/com/cyanogenmod/filemanager/commands/shell/ShellExecutableCreator.java b/src/com/cyanogenmod/filemanager/commands/shell/ShellExecutableCreator.java index 4eabd8f3..adc2ea68 100644 --- a/src/com/cyanogenmod/filemanager/commands/shell/ShellExecutableCreator.java +++ b/src/com/cyanogenmod/filemanager/commands/shell/ShellExecutableCreator.java @@ -311,8 +311,7 @@ public class ShellExecutableCreator implements ExecutableCreator { * {@inheritDoc} */ @Override - public ListExecutable createListExecutable(String src) - throws CommandNotFoundException { + public ListExecutable createListExecutable(String src) throws CommandNotFoundException { try { return new ListCommand(src, this.mConsole); } catch (Throwable throwEx) { diff --git a/src/com/cyanogenmod/filemanager/commands/shell/SyncResultProgram.java b/src/com/cyanogenmod/filemanager/commands/shell/SyncResultProgram.java index ef363b9c..2d73e58c 100644 --- a/src/com/cyanogenmod/filemanager/commands/shell/SyncResultProgram.java +++ b/src/com/cyanogenmod/filemanager/commands/shell/SyncResultProgram.java @@ -16,6 +16,7 @@ package com.cyanogenmod.filemanager.commands.shell; + /** * An abstract class that allow the consumption of the data when it's totally recovery. */ diff --git a/src/com/cyanogenmod/filemanager/console/shell/ShellConsole.java b/src/com/cyanogenmod/filemanager/console/shell/ShellConsole.java index fb3b5075..e7de2fbf 100644 --- a/src/com/cyanogenmod/filemanager/console/shell/ShellConsole.java +++ b/src/com/cyanogenmod/filemanager/console/shell/ShellConsole.java @@ -72,7 +72,7 @@ public abstract class ShellConsole extends Console implements Program.ProgramLis // A timeout of 5 seconds should be enough for no-debugging environments private static final long DEFAULT_TIMEOUT = - FileManagerApplication.isDebuggable() ? 20000L : 5000L; + FileManagerApplication.isDebuggable() ? 20000L : 3000L; private static final int DEFAULT_BUFFER = 512; @@ -312,7 +312,7 @@ public abstract class ShellConsole extends Console implements Program.ProgramLis this.mIdentity.setGroups(groupsCmd.getResult()); } } catch (Exception ex) { - Log.w(TAG, "Groups command failed. Ignored.", ex); + Log.w(TAG, "Groups command failed. Ignored.", ex); //$NON-NLS-1$ } } catch (Exception ex) { @@ -504,7 +504,7 @@ public abstract class ShellConsole extends Console implements Program.ProgramLis (program instanceof AsyncResultProgram && ((AsyncResultProgram)program).isExpectEnd())); - this.mStartControlPattern = startId1 + "\\d{1,3}" + startId2 + "\\n"; //$NON-NLS-1$ //$NON-NLS-2$ + this.mStartControlPattern = startId1 + "\\d{1,3}" + startId2; //$NON-NLS-1$ this.mEndControlPattern = endId1 + "\\d{1,3}" + endId2; //$NON-NLS-1$ String startCmd = Command.getStartCodeCommandInfo( @@ -529,7 +529,10 @@ public abstract class ShellConsole extends Console implements Program.ProgramLis .append(endCmd); } sb.append(FileHelper.NEWLINE); - this.mOut.write(sb.toString().getBytes()); + synchronized (this.mSync) { + this.mFinished = false; + this.mOut.write(sb.toString().getBytes()); + } } catch (InvalidCommandDefinitionException icdEx) { throw new CommandNotFoundException( "ExitCodeCommandInfo not found", icdEx); //$NON-NLS-1$ @@ -537,12 +540,14 @@ public abstract class ShellConsole extends Console implements Program.ProgramLis //Now, wait for buffers to be filled synchronized (this.mSync) { - if (program instanceof AsyncResultProgram) { - this.mSync.wait(); - } else { - this.mSync.wait(DEFAULT_TIMEOUT); - if (!this.mFinished) { - throw new OperationTimeoutException(DEFAULT_TIMEOUT, cmd); + if (!this.mFinished) { + if (program instanceof AsyncResultProgram) { + this.mSync.wait(); + } else { + this.mSync.wait(DEFAULT_TIMEOUT); + if (!this.mFinished) { + throw new OperationTimeoutException(DEFAULT_TIMEOUT, cmd); + } } } } @@ -629,10 +634,11 @@ public abstract class ShellConsole extends Console implements Program.ProgramLis */ private Thread createStdInThread(final InputStream in) { Thread t = new Thread(new Runnable() { + @SuppressWarnings("synthetic-access") @Override public void run() { int read = 0; - + StringBuffer sb = null; try { while (ShellConsole.this.mActive) { //Read only one byte with active wait @@ -645,14 +651,17 @@ public abstract class ShellConsole extends Console implements Program.ProgramLis boolean async = ShellConsole.this.mActiveCommand != null && ShellConsole.this.mActiveCommand instanceof AsyncResultProgram; + if (!async || sb == null) { + sb = new StringBuffer(); + } - StringBuffer sb = new StringBuffer(); if (!ShellConsole.this.mCancelled) { ShellConsole.this.mSbIn.append((char)r); if (!ShellConsole.this.mStarted) { ShellConsole.this.mStarted = isCommandStarted(ShellConsole.this.mSbIn); if (ShellConsole.this.mStarted) { + sb = new StringBuffer(ShellConsole.this.mSbIn.toString()); if (async) { synchronized (ShellConsole.this.mPartialSync) { @@ -668,21 +677,44 @@ public abstract class ShellConsole extends Console implements Program.ProgramLis sb.append((char)r); } + //Check if the command has finished (and extract the control) + boolean finished = isCommandFinished(ShellConsole.this.mSbIn, sb); + //Notify asynchronous partial data if (ShellConsole.this.mStarted && async) { AsyncResultProgram program = ((AsyncResultProgram)ShellConsole.this.mActiveCommand); String partial = sb.toString(); - program.onRequestParsePartialResult(partial); - ShellConsole.this.toStdIn(partial); + int cc = ShellConsole.this.mEndControlPattern.length(); + if (partial.length() >= cc) { + program.onRequestParsePartialResult(partial); + ShellConsole.this.toStdIn(partial); - // Reset the temp buffer - sb = new StringBuffer(); + // Reset the temp buffer + sb = new StringBuffer(); + } } - } - if (!async) { - ShellConsole.this.toStdIn(sb.toString()); + if (finished) { + if (!async) { + ShellConsole.this.toStdIn(String.valueOf((char)r)); + } else { + AsyncResultProgram program = + ((AsyncResultProgram)ShellConsole.this.mActiveCommand); + String partial = sb.toString(); + if (program != null) { + program.onRequestParsePartialResult(partial); + } + ShellConsole.this.toStdIn(partial); + } + + //Notify the end + notifyProcessFinished(); + break; + } + if (!async && !finished) { + ShellConsole.this.toStdIn(String.valueOf((char)r)); + } } //Has more data? Read with available as more as exists @@ -690,8 +722,8 @@ public abstract class ShellConsole extends Console implements Program.ProgramLis int count = 0; while (in.available() > 0 && count < 10) { count++; - int available = Math.min(in.available(), - ShellConsole.this.mBufferSize); + int available = + Math.min(in.available(), ShellConsole.this.mBufferSize); byte[] data = new byte[available]; read = in.read(data); @@ -735,18 +767,29 @@ public abstract class ShellConsole extends Console implements Program.ProgramLis AsyncResultProgram program = ((AsyncResultProgram)ShellConsole.this.mActiveCommand); String partial = sb.toString(); - if (program != null) { - program.onRequestParsePartialResult(partial); - } - ShellConsole.this.toStdIn(partial); + int cc = ShellConsole.this.mEndControlPattern.length(); + if (partial.length() >= cc) { + if (program != null) { + program.onRequestParsePartialResult(partial); + } + ShellConsole.this.toStdIn(partial); - // Reset the temp buffer - sb = new StringBuffer(); + // Reset the temp buffer + sb = new StringBuffer(); + } } if (finished) { if (!async) { ShellConsole.this.toStdIn(s); + } else { + AsyncResultProgram program = + ((AsyncResultProgram)ShellConsole.this.mActiveCommand); + String partial = sb.toString(); + if (program != null) { + program.onRequestParsePartialResult(partial); + } + ShellConsole.this.toStdIn(partial); } //Notify the end @@ -759,10 +802,8 @@ public abstract class ShellConsole extends Console implements Program.ProgramLis //Wait for buffer to be filled try { - Thread.sleep(50L); - } catch (Throwable ex) { - /**NON BLOCK**/ - } + Thread.sleep(1L); + } catch (Throwable ex) {/**NON BLOCK**/} } //Asynchronous programs can cause a lot of output, control buffers diff --git a/src/com/cyanogenmod/filemanager/listeners/OnRequestRefreshListener.java b/src/com/cyanogenmod/filemanager/listeners/OnRequestRefreshListener.java index 216b787b..0de97198 100644 --- a/src/com/cyanogenmod/filemanager/listeners/OnRequestRefreshListener.java +++ b/src/com/cyanogenmod/filemanager/listeners/OnRequestRefreshListener.java @@ -25,15 +25,17 @@ public interface OnRequestRefreshListener { * Invoked when a new refresh is needed. * * @param o The object that should be refreshed + * @param clearSelection If the refresh should clear the selection */ - void onRequestRefresh(Object o); + void onRequestRefresh(Object o, boolean clearSelection); /** * Invoked when the object was removed. * * @param o The object that was removed + * @param clearSelection If the refresh should clear the selection */ - void onRequestRemove(Object o); + void onRequestRemove(Object o, boolean clearSelection); /** * Invoked when the object need to navigate to. diff --git a/src/com/cyanogenmod/filemanager/model/BlockDevice.java b/src/com/cyanogenmod/filemanager/model/BlockDevice.java index 5fa56531..31873b36 100644 --- a/src/com/cyanogenmod/filemanager/model/BlockDevice.java +++ b/src/com/cyanogenmod/filemanager/model/BlockDevice.java @@ -25,7 +25,7 @@ import java.util.Date; */ public class BlockDevice extends SystemFile { - private static final long serialVersionUID = -4090113368100371854L; + private static final long serialVersionUID = 5938248951823805680L; /** * The unix identifier of the object. @@ -41,11 +41,15 @@ public class BlockDevice extends SystemFile { * @param user The user proprietary of the object * @param group The group proprietary of the object * @param permissions The permissions of the object + * @param lastAccessedTime The last time that the object was accessed * @param lastModifiedTime The last time that the object was modified + * @param lastChangedTime The last time that the object was changed */ - public BlockDevice(String name, String parent, User user, Group group, Permissions permissions, - Date lastModifiedTime) { - super(name, parent, user, group, permissions, lastModifiedTime, 0L); + public BlockDevice( + String name, String parent, User user, Group group, Permissions permissions, + Date lastAccessedTime, Date lastModifiedTime, Date lastChangedTime) { + super(name, parent, user, group, permissions, 0L, + lastAccessedTime, lastModifiedTime, lastChangedTime); } /** diff --git a/src/com/cyanogenmod/filemanager/model/CharacterDevice.java b/src/com/cyanogenmod/filemanager/model/CharacterDevice.java index 77c35c7e..489e05ad 100644 --- a/src/com/cyanogenmod/filemanager/model/CharacterDevice.java +++ b/src/com/cyanogenmod/filemanager/model/CharacterDevice.java @@ -25,7 +25,7 @@ import java.util.Date; */ public class CharacterDevice extends SystemFile { - private static final long serialVersionUID = -1226283292403290607L; + private static final long serialVersionUID = -3585051204874199619L; /** * The unix identifier of the object. @@ -41,12 +41,15 @@ public class CharacterDevice extends SystemFile { * @param user The user proprietary of the object * @param group The group proprietary of the object * @param permissions The permissions of the object + * @param lastAccessedTime The last time that the object was accessed * @param lastModifiedTime The last time that the object was modified + * @param lastChangedTime The last time that the object was changed */ public CharacterDevice( - String name, String parent, User user, Group group, - Permissions permissions, Date lastModifiedTime) { - super(name, parent, user, group, permissions, lastModifiedTime, 0L); + String name, String parent, User user, Group group, Permissions permissions, + Date lastAccessedTime, Date lastModifiedTime, Date lastChangedTime) { + super(name, parent, user, group, permissions, 0L, + lastAccessedTime, lastModifiedTime, lastChangedTime); } /** diff --git a/src/com/cyanogenmod/filemanager/model/Directory.java b/src/com/cyanogenmod/filemanager/model/Directory.java index ff1bc8d9..77b12081 100644 --- a/src/com/cyanogenmod/filemanager/model/Directory.java +++ b/src/com/cyanogenmod/filemanager/model/Directory.java @@ -25,7 +25,7 @@ import java.util.Date; */ public class Directory extends FileSystemObject { - private static final long serialVersionUID = 7961695438008458932L; + private static final long serialVersionUID = -3975569940766905884L; //Resource identifier for default icon private static final int RESOURCE_FOLDER_DEFAULT = R.drawable.ic_fso_folder; @@ -44,11 +44,14 @@ public class Directory extends FileSystemObject { * @param user The user proprietary of the object * @param group The group proprietary of the object * @param permissions The permissions of the object + * @param lastAccessedTime The last time that the object was accessed * @param lastModifiedTime The last time that the object was modified + * @param lastChangedTime The last time that the object was changed */ public Directory(String name, String parent, User user, Group group, Permissions permissions, - Date lastModifiedTime) { - super(name, parent, user, group, permissions, lastModifiedTime, 0L); + Date lastAccessedTime, Date lastModifiedTime, Date lastChangedTime) { + super(name, parent, user, group, permissions, 0L, + lastAccessedTime, lastModifiedTime, lastChangedTime); setResourceIconId(RESOURCE_FOLDER_DEFAULT); } diff --git a/src/com/cyanogenmod/filemanager/model/DomainSocket.java b/src/com/cyanogenmod/filemanager/model/DomainSocket.java index ca0f54d6..c7d9af1f 100644 --- a/src/com/cyanogenmod/filemanager/model/DomainSocket.java +++ b/src/com/cyanogenmod/filemanager/model/DomainSocket.java @@ -25,7 +25,7 @@ import java.util.Date; */ public class DomainSocket extends SystemFile { - private static final long serialVersionUID = 2579603247387819438L; + private static final long serialVersionUID = 7821422013567568593L; /** * The unix identifier of the object. @@ -41,11 +41,15 @@ public class DomainSocket extends SystemFile { * @param user The user proprietary of the object * @param group The group proprietary of the object * @param permissions The permissions of the object + * @param lastAccessedTime The last time that the object was accessed * @param lastModifiedTime The last time that the object was modified + * @param lastChangedTime The last time that the object was changed */ - public DomainSocket(String name, String parent, User user, Group group, Permissions permissions, - Date lastModifiedTime) { - super(name, parent, user, group, permissions, lastModifiedTime, 0L); + public DomainSocket( + String name, String parent, User user, Group group, Permissions permissions, + Date lastAccessedTime, Date lastModifiedTime, Date lastChangedTime) { + super(name, parent, user, group, permissions, 0L, + lastAccessedTime, lastModifiedTime, lastChangedTime); } /** diff --git a/src/com/cyanogenmod/filemanager/model/FileSystemObject.java b/src/com/cyanogenmod/filemanager/model/FileSystemObject.java index 245ebce5..75745c4b 100644 --- a/src/com/cyanogenmod/filemanager/model/FileSystemObject.java +++ b/src/com/cyanogenmod/filemanager/model/FileSystemObject.java @@ -33,7 +33,7 @@ import java.util.Date; */ public abstract class FileSystemObject implements Serializable, Comparable<FileSystemObject> { - private static final long serialVersionUID = -8527561430880927320L; + private static final long serialVersionUID = 5877049750925761305L; //Resource identifier for default icon private static final int RESOURCE_ICON_DEFAULT = R.drawable.ic_fso_default; @@ -44,8 +44,11 @@ public abstract class FileSystemObject implements Serializable, Comparable<FileS private User mUser; private Group mGroup; private Permissions mPermissions; - private Date mLastModifiedTime; private long mSize; + private Date mLastAccessedTime; + private Date mLastModifiedTime; + private Date mLastChangedTime; + /** * Constructor of <code>FileSystemObject</code>. @@ -55,19 +58,24 @@ public abstract class FileSystemObject implements Serializable, Comparable<FileS * @param user The user proprietary of the object * @param group The group proprietary of the object * @param permissions The permissions of the object - * @param lastModifiedTime The last time that the object was modified * @param size The size in bytes of the object + * @param lastAccessedTime The last time that the object was accessed + * @param lastModifiedTime The last time that the object was modified + * @param lastChangedTime The last time that the object was changed */ public FileSystemObject(String name, String parent, User user, Group group, - Permissions permissions, Date lastModifiedTime, long size) { + Permissions permissions, long size, + Date lastAccessedTime, Date lastModifiedTime, Date lastChangedTime) { super(); this.mName = name; this.mParent = parent; this.mUser = user; this.mGroup = group; this.mPermissions = permissions; - this.mLastModifiedTime = lastModifiedTime; this.mSize = size; + this.mLastAccessedTime = lastAccessedTime; + this.mLastModifiedTime = lastModifiedTime; + this.mLastChangedTime = lastChangedTime; this.mResourceIconId = RESOURCE_ICON_DEFAULT; } @@ -169,6 +177,42 @@ public abstract class FileSystemObject implements Serializable, Comparable<FileS } /** + * Method that returns the size in bytes of the object. + * + * @return long The size in bytes of the object + */ + public long getSize() { + return this.mSize; + } + + /** + * Method that sets the size in bytes of the object. + * + * @param size The size in bytes of the object + */ + public void setSize(long size) { + this.mSize = size; + } + + /** + * Method that returns the last time that the object was accessed. + * + * @return Date The last time that the object was accessed + */ + public Date getLastAccessedTime() { + return this.mLastAccessedTime; + } + + /** + * Method that sets the last time that the object was accessed. + * + * @param lastAccessedTime The last time that the object was accessed + */ + public void setLastAccessedTime(Date lastAccessedTime) { + this.mLastAccessedTime = lastAccessedTime; + } + + /** * Method that returns the last time that the object was modified. * * @return Date The last time that the object was modified @@ -187,21 +231,21 @@ public abstract class FileSystemObject implements Serializable, Comparable<FileS } /** - * Method that returns the size in bytes of the object. + * Method that returns the last time that the object was changed. * - * @return long The size in bytes of the object + * @return Date The last time that the object was changed */ - public long getSize() { - return this.mSize; + public Date getLastChangedTime() { + return this.mLastChangedTime; } /** - * Method that sets the size in bytes of the object. + * Method that sets the last time that the object was changed. * - * @param size The size in bytes of the object + * @param lastChangedTime The last time that the object was changed */ - public void setSize(long size) { - this.mSize = size; + public void setLastChangedTime(Date lastChangedTime) { + this.mLastChangedTime = lastChangedTime; } /** @@ -262,89 +306,38 @@ public abstract class FileSystemObject implements Serializable, Comparable<FileS return o1.compareTo(o2); } - /** - * {@inheritDoc} + /* (non-Javadoc) + * @see java.lang.Object#hashCode() */ @Override public int hashCode() { final int prime = 31; int result = 1; - result = prime * result + ((this.mGroup == null) ? 0 : this.mGroup.hashCode()); - result = prime * result + ((this.mLastModifiedTime == null) - ? 0 - : this.mLastModifiedTime.hashCode()); result = prime * result + ((this.mName == null) ? 0 : this.mName.hashCode()); result = prime * result + ((this.mParent == null) ? 0 : this.mParent.hashCode()); - result = prime * result + ((this.mPermissions == null) ? 0 : this.mPermissions.hashCode()); - result = prime * result + this.mResourceIconId; - result = prime * result + (int) (this.mSize ^ (this.mSize >>> 32)); - result = prime * result + ((this.mUser == null) ? 0 : this.mUser.hashCode()); return result; } - /** - * {@inheritDoc} + /* (non-Javadoc) + * @see java.lang.Object#equals(java.lang.Object) */ @Override public boolean equals(Object obj) { - if (this == obj) { + if (this == obj) return true; - } - if (obj == null) { + if (obj == null) return false; - } - if (getClass() != obj.getClass()) { - return false; - } FileSystemObject other = (FileSystemObject) obj; - if (this.mGroup == null) { - if (other.mGroup != null) { - return false; - } - } else if (!this.mGroup.equals(other.mGroup)) { - return false; - } - if (this.mLastModifiedTime == null) { - if (other.mLastModifiedTime != null) { - return false; - } - } else if (!this.mLastModifiedTime.equals(other.mLastModifiedTime)) { - return false; - } if (this.mName == null) { - if (other.mName != null) { + if (other.mName != null) return false; - } - } else if (!this.mName.equals(other.mName)) { + } else if (!this.mName.equals(other.mName)) return false; - } if (this.mParent == null) { - if (other.mParent != null) { - return false; - } - } else if (!this.mParent.equals(other.mParent)) { - return false; - } - if (this.mPermissions == null) { - if (other.mPermissions != null) { + if (other.mParent != null) return false; - } - } else if (!this.mPermissions.equals(other.mPermissions)) { - return false; - } - if (this.mResourceIconId != other.mResourceIconId) { + } else if (!this.mParent.equals(other.mParent)) return false; - } - if (this.mSize != other.mSize) { - return false; - } - if (this.mUser == null) { - if (other.mUser != null) { - return false; - } - } else if (!this.mUser.equals(other.mUser)) { - return false; - } return true; } @@ -354,23 +347,26 @@ public abstract class FileSystemObject implements Serializable, Comparable<FileS * * @return String The string representation */ - public String toRawString() { + public String toRawPermissionString() { return String.format("%s%s", //$NON-NLS-1$ String.valueOf(getUnixIdentifier()), getPermissions().toRawString()); } - /** - * {@inheritDoc} + /* (non-Javadoc) + * @see java.lang.Object#toString() */ @Override public String toString() { - return "FileSystemObject [resourceIconId=" + this.mResourceIconId //$NON-NLS-1$ - + ", name=" + this.mName //$NON-NLS-1$ - + ", parent=" + this.mParent + ", user=" + this.mUser //$NON-NLS-1$ //$NON-NLS-2$ - + ", group=" + this.mGroup + ", permissions=" //$NON-NLS-1$ //$NON-NLS-2$ - + this.mPermissions + ", lastModifiedTime=" + this.mLastModifiedTime //$NON-NLS-1$ - + ", size=" + this.mSize + "]"; //$NON-NLS-1$//$NON-NLS-2$ + return "FileSystemObject [mResourceIconId=" + this.mResourceIconId //$NON-NLS-1$ + + ", mName=" + this.mName + ", mParent=" + this.mParent //$NON-NLS-1$ //$NON-NLS-2$ + + ", mUser=" + this.mUser + ", mGroup=" + this.mGroup //$NON-NLS-1$ //$NON-NLS-2$ + + ", mPermissions=" + this.mPermissions //$NON-NLS-1$ + + ", mSize=" + this.mSize //$NON-NLS-1$ + + ", mLastAccessedTime=" + this.mLastAccessedTime //$NON-NLS-1$ + + ", mLastModifiedTime=" + this.mLastModifiedTime //$NON-NLS-1$ + + ", mLastChangedTime=" + this.mLastChangedTime //$NON-NLS-1$ + + "]"; //$NON-NLS-1$ } } diff --git a/src/com/cyanogenmod/filemanager/model/NamedPipe.java b/src/com/cyanogenmod/filemanager/model/NamedPipe.java index 7899f9fa..5a15f850 100644 --- a/src/com/cyanogenmod/filemanager/model/NamedPipe.java +++ b/src/com/cyanogenmod/filemanager/model/NamedPipe.java @@ -25,7 +25,7 @@ import java.util.Date; */ public class NamedPipe extends SystemFile { - private static final long serialVersionUID = -1847920531465352084L; + private static final long serialVersionUID = -5199356055601688190L; /** * The unix identifier of the object. @@ -41,11 +41,15 @@ public class NamedPipe extends SystemFile { * @param user The user proprietary of the object * @param group The group proprietary of the object * @param permissions The permissions of the object + * @param lastAccessedTime The last time that the object was accessed * @param lastModifiedTime The last time that the object was modified + * @param lastChangedTime The last time that the object was changed */ - public NamedPipe(String name, String parent, User user, Group group, Permissions permissions, - Date lastModifiedTime) { - super(name, parent, user, group, permissions, lastModifiedTime, 0L); + public NamedPipe( + String name, String parent, User user, Group group, Permissions permissions, + Date lastAccessedTime, Date lastModifiedTime, Date lastChangedTime) { + super(name, parent, user, group, permissions, 0L, + lastAccessedTime, lastModifiedTime, lastChangedTime); } /** diff --git a/src/com/cyanogenmod/filemanager/model/ParentDirectory.java b/src/com/cyanogenmod/filemanager/model/ParentDirectory.java index f2a905b1..8a713791 100644 --- a/src/com/cyanogenmod/filemanager/model/ParentDirectory.java +++ b/src/com/cyanogenmod/filemanager/model/ParentDirectory.java @@ -24,7 +24,7 @@ import com.cyanogenmod.filemanager.util.FileHelper; */ public class ParentDirectory extends Directory { - private static final long serialVersionUID = 4022696602271512681L; + private static final long serialVersionUID = -3818276335217197479L; /** * Constructor of <code>ParentDirectory</code>. @@ -32,7 +32,7 @@ public class ParentDirectory extends Directory { * @param parent The parent folder of the object */ public ParentDirectory(String parent) { - super(FileHelper.PARENT_DIRECTORY, parent, null, null, null, null); + super(FileHelper.PARENT_DIRECTORY, parent, null, null, null, null, null, null); } /** diff --git a/src/com/cyanogenmod/filemanager/model/RegularFile.java b/src/com/cyanogenmod/filemanager/model/RegularFile.java index 7a3200e8..49c9fd77 100644 --- a/src/com/cyanogenmod/filemanager/model/RegularFile.java +++ b/src/com/cyanogenmod/filemanager/model/RegularFile.java @@ -23,7 +23,7 @@ import java.util.Date; */ public class RegularFile extends FileSystemObject { - private static final long serialVersionUID = -6828866564538453913L; + private static final long serialVersionUID = 7113562456595400525L; /** * The unix identifier of the object. @@ -39,12 +39,16 @@ public class RegularFile extends FileSystemObject { * @param user The user proprietary of the object * @param group The group proprietary of the object * @param permissions The permissions of the object - * @param lastModifiedTime The last time that the object was modified * @param size The size in bytes of the object + * @param lastAccessedTime The last time that the object was accessed + * @param lastModifiedTime The last time that the object was modified + * @param lastChangedTime The last time that the object was changed */ - public RegularFile(String name, String parent, User user, Group group, Permissions permissions, - Date lastModifiedTime, long size) { - super(name, parent, user, group, permissions, lastModifiedTime, size); + public RegularFile(String name, String parent, User user, Group group, + Permissions permissions, long size, + Date lastAccessedTime, Date lastModifiedTime, Date lastChangedTime) { + super(name, parent, user, group, permissions, size, + lastAccessedTime, lastModifiedTime, lastChangedTime); } /** diff --git a/src/com/cyanogenmod/filemanager/model/Symlink.java b/src/com/cyanogenmod/filemanager/model/Symlink.java index b62e32fa..dc001810 100644 --- a/src/com/cyanogenmod/filemanager/model/Symlink.java +++ b/src/com/cyanogenmod/filemanager/model/Symlink.java @@ -25,7 +25,7 @@ import java.util.Date; */ public class Symlink extends FileSystemObject { - private static final long serialVersionUID = 1354790574987082087L; + private static final long serialVersionUID = -6411787401264288389L; /** * The unix identifier of the object. @@ -45,12 +45,15 @@ public class Symlink extends FileSystemObject { * @param user The user proprietary of the object * @param group The group proprietary of the object * @param permissions The permissions of the object + * @param lastAccessedTime The last time that the object was accessed * @param lastModifiedTime The last time that the object was modified + * @param lastChangedTime The last time that the object was changed */ - public Symlink( - String name, String link, String parent, User user, - Group group, Permissions permissions, Date lastModifiedTime) { - super(name, parent, user, group, permissions, lastModifiedTime, 0L); + public Symlink(String name, String link, String parent, User user, + Group group, Permissions permissions, + Date lastAccessedTime, Date lastModifiedTime, Date lastChangedTime) { + super(name, parent, user, group, permissions, 0L, + lastAccessedTime, lastModifiedTime, lastChangedTime); this.mLink = link; } diff --git a/src/com/cyanogenmod/filemanager/model/SystemFile.java b/src/com/cyanogenmod/filemanager/model/SystemFile.java index 637fd536..7767452d 100644 --- a/src/com/cyanogenmod/filemanager/model/SystemFile.java +++ b/src/com/cyanogenmod/filemanager/model/SystemFile.java @@ -28,7 +28,7 @@ import java.util.Date; */ public abstract class SystemFile extends FileSystemObject { - private static final long serialVersionUID = 1064161296325655096L; + private static final long serialVersionUID = -1396396017050697459L; /** * Constructor of <code>SystemFile</code>. @@ -38,12 +38,16 @@ public abstract class SystemFile extends FileSystemObject { * @param user The user proprietary of the object * @param group The group proprietary of the object * @param permissions The permissions of the object - * @param lastModifiedTime The last time that the object was modified * @param size The size in bytes of the object + * @param lastAccessedTime The last time that the object was accessed + * @param lastModifiedTime The last time that the object was modified + * @param lastChangedTime The last time that the object was changed */ public SystemFile( String name, String parent, User user, Group group, - Permissions permissions, Date lastModifiedTime, long size) { - super(name, parent, user, group, permissions, lastModifiedTime, size); + Permissions permissions, long size, + Date lastAccessedTime, Date lastModifiedTime, Date lastChangedTime) { + super(name, parent, user, group, permissions, size, + lastAccessedTime, lastModifiedTime, lastChangedTime); } } diff --git a/src/com/cyanogenmod/filemanager/preferences/Bookmarks.java b/src/com/cyanogenmod/filemanager/preferences/Bookmarks.java index 74573754..998b7153 100644 --- a/src/com/cyanogenmod/filemanager/preferences/Bookmarks.java +++ b/src/com/cyanogenmod/filemanager/preferences/Bookmarks.java @@ -90,12 +90,20 @@ public class Bookmarks { Bookmark.Columns.BOOKMARK_QUERY_COLUMNS, null, null, null); Bookmark bookmark = null; - if (cursor != null) { - if (cursor.moveToFirst()) { - bookmark = new Bookmark(cursor); + try { + if (cursor != null) { + if (cursor.moveToFirst()) { + bookmark = new Bookmark(cursor); + } } - cursor.close(); + } finally { + try { + if (cursor != null) { + cursor.close(); + } + } catch (Exception e) {/**NON BLOCK**/} } + return bookmark; } @@ -126,11 +134,19 @@ public class Bookmarks { Bookmark.Columns.BOOKMARK_QUERY_COLUMNS, where, new String[]{path}, null); Bookmark bookmark = null; - if (cursor != null) { - if (cursor.moveToFirst()) { - bookmark = new Bookmark(cursor); + try { + if (cursor != null) { + if (cursor.moveToFirst()) { + bookmark = new Bookmark(cursor); + } + cursor.close(); } - cursor.close(); + } finally { + try { + if (cursor != null) { + cursor.close(); + } + } catch (Exception e) {/**NON BLOCK**/} } return bookmark; } diff --git a/src/com/cyanogenmod/filemanager/ui/dialogs/ActionsDialog.java b/src/com/cyanogenmod/filemanager/ui/dialogs/ActionsDialog.java index 01ee26f5..ce03ed76 100644 --- a/src/com/cyanogenmod/filemanager/ui/dialogs/ActionsDialog.java +++ b/src/com/cyanogenmod/filemanager/ui/dialogs/ActionsDialog.java @@ -249,7 +249,7 @@ public class ActionsDialog implements OnItemClickListener, OnItemLongClickListen //- Refresh case R.id.mnu_actions_refresh: if (this.mOnRequestRefreshListener != null) { - this.mOnRequestRefreshListener.onRequestRefresh(null); //Refresh all + this.mOnRequestRefreshListener.onRequestRefresh(null, false); //Refresh all } break; diff --git a/src/com/cyanogenmod/filemanager/ui/dialogs/FilesystemInfoDialog.java b/src/com/cyanogenmod/filemanager/ui/dialogs/FilesystemInfoDialog.java index e6bf1116..d0786d10 100644 --- a/src/com/cyanogenmod/filemanager/ui/dialogs/FilesystemInfoDialog.java +++ b/src/com/cyanogenmod/filemanager/ui/dialogs/FilesystemInfoDialog.java @@ -180,7 +180,6 @@ public class FilesystemInfoDialog implements OnClickListener, OnCheckedChangeLis //Gets text views this.mSwStatus = (Switch)contentView.findViewById(R.id.filesystem_info_status); - this.mSwStatus.setOnCheckedChangeListener(this); TextView tvMountPoint = (TextView)contentView.findViewById(R.id.filesystem_info_mount_point); TextView tvDevice = (TextView)contentView.findViewById(R.id.filesystem_info_device); @@ -240,6 +239,9 @@ public class FilesystemInfoDialog implements OnClickListener, OnCheckedChangeLis this.mSwStatus.setEnabled(this.mIsMountAllowed); this.mSwStatus.setChecked(MountPointHelper.isReadWrite(this.mMountPoint)); + // Add the listener after set the value to avoid raising triggers + this.mSwStatus.setOnCheckedChangeListener(this); + //Change the tab onClick(this.mInfoViewTab); } diff --git a/src/com/cyanogenmod/filemanager/ui/dialogs/FsoPropertiesDialog.java b/src/com/cyanogenmod/filemanager/ui/dialogs/FsoPropertiesDialog.java index ecd44040..147682ce 100644 --- a/src/com/cyanogenmod/filemanager/ui/dialogs/FsoPropertiesDialog.java +++ b/src/com/cyanogenmod/filemanager/ui/dialogs/FsoPropertiesDialog.java @@ -297,8 +297,6 @@ public class FsoPropertiesDialog String loadingMsg = this.mContext.getString(R.string.loading_message); setSpinnerMsg(this.mContext, FsoPropertiesDialog.this.mSpnOwner, loadingMsg); setSpinnerMsg(this.mContext, FsoPropertiesDialog.this.mSpnGroup, loadingMsg); - this.mSpnOwner.setOnItemSelectedListener(this); - this.mSpnGroup.setOnItemSelectedListener(this); updatePermissions(); // Load owners and groups AIDs in background @@ -333,6 +331,13 @@ public class FsoPropertiesDialog this.mInfoMsgView.setOnClickListener(this); } + // Add the listener after set the value to avoid raising triggers + this.mSpnOwner.setOnItemSelectedListener(this); + this.mSpnGroup.setOnItemSelectedListener(this); + setPermissionCheckBoxesListener(this.mChkUserPermission); + setPermissionCheckBoxesListener(this.mChkGroupPermission); + setPermissionCheckBoxesListener(this.mChkOthersPermission); + //Change the tab onClick(this.mInfoViewTab); this.mIgnoreCheckEvents = false; @@ -805,7 +810,7 @@ public class FsoPropertiesDialog * @param rootView The root view * @return UserPermission The user permission */ - private CheckBox[] loadCheckBoxUserPermission ( + private static CheckBox[] loadCheckBoxUserPermission ( Context ctx, View rootView, UserPermission permission) { CheckBox[] chkPermissions = loadPermissionCheckBoxes(ctx, rootView, OWNER_TYPE); chkPermissions[0].setChecked(permission.isSetUID()); @@ -820,7 +825,7 @@ public class FsoPropertiesDialog * @param rootView The root view * @return UserPermission The user permission */ - private CheckBox[] loadCheckBoxGroupPermission ( + private static CheckBox[] loadCheckBoxGroupPermission ( Context ctx, View rootView, GroupPermission permission) { CheckBox[] chkPermissions = loadPermissionCheckBoxes(ctx, rootView, GROUP_TYPE); chkPermissions[0].setChecked(permission.isSetGID()); @@ -835,7 +840,7 @@ public class FsoPropertiesDialog * @param rootView The root view * @return UserPermission The user permission */ - private CheckBox[] loadCheckBoxOthersPermission ( + private static CheckBox[] loadCheckBoxOthersPermission ( Context ctx, View rootView, OthersPermission permission) { CheckBox[] chkPermissions = loadPermissionCheckBoxes(ctx, rootView, OTHERS_TYPE); chkPermissions[0].setChecked(permission.isStickybit()); @@ -878,7 +883,7 @@ public class FsoPropertiesDialog * @param type The type of permission [owner, group, others] * @return CheckBox[] The checkboxes associated */ - private CheckBox[] loadPermissionCheckBoxes(Context ctx, View rootView, String type) { + private static CheckBox[] loadPermissionCheckBoxes(Context ctx, View rootView, String type) { Resources res = ctx.getResources(); CheckBox[] chkPermissions = new CheckBox[4]; chkPermissions[0] = (CheckBox)rootView.findViewById( @@ -897,11 +902,19 @@ public class FsoPropertiesDialog ResourcesHelper.getIdentifier( res, "id", //$NON-NLS-1$ String.format("fso_permissions_%s_special", type))); //$NON-NLS-1$ + return chkPermissions; + } + + /** + * Method that sets the listener for the permission checkboxes + * + * @param chkPermissions The checkboxes + */ + private void setPermissionCheckBoxesListener(CheckBox[] chkPermissions) { int cc = chkPermissions.length; for (int i = 0; i < cc; i++) { chkPermissions[i].setOnCheckedChangeListener(this); } - return chkPermissions; } /** diff --git a/src/com/cyanogenmod/filemanager/ui/policy/CompressActionPolicy.java b/src/com/cyanogenmod/filemanager/ui/policy/CompressActionPolicy.java index bdefe198..6e5f57fe 100644 --- a/src/com/cyanogenmod/filemanager/ui/policy/CompressActionPolicy.java +++ b/src/com/cyanogenmod/filemanager/ui/policy/CompressActionPolicy.java @@ -251,7 +251,7 @@ public final class CompressActionPolicy extends ActionsPolicy { //Operation complete. Refresh if (this.mOnRequestRefreshListener != null) { // The reference is not the same, so refresh the complete navigation view - this.mOnRequestRefreshListener.onRequestRefresh(null); + this.mOnRequestRefreshListener.onRequestRefresh(null, true); } if (this.cmd != null) { showOperationSuccessMsg( @@ -552,7 +552,7 @@ public final class CompressActionPolicy extends ActionsPolicy { //Operation complete. Refresh if (this.mOnRequestRefreshListener != null) { // The reference is not the same, so refresh the complete navigation view - this.mOnRequestRefreshListener.onRequestRefresh(null); + this.mOnRequestRefreshListener.onRequestRefresh(null, true); } if (this.cmd != null) { showOperationSuccessMsg( diff --git a/src/com/cyanogenmod/filemanager/ui/policy/CopyMoveActionPolicy.java b/src/com/cyanogenmod/filemanager/ui/policy/CopyMoveActionPolicy.java index 75531480..1f583e96 100644 --- a/src/com/cyanogenmod/filemanager/ui/policy/CopyMoveActionPolicy.java +++ b/src/com/cyanogenmod/filemanager/ui/policy/CopyMoveActionPolicy.java @@ -305,7 +305,7 @@ public final class CopyMoveActionPolicy extends ActionsPolicy { //Operation complete. Refresh if (this.mOnRequestRefreshListener != null) { // The reference is not the same, so refresh the complete navigation view - this.mOnRequestRefreshListener.onRequestRefresh(null); + this.mOnRequestRefreshListener.onRequestRefresh(null, true); } ActionsPolicy.showOperationSuccessMsg(ctx); } diff --git a/src/com/cyanogenmod/filemanager/ui/policy/DeleteActionPolicy.java b/src/com/cyanogenmod/filemanager/ui/policy/DeleteActionPolicy.java index 87c59afe..039f4fe8 100644 --- a/src/com/cyanogenmod/filemanager/ui/policy/DeleteActionPolicy.java +++ b/src/com/cyanogenmod/filemanager/ui/policy/DeleteActionPolicy.java @@ -196,9 +196,9 @@ public final class DeleteActionPolicy extends ActionsPolicy { if (this.mOnRequestRefreshListener != null) { // The reference is not the same, so refresh the complete navigation view if (files != null && files.size() == 1) { - this.mOnRequestRefreshListener.onRequestRemove(files.get(0)); + this.mOnRequestRefreshListener.onRequestRemove(files.get(0), true); } else { - this.mOnRequestRefreshListener.onRequestRemove(null); + this.mOnRequestRefreshListener.onRequestRemove(null, true); } } ActionsPolicy.showOperationSuccessMsg(ctx); diff --git a/src/com/cyanogenmod/filemanager/ui/policy/InfoActionPolicy.java b/src/com/cyanogenmod/filemanager/ui/policy/InfoActionPolicy.java index e7a4704d..ef4639b0 100644 --- a/src/com/cyanogenmod/filemanager/ui/policy/InfoActionPolicy.java +++ b/src/com/cyanogenmod/filemanager/ui/policy/InfoActionPolicy.java @@ -60,7 +60,7 @@ public final class InfoActionPolicy extends ActionsPolicy { // Any change? if (dialog.isHasChanged()) { if (onRequestRefreshListener != null) { - onRequestRefreshListener.onRequestRefresh(dialog.getFso()); + onRequestRefreshListener.onRequestRefresh(dialog.getFso(), false); } } } diff --git a/src/com/cyanogenmod/filemanager/ui/policy/NewActionPolicy.java b/src/com/cyanogenmod/filemanager/ui/policy/NewActionPolicy.java index 6f0bad95..b24cce11 100644 --- a/src/com/cyanogenmod/filemanager/ui/policy/NewActionPolicy.java +++ b/src/com/cyanogenmod/filemanager/ui/policy/NewActionPolicy.java @@ -110,7 +110,7 @@ public final class NewActionPolicy extends ActionsPolicy { try { fso = CommandHelper.getFileInfo(ctx, newName, false, null); } catch (Throwable ex2) {/**NON BLOCK**/} - onRequestRefreshListener.onRequestRefresh(fso); + onRequestRefreshListener.onRequestRefresh(fso, false); } showOperationSuccessMsg(ctx); @@ -129,7 +129,7 @@ public final class NewActionPolicy extends ActionsPolicy { try { fso = CommandHelper.getFileInfo(ctx, newName, false, null); } catch (Throwable ex2) {/**NON BLOCK**/} - onRequestRefreshListener.onRequestRefresh(fso); + onRequestRefreshListener.onRequestRefresh(fso, false); } return Boolean.TRUE; } @@ -185,7 +185,7 @@ public final class NewActionPolicy extends ActionsPolicy { } catch (Throwable ex2) { /**NON BLOCK**/ } - onRequestRefreshListener.onRequestRefresh(fso); + onRequestRefreshListener.onRequestRefresh(fso, false); } showOperationSuccessMsg(ctx); @@ -204,7 +204,7 @@ public final class NewActionPolicy extends ActionsPolicy { try { fso = CommandHelper.getFileInfo(ctx, link, false, null); } catch (Throwable ex2) {/**NON BLOCK**/} - onRequestRefreshListener.onRequestRefresh(fso); + onRequestRefreshListener.onRequestRefresh(fso, false); } return Boolean.TRUE; } diff --git a/src/com/cyanogenmod/filemanager/ui/preferences/ThemeRoulette.java b/src/com/cyanogenmod/filemanager/ui/preferences/ThemeRoulette.java index 3f401d48..c64169ce 100644 --- a/src/com/cyanogenmod/filemanager/ui/preferences/ThemeRoulette.java +++ b/src/com/cyanogenmod/filemanager/ui/preferences/ThemeRoulette.java @@ -16,13 +16,10 @@ package com.cyanogenmod.filemanager.ui.preferences; -import android.app.Activity; import android.content.Context; import android.graphics.Paint; -import android.graphics.Point; import android.graphics.drawable.Drawable; import android.util.AttributeSet; -import android.view.Display; import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; @@ -279,11 +276,9 @@ public class ThemeRoulette extends HorizontalScrollView { * @hide */ int getVisibleThemeViewPosition() { - Display display = ((Activity)getContext()).getWindowManager().getDefaultDisplay(); - Point size = new Point(); - display.getSize(size); - - int x = size.x / 2; + int[] rouletteSize = new int[2]; + this.getLocationOnScreen(rouletteSize); + int x = rouletteSize[0] + (this.getWidth() / 2); int width = 0; int[] location = new int[2]; diff --git a/src/com/cyanogenmod/filemanager/ui/preferences/ThemeSelectorPreference.java b/src/com/cyanogenmod/filemanager/ui/preferences/ThemeSelectorPreference.java index 322bf8ce..bb70bfbd 100644 --- a/src/com/cyanogenmod/filemanager/ui/preferences/ThemeSelectorPreference.java +++ b/src/com/cyanogenmod/filemanager/ui/preferences/ThemeSelectorPreference.java @@ -38,6 +38,7 @@ import com.cyanogenmod.filemanager.R; import com.cyanogenmod.filemanager.ui.ThemeManager; import com.cyanogenmod.filemanager.ui.ThemeManager.Theme; import com.cyanogenmod.filemanager.ui.preferences.ThemeRoulette.OnThemeScrollSelectionListener; +import com.cyanogenmod.filemanager.util.AndroidHelper; import com.cyanogenmod.filemanager.util.DialogHelper; import java.util.ArrayList; @@ -190,10 +191,15 @@ public class ThemeSelectorPreference extends Preference implements OnClickListen display.getSize(size); // Set the preference height - int rowHeight = (int)res.getDimension(R.dimen.extra_margin); + int mh = (int)res.getDimension(R.dimen.theme_max_height); + int rowHeight = 0; + if (!AndroidHelper.isTablet(getContext())) { + rowHeight = (int)res.getDimension(R.dimen.extra_margin); + } int[] window = new int[2]; view.getLocationInWindow(window); - view.getLayoutParams().height = size.y - window[1] - rowHeight; + view.getLayoutParams().height = + Math.min(mh, size.y - window[1] - rowHeight); // The button width int minWidth = (int)res.getDimension(R.dimen.themes_min_width_button); diff --git a/src/com/cyanogenmod/filemanager/ui/widgets/DirectoryInlineAutocompleteTextView.java b/src/com/cyanogenmod/filemanager/ui/widgets/DirectoryInlineAutocompleteTextView.java index 498f017b..b674d98c 100644 --- a/src/com/cyanogenmod/filemanager/ui/widgets/DirectoryInlineAutocompleteTextView.java +++ b/src/com/cyanogenmod/filemanager/ui/widgets/DirectoryInlineAutocompleteTextView.java @@ -141,28 +141,25 @@ public class DirectoryInlineAutocompleteTextView } //Ensure data - if (!value.startsWith(FileHelper.ROOT_DIRECTORY)) { + if (!value.startsWith(File.separator)) { currentFilterData.clear(); this.mLastParent = ""; //$NON-NLS-1$ return; } //Get the new parent - String newParent = new File(value).getParent(); - if (newParent == null) { - newParent = FileHelper.ROOT_DIRECTORY; + String newParent = FileHelper.getParentDir(new File(value)); + if (!newParent.endsWith(File.separator)) { + newParent += File.separator; } - if (!newParent.endsWith(FileHelper.ROOT_DIRECTORY)) { - newParent += FileHelper.ROOT_DIRECTORY; - } - if (value.compareTo(FileHelper.ROOT_DIRECTORY) == 0) { - newParent = FileHelper.ROOT_DIRECTORY; + if (value.compareTo(File.separator) == 0) { + newParent = File.separator; currentFilterData.clear(); - } else if (value.endsWith(FileHelper.ROOT_DIRECTORY)) { + } else if (value.endsWith(File.separator)) { //Force the change of parent newParent = new File(value, "a").getParent(); //$NON-NLS-1$ - if (!newParent.endsWith(FileHelper.ROOT_DIRECTORY)) { - newParent += FileHelper.ROOT_DIRECTORY; + if (!newParent.endsWith(File.separator)) { + newParent += File.separator; } currentFilterData.clear(); } else { diff --git a/src/com/cyanogenmod/filemanager/ui/widgets/NavigationView.java b/src/com/cyanogenmod/filemanager/ui/widgets/NavigationView.java index dd15c7ef..f6e71395 100644 --- a/src/com/cyanogenmod/filemanager/ui/widgets/NavigationView.java +++ b/src/com/cyanogenmod/filemanager/ui/widgets/NavigationView.java @@ -25,6 +25,9 @@ import android.os.storage.StorageVolume; import android.util.AttributeSet; import android.util.Log; import android.view.View; +import android.view.animation.AccelerateInterpolator; +import android.view.animation.AlphaAnimation; +import android.view.animation.Animation; import android.widget.AdapterView; import android.widget.ListAdapter; import android.widget.ListView; @@ -835,15 +838,18 @@ public class NavigationView extends RelativeLayout implements final List<FileSystemObject> files = (List<FileSystemObject>)taskParams[0]; NavigationView.this.mAdapterView.post( - new Runnable() { - @Override - public void run() { - onPostExecuteTask( - files, addToHistory, - isNewHistory, hasChanged, - searchInfo, fNewDir, scrollTo); - } - }); + new Runnable() { + @Override + public void run() { + onPostExecuteTask( + files, addToHistory, + isNewHistory, hasChanged, + searchInfo, fNewDir, scrollTo); + + // Do animation + fadeEfect(false); + } + }); return Boolean.TRUE; } @@ -857,10 +863,41 @@ public class NavigationView extends RelativeLayout implements * {@inheritDoc} */ @Override + protected void onPreExecute() { + // Do animation + fadeEfect(true); + } + + + + /** + * {@inheritDoc} + */ + @Override protected void onPostExecute(List<FileSystemObject> files) { - onPostExecuteTask( - files, addToHistory, isNewHistory, - hasChanged, searchInfo, fNewDir, scrollTo); + if (files != null) { + onPostExecuteTask( + files, addToHistory, isNewHistory, + hasChanged, searchInfo, fNewDir, scrollTo); + + // Do animation + fadeEfect(false); + } + } + + /** + * Method that performs a fade animation. + * + * @param out Fade out (true); Fade in (false) + */ + void fadeEfect(boolean out) { + Animation fadeAnim = out ? + new AlphaAnimation(1, 0) : + new AlphaAnimation(0, 1); + fadeAnim.setDuration(50L); + fadeAnim.setFillAfter(true); + fadeAnim.setInterpolator(new AccelerateInterpolator()); + NavigationView.this.startAnimation(fadeAnim); } }; task.execute(fNewDir); @@ -1021,23 +1058,30 @@ public class NavigationView extends RelativeLayout implements FileSystemObject fso = ((FileSystemObjectAdapter)parent.getAdapter()).getItem(position); if (fso instanceof ParentDirectory) { changeCurrentDir(fso.getParent(), true, false, false, null, null); + return; } else if (fso instanceof Directory) { changeCurrentDir(fso.getFullPath(), true, false, false, null, null); + return; } else if (fso instanceof Symlink) { Symlink symlink = (Symlink)fso; if (symlink.getLinkRef() != null && symlink.getLinkRef() instanceof Directory) { changeCurrentDir( symlink.getLinkRef().getFullPath(), true, false, false, null, null); + return; } + + // Open the link ref + fso = symlink.getLinkRef(); + } + + // Open the file (edit or pick) + if (this.mNavigationMode.compareTo(NAVIGATION_MODE.BROWSABLE) == 0) { + // Open the file with the preferred registered app + IntentsActionPolicy.openFileSystemObject(getContext(), fso, false, null, null); } else { - if (this.mNavigationMode.compareTo(NAVIGATION_MODE.BROWSABLE) == 0) { - // Open the file with the preferred registered app - IntentsActionPolicy.openFileSystemObject(getContext(), fso, false, null, null); - } else { - // Request a file pick selection - if (this.mOnFilePickedListener != null) { - this.mOnFilePickedListener.onFilePicked(fso); - } + // Request a file pick selection + if (this.mOnFilePickedListener != null) { + this.mOnFilePickedListener.onFilePicked(fso); } } } catch (Throwable ex) { @@ -1049,26 +1093,30 @@ public class NavigationView extends RelativeLayout implements * {@inheritDoc} */ @Override - public void onRequestRefresh(Object o) { + public void onRequestRefresh(Object o, boolean clearSelection) { if (o instanceof FileSystemObject) { refresh((FileSystemObject)o); } else if (o == null) { refresh(); } - onDeselectAll(); + if (clearSelection) { + onDeselectAll(); + } } /** * {@inheritDoc} */ @Override - public void onRequestRemove(Object o) { + public void onRequestRemove(Object o, boolean clearSelection) { if (o != null && o instanceof FileSystemObject) { removeItem((FileSystemObject)o); } else { - onRequestRefresh(null); + onRequestRefresh(null, clearSelection); + } + if (clearSelection) { + onDeselectAll(); } - onDeselectAll(); } /** diff --git a/src/com/cyanogenmod/filemanager/util/AIDHelper.java b/src/com/cyanogenmod/filemanager/util/AIDHelper.java index 50b3efef..d49f1687 100644 --- a/src/com/cyanogenmod/filemanager/util/AIDHelper.java +++ b/src/com/cyanogenmod/filemanager/util/AIDHelper.java @@ -97,19 +97,25 @@ public final class AIDHelper { } /** - * Method that return AID from his user identifier + * Method that returns the AID from its identifier. + * + * @param id The id + * @return AID The AID, or null if not found + */ + public static AID getAID(int id) { + return sAids.get(id); + } + + /** + * Method that return AID from its user name. * - * @param ctx The current context * @param name The user identifier * @return AID The AID */ - public static AID getAIDFromName(Context ctx, String name) { - // This method is only used by java console under chrooted mode, so - // is safe to caching aids, because sdcards only allow known aids - SparseArray<AID> aids = getAIDs(ctx, false); - int len = aids.size(); + public static AID getAIDFromName(String name) { + int len = sAids.size(); for (int i = 0; i < len; i++) { - AID aid = aids.valueAt(i); + AID aid = sAids.valueAt(i); if (aid.getName().compareTo(name) == 0) { return aid; } @@ -117,4 +123,18 @@ public final class AIDHelper { return new AID(-1, ""); //$NON-NLS-1$ } + /** + * Method that returns the name in safe way + * + * @param id The id + * @return String The name of the AID of null if not found + */ + public static String getNullSafeName(int id) { + AID aid = getAID(id); + if (aid != null) { + return aid.getName(); + } + return null; + } + } diff --git a/src/com/cyanogenmod/filemanager/util/CommandHelper.java b/src/com/cyanogenmod/filemanager/util/CommandHelper.java index 11b6f35f..f79cb9e9 100644 --- a/src/com/cyanogenmod/filemanager/util/CommandHelper.java +++ b/src/com/cyanogenmod/filemanager/util/CommandHelper.java @@ -420,41 +420,6 @@ public final class CommandHelper { } /** - * Method that retrieves the absolute path of a file or directory. - * - * @param context The current context (needed if console == null) - * @param path The short path - * @param console The console in which execute the program. <code>null</code> - * to attach to the default console - * @return String The absolute path of the directory - * @throws FileNotFoundException If the initial directory not exists - * @throws IOException If initial directory couldn't be checked - * @throws InvalidCommandDefinitionException If the command has an invalid definition - * @throws NoSuchFileOrDirectory If the file or directory was not found - * @throws ConsoleAllocException If the console can't be allocated - * @throws InsufficientPermissionsException If an operation requires elevated permissions - * @throws CommandNotFoundException If the command was not found - * @throws OperationTimeoutException If the operation exceeded the maximum time of wait - * @throws ExecutionException If the operation returns a invalid exit code - * @see ResolveLinkExecutable - */ - public static String getAbsolutePath(Context context, String path, Console console) - throws FileNotFoundException, IOException, ConsoleAllocException, - NoSuchFileOrDirectory, InsufficientPermissionsException, - CommandNotFoundException, OperationTimeoutException, - ExecutionException, InvalidCommandDefinitionException { - Console c = ensureConsole(context, console); - ResolveLinkExecutable executable = - c.getExecutableFactory().newCreator().createResolveLinkExecutable(path); - execute(context, executable, c); - FileSystemObject fso = executable.getResult(); - if (fso == null) { - return null; - } - return fso.getFullPath(); - } - - /** * Method that resolves a symlink to its real file system object. * * @param context The current context (needed if console == null) diff --git a/src/com/cyanogenmod/filemanager/util/DialogHelper.java b/src/com/cyanogenmod/filemanager/util/DialogHelper.java index 69960f8e..0dc9965c 100644 --- a/src/com/cyanogenmod/filemanager/util/DialogHelper.java +++ b/src/com/cyanogenmod/filemanager/util/DialogHelper.java @@ -464,7 +464,9 @@ public final class DialogHelper { R.layout.dialog_message, null); TextView vMsg = (TextView)lyMessage.findViewById(R.id.dialog_message); - vMsg.setText(message); + // Dialog need to be filled with at least two lines to fill the background dialog, + // so we add a new additional line to the message + vMsg.setText(message + "\n"); //$NON-NLS-1$ // Apply the current theme Theme theme = ThemeManager.getCurrentTheme(context); diff --git a/src/com/cyanogenmod/filemanager/util/FileHelper.java b/src/com/cyanogenmod/filemanager/util/FileHelper.java index abf4fed0..d4a2bb75 100644 --- a/src/com/cyanogenmod/filemanager/util/FileHelper.java +++ b/src/com/cyanogenmod/filemanager/util/FileHelper.java @@ -16,7 +16,6 @@ package com.cyanogenmod.filemanager.util; -import android.annotation.SuppressLint; import android.content.Context; import android.content.SharedPreferences; import android.content.res.Resources; @@ -161,7 +160,6 @@ public final class FileHelper { * @param size The size in bytes * @return String The human readable size */ - @SuppressLint("DefaultLocale") public static String getHumanReadableSize(long size) { Resources res = FileManagerApplication.getInstance().getResources(); final String format = "%d %s"; //$NON-NLS-1$ @@ -220,6 +218,28 @@ public final class FileHelper { } /** + * Method that returns if the folder if the root directory. + * + * @param folder The folder + * @return boolean if the folder if the root directory + */ + public static boolean isRootDirectory(String folder) { + if (folder == null) return true; + return isRootDirectory(new File(folder)); + } + + /** + * Method that returns if the folder if the root directory. + * + * @param folder The folder + * @return boolean if the folder if the root directory + */ + public static boolean isRootDirectory(File folder) { + if (folder.getPath() == null) return true; + return folder.getPath().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 @@ -290,6 +310,30 @@ public final class FileHelper { } /** + * Method that returns the parent directory of a file/folder + * + * @param path The file/folder + * @return String The parent directory + */ + public static String getParentDir(String path) { + return getParentDir(new File(path)); + } + + /** + * Method that returns the parent directory of a file/folder + * + * @param path The file/folder + * @return String The parent directory + */ + public static String getParentDir(File path) { + String parent = path.getParent(); + if (parent == null) { + parent = FileHelper.ROOT_DIRECTORY; + } + return parent; + } + + /** * Method that evaluates if a path is relative. * * @param src The path to check @@ -735,6 +779,7 @@ public final class FileHelper { * @return String The path with the trailing slash */ public static String addTrailingSlash(String path) { + if (path == null) return null; return path.endsWith(File.separator) ? path : path + File.separator; } @@ -745,6 +790,7 @@ public final class FileHelper { * @return String The path without the trailing slash */ public static String removeTrailingSlash(String path) { + if (path == null) return null; if (path.trim().compareTo(ROOT_DIRECTORY) == 0) return path; if (path.endsWith(File.separator)) { return path.substring(0, path.length()-1); @@ -870,11 +916,10 @@ public final class FileHelper { /** * Method that creates a {@link FileSystemObject} from a {@link File} * - * @param ctx The current context * @param file The file or folder reference * @return FileSystemObject The file system object reference */ - public static FileSystemObject createFileSystemObject(Context ctx, File file) { + public static FileSystemObject createFileSystemObject(File file) { try { // The user and group name of the files. In ChRoot, aosp give restrict access to // this user and group. @@ -885,20 +930,21 @@ public final class FileHelper { // The user and group name of the files. In ChRoot, aosp give restrict access to // this user and group. This applies for permission also. This has no really much // interest if we not allow to change the permissions - AID userAID = AIDHelper.getAIDFromName(ctx, USER); - AID groupAID = AIDHelper.getAIDFromName(ctx, GROUP); + AID userAID = AIDHelper.getAIDFromName(USER); + AID groupAID = AIDHelper.getAIDFromName(GROUP); User user = new User(userAID.getId(), userAID.getName()); Group group = new Group(groupAID.getId(), groupAID.getName()); Permissions perm = Permissions.fromRawString(PERMISSIONS); // Build a directory? + Date lastModified = new Date(file.lastModified()); if (file.isDirectory()) { return new Directory( file.getName(), file.getParent(), user, group, perm, - new Date(file.lastModified())); + lastModified, lastModified, lastModified); // The only date we have } // Build a regular file @@ -907,8 +953,8 @@ public final class FileHelper { file.getName(), file.getParent(), user, group, perm, - new Date(file.lastModified()), - file.length()); + file.length(), + lastModified, lastModified, lastModified); // The only date we have } catch (Exception e) { Log.e(TAG, "Exception retrieving the fso", e); //$NON-NLS-1$ } diff --git a/src/com/cyanogenmod/filemanager/util/MimeTypeHelper.java b/src/com/cyanogenmod/filemanager/util/MimeTypeHelper.java index 01637082..5a6f8689 100644 --- a/src/com/cyanogenmod/filemanager/util/MimeTypeHelper.java +++ b/src/com/cyanogenmod/filemanager/util/MimeTypeHelper.java @@ -233,8 +233,13 @@ public final class MimeTypeHelper { loadMimeTypes(context); } + // Return the symlink ref mime/type icon + if (fso instanceof Symlink && ((Symlink) fso).getLinkRef() != null) { + return getIcon(context, ((Symlink) fso).getLinkRef()); + } + //Check if the argument is a folder - if (fso instanceof Directory || FileHelper.isSymlinkRefDirectory(fso)) { + if (fso instanceof Directory) { return "ic_fso_folder_drawable"; //$NON-NLS-1$ } @@ -264,7 +269,7 @@ public final class MimeTypeHelper { return "fso_type_system_drawable"; //$NON-NLS-1$ } // Check if the fso is executable (but not a symlink) - if (!(fso instanceof Symlink)) { + if (fso.getPermissions() != null && !(fso instanceof Symlink)) { if (fso.getPermissions().getUser().isExecute() || fso.getPermissions().getGroup().isExecute() || fso.getPermissions().getOthers().isExecute()) { @@ -352,6 +357,35 @@ public final class MimeTypeHelper { * Method that returns the mime/type category of the file. * * @param context The current context + * @param ext The extension of the file + * @return MimeTypeCategory The mime/type category + */ + public static final MimeTypeCategory getCategoryFromExt(Context context, String ext) { + // Ensure that have a context + if (context == null && sMimeTypes == null) { + // No category + return MimeTypeCategory.NONE; + } + //Ensure that mime types are loaded + if (sMimeTypes == null) { + loadMimeTypes(context); + } + if (ext != null) { + //Load from the database of mime types + MimeTypeInfo mimeTypeInfo = sMimeTypes.get(ext.toLowerCase()); + if (mimeTypeInfo != null) { + return mimeTypeInfo.mCategory; + } + } + + // No category + return MimeTypeCategory.NONE; + } + + /** + * Method that returns the mime/type category of the file. + * + * @param context The current context * @param file The file * @return MimeTypeCategory The mime/type category */ diff --git a/src/com/cyanogenmod/filemanager/util/MountPointHelper.java b/src/com/cyanogenmod/filemanager/util/MountPointHelper.java index a91affac..e2e7b4c5 100644 --- a/src/com/cyanogenmod/filemanager/util/MountPointHelper.java +++ b/src/com/cyanogenmod/filemanager/util/MountPointHelper.java @@ -36,13 +36,13 @@ public final class MountPointHelper { private static final String TAG = "MountPointHelper"; //$NON-NLS-1$ - private static final List<String> ALLOWED_FS_TYPE = Arrays.asList(new String[]{ - "rootfs", //$NON-NLS-1$ - "tmpfs", //$NON-NLS-1$ - "vfat", //$NON-NLS-1$ - "ext2", //$NON-NLS-1$ - "ext3", //$NON-NLS-1$ - "ext4" //$NON-NLS-1$ + private static final List<String> RESTRICTED_FS_TYPE = Arrays.asList(new String[]{ + "devpts", //$NON-NLS-1$ + "proc", //$NON-NLS-1$ + "sysfs", //$NON-NLS-1$ + "debugfs", //$NON-NLS-1$ + "cgroup", //$NON-NLS-1$ + "tmpfs" //$NON-NLS-1$ }); private static final long MAX_CACHED_TIME = 60000L * 5; @@ -106,7 +106,7 @@ public final class MountPointHelper { } //Sort mount points in reverse order, needed for avoid - //found an incorrect that matches the name + //found an incorrect mount point that matches the name Collections.sort(sMountPoints, new Comparator<MountPoint>() { @Override public int compare(MountPoint lhs, MountPoint rhs) { @@ -198,12 +198,12 @@ public final class MountPointHelper { } /** - * Method that returns if the filesystem can be mounted. + * Method that returns if a filesystem is allowed to be mounted/unmounted (rw/ro). * * @param mp The mount point to check - * @return boolean If the mount point can be mounted + * @return boolean If the mount point can be mounted/unmount (rw/ro) */ public static boolean isMountAllowed(MountPoint mp) { - return ALLOWED_FS_TYPE.contains(mp.getType()); + return !RESTRICTED_FS_TYPE.contains(mp.getType()); } } diff --git a/src/com/cyanogenmod/filemanager/util/ParseHelper.java b/src/com/cyanogenmod/filemanager/util/ParseHelper.java index 43c4b6e7..ef619ac5 100644 --- a/src/com/cyanogenmod/filemanager/util/ParseHelper.java +++ b/src/com/cyanogenmod/filemanager/util/ParseHelper.java @@ -16,8 +16,6 @@ package com.cyanogenmod.filemanager.util; -import android.os.Process; - import com.cyanogenmod.filemanager.model.BlockDevice; import com.cyanogenmod.filemanager.model.CharacterDevice; import com.cyanogenmod.filemanager.model.Directory; @@ -36,21 +34,68 @@ import com.cyanogenmod.filemanager.model.Symlink; import com.cyanogenmod.filemanager.model.User; import com.cyanogenmod.filemanager.model.UserPermission; +import java.io.File; import java.text.ParseException; -import java.text.SimpleDateFormat; import java.util.Date; -import java.util.regex.Matcher; -import java.util.regex.Pattern; /** * A helper class with useful methods for deal with parse of results. */ public final class ParseHelper { - private static final String DATE_PATTERN = - "\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}"; //$NON-NLS-1$ - private static final SimpleDateFormat DATE_FORMAT = - new SimpleDateFormat("yyyy-MM-dd HH:mm"); //$NON-NLS-1$ + // The structure of a terse stat output + // http://mailman.lug.org.uk/pipermail/nottingham/2007-January/009303.html + private static enum TERSE_STAT_STRUCT { + FILENAME, + SIZE, + BLOCKS, + RAW_MODE, + UID, + GID, + DEVICE, + INODE, + HARD_LINKS, + MAJOR_DEVICE_TYPE, + MINOR_DEVICE_TYPE, + ACCESS, + MODIFY, + CHANGE, + IOBLOCK + } + private static int TERSE_STAT_STRUCT_LENGTH = TERSE_STAT_STRUCT.values().length; + + // The structure of raw mode in hex format (defined with octal values) + // http://unix.stackexchange.com/questions/39716/what-is-raw-mode-in-hex-from-stat-output + private static enum RMIHF { + S_IFMT (0170000), //bit mask for the file type bit fields + S_IFSOCK (0140000), //socket + S_IFLNK (0120000), //symbolic link + S_IFREG (0100000), //regular file + S_IFBLK (0060000), //block device + S_IFDIR (0040000), //directory + S_IFCHR (0020000), //character device + S_IFIFO (0010000), //FIFO + S_ISUID (0004000), //set UID bit + S_ISGID (0002000), //set-group-ID bit (see below) + S_ISVTX (0001000), //sticky bit (see below) + S_IRWXU (0000700), //mask for file owner permissions + S_IRUSR (0000400), //owner has read permission + S_IWUSR (0000200), //owner has write permission + S_IXUSR (0000100), //owner has execute permission + S_IRWXG (0000070), //mask for group permissions + S_IRGRP (0000040), //group has read permission + S_IWGRP (0000020), //group has write permission + S_IXGRP (0000010), //group has execute permission + S_IRWXO (0000007), //mask for permissions for others (not in group) + S_IROTH (0000004), //others have read permission + S_IWOTH (0000002), //others have write permission + S_IXOTH (0000001); //others have execute permission + + final int mValue; + RMIHF(int value) { + this.mValue = value; + } + } /** * Constructor of <code>ParseHelper</code>. @@ -60,166 +105,105 @@ public final class ParseHelper { } /** - * Method that parses and creates a {@link FileSystemObject} references from - * a unix string style line. + * Method that parses the output of a terse stat command.<br/> + * <br/> + * The stat terse format is described as:<br/> + * <br/> + * <code/> + * terse format = "%n %s %b %f %u %g %D %i %h %t %T %X %Y %Z %o": + * filename + * size(bytes) + * blocks + * Raw_mode(HEX) + * Uid + * Gid + * Device(HEX) + * Inode + * hard_links + * major_device_type(HEX) + * minor_device_type(HEX) + * Access(Epoch seconds) + * Modify(Epoch seconds) + * Change(Epoch seconds) + * IOblock + * </code> * - * @param parent The parent of the object - * @param src The unix string style line + * @param output Line with the output of a line of a stat command * @return FileSystemObject The file system object reference - * @throws ParseException If the line can't be parsed - * @see #toFileSystemObject(String, String, boolean) + * @throws ParseException If the permissions can't be parsed + * @{link "http://www.gnu.org/software/coreutils/manual/html_node/stat-invocation.html"} */ - public static FileSystemObject toFileSystemObject( - final String parent, final String src) throws ParseException { - return toFileSystemObject(parent, src, false); - } + public static FileSystemObject parseStatOutput(final String output) throws ParseException { - /** - * Method that parses and creates a {@link FileSystemObject} references from - * a unix string style line. - * - * @param parent The parent of the object - * @param src The unix string style line - * @param quick Do not resolve data (User and Group doesn't have a valid reference) - * @return FileSystemObject The file system object reference - * @throws ParseException If the line can't be parsed - */ - // - //<permission> <user> <group> <size> <last modified> <name> - //-rw-r--r-- root root 229 2012-05-04 01:51 boot.txt - //drwxr-xr-x root root 2012-05-04 01:51 acct - //lrwxrwxrwx root root 2012-05-04 01:51 etc -> /system/etc - //crw-rw-rw- system system 10, 243 2012-05-04 01:51 HPD - //brw------- root root 7, 0 2012-05-04 01:51 loop0 - //srw------- root root 0 2012-05-04 01:51 socket - //prw------- root root 0 2012-05-04 01:51 pipe - // - // - //<permissions>: http://en.wikipedia.org/wiki/File_system_permissions - //-rw-r--r-- - // - //(char 1) - // - denotes a regular file - // d denotes a directory - // b denotes a block special file - // c denotes a character special file - // l denotes a symbolic link - // p denotes a named pipe - // s denotes a domain socket - //(char 2-10) - // r if the read bit is set, - if it is not. - // w if the write bit is set, - if it is not. - // x if the execute bit is set, - if it is not. - //(char 4) - // s if the setuid bit and executable bit are set - // S if the setuid bit is set, but not executable bit - //(char 7) - // s if the setgid bit and executable bit are set - // S if the setgid bit is set, but not executable bit - //(char 10) - // t if the sticky bit and executable bit are set - // T if the sticky bit is set, but not executable bit - // - //<user>: User proprietary of the file - //<group>: Group proprietary of the file - //<last modified>: - //<size>: - // - if object is a type regular file, size of the file in bytes - // - if object is a block or a character device, mayor and minor device number (7, 0) - // - if object is a pipe or a socket, always is 0 - // - if object is a directory or symlink, no value is present - // - //<last modification>: Last file modification (in Android always yyyy-MM-dd HH:mm. - // 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 { - - String raw = src; - - //0.- Object Type - char type = raw.charAt(0); - - //1.- Extract permissions - String szPermissions = raw.substring(0, 10); - Permissions oPermissions = parsePermission(szPermissions); - raw = raw.substring(11); - - //2.- Extract the last modification date - Pattern pattern = Pattern.compile(DATE_PATTERN); - Matcher matcher = pattern.matcher(raw); - if (!matcher.find()) { - throw new ParseException( - "last modification date not found in " + raw, 0); //$NON-NLS-1$ - } - Date dLastModified = null; try { - dLastModified = DATE_FORMAT.parse(matcher.group()); - } catch (ParseException pEx) { - throw new ParseException(pEx.getMessage(), 0); - } - String szStartLine = raw.substring(0, matcher.start()).trim(); - String szEndLine = raw.substring(matcher.end()).trim(); - - //3.- Extract user (user name has no spaces. - int pos = szStartLine.indexOf(" "); //$NON-NLS-1$ - String szUser = szStartLine.substring(0, pos).trim(); - szStartLine = szStartLine.substring(pos).trim(); - User oUser = null; - if (!quick) { - oUser = new User(Process.getUidForName(szUser), szUser); - } else { - oUser = new User(-1, szUser); - } - - //4.- Extract group (group name has no spaces. - pos = szStartLine.indexOf(" "); //$NON-NLS-1$ - String szGroup = szStartLine.substring(0, (pos == -1) ? szStartLine.length() : pos).trim(); - szStartLine = szStartLine.substring((pos == -1) ? szStartLine.length() : pos).trim(); - Group oGroup = null; - if (!quick) { - oGroup = new Group(Process.getGidForName(szGroup), szGroup); - } else { - oGroup = new Group(-1, szGroup); - } - - //5.- Extract size - long lSize = 0; - if (szStartLine.length() != 0) { - //At this moment only size of files is interesting. Mayor/minor block - //devices are no required - if (type == RegularFile.UNIX_ID) { - try { - lSize = Long.parseLong(szStartLine); - } catch (NumberFormatException nfEx) { - throw new ParseException(nfEx.getMessage(), 0); - } + // Split the terse line + String[] data = output.split(" "); //$NON-NLS-1$ + boolean valid = true; + try { + getTerseStatInt(data, TERSE_STAT_STRUCT.IOBLOCK); + } catch (Exception e) { + valid = false; + } + if (valid && output.startsWith("stat:")) { //$NON-NLS-1$ + throw new ParseException( + String.format("Stat failed: %s", output), 0); //$NON-NLS-1$ + } + if (valid && data.length < TERSE_STAT_STRUCT.values().length) { + throw new ParseException( + String.format("Not enought data: %s", output), 0); //$NON-NLS-1$ + } + // Parse the line + String raw = getTerseRawPermissions(data); + char type = raw.charAt(0); + Permissions permissions = parsePermission(raw); + Date lastAccessedTime = getTerseStatDate(data, TERSE_STAT_STRUCT.ACCESS); + Date lastModifiedTime = getTerseStatDate(data, TERSE_STAT_STRUCT.MODIFY); + Date lastChangedTime = getTerseStatDate(data, TERSE_STAT_STRUCT.CHANGE); + int uid = getTerseStatInt(data, TERSE_STAT_STRUCT.UID); + User user = new User(uid, AIDHelper.getNullSafeName(uid)); + int gid = getTerseStatInt(data, TERSE_STAT_STRUCT.GID); + Group group = new Group(gid, AIDHelper.getNullSafeName(gid)); + long size = getTerseStatLong(data, TERSE_STAT_STRUCT.SIZE); + File file = new File(getTerseStatName(data)); + String name = file.getName(); + String parentDir = FileHelper.getParentDir(file); + + // Create the file system object + FileSystemObject fso = + createObject( + parentDir, type, name, null, user, group, permissions, + size, lastAccessedTime, lastModifiedTime, lastChangedTime); + + // Check if its a symlink + if (type == Symlink.UNIX_ID) { + // Extract the ref info + Symlink symlink = (Symlink)fso; + File refFile = file.getCanonicalFile(); + char refType = refFile.isDirectory() ? Directory.UNIX_ID : RegularFile.UNIX_ID; + String refName = refFile.getName(); + String refParentDir = FileHelper.getParentDir(refFile); + Date refLastModifiedTime = new Date(refFile.lastModified()); + long refSize = refFile.length(); + + // Create the ref file system object + FileSystemObject refFso = + createObject( + refParentDir, refType, refName, null, null, null, null, + refSize, null, refLastModifiedTime, null); + + // Update the symlink ref + symlink.setLink(refParentDir); + symlink.setLinkRef(refFso); } - } - //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" - String[] names = szEndLine.split(" -> "); //$NON-NLS-1$ - szName = names[0].trim(); - szLink = names[1].trim(); - } + // Parsed + return fso; - // All the line is parsed now. Create the object - FileSystemObject fso = createObject( - parent, type, szName, szLink, oUser, oGroup, - oPermissions, dLastModified, lSize); - return fso; + } catch (Exception ex) { + // Notify the exception when parsing the data + throw new ParseException(ex.getMessage(), 0); + } } /** @@ -259,64 +243,19 @@ public final class ParseHelper { } /** - * Method that creates the appropriate file system object. - * - * @param parentDir The parent directory - * @param type The raw char type of the file system object - * @param name The name of the object - * @param link The real file that this symlink is point to - * @param user The user proprietary of the object - * @param group The group proprietary of the object - * @param permissions The permissions of the object - * @param lastModifiedTime The last time that the object was modified - * @param size The size in bytes of the object - * @return FileSystemObject The file system object reference - * @throws ParseException If type couldn't be translate into a reference - * file system object - */ - private static FileSystemObject createObject( - String parentDir, char type, String name, String link, User user, - Group group, Permissions permissions, Date lastModifiedTime, long size) - throws ParseException { - - if (type == RegularFile.UNIX_ID) { - return new RegularFile( - name, parentDir, user, group, permissions, lastModifiedTime, size); - } - if (type == Directory.UNIX_ID) { - return new Directory(name, parentDir, user, group, permissions, lastModifiedTime); - } - if (type == Symlink.UNIX_ID) { - return new Symlink(name, link, parentDir, user, group, permissions, lastModifiedTime); - } - if (type == BlockDevice.UNIX_ID) { - return new BlockDevice(name, parentDir, user, group, permissions, lastModifiedTime); - } - if (type == CharacterDevice.UNIX_ID) { - return new CharacterDevice(name, parentDir, user, group, permissions, lastModifiedTime); - } - if (type == NamedPipe.UNIX_ID) { - return new NamedPipe(name, parentDir, user, group, permissions, lastModifiedTime); - } - if (type == DomainSocket.UNIX_ID) { - return new DomainSocket(name, parentDir, user, group, permissions, lastModifiedTime); - } - throw new ParseException("no file system object", 0); //$NON-NLS-1$ - } - - /** * Method that parse a disk usage line. * * @param src The disk usage line * @return DiskUsage The disk usage information * @throws ParseException If the line can't be parsed */ - // Filesystem Size Used Free Blksize - // /dev 414M 48K 414M 4096 - // /mnt/asec 414M 0K 414M 4096 - // /mnt/secure/asec: Permission denied public static DiskUsage toDiskUsage(final String src) throws ParseException { + // Filesystem Size Used Free Blksize + // /dev 414M 48K 414M 4096 + // /mnt/asec 414M 0K 414M 4096 + // /mnt/secure/asec: Permission denied + try { final int fields = 5; @@ -351,14 +290,13 @@ public final class ParseHelper { * @return MountPoint The mount point information * @throws ParseException If the line can't be parsed */ - // rootfs / rootfs ro,relatime 0 0 - // tmpfs /dev tmpfs rw,nosuid,relatime,mode=755 0 0 - // devpts /dev/pts devpts rw,relatime,mode=600 0 0 - // /dev/block/vold/179:25 /mnt/emmc vfat rw,dirsync,nosuid,nodev,noexec,relatime,uid=1000, \ - // gid=1015,fmask=0702,dmask=0702,allow_utime=0020,codepage=cp437,iocharset=iso8859-1, \ - // shortname=mixed,utf8,errors=remount-ro 0 0 public static MountPoint toMountPoint(final String src) throws ParseException { + // rootfs / rootfs ro,relatime 0 0 + // tmpfs /dev tmpfs rw,nosuid,relatime,mode=755 0 0 + // devpts /dev/pts devpts rw,relatime,mode=600 0 0 + // /dev/block/vold/179:25 /mnt/emmc vfat rw,dirsync,nosuid,nodev,noexec,relatime,uid=1000, gid=1015,fmask=0702,dmask=0702,allow_utime=0020,codepage=cp437,iocharset=iso8859-1, shortname=mixed,utf8,errors=remount-ro 0 0 + try { //Extract all the info @@ -389,6 +327,64 @@ public final class ParseHelper { } /** + * Method that creates the appropriate file system object. + * + * @param parentDir The parent directory + * @param type The raw char type of the file system object + * @param name The name of the object + * @param link The real file that this symlink is point to + * @param user The user proprietary of the object + * @param group The group proprietary of the object + * @param permissions The permissions of the object + * @param size The size in bytes of the object + * @param lastAccessedTime The last time that the object was accessed + * @param lastModifiedTime The last time that the object was modified + * @param lastChangedTime The last time that the object was changed + * @return FileSystemObject The file system object reference + * @throws ParseException If type couldn't be translate into a reference + * file system object + */ + private static FileSystemObject createObject( + String parentDir, char type, String name, String link, User user, + Group group, Permissions permissions, long size, + Date lastAccessedTime, Date lastModifiedTime, Date lastChangedTime) + throws ParseException { + + String parent = (parentDir == null) ? FileHelper.ROOT_DIRECTORY : parentDir; + + if (type == RegularFile.UNIX_ID) { + return new RegularFile( + name, parent, user, group, permissions, size, + lastAccessedTime, lastModifiedTime, lastChangedTime); + } + if (type == Directory.UNIX_ID) { + return new Directory(name, parent, user, group, permissions, + lastAccessedTime, lastModifiedTime, lastChangedTime); + } + if (type == Symlink.UNIX_ID) { + return new Symlink(name, link, parent, user, group, permissions, + lastAccessedTime, lastModifiedTime, lastChangedTime); + } + if (type == BlockDevice.UNIX_ID) { + return new BlockDevice(name, parent, user, group, permissions, + lastAccessedTime, lastModifiedTime, lastChangedTime); + } + if (type == CharacterDevice.UNIX_ID) { + return new CharacterDevice(name, parent, user, group, permissions, + lastAccessedTime, lastModifiedTime, lastChangedTime); + } + if (type == NamedPipe.UNIX_ID) { + return new NamedPipe(name, parent, user, group, permissions, + lastAccessedTime, lastModifiedTime, lastChangedTime); + } + if (type == DomainSocket.UNIX_ID) { + return new DomainSocket(name, parent, user, group, permissions, + lastAccessedTime, lastModifiedTime, lastChangedTime); + } + throw new ParseException("no file system object", 0); //$NON-NLS-1$ + } + + /** * Method that converts to bytes the string representation * of a size (10M, 1G, 0K, ...). * @@ -396,20 +392,140 @@ public final class ParseHelper { * @return long The size in bytes */ private static long toBytes(String size) { - long bytes = Long.parseLong(size.substring(0, size.length() - 1)); + double bytes = Double.parseDouble(size.substring(0, size.length() - 1)); String unit = size.substring(size.length() - 1); if (unit.compareToIgnoreCase("G") == 0) { //$NON-NLS-1$ - return bytes * 1024 * 1024 * 1024; + return (long)(bytes * 1024 * 1024 * 1024); } if (unit.compareToIgnoreCase("M") == 0) { //$NON-NLS-1$ - return bytes * 1024 * 1024; + return (long)(bytes * 1024 * 1024); } if (unit.compareToIgnoreCase("K") == 0) { //$NON-NLS-1$ - return bytes * 1024; + return (long)(bytes * 1024); } //Don't touch - return bytes; + return (long)bytes; + } + + /** + * Method that extract a date from a terse stat ouput. + * + * @param stat The terse stat data + * @param e The position of the date + * @return Date The date + */ + private static Date getTerseStatDate(String[] stat, TERSE_STAT_STRUCT e) { + int cc = stat.length; + return new Date( + Long.parseLong(stat[cc - (TERSE_STAT_STRUCT_LENGTH - e.ordinal())]) * 1000L); + } + + /** + * Method that extract a integer value from a terse stat ouput. + * + * @param stat The terse stat data + * @param e The position of the date + * @return int The integer value + */ + private static int getTerseStatInt(String[] stat, TERSE_STAT_STRUCT e) { + int cc = stat.length; + return Integer.parseInt(stat[cc - (TERSE_STAT_STRUCT_LENGTH - e.ordinal())]); + } + + /** + * Method that extract a long value from a terse stat ouput. + * + * @param stat The terse stat data + * @param e The position of the date + * @return long The long value + */ + private static long getTerseStatLong(String[] stat, TERSE_STAT_STRUCT e) { + int cc = stat.length; + return Long.parseLong(stat[cc - (TERSE_STAT_STRUCT_LENGTH - e.ordinal())]); + } + + /** + * Method that returns the name of file + * + * @param stat The terse stat data + * @return String The name of file + */ + private static String getTerseStatName(String[] stat) { + int cc = stat.length; + int to = cc - (TERSE_STAT_STRUCT_LENGTH - TERSE_STAT_STRUCT.SIZE.ordinal()); + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < to; i++) { + sb.append(stat[i]); + if (i < to-1) { + sb.append(" "); //$NON-NLS-1$ + } + } + return sb.toString(); + } + + /** + * Method that retrieve the raw string with the permissions. + * + * @param stat The terse stat data + * @return String The raw string + */ + private static String getTerseRawPermissions(String[] stat) { + int cc = stat.length; + int rawInt = Integer.parseInt( + stat[cc - (TERSE_STAT_STRUCT_LENGTH - TERSE_STAT_STRUCT.RAW_MODE.ordinal())],16); + + // Extract the type + char t = RegularFile.UNIX_ID; + if (RMIHF.S_IFSOCK.mValue == (rawInt & RMIHF.S_IFSOCK.mValue)) { + t = DomainSocket.UNIX_ID; + } else if (RMIHF.S_IFLNK.mValue == (rawInt & RMIHF.S_IFLNK.mValue)) { + t = Symlink.UNIX_ID; + } else if (RMIHF.S_IFREG.mValue == (rawInt & RMIHF.S_IFREG.mValue)) { + t = RegularFile.UNIX_ID; + } else if (RMIHF.S_IFBLK.mValue == (rawInt & RMIHF.S_IFBLK.mValue)) { + t = BlockDevice.UNIX_ID; + } else if (RMIHF.S_IFDIR.mValue == (rawInt & RMIHF.S_IFDIR.mValue)) { + t = Directory.UNIX_ID; + } else if (RMIHF.S_IFCHR.mValue == (rawInt & RMIHF.S_IFCHR.mValue)) { + t = CharacterDevice.UNIX_ID; + } else if (RMIHF.S_IFIFO.mValue == (rawInt & RMIHF.S_IFIFO.mValue)) { + t = NamedPipe.UNIX_ID; + } + + // Extract User/Group/Others + boolean us = RMIHF.S_ISUID.mValue == (rawInt & RMIHF.S_ISUID.mValue); + boolean ur = RMIHF.S_IRUSR.mValue == (rawInt & RMIHF.S_IRUSR.mValue); + boolean uw = RMIHF.S_IWUSR.mValue == (rawInt & RMIHF.S_IWUSR.mValue); + boolean ux = RMIHF.S_IXUSR.mValue == (rawInt & RMIHF.S_IXUSR.mValue); + boolean gs = RMIHF.S_ISGID.mValue == (rawInt & RMIHF.S_ISGID.mValue); + boolean gr = RMIHF.S_IRGRP.mValue == (rawInt & RMIHF.S_IRGRP.mValue); + boolean gw = RMIHF.S_IWGRP.mValue == (rawInt & RMIHF.S_IWGRP.mValue); + boolean gx = RMIHF.S_IXGRP.mValue == (rawInt & RMIHF.S_IXGRP.mValue); + boolean os = RMIHF.S_ISVTX.mValue == (rawInt & RMIHF.S_ISVTX.mValue); + boolean or = RMIHF.S_IROTH.mValue == (rawInt & RMIHF.S_IROTH.mValue); + boolean ow = RMIHF.S_IWOTH.mValue == (rawInt & RMIHF.S_IWOTH.mValue); + boolean ox = RMIHF.S_IXOTH.mValue == (rawInt & RMIHF.S_IXOTH.mValue); + + // Build the raw string + StringBuilder sb = new StringBuilder(); + sb.append(t); + sb.append(ur ? Permission.READ : Permission.UNASIGNED); + sb.append(uw ? Permission.WRITE : Permission.UNASIGNED); + sb.append(us ? (ux ? + UserPermission.SETUID_E : UserPermission.SETUID) + : (ux ? Permission.EXECUTE : Permission.UNASIGNED)); + sb.append(gr ? Permission.READ : Permission.UNASIGNED); + sb.append(gw ? Permission.WRITE : Permission.UNASIGNED); + sb.append(gs ? (gx ? + GroupPermission.SETGID_E : GroupPermission.SETGID) + : (gx ? Permission.EXECUTE : Permission.UNASIGNED)); + sb.append(or ? Permission.READ : Permission.UNASIGNED); + sb.append(ow ? Permission.WRITE : Permission.UNASIGNED); + sb.append(os ? (ox ? + OthersPermission.STICKY_E : OthersPermission.STICKY) + : (ox ? Permission.EXECUTE : Permission.UNASIGNED)); + return sb.toString(); } } diff --git a/tests/src/com/cyanogenmod/filemanager/commands/shell/CompressCommandTest.java b/tests/src/com/cyanogenmod/filemanager/commands/shell/CompressCommandTest.java index 2c02732e..dc46d6a9 100644 --- a/tests/src/com/cyanogenmod/filemanager/commands/shell/CompressCommandTest.java +++ b/tests/src/com/cyanogenmod/filemanager/commands/shell/CompressCommandTest.java @@ -138,21 +138,26 @@ public class CompressCommandTest extends AbstractConsoleTest { CompressExecutable cmd = CommandHelper.compress( getContext(), mode, dst, ARCHIVE_DATA, new AsyncResultListener() { + @Override public void onAsyncStart() { /**NON BLOCK**/ } + @Override public void onAsyncEnd(boolean cancelled) { synchronized (CompressCommandTest.this.mSync) { CompressCommandTest.this.mNormalEnd = true; CompressCommandTest.this.mSync.notify(); } } + @Override public void onAsyncExitCode(int exitCode) { /**NON BLOCK**/ } + @Override public void onException(Exception cause) { fail(String.valueOf(cause)); } + @Override public void onPartialResult(Object result) { CompressCommandTest.this.mNewPartialData = true; Log.d(TAG, (String)result); @@ -199,21 +204,26 @@ public class CompressCommandTest extends AbstractConsoleTest { cmd = CommandHelper.compress( getContext(), mode, COMPRESS_DATA_DST, new AsyncResultListener() { + @Override public void onAsyncStart() { /**NON BLOCK**/ } + @Override public void onAsyncEnd(boolean cancelled) { synchronized (CompressCommandTest.this.mSync) { CompressCommandTest.this.mNormalEnd = true; CompressCommandTest.this.mSync.notify(); } } + @Override public void onAsyncExitCode(int exitCode) { /**NON BLOCK**/ } + @Override public void onException(Exception cause) { fail(String.valueOf(cause)); } + @Override public void onPartialResult(Object result) { CompressCommandTest.this.mNewPartialData = true; Log.d(TAG, (String)result); diff --git a/tests/src/com/cyanogenmod/filemanager/commands/shell/ExecCommandTest.java b/tests/src/com/cyanogenmod/filemanager/commands/shell/ExecCommandTest.java index 7cfd0964..a456c059 100644 --- a/tests/src/com/cyanogenmod/filemanager/commands/shell/ExecCommandTest.java +++ b/tests/src/com/cyanogenmod/filemanager/commands/shell/ExecCommandTest.java @@ -16,8 +16,6 @@ package com.cyanogenmod.filemanager.commands.shell; -import java.io.OutputStream; - import android.os.Environment; import android.test.suitebuilder.annotation.MediumTest; @@ -26,6 +24,8 @@ import com.cyanogenmod.filemanager.commands.WriteExecutable; import com.cyanogenmod.filemanager.model.Permissions; import com.cyanogenmod.filemanager.util.CommandHelper; +import java.io.OutputStream; + /** * A class for testing exec command. * @@ -81,20 +81,25 @@ public class ExecCommandTest extends AbstractConsoleTest { // Execute the test program this.mNewPartialData = false; CommandHelper.exec(getContext(), EXEC_CMD, new AsyncResultListener() { + @Override public void onAsyncStart() { /**NON BLOCK**/ } + @Override public void onAsyncEnd(boolean cancelled) { synchronized (ExecCommandTest.this.mSync) { ExecCommandTest.this.mSync.notify(); } } + @Override public void onAsyncExitCode(int exitCode) { /**NON BLOCK**/ } + @Override public void onException(Exception cause) { fail(String.valueOf(cause)); } + @Override public void onPartialResult(Object results) { ExecCommandTest.this.mNewPartialData = true; } diff --git a/tests/src/com/cyanogenmod/filemanager/commands/shell/FindCommandTest.java b/tests/src/com/cyanogenmod/filemanager/commands/shell/FindCommandTest.java index 46ce9daa..d12b69e4 100644 --- a/tests/src/com/cyanogenmod/filemanager/commands/shell/FindCommandTest.java +++ b/tests/src/com/cyanogenmod/filemanager/commands/shell/FindCommandTest.java @@ -16,9 +16,6 @@ package com.cyanogenmod.filemanager.commands.shell; -import java.util.ArrayList; -import java.util.List; - import android.os.Environment; import android.test.suitebuilder.annotation.LargeTest; @@ -28,6 +25,10 @@ import com.cyanogenmod.filemanager.model.FileSystemObject; import com.cyanogenmod.filemanager.model.Query; import com.cyanogenmod.filemanager.util.CommandHelper; +import java.io.File; +import java.util.ArrayList; +import java.util.List; + /** * A class for testing find command. * @@ -36,8 +37,12 @@ import com.cyanogenmod.filemanager.util.CommandHelper; public class FindCommandTest extends AbstractConsoleTest { private static final String FIND_PATH = - Environment.getDataDirectory().getAbsolutePath(); - private static final String FIND_TERM_PARTIAL = "shared"; //$NON-NLS-1$ + Environment.getRootDirectory().getAbsolutePath(); + private static final String FIND_TERM_PARTIAL = "build"; //$NON-NLS-1$ + + private static final File TEST_FILE = + new File (Environment.getRootDirectory(), + "build.prop"); //$NON-NLS-1$ /** * @hide @@ -73,21 +78,26 @@ public class FindCommandTest extends AbstractConsoleTest { final List<FileSystemObject> files = new ArrayList<FileSystemObject>(); AsyncResultExecutable cmd = CommandHelper.findFiles(getContext(), FIND_PATH, query, new AsyncResultListener() { + @Override public void onAsyncStart() { /**NON BLOCK**/ } + @Override public void onAsyncEnd(boolean cancelled) { synchronized (FindCommandTest.this.mSync) { FindCommandTest.this.mNormalEnd = true; FindCommandTest.this.mSync.notify(); } } + @Override public void onAsyncExitCode(int exitCode) { /**NON BLOCK**/ } + @Override public void onException(Exception cause) { fail(String.valueOf(cause)); } + @Override @SuppressWarnings("unchecked") public void onPartialResult(Object results) { FindCommandTest.this.mNewPartialData = true; @@ -105,6 +115,16 @@ public class FindCommandTest extends AbstractConsoleTest { assertTrue("no new partial data", this.mNewPartialData); //$NON-NLS-1$ assertNotNull("files==null", files); //$NON-NLS-1$ assertTrue("no objects returned", files.size() > 0); //$NON-NLS-1$ + boolean found = false; + int cc = files.size(); + for (int i = 0; i < cc; i++) { + FileSystemObject fso = files.get(i); + if (fso.getParent().compareTo(TEST_FILE.getParent()) == 0 && + fso.getName().compareTo(TEST_FILE.getName()) == 0) { + found = true; + } + } + assertTrue(String.format("test file %s not found", TEST_FILE), found); //$NON-NLS-1$ } } diff --git a/tests/src/com/cyanogenmod/filemanager/commands/shell/FolderUsageCommandTest.java b/tests/src/com/cyanogenmod/filemanager/commands/shell/FolderUsageCommandTest.java index 6a9b0ed7..fca1b04a 100644 --- a/tests/src/com/cyanogenmod/filemanager/commands/shell/FolderUsageCommandTest.java +++ b/tests/src/com/cyanogenmod/filemanager/commands/shell/FolderUsageCommandTest.java @@ -75,21 +75,26 @@ public class FolderUsageCommandTest extends AbstractConsoleTest { this.mUsage = null; AsyncResultExecutable cmd = CommandHelper.getFolderUsage(getContext(), PATH, new AsyncResultListener() { + @Override public void onAsyncStart() { /**NON BLOCK**/ } + @Override public void onAsyncEnd(boolean cancelled) { synchronized (FolderUsageCommandTest.this.mSync) { FolderUsageCommandTest.this.mNormalEnd = true; FolderUsageCommandTest.this.mSync.notify(); } } + @Override public void onAsyncExitCode(int exitCode) { /**NON BLOCK**/ } + @Override public void onException(Exception cause) { fail(String.valueOf(cause)); } + @Override public void onPartialResult(Object result) { FolderUsageCommandTest.this.mNewPartialData = true; try { diff --git a/tests/src/com/cyanogenmod/filemanager/commands/shell/ListCommandTest.java b/tests/src/com/cyanogenmod/filemanager/commands/shell/ListCommandTest.java index 5fcc8bc1..7b3e5873 100644 --- a/tests/src/com/cyanogenmod/filemanager/commands/shell/ListCommandTest.java +++ b/tests/src/com/cyanogenmod/filemanager/commands/shell/ListCommandTest.java @@ -16,22 +16,18 @@ package com.cyanogenmod.filemanager.commands.shell; -import java.util.List; - import android.test.suitebuilder.annotation.MediumTest; import android.test.suitebuilder.annotation.SmallTest; -import com.cyanogenmod.filemanager.model.BlockDevice; -import com.cyanogenmod.filemanager.model.CharacterDevice; import com.cyanogenmod.filemanager.model.Directory; -import com.cyanogenmod.filemanager.model.DomainSocket; import com.cyanogenmod.filemanager.model.FileSystemObject; -import com.cyanogenmod.filemanager.model.NamedPipe; import com.cyanogenmod.filemanager.model.RegularFile; import com.cyanogenmod.filemanager.model.Symlink; import com.cyanogenmod.filemanager.util.CommandHelper; import com.cyanogenmod.filemanager.util.FileHelper; +import java.util.List; + /** * A class for testing list command. * @@ -90,21 +86,16 @@ public class ListCommandTest extends AbstractConsoleTest { public void testParse() throws Exception { ListCommand cmd = new ListCommand(LS_PATH, getConsole()); String in = - "drwxr-xr-x root root 2012-05-04 01:51 acct\n" + //$NON-NLS-1$ - "-rw-r--r-- root root2 229 2012-05-04 01:51 boot.txt\n" + //$NON-NLS-1$ - "lrwxrwxrwx root root 2012-05-04 01:51 d -> " //$NON-NLS-1$ - + "/sys/kernel/debug\n" + //$NON-NLS-1$ - "prw-r--r-- root root 0 2012-05-04 01:51 pipe\n" + //$NON-NLS-1$ - "srw-r--r-- root root 0 2012-05-04 01:51 socket\n" + //$NON-NLS-1$ - "brw------- root root 7, 0 2012-05-04 01:51 loop0\n" + //$NON-NLS-1$ - "crw------- root root 4, 64 2012-05-04 01:51 ttyS0\n" + //$NON-NLS-1$ - "-rwsr-sr-t root root 229 2012-05-04 01:51 permission1\n" + //$NON-NLS-1$ - "-rwSr-Sr-T root root 229 2012-05-04 01:51 permission2"; //$NON-NLS-1$ + "/acct 0 0 41ed 0 0 d 1054 3 0 0 1357390899 1357390899 1357390899 4096\n" + //$NON-NLS-1$ + "/init.cm.rc 1238 8 81e8 0 0 1 370 1 0 0 1357390899 1357390899 1357390899 4096\n" + //$NON-NLS-1$ + "/vendor 14 0 a1ff 0 0 1 1052 1 0 0 1357390899 1357390899 1357390899 4096\n" + //$NON-NLS-1$ + "/cache 4096 8 41f9 1000 2001 b307 2 5 0 0 0 1357390900 1357390900 4096\n"; //$NON-NLS-1$ + String err = ""; //$NON-NLS-1$ cmd.parse(in, err); List<FileSystemObject> files = cmd.getResult(); assertNotNull("files==null", files); //$NON-NLS-1$ - assertTrue("length!=9", files.size() == 9); //$NON-NLS-1$ + assertTrue("length!=4", files.size() == 4); //$NON-NLS-1$ assertTrue( "files(0) is not a directory", //$NON-NLS-1$ files.get(0) instanceof Directory); @@ -114,77 +105,22 @@ public class ListCommandTest extends AbstractConsoleTest { assertTrue( "files(2) is not a symlink", //$NON-NLS-1$ files.get(2) instanceof Symlink); + assertNotNull( + "files(2) linkref is null", //$NON-NLS-1$ + ((Symlink)files.get(2)).getLinkRef()); assertTrue( - "files(3) is not a named pipe", //$NON-NLS-1$ - files.get(3) instanceof NamedPipe); - assertTrue( - "files(4) is not a domain socket", //$NON-NLS-1$ - files.get(4) instanceof DomainSocket); - assertTrue( - "files(5) is not a block device", //$NON-NLS-1$ - files.get(5) instanceof BlockDevice); - assertTrue( - "files(6) is not a character device", //$NON-NLS-1$ - files.get(6) instanceof CharacterDevice); - assertTrue( - "files(0) != name", //$NON-NLS-1$ - files.get(0).getName().compareTo("acct") == 0); //$NON-NLS-1$ - assertTrue( - "files(2) != name", //$NON-NLS-1$ - files.get(2).getName().compareTo("d") == 0); //$NON-NLS-1$ - assertTrue( - "files(2) != link", //$NON-NLS-1$ - ((Symlink)files.get(2)).getLink().compareTo( - "/sys/kernel/debug") == 0); //$NON-NLS-1$ - assertTrue( - "files(1) != user", //$NON-NLS-1$ - files.get(1).getUser().getName().compareTo("root") == 0); //$NON-NLS-1$ + "files(3) != user", //$NON-NLS-1$ + files.get(3).getUser().getName().compareTo("system") == 0); //$NON-NLS-1$ assertTrue( - "files(1) != group", //$NON-NLS-1$ - files.get(1).getGroup().getName().compareTo("root2") == 0); //$NON-NLS-1$ + "files(3) != group", //$NON-NLS-1$ + files.get(3).getGroup().getName().compareTo("cache") == 0); //$NON-NLS-1$ assertTrue( "files(1) != size", //$NON-NLS-1$ - files.get(1).getSize() == 229); + files.get(1).getSize() == 1238); assertTrue( "files(1) != permissions", //$NON-NLS-1$ files.get(1).getPermissions() - .toRawString().compareTo("rw-r--r--") == 0); //$NON-NLS-1$ - assertTrue( - "files(7) != setuid", //$NON-NLS-1$ - files.get(7).getPermissions().getUser().isSetUID()); - assertTrue( - "files(7) != setgid", //$NON-NLS-1$ - files.get(7).getPermissions().getGroup().isSetGID()); - assertTrue( - "files(7) != stickybit", //$NON-NLS-1$ - files.get(7).getPermissions().getOthers().isStickybit()); - assertTrue( - "files(7) != setuid+execute", //$NON-NLS-1$ - files.get(7).getPermissions().getUser().isExecute()); - assertTrue( - "files(7) != setgid+execute", //$NON-NLS-1$ - files.get(7).getPermissions().getGroup().isExecute()); - assertTrue( - "files(7) != stickybit+execute", //$NON-NLS-1$ - files.get(7).getPermissions().getOthers().isExecute()); - assertTrue( - "files(8) != setuid", //$NON-NLS-1$ - files.get(8).getPermissions().getUser().isSetUID()); - assertTrue( - "files(8) != setgid", //$NON-NLS-1$ - files.get(8).getPermissions().getGroup().isSetGID()); - assertTrue( - "files(8) != stickybit", //$NON-NLS-1$ - files.get(8).getPermissions().getOthers().isStickybit()); - assertTrue( - "files(8) != setuid+execute", //$NON-NLS-1$ - !files.get(8).getPermissions().getUser().isExecute()); - assertTrue( - "files(8) != setgid+execute", //$NON-NLS-1$ - !files.get(8).getPermissions().getGroup().isExecute()); - assertTrue( - "files(8) != stickybit+execute", //$NON-NLS-1$ - !files.get(8).getPermissions().getOthers().isExecute()); + .toRawString().compareTo("rwxr-x---") == 0); //$NON-NLS-1$ } } diff --git a/tests/src/com/cyanogenmod/filemanager/commands/shell/ReadCommandTest.java b/tests/src/com/cyanogenmod/filemanager/commands/shell/ReadCommandTest.java index b0625dbd..51cb8a5a 100644 --- a/tests/src/com/cyanogenmod/filemanager/commands/shell/ReadCommandTest.java +++ b/tests/src/com/cyanogenmod/filemanager/commands/shell/ReadCommandTest.java @@ -68,21 +68,26 @@ public class ReadCommandTest extends AbstractConsoleTest { final StringBuffer sb = new StringBuffer(); AsyncResultExecutable cmd = CommandHelper.read(getContext(), READ_FILE, new AsyncResultListener() { + @Override public void onAsyncStart() { /**NON BLOCK**/ } + @Override public void onAsyncEnd(boolean cancelled) { synchronized (ReadCommandTest.this.mSync) { ReadCommandTest.this.mNormalEnd = true; ReadCommandTest.this.mSync.notify(); } } + @Override public void onAsyncExitCode(int exitCode) { /**NON BLOCK**/ } + @Override public void onException(Exception cause) { fail(String.valueOf(cause)); } + @Override public void onPartialResult(Object results) { ReadCommandTest.this.mNewPartialData = true; sb.append(new String((byte[])results)); diff --git a/tests/src/com/cyanogenmod/filemanager/commands/shell/UncompressCommandTest.java b/tests/src/com/cyanogenmod/filemanager/commands/shell/UncompressCommandTest.java index 6fbfb3aa..59c4041c 100644 --- a/tests/src/com/cyanogenmod/filemanager/commands/shell/UncompressCommandTest.java +++ b/tests/src/com/cyanogenmod/filemanager/commands/shell/UncompressCommandTest.java @@ -184,21 +184,26 @@ public class UncompressCommandTest extends AbstractConsoleTest { cmd = CommandHelper.uncompress( getContext(), src, null, new AsyncResultListener() { + @Override public void onAsyncStart() { /**NON BLOCK**/ } + @Override public void onAsyncEnd(boolean cancelled) { synchronized (UncompressCommandTest.this.mSync) { UncompressCommandTest.this.mNormalEnd = true; UncompressCommandTest.this.mSync.notify(); } } + @Override public void onAsyncExitCode(int exitCode) { /**NON BLOCK**/ } + @Override public void onException(Exception cause) { fail(String.valueOf(cause)); } + @Override public void onPartialResult(Object result) { UncompressCommandTest.this.mNewPartialData = true; Log.d(TAG, (String)result); diff --git a/tests/src/com/cyanogenmod/filemanager/commands/shell/WriteCommandTest.java b/tests/src/com/cyanogenmod/filemanager/commands/shell/WriteCommandTest.java index 2e14a993..ec04ab10 100644 --- a/tests/src/com/cyanogenmod/filemanager/commands/shell/WriteCommandTest.java +++ b/tests/src/com/cyanogenmod/filemanager/commands/shell/WriteCommandTest.java @@ -16,9 +16,6 @@ package com.cyanogenmod.filemanager.commands.shell; -import java.io.OutputStream; -import java.util.Random; - import android.os.Environment; import android.test.suitebuilder.annotation.LargeTest; import android.test.suitebuilder.annotation.SmallTest; @@ -27,6 +24,9 @@ import com.cyanogenmod.filemanager.commands.AsyncResultListener; import com.cyanogenmod.filemanager.commands.WriteExecutable; import com.cyanogenmod.filemanager.util.CommandHelper; +import java.io.OutputStream; +import java.util.Random; + /** * A class for testing write command. * @@ -61,12 +61,17 @@ public class WriteCommandTest extends AbstractConsoleTest { WriteExecutable cmd = CommandHelper.write(getContext(), WRITE_FILE_SMALL, new AsyncResultListener() { + @Override public void onAsyncStart() {/**NON BLOCK**/} + @Override public void onAsyncEnd(boolean cancelled) {/**NON BLOCK**/} + @Override public void onAsyncExitCode(int exitCode) {/**NON BLOCK**/} + @Override public void onException(Exception cause) { fail(String.valueOf(cause)); } + @Override public void onPartialResult(Object results) {/**NON BLOCK**/} }, getConsole()); OutputStream os = cmd.createOutputStream(); @@ -93,12 +98,17 @@ public class WriteCommandTest extends AbstractConsoleTest { WriteExecutable cmd = CommandHelper.write(getContext(), WRITE_FILE_LARGE, new AsyncResultListener() { + @Override public void onAsyncStart() {/**NON BLOCK**/} + @Override public void onAsyncEnd(boolean cancelled) {/**NON BLOCK**/} + @Override public void onAsyncExitCode(int exitCode) {/**NON BLOCK**/} + @Override public void onException(Exception cause) { fail(String.valueOf(cause)); } + @Override public void onPartialResult(Object results) {/**NON BLOCK**/} }, getConsole()); OutputStream os = cmd.createOutputStream(); diff --git a/themes/res/values/arrays.xml b/themes/res/values/arrays.xml index dc6d8fee..ec6409b1 100644 --- a/themes/res/values/arrays.xml +++ b/themes/res/values/arrays.xml @@ -14,7 +14,7 @@ limitations under the License. --> -<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> +<resources xmlns:android="http://schemas.android.com/apk/res/android"> <!-- The identifiers of the themes that this app contains. All the resources of every theme MUST be qualified with the identifier of the theme --> |