diff options
Diffstat (limited to 'src/com/cyanogenmod')
70 files changed, 1537 insertions, 1811 deletions
diff --git a/src/com/cyanogenmod/filemanager/FileManagerApplication.java b/src/com/cyanogenmod/filemanager/FileManagerApplication.java index c765ee35..0e3ac357 100644 --- a/src/com/cyanogenmod/filemanager/FileManagerApplication.java +++ b/src/com/cyanogenmod/filemanager/FileManagerApplication.java @@ -35,7 +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.FileHelper; +import com.cyanogenmod.filemanager.util.AIDHelper; import com.cyanogenmod.filemanager.util.MimeTypeHelper; import java.io.File; @@ -100,7 +100,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 +109,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 +165,8 @@ public final class FileManagerApplication extends Application { if (DEBUG) { Log.d(TAG, "FileManagerApplication.onCreate"); //$NON-NLS-1$ } - register(); init(); + register(); } /** @@ -192,19 +204,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 +221,25 @@ 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 +257,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()); @@ -336,13 +353,11 @@ public final class FileManagerApplication extends Application { if (ConsoleBuilder.isPrivileged()) { sBackgroundConsole = new ConsoleHolder( - ConsoleBuilder.createPrivilegedConsole( - ctx, FileHelper.ROOT_DIRECTORY)); + ConsoleBuilder.createPrivilegedConsole(ctx)); } else { sBackgroundConsole = new ConsoleHolder( - ConsoleBuilder.createNonPrivilegedConsole( - ctx, FileHelper.ROOT_DIRECTORY)); + ConsoleBuilder.createNonPrivilegedConsole(ctx)); } } catch (Exception e) { Log.e(TAG, @@ -371,8 +386,7 @@ public final class FileManagerApplication extends Application { sBackgroundConsole = new ConsoleHolder( ConsoleBuilder.createPrivilegedConsole( - getInstance().getApplicationContext(), - FileHelper.ROOT_DIRECTORY)); + getInstance().getApplicationContext())); } catch (Exception e) { try { if (sBackgroundConsole != null) { @@ -392,6 +406,9 @@ public final class FileManagerApplication extends Application { * @return boolean If the access mode of the application */ public static AccessMode getAccessMode() { + if (!sIsDeviceRooted) { + return AccessMode.SAFE; + } String defaultValue = ((ObjectStringIdentifier)FileManagerSettings. SETTINGS_ACCESS_MODE.getDefaultValue()).getId(); 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..3221002e 100644 --- a/src/com/cyanogenmod/filemanager/activities/NavigationActivity.java +++ b/src/com/cyanogenmod/filemanager/activities/NavigationActivity.java @@ -580,10 +580,10 @@ public class NavigationActivity extends Activity } } catch (Throwable ex) { if (!NavigationActivity.this.mChRooted) { - //Show exception and exists + //Show exception and exit Log.e(TAG, getString(R.string.msgs_cant_create_console), ex); // We don't have any console - // Show exception and exists + // Show exception and exit DialogHelper.showToast( NavigationActivity.this, R.string.msgs_cant_create_console, Toast.LENGTH_LONG); @@ -612,14 +612,19 @@ public class NavigationActivity extends Activity StorageHelper.getStorageVolumes(NavigationActivity.this); if (volumes != null && volumes.length > 0) { initialDir = volumes[0].getPath(); + } else { + // Show exception and exit + DialogHelper.showToast( + NavigationActivity.this, + R.string.msgs_cant_create_console, Toast.LENGTH_LONG); + exit(); + return; } } //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 +921,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 +929,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 +946,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 +1196,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; } @@ -1419,7 +1427,7 @@ public class NavigationActivity extends Activity public void onClick(DialogInterface alertDialog, int which) { if (which == DialogInterface.BUTTON_NEGATIVE) { // We don't have any console - // Show exception and exists + // Show exception and exit DialogHelper.showToast( NavigationActivity.this, R.string.msgs_cant_create_console, Toast.LENGTH_LONG); @@ -1596,10 +1604,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/PickerActivity.java b/src/com/cyanogenmod/filemanager/activities/PickerActivity.java index c1fce9d9..14eef9b5 100644 --- a/src/com/cyanogenmod/filemanager/activities/PickerActivity.java +++ b/src/com/cyanogenmod/filemanager/activities/PickerActivity.java @@ -58,6 +58,7 @@ import com.cyanogenmod.filemanager.ui.widgets.NavigationView.OnFilePickedListene import com.cyanogenmod.filemanager.util.DialogHelper; import com.cyanogenmod.filemanager.util.ExceptionUtil; import com.cyanogenmod.filemanager.util.FileHelper; +import com.cyanogenmod.filemanager.util.MimeTypeHelper; import com.cyanogenmod.filemanager.util.StorageHelper; import java.io.File; @@ -184,6 +185,10 @@ public class PickerActivity extends Activity String mimeType = getIntent().getType(); Log.d(TAG, "PickerActivity. type: " + String.valueOf(mimeType)); //$NON-NLS-1$ if (mimeType != null) { + if (!MimeTypeHelper.isMimeTypeKnown(this, mimeType)) { + Log.i(TAG, "Mime type " + mimeType + " unknown, falling back to wildcard."); + mimeType = MimeTypeHelper.ALL_MIME_TYPES; + } restrictions.put(DisplayRestrictions.MIME_TYPE_RESTRICTION, mimeType); } // Other restrictions 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/ChangeCurrentDirExecutable.java b/src/com/cyanogenmod/filemanager/commands/ChangeCurrentDirExecutable.java deleted file mode 100644 index 5999cfc7..00000000 --- a/src/com/cyanogenmod/filemanager/commands/ChangeCurrentDirExecutable.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright (C) 2012 The CyanogenMod Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.cyanogenmod.filemanager.commands; - -/** - * An interface that represents an executable for retrieve the current directory. - */ -public interface ChangeCurrentDirExecutable extends SyncResultExecutable { - - /** - * {@inheritDoc} - */ - @Override - Boolean getResult(); -} diff --git a/src/com/cyanogenmod/filemanager/commands/CurrentDirExecutable.java b/src/com/cyanogenmod/filemanager/commands/CurrentDirExecutable.java deleted file mode 100644 index 1d951f88..00000000 --- a/src/com/cyanogenmod/filemanager/commands/CurrentDirExecutable.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright (C) 2012 The CyanogenMod Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.cyanogenmod.filemanager.commands; - -/** - * An interface that represents an executable for retrieve the current directory. - */ -public interface CurrentDirExecutable extends SyncResultExecutable { - - /** - * {@inheritDoc} - */ - @Override - String getResult(); -} diff --git a/src/com/cyanogenmod/filemanager/commands/ExecutableCreator.java b/src/com/cyanogenmod/filemanager/commands/ExecutableCreator.java index 630546f8..5d537a9b 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; @@ -31,17 +33,6 @@ import com.cyanogenmod.filemanager.preferences.CompressionMode; public interface ExecutableCreator { /** - * Method that creates an executable for change the current directory. - * - * @param dir The absolute path of the new directory to establish as current directory - * @return ChangeCurrentDirExecutable A {@link ChangeCurrentDirExecutable} executable - * implementation reference - * @throws CommandNotFoundException If the executable can't be created - */ - ChangeCurrentDirExecutable createChangeCurrentDirExecutable( - String dir) throws CommandNotFoundException; - - /** * Method that creates an executable for change the owner of a file system object. * * @param fso The absolute path to the source file system object @@ -50,9 +41,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 +56,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 +71,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 +84,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,17 +98,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; - - /** - * Method that creates an executable for retrieve the current directory. - * - * @return CurrentDirExecutable A {@link CurrentDirExecutable} executable - * implementation reference - * @throws CommandNotFoundException If the executable can't be created - */ - CurrentDirExecutable createCurrentDirExecutable() throws CommandNotFoundException; + CreateFileExecutable createCreateFileExecutable(String file) throws CommandNotFoundException, + NoSuchFileOrDirectory, InsufficientPermissionsException; /** * Method that creates an executable for delete a directory. @@ -114,8 +111,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 +124,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 +137,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 +151,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 +164,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 +177,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 +192,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 +208,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 +246,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 +259,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 +274,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 +289,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 +302,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 +316,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 +330,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 +343,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 +358,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 +373,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 +387,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 +403,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 +416,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 +430,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 +444,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 +461,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 +478,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 +495,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/ChangeCurrentDirCommand.java b/src/com/cyanogenmod/filemanager/commands/java/ChangeCurrentDirCommand.java deleted file mode 100644 index 476d4041..00000000 --- a/src/com/cyanogenmod/filemanager/commands/java/ChangeCurrentDirCommand.java +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Copyright (C) 2012 The CyanogenMod Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.cyanogenmod.filemanager.commands.java; - -import android.util.Log; - -import com.cyanogenmod.filemanager.commands.ChangeCurrentDirExecutable; -import com.cyanogenmod.filemanager.console.ExecutionException; -import com.cyanogenmod.filemanager.console.InsufficientPermissionsException; -import com.cyanogenmod.filemanager.console.NoSuchFileOrDirectory; -import com.cyanogenmod.filemanager.console.java.JavaConsole; - -import java.io.File; - - -/** - * A class for change the current directory. - */ -public class ChangeCurrentDirCommand extends Program implements ChangeCurrentDirExecutable { - - private static final String TAG = "ChangeCurrentDirCommand"; //$NON-NLS-1$ - - private final JavaConsole mConsole; - private final String mNewDir; - - /** - * Constructor of <code>ChangeCurrentDirCommand</code>. - * - * @param console The console - * @param newDir The new directory to which to change - */ - public ChangeCurrentDirCommand(JavaConsole console, String newDir) { - super(); - this.mNewDir = newDir; - this.mConsole = console; - } - - /** - * {@inheritDoc} - */ - @Override - public Boolean getResult() { - return Boolean.TRUE; - } - - /** - * {@inheritDoc} - */ - @Override - public void execute() - throws InsufficientPermissionsException, NoSuchFileOrDirectory, ExecutionException { - if (isTrace()) { - Log.v(TAG, - String.format("Changing current directory to %s", this.mNewDir)); //$NON-NLS-1$ - } - - // Check that the file exists and is a directory - File f = new File(this.mNewDir); - if (!f.exists() || !f.isDirectory()) { - if (isTrace()) { - Log.v(TAG, "Result: FAIL. NoSuchFileOrDirectory"); //$NON-NLS-1$ - } - throw new NoSuchFileOrDirectory(this.mNewDir); - } - - // Check that we have the access to the directory - if (!f.canRead() || !f.canExecute()) { - if (isTrace()) { - Log.v(TAG, "Result: FAIL. InsufficientPermissionsException"); //$NON-NLS-1$ - } - throw new InsufficientPermissionsException(); - } - - // Set the new current directory - this.mConsole.setCurrentDir(this.mNewDir); - - if (isTrace()) { - Log.v(TAG, "Result: OK"); //$NON-NLS-1$ - } - } - -} diff --git a/src/com/cyanogenmod/filemanager/commands/java/CurrentDirCommand.java b/src/com/cyanogenmod/filemanager/commands/java/CurrentDirCommand.java deleted file mode 100644 index 8ba8dd8f..00000000 --- a/src/com/cyanogenmod/filemanager/commands/java/CurrentDirCommand.java +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright (C) 2012 The CyanogenMod Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.cyanogenmod.filemanager.commands.java; - -import android.util.Log; - -import com.cyanogenmod.filemanager.commands.CurrentDirExecutable; -import com.cyanogenmod.filemanager.console.ExecutionException; -import com.cyanogenmod.filemanager.console.InsufficientPermissionsException; -import com.cyanogenmod.filemanager.console.NoSuchFileOrDirectory; -import com.cyanogenmod.filemanager.console.java.JavaConsole; - - -/** - * A class for returns the current directory. - */ -public class CurrentDirCommand extends Program implements CurrentDirExecutable { - - private static final String TAG = "CurrentDirCommand"; //$NON-NLS-1$ - - private final JavaConsole mConsole; - private String mCurrentDir; - - /** - * Constructor of <code>CurrentDirCommand</code>. - * - * @param console The console - */ - public CurrentDirCommand(JavaConsole console) { - super(); - this.mConsole = console; - } - - /** - * {@inheritDoc} - */ - @Override - public String getResult() { - return this.mCurrentDir; - } - - /** - * {@inheritDoc} - */ - @Override - public void execute() - throws InsufficientPermissionsException, NoSuchFileOrDirectory, ExecutionException { - if (isTrace()) { - Log.v(TAG, "Obtaing current directory"); //$NON-NLS-1$ - } - - this.mCurrentDir = this.mConsole.getCurrentDir(); - - if (isTrace()) { - Log.v(TAG, - String.format( - "Result: OK. Current directory: %s", this.mCurrentDir)); //$NON-NLS-1$ - } - } - -} 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..1186515d 100644 --- a/src/com/cyanogenmod/filemanager/commands/java/JavaExecutableCreator.java +++ b/src/com/cyanogenmod/filemanager/commands/java/JavaExecutableCreator.java @@ -18,14 +18,12 @@ package com.cyanogenmod.filemanager.commands.java; import com.cyanogenmod.filemanager.R; import com.cyanogenmod.filemanager.commands.AsyncResultListener; -import com.cyanogenmod.filemanager.commands.ChangeCurrentDirExecutable; import com.cyanogenmod.filemanager.commands.ChangeOwnerExecutable; import com.cyanogenmod.filemanager.commands.ChangePermissionsExecutable; import com.cyanogenmod.filemanager.commands.CompressExecutable; import com.cyanogenmod.filemanager.commands.CopyExecutable; import com.cyanogenmod.filemanager.commands.CreateDirExecutable; import com.cyanogenmod.filemanager.commands.CreateFileExecutable; -import com.cyanogenmod.filemanager.commands.CurrentDirExecutable; import com.cyanogenmod.filemanager.commands.DeleteDirExecutable; import com.cyanogenmod.filemanager.commands.DeleteFileExecutable; import com.cyanogenmod.filemanager.commands.DiskUsageExecutable; @@ -81,15 +79,6 @@ public class JavaExecutableCreator implements ExecutableCreator { * {@inheritDoc} */ @Override - public ChangeCurrentDirExecutable createChangeCurrentDirExecutable(String dir) - throws CommandNotFoundException { - return new ChangeCurrentDirCommand(this.mConsole, dir); - } - - /** - * {@inheritDoc} - */ - @Override public ChangeOwnerExecutable createChangeOwnerExecutable( String fso, User newUser, Group newGroup) throws CommandNotFoundException { throw new CommandNotFoundException("Not implemented"); //$NON-NLS-1$ @@ -135,14 +124,6 @@ public class JavaExecutableCreator implements ExecutableCreator { * {@inheritDoc} */ @Override - public CurrentDirExecutable createCurrentDirExecutable() throws CommandNotFoundException { - return new CurrentDirCommand(this.mConsole); - } - - /** - * {@inheritDoc} - */ - @Override public DeleteDirExecutable createDeleteDirExecutable(String dir) throws CommandNotFoundException { return new DeleteDirCommand(dir); @@ -200,7 +181,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 +226,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 +235,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 +317,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..922de7b0 100644 --- a/src/com/cyanogenmod/filemanager/commands/shell/AsyncResultProgram.java +++ b/src/com/cyanogenmod/filemanager/commands/shell/AsyncResultProgram.java @@ -51,7 +51,7 @@ public abstract class AsyncResultProgram * @hide */ final List<Byte> mPartialDataType; - private final Object mSync = new Object(); + final Object mSync = new Object(); /** * @hide */ @@ -106,7 +106,7 @@ public abstract class AsyncResultProgram * @hide */ public final void onRequestStartParsePartialResult() { - this.mWorkerThread = new AsyncResultProgramThread(this.mSync); + this.mWorkerThread = new AsyncResultProgramThread(); this.mWorkerThread.start(); //Notify start to command class @@ -131,17 +131,12 @@ public abstract class AsyncResultProgram this.mSync.notify(); } synchronized (this.mTerminateSync) { - try { - this.mSync.wait(); - } catch (Exception e) { - /**NON BLOCK**/ - } - try { - if (this.mWorkerThread.isAlive()) { - this.mWorkerThread.interrupt(); + if (this.mWorkerThread.isAlive()) { + try { + this.mTerminateSync.wait(); + } catch (Exception e) { + /**NON BLOCK**/ } - } catch (Exception e) { - /**NON BLOCK**/ } } @@ -176,6 +171,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 +182,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 +201,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 +212,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(); } } @@ -349,16 +348,12 @@ public abstract class AsyncResultProgram */ private class AsyncResultProgramThread extends Thread { boolean mAlive = true; - private final Object mSyncObj; /** * Constructor of <code>AsyncResultProgramThread</code>. - * - * @param sync The synchronized object */ - AsyncResultProgramThread(Object sync) { + AsyncResultProgramThread() { super(); - this.mSyncObj = sync; } /** @@ -369,12 +364,9 @@ public abstract class AsyncResultProgram try { this.mAlive = true; while (this.mAlive) { - synchronized (this.mSyncObj) { - this.mSyncObj.wait(); + synchronized (AsyncResultProgram.this.mSync) { + AsyncResultProgram.this.mSync.wait(); while (AsyncResultProgram.this.mPartialData.size() > 0) { - if (!this.mAlive) { - return; - } Byte type = AsyncResultProgram.this.mPartialDataType.remove(0); String data = AsyncResultProgram.this.mPartialData.remove(0); try { diff --git a/src/com/cyanogenmod/filemanager/commands/shell/ChangeCurrentDirCommand.java b/src/com/cyanogenmod/filemanager/commands/shell/ChangeCurrentDirCommand.java deleted file mode 100644 index 443e1f44..00000000 --- a/src/com/cyanogenmod/filemanager/commands/shell/ChangeCurrentDirCommand.java +++ /dev/null @@ -1,113 +0,0 @@ -/* - * Copyright (C) 2012 The CyanogenMod Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.cyanogenmod.filemanager.commands.shell; - -import com.cyanogenmod.filemanager.commands.ChangeCurrentDirExecutable; -import com.cyanogenmod.filemanager.console.CommandNotFoundException; -import com.cyanogenmod.filemanager.console.ExecutionException; -import com.cyanogenmod.filemanager.console.InsufficientPermissionsException; - -import java.io.BufferedReader; -import java.io.IOException; -import java.io.StringReader; -import java.text.ParseException; - - -/** - * A class for change the current directory of the shell. - * - * {@link "http://unixhelp.ed.ac.uk/CGI/man-cgi?cd"} - */ -public class ChangeCurrentDirCommand - extends SyncResultProgram implements ChangeCurrentDirExecutable { - - private static final String ID = "cd"; //$NON-NLS-1$ - private Boolean mRet; - - /** - * Constructor of <code>ChangeCurrentDirCommand</code>. - * - * @param newDir The new directory to which to change - * @throws InvalidCommandDefinitionException If the command has an invalid definition - */ - public ChangeCurrentDirCommand(String newDir) throws InvalidCommandDefinitionException { - super(ID, newDir); - } - - /** - * {@inheritDoc} - */ - @Override - public void parse(String in, String err) throws ParseException { - //Release the return object - this.mRet = Boolean.TRUE; - - // Check the in and err buffer to extract information - BufferedReader br = null; - try { - br = new BufferedReader(new StringReader(err)); - String szLine = br.readLine(); - if (szLine != null) { - if (szLine.indexOf("No such file or directory") != -1) { //$NON-NLS-1$ - this.mRet = Boolean.FALSE; - } - } - br.close(); - br = new BufferedReader(new StringReader(in)); - szLine = br.readLine(); - if (szLine != null) { - if (szLine.indexOf("No such file or directory") != -1) { //$NON-NLS-1$ - this.mRet = Boolean.FALSE; - } - } - - } catch (IOException ioEx) { - throw new ParseException(ioEx.getMessage(), 0); - - } catch (Exception ex) { - throw new ParseException(ex.getMessage(), 0); - - } finally { - try { - if (br != null) { - br.close(); - } - } catch (Throwable ex) { - /**NON BLOCK**/ - } - } - } - - /** - * {@inheritDoc} - */ - @Override - public Boolean getResult() { - return this.mRet; - } - - /** - * {@inheritDoc} - */ - @Override - public void checkExitCode(int exitCode) - throws InsufficientPermissionsException, CommandNotFoundException, ExecutionException { - if (exitCode != 0) { - throw new ExecutionException("exitcode != 0"); //$NON-NLS-1$ - } - } -} diff --git a/src/com/cyanogenmod/filemanager/commands/shell/CurrentDirCommand.java b/src/com/cyanogenmod/filemanager/commands/shell/CurrentDirCommand.java deleted file mode 100644 index 9c106a68..00000000 --- a/src/com/cyanogenmod/filemanager/commands/shell/CurrentDirCommand.java +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Copyright (C) 2012 The CyanogenMod Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.cyanogenmod.filemanager.commands.shell; - -import com.cyanogenmod.filemanager.commands.CurrentDirExecutable; -import com.cyanogenmod.filemanager.console.CommandNotFoundException; -import com.cyanogenmod.filemanager.console.ExecutionException; -import com.cyanogenmod.filemanager.console.InsufficientPermissionsException; - -import java.io.BufferedReader; -import java.io.IOException; -import java.io.StringReader; -import java.text.ParseException; - - -/** - * A class for retrieve the current directory of the shell. - * - * {@link "http://unixhelp.ed.ac.uk/CGI/man-cgi?pwd"} - */ -public class CurrentDirCommand extends SyncResultProgram implements CurrentDirExecutable { - - private static final String ID = "pwd"; //$NON-NLS-1$ - private String mPwd; - - /** - * Constructor of <code>CurrentDirCommand</code>. - * - * @throws InvalidCommandDefinitionException If the command has an invalid definition - */ - public CurrentDirCommand() throws InvalidCommandDefinitionException { - super(ID); - } - - /** - * {@inheritDoc} - */ - @Override - public void parse(String in, String err) throws ParseException { - //Release the return object - this.mPwd = ""; //$NON-NLS-1$ - - // Check the in buffer to extract information - BufferedReader br = null; - try { - br = new BufferedReader(new StringReader(in)); - String szLine = br.readLine(); - if (szLine == null) { - throw new ParseException("no information", 0); //$NON-NLS-1$ - } - this.mPwd = szLine; - - } catch (IOException ioEx) { - throw new ParseException(ioEx.getMessage(), 0); - - } catch (Exception ex) { - throw new ParseException(ex.getMessage(), 0); - - } finally { - try { - if (br != null) { - br.close(); - } - } catch (Throwable ex) { - /**NON BLOCK**/ - } - } - } - - /** - * {@inheritDoc} - */ - @Override - public String getResult() { - return this.mPwd; - } - - /** - * {@inheritDoc} - */ - @Override - public void checkExitCode(int exitCode) - throws InsufficientPermissionsException, CommandNotFoundException, ExecutionException { - if (exitCode != 0) { - throw new ExecutionException("exitcode != 0"); //$NON-NLS-1$ - } - } -} 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..e4741845 100644 --- a/src/com/cyanogenmod/filemanager/commands/shell/ShellExecutableCreator.java +++ b/src/com/cyanogenmod/filemanager/commands/shell/ShellExecutableCreator.java @@ -17,14 +17,12 @@ package com.cyanogenmod.filemanager.commands.shell; import com.cyanogenmod.filemanager.commands.AsyncResultListener; -import com.cyanogenmod.filemanager.commands.ChangeCurrentDirExecutable; import com.cyanogenmod.filemanager.commands.ChangeOwnerExecutable; import com.cyanogenmod.filemanager.commands.ChangePermissionsExecutable; import com.cyanogenmod.filemanager.commands.CompressExecutable; import com.cyanogenmod.filemanager.commands.CopyExecutable; import com.cyanogenmod.filemanager.commands.CreateDirExecutable; import com.cyanogenmod.filemanager.commands.CreateFileExecutable; -import com.cyanogenmod.filemanager.commands.CurrentDirExecutable; import com.cyanogenmod.filemanager.commands.DeleteDirExecutable; import com.cyanogenmod.filemanager.commands.DeleteFileExecutable; import com.cyanogenmod.filemanager.commands.DiskUsageExecutable; @@ -79,19 +77,6 @@ public class ShellExecutableCreator implements ExecutableCreator { * {@inheritDoc} */ @Override - public ChangeCurrentDirExecutable createChangeCurrentDirExecutable(String dir) - throws CommandNotFoundException { - try { - return new ChangeCurrentDirCommand(dir); - } catch (InvalidCommandDefinitionException icdEx) { - throw new CommandNotFoundException("ChangeCurrentDirCommand", icdEx); //$NON-NLS-1$ - } - } - - /** - * {@inheritDoc} - */ - @Override public ChangeOwnerExecutable createChangeOwnerExecutable( String fso, User newUser, Group newGroup) throws CommandNotFoundException { try { @@ -157,18 +142,6 @@ public class ShellExecutableCreator implements ExecutableCreator { * {@inheritDoc} */ @Override - public CurrentDirExecutable createCurrentDirExecutable() throws CommandNotFoundException { - try { - return new CurrentDirCommand(); - } catch (InvalidCommandDefinitionException icdEx) { - throw new CommandNotFoundException("CurrentDirCommand", icdEx); //$NON-NLS-1$ - } - } - - /** - * {@inheritDoc} - */ - @Override public DeleteDirExecutable createDeleteDirExecutable(String dir) throws CommandNotFoundException { try { @@ -311,8 +284,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/commands/shell/WriteCommand.java b/src/com/cyanogenmod/filemanager/commands/shell/WriteCommand.java index 08968305..51c0800c 100644 --- a/src/com/cyanogenmod/filemanager/commands/shell/WriteCommand.java +++ b/src/com/cyanogenmod/filemanager/commands/shell/WriteCommand.java @@ -44,7 +44,7 @@ public class WriteCommand extends AsyncResultProgram implements WriteExecutable /** * @hide */ - final Object mSync = new Object(); + final Object mWriteSync = new Object(); private boolean mReady; /** * @hide @@ -81,10 +81,10 @@ public class WriteCommand extends AsyncResultProgram implements WriteExecutable public OutputStream createOutputStream() throws IOException { // Wait until command is ready - synchronized (this.mSync) { + synchronized (this.mWriteSync) { if (!this.mReady) { try { - this.mSync.wait(TIMEOUT); + this.mWriteSync.wait(TIMEOUT); } catch (Exception e) {/**NON BLOCK**/} } } @@ -96,9 +96,9 @@ public class WriteCommand extends AsyncResultProgram implements WriteExecutable */ @Override public void onStartParsePartialResult() { - synchronized (this.mSync) { + synchronized (this.mWriteSync) { this.mReady = true; - this.mSync.notify(); + this.mWriteSync.notify(); } } diff --git a/src/com/cyanogenmod/filemanager/console/ConsoleBuilder.java b/src/com/cyanogenmod/filemanager/console/ConsoleBuilder.java index 1552abd9..17914693 100644 --- a/src/com/cyanogenmod/filemanager/console/ConsoleBuilder.java +++ b/src/com/cyanogenmod/filemanager/console/ConsoleBuilder.java @@ -30,7 +30,6 @@ import com.cyanogenmod.filemanager.preferences.AccessMode; import com.cyanogenmod.filemanager.preferences.FileManagerSettings; import com.cyanogenmod.filemanager.preferences.Preferences; import com.cyanogenmod.filemanager.util.DialogHelper; -import com.cyanogenmod.filemanager.util.FileHelper; import java.io.FileNotFoundException; import java.io.IOException; @@ -125,7 +124,7 @@ public final class ConsoleBuilder { try { //Create the console, destroy the current console, and marks as current holder = new ConsoleHolder( - createNonPrivilegedConsole(context, FileHelper.ROOT_DIRECTORY)); + createNonPrivilegedConsole(context)); destroyConsole(); sHolder = holder; return true; @@ -157,7 +156,7 @@ public final class ConsoleBuilder { try { //Create the console, destroy the current console, and marks as current holder = new ConsoleHolder( - createAndCheckPrivilegedConsole(context, FileHelper.ROOT_DIRECTORY)); + createAndCheckPrivilegedConsole(context)); destroyConsole(); sHolder = holder; @@ -243,11 +242,8 @@ public final class ConsoleBuilder { //Is there a console allocated if (sHolder == null) { sHolder = (superuserMode) - ? new ConsoleHolder( - createAndCheckPrivilegedConsole( - context, FileHelper.ROOT_DIRECTORY)) - : new ConsoleHolder( - createNonPrivilegedConsole(context, FileHelper.ROOT_DIRECTORY)); + ? new ConsoleHolder(createAndCheckPrivilegedConsole(context)) + : new ConsoleHolder(createNonPrivilegedConsole(context)); if (superuserMode) { // Change also the background console to privileged FileManagerApplication.changeBackgroundConsoleToPriviligedConsole(); @@ -275,7 +271,6 @@ public final class ConsoleBuilder { * Method that creates a new non privileged console. * * @param context The current context - * @param initialDirectory The initial directory of the console * @return Console The non privileged console * @throws FileNotFoundException If the initial directory not exists * @throws IOException If initial directory couldn't be checked @@ -283,7 +278,7 @@ public final class ConsoleBuilder { * @throws ConsoleAllocException If the console can't be allocated * @see NonPriviledgeConsole */ - public static Console createNonPrivilegedConsole(Context context, String initialDirectory) + public static Console createNonPrivilegedConsole(Context context) throws FileNotFoundException, IOException, InvalidCommandDefinitionException, ConsoleAllocException { @@ -291,14 +286,14 @@ public final class ConsoleBuilder { // Is rooted? Then create a shell console if (FileManagerApplication.isDeviceRooted()) { - NonPriviledgeConsole console = new NonPriviledgeConsole(initialDirectory); + NonPriviledgeConsole console = new NonPriviledgeConsole(); console.setBufferSize(bufferSize); console.alloc(); return console; } // No rooted. Then create a java console - JavaConsole console = new JavaConsole(context, initialDirectory, bufferSize); + JavaConsole console = new JavaConsole(context, bufferSize); console.alloc(); return console; } @@ -308,7 +303,6 @@ public final class ConsoleBuilder { * privileged console fails, the a non privileged console * * @param context The current context - * @param initialDirectory The initial directory of the console * @return Console The privileged console * @throws FileNotFoundException If the initial directory not exists * @throws IOException If initial directory couldn't be checked @@ -317,10 +311,10 @@ public final class ConsoleBuilder { * @throws InsufficientPermissionsException If the console created is not a privileged console * @see PrivilegedConsole */ - public static Console createPrivilegedConsole(Context context, String initialDirectory) + public static Console createPrivilegedConsole(Context context) throws FileNotFoundException, IOException, InvalidCommandDefinitionException, ConsoleAllocException, InsufficientPermissionsException { - PrivilegedConsole console = new PrivilegedConsole(initialDirectory); + PrivilegedConsole console = new PrivilegedConsole(); console.setBufferSize(context.getResources().getInteger(R.integer.buffer_size)); console.alloc(); if (console.getIdentity().getUser().getId() != ROOT_UID) { @@ -340,7 +334,6 @@ public final class ConsoleBuilder { * privileged console fails, the a non privileged console * * @param context The current context - * @param initialDirectory The initial directory of the console * @return Console The privileged console * @throws FileNotFoundException If the initial directory not exists * @throws IOException If initial directory couldn't be checked @@ -349,10 +342,10 @@ public final class ConsoleBuilder { * @throws InsufficientPermissionsException If the console created is not a privileged console * @see PrivilegedConsole */ - public static Console createAndCheckPrivilegedConsole(Context context, String initialDirectory) + public static Console createAndCheckPrivilegedConsole(Context context) throws FileNotFoundException, IOException, InvalidCommandDefinitionException, ConsoleAllocException, InsufficientPermissionsException { - return createAndCheckPrivilegedConsole(context, initialDirectory, true); + return createAndCheckPrivilegedConsole(context, true); } /** @@ -360,7 +353,6 @@ public final class ConsoleBuilder { * privileged console fails, the a non privileged console * * @param context The current context - * @param initialDirectory The initial directory of the console * @param silent Indicates that no message have to be displayed * @return Console The privileged console * @throws FileNotFoundException If the initial directory not exists @@ -371,12 +363,12 @@ public final class ConsoleBuilder { * @see PrivilegedConsole */ public static Console createAndCheckPrivilegedConsole( - Context context, String initialDirectory, boolean silent) + Context context, boolean silent) throws FileNotFoundException, IOException, InvalidCommandDefinitionException, ConsoleAllocException, InsufficientPermissionsException { try { // Create the privileged console - return createPrivilegedConsole(context, initialDirectory); + return createPrivilegedConsole(context); } catch (ConsoleAllocException caEx) { //Show a message with the problem? @@ -404,7 +396,7 @@ public final class ConsoleBuilder { } //Create the non-privileged console - return createNonPrivilegedConsole(context, initialDirectory); + return createNonPrivilegedConsole(context); } // Rethrow the exception diff --git a/src/com/cyanogenmod/filemanager/console/java/JavaConsole.java b/src/com/cyanogenmod/filemanager/console/java/JavaConsole.java index df04d4a5..2edb42a9 100644 --- a/src/com/cyanogenmod/filemanager/console/java/JavaConsole.java +++ b/src/com/cyanogenmod/filemanager/console/java/JavaConsole.java @@ -17,10 +17,8 @@ package com.cyanogenmod.filemanager.console.java; import android.content.Context; -import android.os.storage.StorageVolume; import android.util.Log; -import com.cyanogenmod.filemanager.commands.ChangeCurrentDirExecutable; import com.cyanogenmod.filemanager.commands.Executable; import com.cyanogenmod.filemanager.commands.ExecutableFactory; import com.cyanogenmod.filemanager.commands.SIGNAL; @@ -35,7 +33,6 @@ import com.cyanogenmod.filemanager.console.NoSuchFileOrDirectory; import com.cyanogenmod.filemanager.console.OperationTimeoutException; import com.cyanogenmod.filemanager.console.ReadOnlyFilesystemException; import com.cyanogenmod.filemanager.model.Identity; -import com.cyanogenmod.filemanager.util.StorageHelper; /** * An implementation of a {@link Console} based on a java implementation.<br/> @@ -48,7 +45,6 @@ public final class JavaConsole extends Console { private static final String TAG = "JavaConsole"; //$NON-NLS-1$ private boolean mActive; - private String mCurrentDir; private final Context mCtx; private final int mBufferSize; @@ -57,14 +53,12 @@ public final class JavaConsole extends Console { * Constructor of <code>JavaConsole</code> * * @param ctx The current context - * @param initialDir The initial directory * @param bufferSize The buffer size */ - public JavaConsole(Context ctx, String initialDir, int bufferSize) { + public JavaConsole(Context ctx, int bufferSize) { super(); this.mCtx = ctx; this.mBufferSize = bufferSize; - this.mCurrentDir = initialDir; } /** @@ -76,21 +70,6 @@ public final class JavaConsole extends Console { if (isTrace()) { Log.v(TAG, "Allocating Java console"); //$NON-NLS-1$ } - - //Retrieve the current directory from the first storage volume - StorageVolume[] vols = StorageHelper.getStorageVolumes(this.mCtx); - if (vols == null || vols.length == 0) { - throw new ConsoleAllocException("Can't stat any directory"); //$NON-NLS-1$ - } - - // Test to change to current directory - ChangeCurrentDirExecutable currentDirCmd = - getExecutableFactory(). - newCreator().createChangeCurrentDirExecutable(this.mCurrentDir); - execute(currentDirCmd); - - // Tested. Is not active - this.mCurrentDir = vols[0].getPath(); this.mActive = true; } catch (Exception e) { Log.e(TAG, "Failed to allocate Java console", e); //$NON-NLS-1$ @@ -151,24 +130,6 @@ public final class JavaConsole extends Console { } /** - * Method that returns the current directory of the console - * - * @return String The current directory - */ - public String getCurrentDir() { - return this.mCurrentDir; - } - - /** - * Method that sets the current directory of the console - * - * @param currentDir The current directory - */ - public void setCurrentDir(String currentDir) { - this.mCurrentDir = currentDir; - } - - /** * Method that returns the current context * * @return Context The current context diff --git a/src/com/cyanogenmod/filemanager/console/shell/NonPriviledgeConsole.java b/src/com/cyanogenmod/filemanager/console/shell/NonPriviledgeConsole.java index aec764f8..7673bbf0 100644 --- a/src/com/cyanogenmod/filemanager/console/shell/NonPriviledgeConsole.java +++ b/src/com/cyanogenmod/filemanager/console/shell/NonPriviledgeConsole.java @@ -33,19 +33,6 @@ public class NonPriviledgeConsole extends ShellConsole { /** * Constructor of <code>NonPriviledgeConsole</code>. * - * @param initialDirectory The initial directory of the shell - * @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 - */ - public NonPriviledgeConsole(String initialDirectory) - throws FileNotFoundException, IOException, InvalidCommandDefinitionException { - super(new BashShell(), initialDirectory); - } - - /** - * Constructor of <code>NonPriviledgeConsole</code>. - * * @throws FileNotFoundException If the default initial directory not exists * @throws IOException If initial directory couldn't be checked * @throws InvalidCommandDefinitionException If the command has an invalid definition diff --git a/src/com/cyanogenmod/filemanager/console/shell/PrivilegedConsole.java b/src/com/cyanogenmod/filemanager/console/shell/PrivilegedConsole.java index 4e5d3088..cc441314 100644 --- a/src/com/cyanogenmod/filemanager/console/shell/PrivilegedConsole.java +++ b/src/com/cyanogenmod/filemanager/console/shell/PrivilegedConsole.java @@ -34,19 +34,6 @@ public class PrivilegedConsole extends ShellConsole { /** * Constructor of <code>PrivilegedConsole</code>. * - * @param initialDirectory The initial directory of the shell - * @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 - */ - public PrivilegedConsole(String initialDirectory) - throws FileNotFoundException, IOException, InvalidCommandDefinitionException { - super(new SuperuserShell(), initialDirectory); - } - - /** - * Constructor of <code>PrivilegedConsole</code>. - * * @throws FileNotFoundException If the default initial directory not exists * @throws IOException If initial directory couldn't be checked * @throws InvalidCommandDefinitionException If the command has an invalid definition diff --git a/src/com/cyanogenmod/filemanager/console/shell/ShellConsole.java b/src/com/cyanogenmod/filemanager/console/shell/ShellConsole.java index fb3b5075..12b7fe26 100644 --- a/src/com/cyanogenmod/filemanager/console/shell/ShellConsole.java +++ b/src/com/cyanogenmod/filemanager/console/shell/ShellConsole.java @@ -42,8 +42,6 @@ import com.cyanogenmod.filemanager.console.NoSuchFileOrDirectory; import com.cyanogenmod.filemanager.console.OperationTimeoutException; import com.cyanogenmod.filemanager.console.ReadOnlyFilesystemException; import com.cyanogenmod.filemanager.model.Identity; -import com.cyanogenmod.filemanager.preferences.FileManagerSettings; -import com.cyanogenmod.filemanager.preferences.Preferences; import com.cyanogenmod.filemanager.util.CommandHelper; import com.cyanogenmod.filemanager.util.FileHelper; @@ -72,13 +70,12 @@ 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; //Shell References private final Shell mShell; - private final String mInitialDirectory; private Identity mIdentity; //Process References @@ -134,24 +131,10 @@ public abstract class ShellConsole extends Console implements Program.ProgramLis * Constructor of <code>ShellConsole</code>. * * @param shell The shell used to execute commands - * @throws FileNotFoundException If the default initial directory not exists - * @throws IOException If initial directory couldn't be resolved - */ - public ShellConsole(Shell shell) throws FileNotFoundException, IOException { - this(shell, Preferences.getSharedPreferences().getString( - FileManagerSettings.SETTINGS_INITIAL_DIR.getId(), - (String)FileManagerSettings.SETTINGS_INITIAL_DIR.getDefaultValue())); - } - - /** - * Constructor of <code>ShellConsole</code>. - * - * @param shell The shell used to execute commands - * @param initialDirectory The initial directory of the shell * @throws FileNotFoundException If the initial directory not exists * @throws IOException If initial directory couldn't be resolved */ - public ShellConsole(Shell shell, String initialDirectory) + public ShellConsole(Shell shell) throws FileNotFoundException, IOException { super(); this.mShell = shell; @@ -159,16 +142,6 @@ public abstract class ShellConsole extends Console implements Program.ProgramLis this.mBufferSize = DEFAULT_BUFFER; - //Resolve and checks the initial directory - File f = new File(initialDirectory); - while (FileHelper.isSymlink(f)) { - f = FileHelper.resolveSymlink(f); - } - if (!f.exists() || !f.isDirectory()) { - throw new FileNotFoundException(f.toString()); - } - this.mInitialDirectory = initialDirectory; - //Restart the buffers this.mSbIn = new StringBuffer(); this.mSbErr = new StringBuffer(); @@ -242,7 +215,7 @@ public abstract class ShellConsole extends Console implements Program.ProgramLis rt.exec( cmd.toArray(new String[cmd.size()]), null, - new File(this.mInitialDirectory)); + new File(FileHelper.ROOT_DIRECTORY).getCanonicalFile()); synchronized (this.mSync) { this.mActive = true; } @@ -312,7 +285,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 +477,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 +502,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 +513,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 +607,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 +624,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 +650,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 +695,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 +740,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 +775,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 @@ -1094,28 +1108,32 @@ public abstract class ShellConsole extends Console implements Program.ProgramLis if (program.getCommand() != null) { try { if (program.isCancellable()) { - //Get the PID in background - Integer pid = - CommandHelper.getProcessId( + try { + //Get the PID in background + Integer pid = + CommandHelper.getProcessId( + null, + this.mShell.getPid(), + program.getCommand(), + FileManagerApplication.getBackgroundConsole()); + if (pid != null) { + CommandHelper.sendSignal( null, - this.mShell.getPid(), - program.getCommand(), + pid.intValue(), FileManagerApplication.getBackgroundConsole()); - if (pid != null) { - CommandHelper.sendSignal( - null, - pid.intValue(), - FileManagerApplication.getBackgroundConsole()); - try { - //Wait for process kill - Thread.sleep(100L); - } catch (Throwable ex) { - /**NON BLOCK**/ + try { + //Wait for process kill + Thread.sleep(100L); + } catch (Throwable ex) { + /**NON BLOCK**/ + } + return true; } + } finally { + // It's finished this.mCancelled = true; notifyProcessFinished(); this.mSync.notify(); - return this.mCancelled; } } } catch (Throwable ex) { 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..397b0f11 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; } /** @@ -269,16 +313,8 @@ public abstract class FileSystemObject implements Serializable, Comparable<FileS 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; } @@ -287,64 +323,21 @@ public abstract class FileSystemObject implements Serializable, Comparable<FileS */ @Override public boolean equals(Object obj) { - if (this == obj) { + if (this == obj) return true; - } - if (obj == null) { - return false; - } - if (getClass() != obj.getClass()) { + if (obj == null) 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) { + if (other.mParent != null) return false; - } - } else if (!this.mParent.equals(other.mParent)) { + } else if (!this.mParent.equals(other.mParent)) return false; - } - if (this.mPermissions == null) { - if (other.mPermissions != null) { - return false; - } - } else if (!this.mPermissions.equals(other.mPermissions)) { - return false; - } - if (this.mResourceIconId != other.mResourceIconId) { - 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,7 +347,7 @@ 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()); @@ -365,12 +358,15 @@ public abstract class FileSystemObject implements Serializable, Comparable<FileS */ @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..95fa193a 100644 --- a/src/com/cyanogenmod/filemanager/ui/dialogs/FsoPropertiesDialog.java +++ b/src/com/cyanogenmod/filemanager/ui/dialogs/FsoPropertiesDialog.java @@ -111,7 +111,7 @@ public class FsoPropertiesDialog /** * @hide */ - CheckBox[] mChkUserPermission; + private CheckBox[] mChkUserPermission; private CheckBox[] mChkGroupPermission; private CheckBox[] mChkOthersPermission; private TextView mInfoMsgView; @@ -253,7 +253,12 @@ public class FsoPropertiesDialog this.mTvSize = (TextView)contentView.findViewById(R.id.fso_properties_size); View vContatinsRow = contentView.findViewById(R.id.fso_properties_contains_row); this.mTvContains = (TextView)contentView.findViewById(R.id.fso_properties_contains); - TextView tvDate = (TextView)contentView.findViewById(R.id.fso_properties_date); + TextView tvLastAccessedTime = + (TextView)contentView.findViewById(R.id.fso_properties_last_accessed); + TextView tvLastModifiedTime = + (TextView)contentView.findViewById(R.id.fso_properties_last_modified); + TextView tvLastChangedTime = + (TextView)contentView.findViewById(R.id.fso_properties_last_changed); this.mSpnOwner = (Spinner)contentView.findViewById(R.id.fso_properties_owner); this.mSpnGroup = (Spinner)contentView.findViewById(R.id.fso_properties_group); this.mInfoMsgView = (TextView)contentView.findViewById(R.id.fso_info_msg); @@ -291,14 +296,26 @@ public class FsoPropertiesDialog this.mTvSize.setText(size); this.mTvContains.setText("-"); //$NON-NLS-1$ DateFormat df = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT); - tvDate.setText(df.format(this.mFso.getLastModifiedTime())); + try { + tvLastAccessedTime.setText(df.format(this.mFso.getLastAccessedTime())); + } catch (Exception e) { + tvLastAccessedTime.setText("-"); //$NON-NLS-1$ + } + try { + tvLastModifiedTime.setText(df.format(this.mFso.getLastModifiedTime())); + } catch (Exception e) { + tvLastModifiedTime.setText("-"); //$NON-NLS-1$ + } + try { + tvLastChangedTime.setText(df.format(this.mFso.getLastChangedTime())); + } catch (Exception e) { + tvLastChangedTime.setText("-"); //$NON-NLS-1$ + } //- Permissions 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 +350,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 +829,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 +844,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 +859,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,30 +902,38 @@ 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( ResourcesHelper.getIdentifier( res, "id", //$NON-NLS-1$ - String.format("fso_permissions_%s_read", type))); //$NON-NLS-1$ + String.format("fso_permissions_%s_special", type))); //$NON-NLS-1$ chkPermissions[1] = (CheckBox)rootView.findViewById( ResourcesHelper.getIdentifier( res, "id", //$NON-NLS-1$ - String.format("fso_permissions_%s_write", type))); //$NON-NLS-1$ + String.format("fso_permissions_%s_read", type))); //$NON-NLS-1$ chkPermissions[2] = (CheckBox)rootView.findViewById( ResourcesHelper.getIdentifier( res, "id", //$NON-NLS-1$ - String.format("fso_permissions_%s_execute", type))); //$NON-NLS-1$ + String.format("fso_permissions_%s_write", type))); //$NON-NLS-1$ chkPermissions[3] = (CheckBox)rootView.findViewById( ResourcesHelper.getIdentifier( res, "id", //$NON-NLS-1$ - String.format("fso_permissions_%s_special", type))); //$NON-NLS-1$ + String.format("fso_permissions_%s_execute", 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; } /** @@ -1085,19 +1117,17 @@ public class FsoPropertiesDialog * @param spinner The spinner */ private void adjustSpinnerSize(final Spinner spinner) { + final View v = this.mContentView.findViewById(R.id.fso_properties_dialog_tabhost); spinner.post(new Runnable() { @Override public void run() { // Align with the last checkbox of the column - CheckBox cb = FsoPropertiesDialog.this.mChkUserPermission[3]; - int cbW = cb.getMeasuredWidth(); - int[] cbPos = new int[2]; - cb.getLocationInWindow(cbPos); + int vW = v.getMeasuredWidth(); int[] cbSpn = new int[2]; spinner.getLocationInWindow(cbSpn); // Set the width - spinner.getLayoutParams().width = (cbPos[0] - cbSpn[0]) + cbW; + spinner.getLayoutParams().width = vW - cbSpn[0]; } }); } @@ -1145,9 +1175,17 @@ public class FsoPropertiesDialog theme.setTextColor(this.mContext, (TextView)v, "text_color"); //$NON-NLS-1$ v = this.mContentView.findViewById(R.id.fso_properties_contains); theme.setTextColor(this.mContext, (TextView)v, "text_color"); //$NON-NLS-1$ - v = this.mContentView.findViewById(R.id.fso_properties_date_label); + v = this.mContentView.findViewById(R.id.fso_properties_last_accessed_label); + theme.setTextColor(this.mContext, (TextView)v, "text_color"); //$NON-NLS-1$ + v = this.mContentView.findViewById(R.id.fso_properties_last_accessed); + theme.setTextColor(this.mContext, (TextView)v, "text_color"); //$NON-NLS-1$ + v = this.mContentView.findViewById(R.id.fso_properties_last_modified_label); + theme.setTextColor(this.mContext, (TextView)v, "text_color"); //$NON-NLS-1$ + v = this.mContentView.findViewById(R.id.fso_properties_last_modified); + theme.setTextColor(this.mContext, (TextView)v, "text_color"); //$NON-NLS-1$ + v = this.mContentView.findViewById(R.id.fso_properties_last_changed_label); theme.setTextColor(this.mContext, (TextView)v, "text_color"); //$NON-NLS-1$ - v = this.mContentView.findViewById(R.id.fso_properties_date); + v = this.mContentView.findViewById(R.id.fso_properties_last_changed); theme.setTextColor(this.mContext, (TextView)v, "text_color"); //$NON-NLS-1$ v = this.mContentView.findViewById(R.id.fso_properties_owner_label); 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..6ab30179 100644 --- a/src/com/cyanogenmod/filemanager/ui/widgets/DirectoryInlineAutocompleteTextView.java +++ b/src/com/cyanogenmod/filemanager/ui/widgets/DirectoryInlineAutocompleteTextView.java @@ -141,28 +141,28 @@ 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(); + String newParent = FileHelper.getParentDir(new File(value)); if (newParent == null) { newParent = FileHelper.ROOT_DIRECTORY; } - if (!newParent.endsWith(FileHelper.ROOT_DIRECTORY)) { - newParent += FileHelper.ROOT_DIRECTORY; + if (!newParent.endsWith(File.separator)) { + newParent += File.separator; } - 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..69746693 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; @@ -60,6 +63,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; @@ -825,7 +829,7 @@ public class NavigationView extends RelativeLayout implements } } - //Capture exception + //Capture exception (attach task, and use listener to do the anim) ExceptionUtil.attachAsyncTask( ex, new AsyncTask<Object, Integer, Boolean>() { @@ -835,20 +839,38 @@ 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); + } + }); return Boolean.TRUE; } - }); - ExceptionUtil.translateException(getContext(), ex); + final OnRelaunchCommandResult exListener = + new OnRelaunchCommandResult() { + @Override + public void onSuccess() { + // Do animation + fadeEfect(false); + } + @Override + public void onFailed(Throwable cause) { + // Do animation + fadeEfect(false); + } + @Override + public void onCancelled() { + // Do animation + fadeEfect(false); + } + }; + ExceptionUtil.translateException( + getContext(), ex, false, true, exListener); } return null; } @@ -857,10 +879,47 @@ 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(final boolean out) { + Activity activity = (Activity)getContext(); + activity.runOnUiThread(new Runnable() { + @Override + public void run() { + 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 +1080,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 +1115,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..932e219c 100644 --- a/src/com/cyanogenmod/filemanager/util/CommandHelper.java +++ b/src/com/cyanogenmod/filemanager/util/CommandHelper.java @@ -19,14 +19,12 @@ package com.cyanogenmod.filemanager.util; import android.content.Context; import com.cyanogenmod.filemanager.commands.AsyncResultListener; -import com.cyanogenmod.filemanager.commands.ChangeCurrentDirExecutable; import com.cyanogenmod.filemanager.commands.ChangeOwnerExecutable; import com.cyanogenmod.filemanager.commands.ChangePermissionsExecutable; import com.cyanogenmod.filemanager.commands.CompressExecutable; import com.cyanogenmod.filemanager.commands.CopyExecutable; import com.cyanogenmod.filemanager.commands.CreateDirExecutable; import com.cyanogenmod.filemanager.commands.CreateFileExecutable; -import com.cyanogenmod.filemanager.commands.CurrentDirExecutable; import com.cyanogenmod.filemanager.commands.DeleteDirExecutable; import com.cyanogenmod.filemanager.commands.DeleteFileExecutable; import com.cyanogenmod.filemanager.commands.DiskUsageExecutable; @@ -190,37 +188,6 @@ public final class CommandHelper { } /** - * Method that changes the current directory of the shell. - * - * @param context The current context (needed if console == null) - * @param dst The new directory - * @return boolean The operation result - * @param console The console in which execute the program. <code>null</code> - * to attach to the default console - * @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 ChangeCurrentDirExecutable - */ - public static boolean changeCurrentDir(Context context, String dst, Console console) - throws FileNotFoundException, IOException, ConsoleAllocException, - NoSuchFileOrDirectory, InsufficientPermissionsException, - CommandNotFoundException, OperationTimeoutException, - ExecutionException, InvalidCommandDefinitionException { - Console c = ensureConsole(context, console); - ChangeCurrentDirExecutable executable = - c.getExecutableFactory().newCreator().createChangeCurrentDirExecutable(dst); - execute(context, executable, c); - return executable.getResult().booleanValue(); - } - - /** * Method that changes the owner of a file system object. * * @param context The current context (needed if console == null) @@ -420,41 +387,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) @@ -486,36 +418,6 @@ public final class CommandHelper { } /** - * Method that retrieves the current directory of the shell. - * - * @param context The current context (needed if console == null) - * @param console The console in which execute the program. <code>null</code> - * to attach to the default console - * @return String The current 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 CurrentDirExecutable - */ - public static String getCurrentDir(Context context, Console console) - throws FileNotFoundException, IOException, ConsoleAllocException, - NoSuchFileOrDirectory, InsufficientPermissionsException, - CommandNotFoundException, OperationTimeoutException, - ExecutionException, InvalidCommandDefinitionException { - Console c = ensureConsole(context, console); - CurrentDirExecutable executable = - c.getExecutableFactory().newCreator().createCurrentDirExecutable(); - execute(context, executable, c); - return executable.getResult(); - } - - /** * Method that retrieves the information of a 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/ExceptionUtil.java b/src/com/cyanogenmod/filemanager/util/ExceptionUtil.java index 658a28cc..e7d6074d 100644 --- a/src/com/cyanogenmod/filemanager/util/ExceptionUtil.java +++ b/src/com/cyanogenmod/filemanager/util/ExceptionUtil.java @@ -293,6 +293,7 @@ public final class ExceptionUtil { Object result = CommandHelper.reexecute( context, executable, null); if (relaunchable.getTask() != null) { + relaunchable.getTask().cancel(true); relaunchable.getTask().execute(result); } } diff --git a/src/com/cyanogenmod/filemanager/util/FileHelper.java b/src/com/cyanogenmod/filemanager/util/FileHelper.java index abf4fed0..745596af 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; @@ -79,7 +78,7 @@ public final class FileHelper { * The root directory. * @hide */ - public static String ROOT_DIRECTORY = "/"; //$NON-NLS-1$ + public static final String ROOT_DIRECTORY = "/"; //$NON-NLS-1$ /** * The parent directory string. @@ -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 && path.getAbsolutePath().compareTo(FileHelper.ROOT_DIRECTORY) != 0) { + 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 b87110dd..5a6f8689 100644 --- a/src/com/cyanogenmod/filemanager/util/MimeTypeHelper.java +++ b/src/com/cyanogenmod/filemanager/util/MimeTypeHelper.java @@ -192,6 +192,34 @@ public final class MimeTypeHelper { } /** + * Method that checks whether a certain mime type is known to + * the application. + * + * @param context The current context + * @param mimeType The mime type to be checked + * @return true if mime type is known, false otherwise + */ + public static final boolean isMimeTypeKnown(Context context, String mimeType) { + //Ensure that mime types are loaded + if (sMimeTypes == null) { + loadMimeTypes(context); + } + + if (mimeType == null) { + return false; + } + + for (MimeTypeInfo info : sMimeTypes.values()) { + String mimeTypeRegExp = convertToRegExp(mimeType); + if (info.mMimeType.matches(mimeTypeRegExp)) { + return true; + } + } + + return false; + } + + /** * Method that returns the associated mime/type icon resource identifier of * the {@link FileSystemObject}. * @@ -205,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$ } @@ -236,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()) { @@ -324,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..b593875a 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,108 @@ 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(); + if (name.trim().length() == 0) { + name = FileHelper.ROOT_DIRECTORY; + } + 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 +246,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 +293,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 +330,67 @@ 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 && name.compareTo(FileHelper.ROOT_DIRECTORY) != 0) ? + 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 +398,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(); } } |