aboutsummaryrefslogtreecommitdiffstats
path: root/src/com/cyanogenmod/filemanager/ui/widgets/NavigationView.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/com/cyanogenmod/filemanager/ui/widgets/NavigationView.java')
-rw-r--r--src/com/cyanogenmod/filemanager/ui/widgets/NavigationView.java1154
1 files changed, 1154 insertions, 0 deletions
diff --git a/src/com/cyanogenmod/filemanager/ui/widgets/NavigationView.java b/src/com/cyanogenmod/filemanager/ui/widgets/NavigationView.java
new file mode 100644
index 00000000..40035331
--- /dev/null
+++ b/src/com/cyanogenmod/filemanager/ui/widgets/NavigationView.java
@@ -0,0 +1,1154 @@
+/*
+ * 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.ui.widgets;
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.content.res.TypedArray;
+import android.os.AsyncTask;
+import android.os.storage.StorageVolume;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.View;
+import android.widget.AdapterView;
+import android.widget.ListAdapter;
+import android.widget.RelativeLayout;
+import android.widget.Toast;
+
+import com.cyanogenmod.filemanager.FileManagerApplication;
+import com.cyanogenmod.filemanager.R;
+import com.cyanogenmod.filemanager.adapters.FileSystemObjectAdapter;
+import com.cyanogenmod.filemanager.adapters.FileSystemObjectAdapter.OnRequestMenuListener;
+import com.cyanogenmod.filemanager.adapters.FileSystemObjectAdapter.OnSelectionChangedListener;
+import com.cyanogenmod.filemanager.console.ConsoleAllocException;
+import com.cyanogenmod.filemanager.listeners.OnHistoryListener;
+import com.cyanogenmod.filemanager.listeners.OnRequestRefreshListener;
+import com.cyanogenmod.filemanager.listeners.OnSelectionListener;
+import com.cyanogenmod.filemanager.model.Directory;
+import com.cyanogenmod.filemanager.model.FileSystemObject;
+import com.cyanogenmod.filemanager.model.ParentDirectory;
+import com.cyanogenmod.filemanager.model.Symlink;
+import com.cyanogenmod.filemanager.parcelables.NavigationViewInfoParcelable;
+import com.cyanogenmod.filemanager.parcelables.SearchInfoParcelable;
+import com.cyanogenmod.filemanager.preferences.DefaultLongClickAction;
+import com.cyanogenmod.filemanager.preferences.FileManagerSettings;
+import com.cyanogenmod.filemanager.preferences.NavigationLayoutMode;
+import com.cyanogenmod.filemanager.preferences.ObjectIdentifier;
+import com.cyanogenmod.filemanager.preferences.ObjectStringIdentifier;
+import com.cyanogenmod.filemanager.preferences.Preferences;
+import com.cyanogenmod.filemanager.ui.policy.InfoActionPolicy;
+import com.cyanogenmod.filemanager.ui.policy.IntentsActionPolicy;
+import com.cyanogenmod.filemanager.util.CommandHelper;
+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.util.ArrayList;
+import java.util.List;
+
+/**
+ * The file manager implementation view (contains the graphical representation and the input
+ * management for a file manager; shows the folders/files, the mode view, react touch events,
+ * navigate, ...).
+ */
+public class NavigationView extends RelativeLayout implements
+ AdapterView.OnItemClickListener, AdapterView.OnItemLongClickListener,
+ BreadcrumbListener, OnSelectionChangedListener, OnRequestMenuListener,
+ OnSelectionListener, OnRequestRefreshListener {
+
+ /**
+ * An interface to communicate selection changes events.
+ */
+ public interface OnNavigationSelectionChangedListener {
+ /**
+ * Method invoked when the selection changed.
+ *
+ * @param navView The navigation view that generate the event
+ * @param selectedItems The new selected items
+ */
+ void onSelectionChanged(NavigationView navView, List<FileSystemObject> selectedItems);
+ }
+
+ /**
+ * An interface to communicate a request for show the menu associated
+ * with an item.
+ */
+ public interface OnNavigationRequestMenuListener {
+ /**
+ * Method invoked when a request to show the menu associated
+ * with an item is started.
+ *
+ * @param navView The navigation view that generate the event
+ * @param item The item for which the request was started
+ */
+ void onRequestMenu(NavigationView navView, FileSystemObject item);
+ }
+
+ /**
+ * An interface to communicate a request when the user choose a file.
+ */
+ public interface OnFilePickedListener {
+ /**
+ * Method invoked when a request when the user choose a file.
+ *
+ * @param item The item choose
+ */
+ void onFilePicked(FileSystemObject item);
+ }
+
+ /**
+ * The navigation view mode
+ * @hide
+ */
+ public enum NAVIGATION_MODE {
+ /**
+ * The navigation view acts as a browser, and allow open files itself.
+ */
+ BROWSABLE,
+ /**
+ * The navigation view acts as a picker of files
+ */
+ PICKABLE,
+ }
+
+ private static final String TAG = "NavigationView"; //$NON-NLS-1$
+
+ private int mId;
+ private String mCurrentDir;
+ private NavigationLayoutMode mCurrentMode;
+ /**
+ * @hide
+ */
+ List<FileSystemObject> mFiles;
+ private FileSystemObjectAdapter mAdapter;
+ private DefaultLongClickAction mDefaultLongClickAction;
+
+ private final Object mSync = new Object();
+
+ private OnHistoryListener mOnHistoryListener;
+ private OnNavigationSelectionChangedListener mOnNavigationSelectionChangedListener;
+ private OnNavigationRequestMenuListener mOnNavigationRequestMenuListener;
+ private OnFilePickedListener mOnFilePickedListener;
+
+ private boolean mChRooted;
+
+ private NAVIGATION_MODE mNavigationMode;
+
+ private String mMimeType = MimeTypeHelper.ALL_MIME_TYPES;
+
+ /**
+ * @hide
+ */
+ Breadcrumb mBreadcrumb;
+ /**
+ * @hide
+ */
+ NavigationCustomTitleView mTitle;
+ /**
+ * @hide
+ */
+ AdapterView<?> mAdapterView;
+
+ //The layout for icons mode
+ private static final int RESOURCE_MODE_ICONS_LAYOUT = R.layout.navigation_view_icons;
+ private static final int RESOURCE_MODE_ICONS_ITEM = R.layout.navigation_view_icons_item;
+ //The layout for simple mode
+ private static final int RESOURCE_MODE_SIMPLE_LAYOUT = R.layout.navigation_view_simple;
+ private static final int RESOURCE_MODE_SIMPLE_ITEM = R.layout.navigation_view_simple_item;
+ //The layout for details mode
+ private static final int RESOURCE_MODE_DETAILS_LAYOUT = R.layout.navigation_view_details;
+ private static final int RESOURCE_MODE_DETAILS_ITEM = R.layout.navigation_view_details_item;
+
+ //The current layout identifier (is shared for all the mode layout)
+ private static final int RESOURCE_CURRENT_LAYOUT = R.id.navigation_view_layout;
+
+ /**
+ * Constructor of <code>NavigationView</code>.
+ *
+ * @param context The current context
+ * @param attrs The attributes of the XML tag that is inflating the view.
+ */
+ public NavigationView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.Navigable);
+ try {
+ init(a);
+ } finally {
+ a.recycle();
+ }
+ }
+
+ /**
+ * Constructor of <code>NavigationView</code>.
+ *
+ * @param context The current context
+ * @param attrs The attributes of the XML tag that is inflating the view.
+ * @param defStyle The default style to apply to this view. If 0, no style
+ * will be applied (beyond what is included in the theme). This may
+ * either be an attribute resource, whose value will be retrieved
+ * from the current theme, or an explicit style resource.
+ */
+ public NavigationView(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+ TypedArray a = context.obtainStyledAttributes(
+ attrs, R.styleable.Navigable, defStyle, 0);
+ try {
+ init(a);
+ } finally {
+ a.recycle();
+ }
+ }
+
+ /**
+ * Invoked when the instance need to be saved.
+ *
+ * @return NavigationViewInfoParcelable The serialized info
+ */
+ public NavigationViewInfoParcelable onSaveState() {
+ //Return the persistent the data
+ NavigationViewInfoParcelable parcel = new NavigationViewInfoParcelable();
+ parcel.setId(this.mId);
+ parcel.setCurrentDir(this.mCurrentDir);
+ parcel.setChRooted(this.mChRooted);
+ parcel.setSelectedFiles(this.mAdapter.getSelectedItems());
+ parcel.setFiles(this.mFiles);
+ return parcel;
+ }
+
+ /**
+ * Invoked when the instance need to be restored.
+ *
+ * @param info The serialized info
+ */
+ public void onRestoreState(NavigationViewInfoParcelable info) {
+ //Restore the data
+ this.mId = info.getId();
+ this.mCurrentDir = info.getCurrentDir();
+ this.mChRooted = info.getChRooted();
+ this.mFiles = info.getFiles();
+ this.mAdapter.setSelectedItems(info.getSelectedFiles());
+
+ //Update the views
+ refresh();
+ }
+
+ /**
+ * Method that initializes the view. This method loads all the necessary
+ * information and create an appropriate layout for the view.
+ *
+ * @param tarray The type array
+ */
+ private void init(TypedArray tarray) {
+ // Retrieve the mode
+ this.mNavigationMode = NAVIGATION_MODE.BROWSABLE;
+ int mode = tarray.getInteger(
+ R.styleable.Navigable_navigation,
+ NAVIGATION_MODE.BROWSABLE.ordinal());
+ if (mode >= 0 && mode < NAVIGATION_MODE.values().length) {
+ this.mNavigationMode = NAVIGATION_MODE.values()[mode];
+ }
+
+ //Initialize variables
+ this.mFiles = new ArrayList<FileSystemObject>();
+
+ // Is ChRooted environment?
+ if (this.mNavigationMode.compareTo(NAVIGATION_MODE.PICKABLE) == 0) {
+ // Pick mode is always ChRooted
+ this.mChRooted = true;
+ } else {
+ this.mChRooted = !FileManagerApplication.isAdvancedMode();
+ }
+
+ // Default long-click action
+ String defaultValue = ((ObjectStringIdentifier)FileManagerSettings.
+ SETTINGS_DEFAULT_LONG_CLICK_ACTION.getDefaultValue()).getId();
+ String value = Preferences.getSharedPreferences().getString(
+ FileManagerSettings.SETTINGS_DEFAULT_LONG_CLICK_ACTION.getId(),
+ defaultValue);
+ DefaultLongClickAction lcMode = DefaultLongClickAction.fromId(value);
+ this.mDefaultLongClickAction = lcMode;
+
+ //Retrieve the default configuration
+ if (this.mNavigationMode.compareTo(NAVIGATION_MODE.BROWSABLE) == 0) {
+ SharedPreferences preferences = Preferences.getSharedPreferences();
+ int viewMode = preferences.getInt(
+ FileManagerSettings.SETTINGS_LAYOUT_MODE.getId(),
+ ((ObjectIdentifier)FileManagerSettings.
+ SETTINGS_LAYOUT_MODE.getDefaultValue()).getId());
+ changeViewMode(NavigationLayoutMode.fromId(viewMode));
+ } else {
+ // Pick mode has always a details layout
+ changeViewMode(NavigationLayoutMode.DETAILS);
+ }
+ }
+
+ /**
+ * Method that returns the mime/type used by this class. Only the files with this mime/type
+ * are shown.
+ *
+ * @return String The mime/type
+ */
+ public String getMimeType() {
+ return this.mMimeType;
+ }
+
+ /**
+ * Method that sets the mime/type used by this class. Only the files with this mime/type
+ * are shown.
+ *
+ * @param mimeType String The mime/type
+ */
+ public void setMimeType(String mimeType) {
+ this.mMimeType = mimeType;
+ }
+
+ /**
+ * Method that returns the current file list of the navigation view.
+ *
+ * @return List<FileSystemObject> The current file list of the navigation view
+ */
+ public List<FileSystemObject> getFiles() {
+ if (this.mFiles == null) {
+ return null;
+ }
+ return new ArrayList<FileSystemObject>(this.mFiles);
+ }
+
+ /**
+ * Method that returns the current file list of the navigation view.
+ *
+ * @return List<FileSystemObject> The current file list of the navigation view
+ */
+ public List<FileSystemObject> getSelectedFiles() {
+ if (this.mAdapter != null && this.mAdapter.getSelectedItems() != null) {
+ return new ArrayList<FileSystemObject>(this.mAdapter.getSelectedItems());
+ }
+ return null;
+ }
+
+ /**
+ * Method that returns the custom title fragment associated with this navigation view.
+ *
+ * @return NavigationCustomTitleView The custom title view fragment
+ */
+ public NavigationCustomTitleView getCustomTitle() {
+ return this.mTitle;
+ }
+
+ /**
+ * Method that associates the custom title fragment with this navigation view.
+ *
+ * @param title The custom title view fragment
+ */
+ public void setCustomTitle(NavigationCustomTitleView title) {
+ this.mTitle = title;
+ }
+
+ /**
+ * Method that returns the breadcrumb associated with this navigation view.
+ *
+ * @return Breadcrumb The breadcrumb view fragment
+ */
+ public Breadcrumb getBreadcrumb() {
+ return this.mBreadcrumb;
+ }
+
+ /**
+ * Method that associates the breadcrumb with this navigation view.
+ *
+ * @param breadcrumb The breadcrumb view fragment
+ */
+ public void setBreadcrumb(Breadcrumb breadcrumb) {
+ this.mBreadcrumb = breadcrumb;
+ this.mBreadcrumb.addBreadcrumbListener(this);
+ }
+
+ /**
+ * Method that sets the default long-click action
+ *
+ * @param mDefaultLongClickAction The default long-click action
+ */
+ public void setDefaultLongClickAction(DefaultLongClickAction mDefaultLongClickAction) {
+ this.mDefaultLongClickAction = mDefaultLongClickAction;
+
+ // Pick mode doesn't implements the onlongclick
+ if (this.mNavigationMode.compareTo(NAVIGATION_MODE.BROWSABLE) == 0) {
+ // Register the long-click listener only if needed. Icon layout mode always use
+ // actions menu on long-click
+ if (this.mDefaultLongClickAction.compareTo(DefaultLongClickAction.NONE) != 0 ||
+ this.mCurrentMode.compareTo(NavigationLayoutMode.ICONS) == 0) {
+ this.mAdapterView.setOnItemLongClickListener(this);
+ } else {
+ this.mAdapterView.setOnItemLongClickListener(null);
+ }
+ } else {
+ this.mAdapterView.setOnItemLongClickListener(null);
+ }
+ }
+
+ /**
+ * Method that sets the listener for communicate history changes.
+ *
+ * @param onHistoryListener The listener for communicate history changes
+ */
+ public void setOnHistoryListener(OnHistoryListener onHistoryListener) {
+ this.mOnHistoryListener = onHistoryListener;
+ }
+
+ /**
+ * Method that sets the listener which communicates selection changes.
+ *
+ * @param onNavigationSelectionChangedListener The listener reference
+ */
+ public void setOnNavigationSelectionChangedListener(
+ OnNavigationSelectionChangedListener onNavigationSelectionChangedListener) {
+ this.mOnNavigationSelectionChangedListener = onNavigationSelectionChangedListener;
+ }
+
+ /**
+ * Method that sets the listener for menu item requests.
+ *
+ * @param onNavigationRequestMenuListener The listener reference
+ */
+ public void setOnNavigationOnRequestMenuListener(
+ OnNavigationRequestMenuListener onNavigationRequestMenuListener) {
+ this.mOnNavigationRequestMenuListener = onNavigationRequestMenuListener;
+ }
+
+ /**
+ * @return the mOnFilePickedListener
+ */
+ public OnFilePickedListener getOnFilePickedListener() {
+ return this.mOnFilePickedListener;
+ }
+
+ /**
+ * Method that sets the listener for picked items
+ *
+ * @param onFilePickedListener The listener reference
+ */
+ public void setOnFilePickedListener(OnFilePickedListener onFilePickedListener) {
+ this.mOnFilePickedListener = onFilePickedListener;
+ }
+
+ /**
+ * Method that forces the view to scroll to the file system object passed.
+ *
+ * @param fso The file system object
+ */
+ public void scrollTo(FileSystemObject fso) {
+ if (fso != null) {
+ try {
+ int position = this.mAdapter.getPosition(fso);
+ this.mAdapterView.setSelection(position);
+ } catch (Exception e) {
+ this.mAdapterView.setSelection(0);
+ }
+ }
+ }
+
+ /**
+ * Method that refresh the view data.
+ */
+ public void refresh() {
+ FileSystemObject fso = null;
+ // Try to restore the previous scroll position
+ try {
+ if (this.mAdapterView != null && this.mAdapter != null) {
+ int position = this.mAdapterView.getFirstVisiblePosition();
+ fso = this.mAdapter.getItem(position);
+ }
+ } catch (Throwable _throw) {/**NON BLOCK**/}
+ refresh(fso);
+ }
+
+ /**
+ * Method that refresh the view data.
+ *
+ * @param scrollTo Scroll to object
+ */
+ public void refresh(FileSystemObject scrollTo) {
+ //Check that current directory was set
+ if (this.mCurrentDir == null || this.mFiles == null) {
+ return;
+ }
+
+ //Reload data
+ changeCurrentDir(this.mCurrentDir, false, true, false, null, scrollTo);
+ }
+
+ /**
+ * Method that change the view mode.
+ *
+ * @param newMode The new mode
+ */
+ @SuppressWarnings({ "unchecked", "null" })
+ public void changeViewMode(final NavigationLayoutMode newMode) {
+ synchronized (this.mSync) {
+ //Check that it is really necessary change the mode
+ if (this.mCurrentMode != null && this.mCurrentMode.compareTo(newMode) == 0) {
+ return;
+ }
+
+ //Creates the new layout
+ AdapterView<ListAdapter> newView = null;
+ int itemResourceId = -1;
+ if (newMode.compareTo(NavigationLayoutMode.ICONS) == 0) {
+ newView = (AdapterView<ListAdapter>)inflate(
+ getContext(), RESOURCE_MODE_ICONS_LAYOUT, null);
+ itemResourceId = RESOURCE_MODE_ICONS_ITEM;
+ } else if (newMode.compareTo(NavigationLayoutMode.SIMPLE) == 0) {
+ newView = (AdapterView<ListAdapter>)inflate(
+ getContext(), RESOURCE_MODE_SIMPLE_LAYOUT, null);
+ itemResourceId = RESOURCE_MODE_SIMPLE_ITEM;
+ } else if (newMode.compareTo(NavigationLayoutMode.DETAILS) == 0) {
+ newView = (AdapterView<ListAdapter>)inflate(
+ getContext(), RESOURCE_MODE_DETAILS_LAYOUT, null);
+ itemResourceId = RESOURCE_MODE_DETAILS_ITEM;
+ }
+
+ //Get the current adapter and its adapter list
+ List<FileSystemObject> files = new ArrayList<FileSystemObject>(this.mFiles);
+ final AdapterView<ListAdapter> current =
+ (AdapterView<ListAdapter>)findViewById(RESOURCE_CURRENT_LAYOUT);
+ FileSystemObjectAdapter adapter =
+ new FileSystemObjectAdapter(
+ getContext(),
+ new ArrayList<FileSystemObject>(),
+ itemResourceId,
+ this.mNavigationMode.compareTo(NAVIGATION_MODE.PICKABLE) == 0);
+ adapter.setOnSelectionChangedListener(this);
+ adapter.setOnRequestMenuListener(this);
+
+ //Remove current layout
+ if (current != null) {
+ if (current.getAdapter() != null) {
+ //Save selected items before dispose adapter
+ FileSystemObjectAdapter currentAdapter =
+ ((FileSystemObjectAdapter)current.getAdapter());
+ adapter.setSelectedItems(currentAdapter.getSelectedItems());
+ currentAdapter.dispose();
+ }
+ removeView(current);
+ }
+ this.mFiles = files;
+ adapter.addAll(files);
+ adapter.notifyDataSetChanged();
+
+ //Set the adapter
+ this.mAdapter = adapter;
+ newView.setAdapter(this.mAdapter);
+ newView.setOnItemClickListener(NavigationView.this);
+
+ //Add the new layout
+ this.mAdapterView = newView;
+ addView(newView, 0);
+ this.mCurrentMode = newMode;
+
+ // Pick mode doesn't implements the onlongclick
+ setDefaultLongClickAction(this.mDefaultLongClickAction);
+
+ //Save the preference (only in navigation browse mode)
+ if (this.mNavigationMode.compareTo(NAVIGATION_MODE.BROWSABLE) == 0) {
+ try {
+ Preferences.savePreference(
+ FileManagerSettings.SETTINGS_LAYOUT_MODE, newMode, true);
+ } catch (Exception ex) {
+ Log.e(TAG, "Save of view mode preference fails", ex); //$NON-NLS-1$
+ }
+ }
+ }
+ }
+
+ /**
+ * Method that removes a {@link FileSystemObject} from the view
+ *
+ * @param fso The file system object
+ */
+ public void removeItem(FileSystemObject fso) {
+ this.mAdapter.remove(fso);
+ this.mAdapter.notifyDataSetChanged();
+ }
+
+ /**
+ * Method that removes a file system object from his path from the view
+ *
+ * @param path The file system object path
+ */
+ public void removeItem(String path) {
+ FileSystemObject fso = this.mAdapter.getItem(path);
+ if (fso != null) {
+ this.mAdapter.remove(fso);
+ this.mAdapter.notifyDataSetChanged();
+ }
+ }
+
+ /**
+ * Method that returns the current directory.
+ *
+ * @return String The current directory
+ */
+ public String getCurrentDir() {
+ return this.mCurrentDir;
+ }
+
+ /**
+ * Method that changes the current directory of the view.
+ *
+ * @param newDir The new directory location
+ */
+ public void changeCurrentDir(final String newDir) {
+ changeCurrentDir(newDir, true, false, false, null, null);
+ }
+
+ /**
+ * Method that changes the current directory of the view.
+ *
+ * @param newDir The new directory location
+ * @param searchInfo The search information (if calling activity is {@link "SearchActivity"})
+ */
+ public void changeCurrentDir(final String newDir, SearchInfoParcelable searchInfo) {
+ changeCurrentDir(newDir, true, false, false, searchInfo, null);
+ }
+
+ /**
+ * Method that changes the current directory of the view.
+ *
+ * @param newDir The new directory location
+ * @param addToHistory Add the directory to history
+ * @param reload Force the reload of the data
+ * @param useCurrent If this method must use the actual data (for back actions)
+ * @param searchInfo The search information (if calling activity is {@link "SearchActivity"})
+ * @param scrollTo If not null, then listview must scroll to this item
+ */
+ private void changeCurrentDir(
+ final String newDir, final boolean addToHistory,
+ final boolean reload, final boolean useCurrent,
+ final SearchInfoParcelable searchInfo, final FileSystemObject scrollTo) {
+
+ // Check navigation security (don't allow to go outside the ChRooted environment if one
+ // is created)
+ final String fNewDir = checkChRootedNavigation(newDir);
+
+ synchronized (this.mSync) {
+ //Check that it is really necessary change the directory
+ if (!reload && this.mCurrentDir != null && this.mCurrentDir.compareTo(fNewDir) == 0) {
+ return;
+ }
+
+ final boolean hasChanged =
+ !(this.mCurrentDir != null && this.mCurrentDir.compareTo(fNewDir) == 0);
+ final boolean isNewHistory = (this.mCurrentDir != null);
+
+ //Execute the listing in a background process
+ AsyncTask<String, Integer, List<FileSystemObject>> task =
+ new AsyncTask<String, Integer, List<FileSystemObject>>() {
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected List<FileSystemObject> doInBackground(String... params) {
+ try {
+ //Reset the custom title view and returns to breadcrumb
+ if (NavigationView.this.mTitle != null) {
+ NavigationView.this.mTitle.post(new Runnable() {
+ @Override
+ public void run() {
+ try {
+ NavigationView.this.mTitle.restoreView();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ });
+ }
+
+
+ //Start of loading data
+ if (NavigationView.this.mBreadcrumb != null) {
+ try {
+ NavigationView.this.mBreadcrumb.startLoading();
+ } catch (Throwable ex) {
+ /**NON BLOCK**/
+ }
+ }
+
+ //Get the files, resolve links and apply configuration
+ //(sort, hidden, ...)
+ List<FileSystemObject> files = NavigationView.this.mFiles;
+ if (!useCurrent) {
+ files = CommandHelper.listFiles(getContext(), fNewDir, null);
+ }
+ return files;
+ } catch (final ConsoleAllocException e) {
+ //Show exception and exists
+ NavigationView.this.post(new Runnable() {
+ @Override
+ public void run() {
+ Context ctx = getContext();
+ Log.e(TAG, ctx.getString(
+ R.string.msgs_cant_create_console), e);
+ DialogHelper.showToast(ctx,
+ R.string.msgs_cant_create_console,
+ Toast.LENGTH_LONG);
+ ((Activity)ctx).finish();
+ }
+ });
+ return null;
+
+ } catch (Exception ex) {
+ //End of loading data
+ if (NavigationView.this.mBreadcrumb != null) {
+ try {
+ NavigationView.this.mBreadcrumb.endLoading();
+ } catch (Throwable ex2) {
+ /**NON BLOCK**/
+ }
+ }
+
+ //Capture exception
+ ExceptionUtil.attachAsyncTask(
+ ex,
+ new AsyncTask<Object, Integer, Boolean>() {
+ @Override
+ @SuppressWarnings("unchecked")
+ protected Boolean doInBackground(Object... taskParams) {
+ 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);
+ }
+ });
+ return Boolean.TRUE;
+ }
+
+ });
+ ExceptionUtil.translateException(getContext(), ex);
+ }
+ return null;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected void onPostExecute(List<FileSystemObject> files) {
+ onPostExecuteTask(
+ files, addToHistory, isNewHistory,
+ hasChanged, searchInfo, fNewDir, scrollTo);
+ }
+ };
+ task.execute(fNewDir);
+ }
+ }
+
+
+ /**
+ * Method invoked when a execution ends.
+ *
+ * @param files The files obtains from the list
+ * @param addToHistory If add path to history
+ * @param isNewHistory If is new history
+ * @param hasChanged If current directory was changed
+ * @param searchInfo The search information (if calling activity is {@link "SearchActivity"})
+ * @param newDir The new directory
+ * @param scrollTo If not null, then listview must scroll to this item
+ * @hide
+ */
+ void onPostExecuteTask(
+ List<FileSystemObject> files, boolean addToHistory, boolean isNewHistory,
+ boolean hasChanged, SearchInfoParcelable searchInfo,
+ String newDir, final FileSystemObject scrollTo) {
+ try {
+ //Check that there is not errors and have some data
+ if (files == null) {
+ return;
+ }
+
+ //Apply user preferences
+ List<FileSystemObject> sortedFiles =
+ FileHelper.applyUserPreferences(files, this.mMimeType, this.mChRooted);
+
+ //Remove parent directory if we are in the root of a chrooted environment
+ if (this.mChRooted && StorageHelper.isStorageVolume(newDir)) {
+ if (files.size() > 0 && files.get(0) instanceof ParentDirectory) {
+ files.remove(0);
+ }
+ }
+
+ //Load the data
+ loadData(sortedFiles);
+ NavigationView.this.mFiles = sortedFiles;
+ if (searchInfo != null) {
+ searchInfo.setSuccessNavigation(true);
+ }
+
+ //Add to history?
+ if (addToHistory && hasChanged && isNewHistory) {
+ if (NavigationView.this.mOnHistoryListener != null) {
+ //Communicate the need of a history change
+ NavigationView.this.mOnHistoryListener.onNewHistory(onSaveState());
+ }
+ }
+
+ //Change the breadcrumb
+ if (NavigationView.this.mBreadcrumb != null) {
+ NavigationView.this.mBreadcrumb.changeBreadcrumbPath(newDir, this.mChRooted);
+ }
+
+ //Scroll to object?
+ if (scrollTo != null) {
+ scrollTo(scrollTo);
+ }
+
+ //The current directory is now the "newDir"
+ NavigationView.this.mCurrentDir = newDir;
+
+ } finally {
+ //If calling activity is search, then save the search history
+ if (searchInfo != null) {
+ NavigationView.this.mOnHistoryListener.onNewHistory(searchInfo);
+ }
+
+ //End of loading data
+ try {
+ NavigationView.this.mBreadcrumb.endLoading();
+ } catch (Throwable ex) {
+ /**NON BLOCK**/
+ }
+ }
+ }
+
+ /**
+ * Method that loads the files in the adapter.
+ *
+ * @param files The files to load in the adapter
+ * @hide
+ */
+ @SuppressWarnings("unchecked")
+ private void loadData(final List<FileSystemObject> files) {
+ //Notify data to adapter view
+ final AdapterView<ListAdapter> view =
+ (AdapterView<ListAdapter>)findViewById(RESOURCE_CURRENT_LAYOUT);
+ FileSystemObjectAdapter adapter = (FileSystemObjectAdapter)view.getAdapter();
+ adapter.clear();
+ adapter.addAll(files);
+ adapter.notifyDataSetChanged();
+ view.setSelection(0);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
+ // Different actions depending on user preference
+
+ // Get the adapter and the fso
+ FileSystemObjectAdapter adapter = ((FileSystemObjectAdapter)parent.getAdapter());
+ FileSystemObject fso = adapter.getItem(position);
+
+ // Parent directory hasn't actions
+ if (fso instanceof ParentDirectory) {
+ return false;
+ }
+
+ // In icons layout mode, always long-click is associated to show actions menu
+ if (this.mCurrentMode.compareTo(NavigationLayoutMode.ICONS) == 0) {
+ onRequestMenu(fso);
+ return true;
+ }
+
+ // Select/deselect
+ if (this.mDefaultLongClickAction.compareTo(
+ DefaultLongClickAction.SELECT_DESELECT) == 0) {
+ if (adapter.isSelectable(view)) {
+ adapter.toggleSelection(view);
+ }
+ }
+
+ // Show content description
+ else if (this.mDefaultLongClickAction.compareTo(
+ DefaultLongClickAction.SHOW_CONTENT_DESCRIPTION) == 0) {
+ InfoActionPolicy.showContentDescription(getContext(), fso);
+ }
+
+ // Open with
+ else if (this.mDefaultLongClickAction.compareTo(DefaultLongClickAction.OPEN_WITH) == 0) {
+ if (!FileHelper.isDirectory(fso)) {
+ IntentsActionPolicy.openFileSystemObject(getContext(), fso, true, null, null);
+ } else {
+ return false;
+ }
+ }
+
+ // Show properties
+ else if (this.mDefaultLongClickAction.compareTo(
+ DefaultLongClickAction.SHOW_PROPERTIES) == 0) {
+ InfoActionPolicy.showPropertiesDialog(getContext(), fso, this);
+ }
+
+ // Show actions
+ else if (this.mDefaultLongClickAction.compareTo(
+ DefaultLongClickAction.SHOW_ACTIONS) == 0) {
+ onRequestMenu(fso);
+ }
+
+ return true; //Always consume the event
+ }
+
+ /**
+ * Method that opens or navigates to the {@link FileSystemObject}
+ *
+ * @param fso The file system object
+ */
+ public void open(FileSystemObject fso) {
+ open(fso, null);
+ }
+
+ /**
+ * Method that opens or navigates to the {@link FileSystemObject}
+ *
+ * @param fso The file system object
+ * @param searchInfo The search info
+ */
+ public void open(FileSystemObject fso, SearchInfoParcelable searchInfo) {
+ // If is a folder, then navigate to
+ if (FileHelper.isDirectory(fso)) {
+ changeCurrentDir(fso.getFullPath(), searchInfo);
+ } else {
+ // Open the file with the preferred registered app
+ IntentsActionPolicy.openFileSystemObject(getContext(), fso, false, null, null);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
+ try {
+ FileSystemObject fso = ((FileSystemObjectAdapter)parent.getAdapter()).getItem(position);
+ if (fso instanceof ParentDirectory) {
+ changeCurrentDir(fso.getParent(), true, false, false, null, null);
+ } else if (fso instanceof Directory) {
+ changeCurrentDir(fso.getFullPath(), true, false, false, null, null);
+ } 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);
+ }
+ } 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);
+ }
+ }
+ }
+ } catch (Throwable ex) {
+ ExceptionUtil.translateException(getContext(), ex);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void onRequestRefresh(Object o) {
+ if (o instanceof FileSystemObject) {
+ refresh((FileSystemObject)o);
+ }
+ onDeselectAll();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void onRequestRemove(Object o) {
+ if (o instanceof FileSystemObject) {
+ removeItem((FileSystemObject)o);
+ }
+ onDeselectAll();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void onNavigateTo(Object o) {
+ // Ignored
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void onBreadcrumbItemClick(BreadcrumbItem item) {
+ changeCurrentDir(item.getItemPath(), true, true, false, null, null);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void onSelectionChanged(final List<FileSystemObject> selectedItems) {
+ if (this.mOnNavigationSelectionChangedListener != null) {
+ this.mOnNavigationSelectionChangedListener.onSelectionChanged(this, selectedItems);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void onRequestMenu(final FileSystemObject item) {
+ if (this.mOnNavigationRequestMenuListener != null) {
+ this.mOnNavigationRequestMenuListener.onRequestMenu(this, item);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void onToggleSelection(FileSystemObject fso) {
+ if (this.mAdapter != null) {
+ this.mAdapter.toggleSelection(fso);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void onDeselectAll() {
+ if (this.mAdapter != null) {
+ this.mAdapter.deselectedAll();
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void onSelectAllVisibleItems() {
+ if (this.mAdapter != null) {
+ this.mAdapter.selectedAllVisibleItems();
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void onDeselectAllVisibleItems() {
+ if (this.mAdapter != null) {
+ this.mAdapter.deselectedAllVisibleItems();
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public List<FileSystemObject> onRequestSelectedFiles() {
+ return this.getSelectedFiles();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public List<FileSystemObject> onRequestCurrentItems() {
+ return this.getFiles();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String onRequestCurrentDir() {
+ return this.mCurrentDir;
+ }
+
+ /**
+ * Method that creates a ChRooted environment, protecting the user to break anything
+ * in the device
+ * @hide
+ */
+ public void createChRooted() {
+ // If we are in a ChRooted environment, then do nothing
+ if (this.mChRooted) return;
+ this.mChRooted = true;
+
+ //Change to first storage volume
+ StorageVolume[] volumes =
+ StorageHelper.getStorageVolumes(getContext());
+ if (volumes != null && volumes.length > 0) {
+ changeCurrentDir(volumes[0].getPath(), false, true, false, null, null);
+ }
+ }
+
+ /**
+ * Method that exits from a ChRooted environment
+ * @hide
+ */
+ public void exitChRooted() {
+ // If we aren't in a ChRooted environment, then do nothing
+ if (!this.mChRooted) return;
+ this.mChRooted = false;
+
+ // Refresh
+ refresh();
+ }
+
+ /**
+ * Method that ensures that the user don't go outside the ChRooted environment
+ *
+ * @param newDir The new directory to navigate to
+ * @return String
+ */
+ private String checkChRootedNavigation(String newDir) {
+ // If we aren't in ChRooted environment, then there is nothing to check
+ if (!this.mChRooted) return newDir;
+
+ // Check if the path is owned by one of the storage volumes
+ if (!StorageHelper.isPathInStorageVolume(newDir)) {
+ StorageVolume[] volumes = StorageHelper.getStorageVolumes(getContext());
+ if (volumes != null && volumes.length > 0) {
+ return volumes[0].getPath();
+ }
+ }
+ return newDir;
+ }
+
+}