2 * Copyright (C) 2012 The CyanogenMod Project
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 package com.cyanogenmod.filemanager.ui.widgets;
19 import android.app.Activity;
20 import android.content.Context;
21 import android.content.SharedPreferences;
22 import android.content.res.TypedArray;
23 import android.os.AsyncTask;
24 import android.os.storage.StorageVolume;
25 import android.util.AttributeSet;
26 import android.util.Log;
27 import android.view.View;
28 import android.widget.AdapterView;
29 import android.widget.ListAdapter;
30 import android.widget.RelativeLayout;
31 import android.widget.Toast;
33 import com.cyanogenmod.filemanager.FileManagerApplication;
34 import com.cyanogenmod.filemanager.R;
35 import com.cyanogenmod.filemanager.adapters.FileSystemObjectAdapter;
36 import com.cyanogenmod.filemanager.adapters.FileSystemObjectAdapter.OnSelectionChangedListener;
37 import com.cyanogenmod.filemanager.console.ConsoleAllocException;
38 import com.cyanogenmod.filemanager.listeners.OnHistoryListener;
39 import com.cyanogenmod.filemanager.listeners.OnRequestRefreshListener;
40 import com.cyanogenmod.filemanager.listeners.OnSelectionListener;
41 import com.cyanogenmod.filemanager.model.Directory;
42 import com.cyanogenmod.filemanager.model.FileSystemObject;
43 import com.cyanogenmod.filemanager.model.ParentDirectory;
44 import com.cyanogenmod.filemanager.model.Symlink;
45 import com.cyanogenmod.filemanager.parcelables.NavigationViewInfoParcelable;
46 import com.cyanogenmod.filemanager.parcelables.SearchInfoParcelable;
47 import com.cyanogenmod.filemanager.preferences.AccessMode;
48 import com.cyanogenmod.filemanager.preferences.FileManagerSettings;
49 import com.cyanogenmod.filemanager.preferences.NavigationLayoutMode;
50 import com.cyanogenmod.filemanager.preferences.ObjectIdentifier;
51 import com.cyanogenmod.filemanager.preferences.Preferences;
52 import com.cyanogenmod.filemanager.ui.policy.IntentsActionPolicy;
53 import com.cyanogenmod.filemanager.util.CommandHelper;
54 import com.cyanogenmod.filemanager.util.DialogHelper;
55 import com.cyanogenmod.filemanager.util.ExceptionUtil;
56 import com.cyanogenmod.filemanager.util.FileHelper;
57 import com.cyanogenmod.filemanager.util.MimeTypeHelper;
58 import com.cyanogenmod.filemanager.util.StorageHelper;
60 import java.util.ArrayList;
61 import java.util.List;
64 * The file manager implementation view (contains the graphical representation and the input
65 * management for a file manager; shows the folders/files, the mode view, react touch events,
68 public class NavigationView extends RelativeLayout implements
69 AdapterView.OnItemClickListener, AdapterView.OnItemLongClickListener,
70 BreadcrumbListener, OnSelectionChangedListener, OnSelectionListener, OnRequestRefreshListener {
73 * An interface to communicate selection changes events.
75 public interface OnNavigationSelectionChangedListener {
77 * Method invoked when the selection changed.
79 * @param navView The navigation view that generate the event
80 * @param selectedItems The new selected items
82 void onSelectionChanged(NavigationView navView, List<FileSystemObject> selectedItems);
86 * An interface to communicate a request for show the menu associated
89 public interface OnNavigationRequestMenuListener {
91 * Method invoked when a request to show the menu associated
92 * with an item is started.
94 * @param navView The navigation view that generate the event
95 * @param item The item for which the request was started
97 void onRequestMenu(NavigationView navView, FileSystemObject item);
101 * An interface to communicate a request when the user choose a file.
103 public interface OnFilePickedListener {
105 * Method invoked when a request when the user choose a file.
107 * @param item The item choose
109 void onFilePicked(FileSystemObject item);
113 * The navigation view mode
116 public enum NAVIGATION_MODE {
118 * The navigation view acts as a browser, and allow open files itself.
122 * The navigation view acts as a picker of files
127 private static final String TAG = "NavigationView"; //$NON-NLS-1$
130 private String mCurrentDir;
131 private NavigationLayoutMode mCurrentMode;
135 List<FileSystemObject> mFiles;
136 private FileSystemObjectAdapter mAdapter;
138 private final Object mSync = new Object();
140 private OnHistoryListener mOnHistoryListener;
141 private OnNavigationSelectionChangedListener mOnNavigationSelectionChangedListener;
142 private OnNavigationRequestMenuListener mOnNavigationRequestMenuListener;
143 private OnFilePickedListener mOnFilePickedListener;
145 private boolean mChRooted;
147 private NAVIGATION_MODE mNavigationMode;
149 private String mMimeType = MimeTypeHelper.ALL_MIME_TYPES;
154 Breadcrumb mBreadcrumb;
158 NavigationCustomTitleView mTitle;
162 AdapterView<?> mAdapterView;
164 //The layout for icons mode
165 private static final int RESOURCE_MODE_ICONS_LAYOUT = R.layout.navigation_view_icons;
166 private static final int RESOURCE_MODE_ICONS_ITEM = R.layout.navigation_view_icons_item;
167 //The layout for simple mode
168 private static final int RESOURCE_MODE_SIMPLE_LAYOUT = R.layout.navigation_view_simple;
169 private static final int RESOURCE_MODE_SIMPLE_ITEM = R.layout.navigation_view_simple_item;
170 //The layout for details mode
171 private static final int RESOURCE_MODE_DETAILS_LAYOUT = R.layout.navigation_view_details;
172 private static final int RESOURCE_MODE_DETAILS_ITEM = R.layout.navigation_view_details_item;
174 //The current layout identifier (is shared for all the mode layout)
175 private static final int RESOURCE_CURRENT_LAYOUT = R.id.navigation_view_layout;
178 * Constructor of <code>NavigationView</code>.
180 * @param context The current context
181 * @param attrs The attributes of the XML tag that is inflating the view.
183 public NavigationView(Context context, AttributeSet attrs) {
184 super(context, attrs);
185 TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.Navigable);
194 * Constructor of <code>NavigationView</code>.
196 * @param context The current context
197 * @param attrs The attributes of the XML tag that is inflating the view.
198 * @param defStyle The default style to apply to this view. If 0, no style
199 * will be applied (beyond what is included in the theme). This may
200 * either be an attribute resource, whose value will be retrieved
201 * from the current theme, or an explicit style resource.
203 public NavigationView(Context context, AttributeSet attrs, int defStyle) {
204 super(context, attrs, defStyle);
205 TypedArray a = context.obtainStyledAttributes(
206 attrs, R.styleable.Navigable, defStyle, 0);
215 * Invoked when the instance need to be saved.
217 * @return NavigationViewInfoParcelable The serialized info
219 public NavigationViewInfoParcelable onSaveState() {
220 //Return the persistent the data
221 NavigationViewInfoParcelable parcel = new NavigationViewInfoParcelable();
222 parcel.setId(this.mId);
223 parcel.setCurrentDir(this.mCurrentDir);
224 parcel.setChRooted(this.mChRooted);
225 parcel.setSelectedFiles(this.mAdapter.getSelectedItems());
226 parcel.setFiles(this.mFiles);
231 * Invoked when the instance need to be restored.
233 * @param info The serialized info
235 public void onRestoreState(NavigationViewInfoParcelable info) {
237 this.mId = info.getId();
238 this.mCurrentDir = info.getCurrentDir();
239 this.mChRooted = info.getChRooted();
240 this.mFiles = info.getFiles();
241 this.mAdapter.setSelectedItems(info.getSelectedFiles());
248 * Method that initializes the view. This method loads all the necessary
249 * information and create an appropriate layout for the view.
251 * @param tarray The type array
253 private void init(TypedArray tarray) {
255 this.mNavigationMode = NAVIGATION_MODE.BROWSABLE;
256 int mode = tarray.getInteger(
257 R.styleable.Navigable_navigation,
258 NAVIGATION_MODE.BROWSABLE.ordinal());
259 if (mode >= 0 && mode < NAVIGATION_MODE.values().length) {
260 this.mNavigationMode = NAVIGATION_MODE.values()[mode];
263 //Initialize variables
264 this.mFiles = new ArrayList<FileSystemObject>();
266 // Is ChRooted environment?
267 if (this.mNavigationMode.compareTo(NAVIGATION_MODE.PICKABLE) == 0) {
268 // Pick mode is always ChRooted
269 this.mChRooted = true;
272 FileManagerApplication.getAccessMode().compareTo(AccessMode.SAFE) == 0;
275 //Retrieve the default configuration
276 if (this.mNavigationMode.compareTo(NAVIGATION_MODE.BROWSABLE) == 0) {
277 SharedPreferences preferences = Preferences.getSharedPreferences();
278 int viewMode = preferences.getInt(
279 FileManagerSettings.SETTINGS_LAYOUT_MODE.getId(),
280 ((ObjectIdentifier)FileManagerSettings.
281 SETTINGS_LAYOUT_MODE.getDefaultValue()).getId());
282 changeViewMode(NavigationLayoutMode.fromId(viewMode));
284 // Pick mode has always a details layout
285 changeViewMode(NavigationLayoutMode.DETAILS);
290 * Method that returns the mime/type used by this class. Only the files with this mime/type
293 * @return String The mime/type
295 public String getMimeType() {
296 return this.mMimeType;
300 * Method that sets the mime/type used by this class. Only the files with this mime/type
303 * @param mimeType String The mime/type
305 public void setMimeType(String mimeType) {
306 this.mMimeType = mimeType;
310 * Method that returns the current file list of the navigation view.
312 * @return List<FileSystemObject> The current file list of the navigation view
314 public List<FileSystemObject> getFiles() {
315 if (this.mFiles == null) {
318 return new ArrayList<FileSystemObject>(this.mFiles);
322 * Method that returns the current file list of the navigation view.
324 * @return List<FileSystemObject> The current file list of the navigation view
326 public List<FileSystemObject> getSelectedFiles() {
327 if (this.mAdapter != null && this.mAdapter.getSelectedItems() != null) {
328 return new ArrayList<FileSystemObject>(this.mAdapter.getSelectedItems());
334 * Method that returns the custom title fragment associated with this navigation view.
336 * @return NavigationCustomTitleView The custom title view fragment
338 public NavigationCustomTitleView getCustomTitle() {
343 * Method that associates the custom title fragment with this navigation view.
345 * @param title The custom title view fragment
347 public void setCustomTitle(NavigationCustomTitleView title) {
352 * Method that returns the breadcrumb associated with this navigation view.
354 * @return Breadcrumb The breadcrumb view fragment
356 public Breadcrumb getBreadcrumb() {
357 return this.mBreadcrumb;
361 * Method that associates the breadcrumb with this navigation view.
363 * @param breadcrumb The breadcrumb view fragment
365 public void setBreadcrumb(Breadcrumb breadcrumb) {
366 this.mBreadcrumb = breadcrumb;
367 this.mBreadcrumb.addBreadcrumbListener(this);
371 * Method that sets the listener for communicate history changes.
373 * @param onHistoryListener The listener for communicate history changes
375 public void setOnHistoryListener(OnHistoryListener onHistoryListener) {
376 this.mOnHistoryListener = onHistoryListener;
380 * Method that sets the listener which communicates selection changes.
382 * @param onNavigationSelectionChangedListener The listener reference
384 public void setOnNavigationSelectionChangedListener(
385 OnNavigationSelectionChangedListener onNavigationSelectionChangedListener) {
386 this.mOnNavigationSelectionChangedListener = onNavigationSelectionChangedListener;
390 * Method that sets the listener for menu item requests.
392 * @param onNavigationRequestMenuListener The listener reference
394 public void setOnNavigationOnRequestMenuListener(
395 OnNavigationRequestMenuListener onNavigationRequestMenuListener) {
396 this.mOnNavigationRequestMenuListener = onNavigationRequestMenuListener;
400 * @return the mOnFilePickedListener
402 public OnFilePickedListener getOnFilePickedListener() {
403 return this.mOnFilePickedListener;
407 * Method that sets the listener for picked items
409 * @param onFilePickedListener The listener reference
411 public void setOnFilePickedListener(OnFilePickedListener onFilePickedListener) {
412 this.mOnFilePickedListener = onFilePickedListener;
416 * Method that forces the view to scroll to the file system object passed.
418 * @param fso The file system object
420 public void scrollTo(FileSystemObject fso) {
423 int position = this.mAdapter.getPosition(fso);
424 this.mAdapterView.setSelection(position);
425 } catch (Exception e) {
426 this.mAdapterView.setSelection(0);
432 * Method that refresh the view data.
434 public void refresh() {
435 FileSystemObject fso = null;
436 // Try to restore the previous scroll position
438 if (this.mAdapterView != null && this.mAdapter != null) {
439 int position = this.mAdapterView.getFirstVisiblePosition();
440 fso = this.mAdapter.getItem(position);
442 } catch (Throwable _throw) {/**NON BLOCK**/}
447 * Method that refresh the view data.
449 * @param scrollTo Scroll to object
451 public void refresh(FileSystemObject scrollTo) {
452 //Check that current directory was set
453 if (this.mCurrentDir == null || this.mFiles == null) {
458 changeCurrentDir(this.mCurrentDir, false, true, false, null, scrollTo);
462 * Method that change the view mode.
464 * @param newMode The new mode
466 @SuppressWarnings({ "unchecked", "null" })
467 public void changeViewMode(final NavigationLayoutMode newMode) {
468 synchronized (this.mSync) {
469 //Check that it is really necessary change the mode
470 if (this.mCurrentMode != null && this.mCurrentMode.compareTo(newMode) == 0) {
474 //Creates the new layout
475 AdapterView<ListAdapter> newView = null;
476 int itemResourceId = -1;
477 if (newMode.compareTo(NavigationLayoutMode.ICONS) == 0) {
478 newView = (AdapterView<ListAdapter>)inflate(
479 getContext(), RESOURCE_MODE_ICONS_LAYOUT, null);
480 itemResourceId = RESOURCE_MODE_ICONS_ITEM;
481 } else if (newMode.compareTo(NavigationLayoutMode.SIMPLE) == 0) {
482 newView = (AdapterView<ListAdapter>)inflate(
483 getContext(), RESOURCE_MODE_SIMPLE_LAYOUT, null);
484 itemResourceId = RESOURCE_MODE_SIMPLE_ITEM;
485 } else if (newMode.compareTo(NavigationLayoutMode.DETAILS) == 0) {
486 newView = (AdapterView<ListAdapter>)inflate(
487 getContext(), RESOURCE_MODE_DETAILS_LAYOUT, null);
488 itemResourceId = RESOURCE_MODE_DETAILS_ITEM;
491 //Get the current adapter and its adapter list
492 List<FileSystemObject> files = new ArrayList<FileSystemObject>(this.mFiles);
493 final AdapterView<ListAdapter> current =
494 (AdapterView<ListAdapter>)findViewById(RESOURCE_CURRENT_LAYOUT);
495 FileSystemObjectAdapter adapter =
496 new FileSystemObjectAdapter(
498 new ArrayList<FileSystemObject>(),
500 this.mNavigationMode.compareTo(NAVIGATION_MODE.PICKABLE) == 0);
501 adapter.setOnSelectionChangedListener(this);
503 //Remove current layout
504 if (current != null) {
505 if (current.getAdapter() != null) {
506 //Save selected items before dispose adapter
507 FileSystemObjectAdapter currentAdapter =
508 ((FileSystemObjectAdapter)current.getAdapter());
509 adapter.setSelectedItems(currentAdapter.getSelectedItems());
510 currentAdapter.dispose();
515 adapter.addAll(files);
516 adapter.notifyDataSetChanged();
519 this.mAdapter = adapter;
520 newView.setAdapter(this.mAdapter);
521 newView.setOnItemClickListener(NavigationView.this);
524 this.mAdapterView = newView;
526 this.mCurrentMode = newMode;
528 // Pick mode doesn't implements the onlongclick
529 if (this.mNavigationMode.compareTo(NAVIGATION_MODE.BROWSABLE) == 0) {
530 this.mAdapterView.setOnItemLongClickListener(this);
532 this.mAdapterView.setOnItemLongClickListener(null);
535 //Save the preference (only in navigation browse mode)
536 if (this.mNavigationMode.compareTo(NAVIGATION_MODE.BROWSABLE) == 0) {
538 Preferences.savePreference(
539 FileManagerSettings.SETTINGS_LAYOUT_MODE, newMode, true);
540 } catch (Exception ex) {
541 Log.e(TAG, "Save of view mode preference fails", ex); //$NON-NLS-1$
548 * Method that removes a {@link FileSystemObject} from the view
550 * @param fso The file system object
552 public void removeItem(FileSystemObject fso) {
553 this.mAdapter.remove(fso);
554 this.mAdapter.notifyDataSetChanged();
558 * Method that removes a file system object from his path from the view
560 * @param path The file system object path
562 public void removeItem(String path) {
563 FileSystemObject fso = this.mAdapter.getItem(path);
565 this.mAdapter.remove(fso);
566 this.mAdapter.notifyDataSetChanged();
571 * Method that returns the current directory.
573 * @return String The current directory
575 public String getCurrentDir() {
576 return this.mCurrentDir;
580 * Method that changes the current directory of the view.
582 * @param newDir The new directory location
584 public void changeCurrentDir(final String newDir) {
585 changeCurrentDir(newDir, true, false, false, null, null);
589 * Method that changes the current directory of the view.
591 * @param newDir The new directory location
592 * @param searchInfo The search information (if calling activity is {@link "SearchActivity"})
594 public void changeCurrentDir(final String newDir, SearchInfoParcelable searchInfo) {
595 changeCurrentDir(newDir, true, false, false, searchInfo, null);
599 * Method that changes the current directory of the view.
601 * @param newDir The new directory location
602 * @param addToHistory Add the directory to history
603 * @param reload Force the reload of the data
604 * @param useCurrent If this method must use the actual data (for back actions)
605 * @param searchInfo The search information (if calling activity is {@link "SearchActivity"})
606 * @param scrollTo If not null, then listview must scroll to this item
608 private void changeCurrentDir(
609 final String newDir, final boolean addToHistory,
610 final boolean reload, final boolean useCurrent,
611 final SearchInfoParcelable searchInfo, final FileSystemObject scrollTo) {
613 // Check navigation security (don't allow to go outside the ChRooted environment if one
615 final String fNewDir = checkChRootedNavigation(newDir);
617 synchronized (this.mSync) {
618 //Check that it is really necessary change the directory
619 if (!reload && this.mCurrentDir != null && this.mCurrentDir.compareTo(fNewDir) == 0) {
623 final boolean hasChanged =
624 !(this.mCurrentDir != null && this.mCurrentDir.compareTo(fNewDir) == 0);
625 final boolean isNewHistory = (this.mCurrentDir != null);
627 //Execute the listing in a background process
628 AsyncTask<String, Integer, List<FileSystemObject>> task =
629 new AsyncTask<String, Integer, List<FileSystemObject>>() {
634 protected List<FileSystemObject> doInBackground(String... params) {
636 //Reset the custom title view and returns to breadcrumb
637 if (NavigationView.this.mTitle != null) {
638 NavigationView.this.mTitle.post(new Runnable() {
642 NavigationView.this.mTitle.restoreView();
643 } catch (Exception e) {
651 //Start of loading data
652 if (NavigationView.this.mBreadcrumb != null) {
654 NavigationView.this.mBreadcrumb.startLoading();
655 } catch (Throwable ex) {
660 //Get the files, resolve links and apply configuration
661 //(sort, hidden, ...)
662 List<FileSystemObject> files = NavigationView.this.mFiles;
664 files = CommandHelper.listFiles(getContext(), fNewDir, null);
667 } catch (final ConsoleAllocException e) {
668 //Show exception and exists
669 NavigationView.this.post(new Runnable() {
672 Context ctx = getContext();
673 Log.e(TAG, ctx.getString(
674 R.string.msgs_cant_create_console), e);
675 DialogHelper.showToast(ctx,
676 R.string.msgs_cant_create_console,
678 ((Activity)ctx).finish();
683 } catch (Exception ex) {
684 //End of loading data
685 if (NavigationView.this.mBreadcrumb != null) {
687 NavigationView.this.mBreadcrumb.endLoading();
688 } catch (Throwable ex2) {
694 ExceptionUtil.attachAsyncTask(
696 new AsyncTask<Object, Integer, Boolean>() {
698 @SuppressWarnings("unchecked")
699 protected Boolean doInBackground(Object... taskParams) {
700 final List<FileSystemObject> files =
701 (List<FileSystemObject>)taskParams[0];
702 NavigationView.this.mAdapterView.post(
708 isNewHistory, hasChanged,
709 searchInfo, fNewDir, scrollTo);
716 ExceptionUtil.translateException(getContext(), ex);
725 protected void onPostExecute(List<FileSystemObject> files) {
727 files, addToHistory, isNewHistory,
728 hasChanged, searchInfo, fNewDir, scrollTo);
731 task.execute(fNewDir);
737 * Method invoked when a execution ends.
739 * @param files The files obtains from the list
740 * @param addToHistory If add path to history
741 * @param isNewHistory If is new history
742 * @param hasChanged If current directory was changed
743 * @param searchInfo The search information (if calling activity is {@link "SearchActivity"})
744 * @param newDir The new directory
745 * @param scrollTo If not null, then listview must scroll to this item
748 void onPostExecuteTask(
749 List<FileSystemObject> files, boolean addToHistory, boolean isNewHistory,
750 boolean hasChanged, SearchInfoParcelable searchInfo,
751 String newDir, final FileSystemObject scrollTo) {
753 //Check that there is not errors and have some data
758 //Apply user preferences
759 List<FileSystemObject> sortedFiles =
760 FileHelper.applyUserPreferences(files, this.mMimeType, this.mChRooted);
762 //Remove parent directory if we are in the root of a chrooted environment
763 if (this.mChRooted && StorageHelper.isStorageVolume(newDir)) {
764 if (files.size() > 0 && files.get(0) instanceof ParentDirectory) {
770 loadData(sortedFiles);
771 NavigationView.this.mFiles = sortedFiles;
772 if (searchInfo != null) {
773 searchInfo.setSuccessNavigation(true);
777 if (addToHistory && hasChanged && isNewHistory) {
778 if (NavigationView.this.mOnHistoryListener != null) {
779 //Communicate the need of a history change
780 NavigationView.this.mOnHistoryListener.onNewHistory(onSaveState());
784 //Change the breadcrumb
785 if (NavigationView.this.mBreadcrumb != null) {
786 NavigationView.this.mBreadcrumb.changeBreadcrumbPath(newDir, this.mChRooted);
790 if (scrollTo != null) {
794 //The current directory is now the "newDir"
795 NavigationView.this.mCurrentDir = newDir;
798 //If calling activity is search, then save the search history
799 if (searchInfo != null) {
800 NavigationView.this.mOnHistoryListener.onNewHistory(searchInfo);
803 //End of loading data
805 NavigationView.this.mBreadcrumb.endLoading();
806 } catch (Throwable ex) {
813 * Method that loads the files in the adapter.
815 * @param files The files to load in the adapter
818 @SuppressWarnings("unchecked")
819 private void loadData(final List<FileSystemObject> files) {
820 //Notify data to adapter view
821 final AdapterView<ListAdapter> view =
822 (AdapterView<ListAdapter>)findViewById(RESOURCE_CURRENT_LAYOUT);
823 FileSystemObjectAdapter adapter = (FileSystemObjectAdapter)view.getAdapter();
825 adapter.addAll(files);
826 adapter.notifyDataSetChanged();
827 view.setSelection(0);
834 public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
835 // Different actions depending on user preference
837 // Get the adapter and the fso
838 FileSystemObjectAdapter adapter = ((FileSystemObjectAdapter)parent.getAdapter());
839 FileSystemObject fso = adapter.getItem(position);
841 // Parent directory hasn't actions
842 if (fso instanceof ParentDirectory) {
846 // Pick mode doesn't implements the onlongclick
847 if (this.mNavigationMode.compareTo(NAVIGATION_MODE.PICKABLE) == 0) {
852 return true; //Always consume the event
856 * Method that opens or navigates to the {@link FileSystemObject}
858 * @param fso The file system object
860 public void open(FileSystemObject fso) {
865 * Method that opens or navigates to the {@link FileSystemObject}
867 * @param fso The file system object
868 * @param searchInfo The search info
870 public void open(FileSystemObject fso, SearchInfoParcelable searchInfo) {
871 // If is a folder, then navigate to
872 if (FileHelper.isDirectory(fso)) {
873 changeCurrentDir(fso.getFullPath(), searchInfo);
875 // Open the file with the preferred registered app
876 IntentsActionPolicy.openFileSystemObject(getContext(), fso, false, null, null);
884 public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
886 FileSystemObject fso = ((FileSystemObjectAdapter)parent.getAdapter()).getItem(position);
887 if (fso instanceof ParentDirectory) {
888 changeCurrentDir(fso.getParent(), true, false, false, null, null);
889 } else if (fso instanceof Directory) {
890 changeCurrentDir(fso.getFullPath(), true, false, false, null, null);
891 } else if (fso instanceof Symlink) {
892 Symlink symlink = (Symlink)fso;
893 if (symlink.getLinkRef() != null && symlink.getLinkRef() instanceof Directory) {
895 symlink.getLinkRef().getFullPath(), true, false, false, null, null);
898 if (this.mNavigationMode.compareTo(NAVIGATION_MODE.BROWSABLE) == 0) {
899 // Open the file with the preferred registered app
900 IntentsActionPolicy.openFileSystemObject(getContext(), fso, false, null, null);
902 // Request a file pick selection
903 if (this.mOnFilePickedListener != null) {
904 this.mOnFilePickedListener.onFilePicked(fso);
908 } catch (Throwable ex) {
909 ExceptionUtil.translateException(getContext(), ex);
917 public void onRequestRefresh(Object o) {
918 if (o instanceof FileSystemObject) {
919 refresh((FileSystemObject)o);
928 public void onRequestRemove(Object o) {
929 if (o instanceof FileSystemObject) {
930 removeItem((FileSystemObject)o);
939 public void onNavigateTo(Object o) {
947 public void onBreadcrumbItemClick(BreadcrumbItem item) {
948 changeCurrentDir(item.getItemPath(), true, true, false, null, null);
955 public void onSelectionChanged(final List<FileSystemObject> selectedItems) {
956 if (this.mOnNavigationSelectionChangedListener != null) {
957 this.mOnNavigationSelectionChangedListener.onSelectionChanged(this, selectedItems);
962 * Method invoked when a request to show the menu associated
963 * with an item is started.
965 * @param item The item for which the request was started
967 public void onRequestMenu(final FileSystemObject item) {
968 if (this.mOnNavigationRequestMenuListener != null) {
969 this.mOnNavigationRequestMenuListener.onRequestMenu(this, item);
977 public void onToggleSelection(FileSystemObject fso) {
978 if (this.mAdapter != null) {
979 this.mAdapter.toggleSelection(fso);
987 public void onDeselectAll() {
988 if (this.mAdapter != null) {
989 this.mAdapter.deselectedAll();
997 public void onSelectAllVisibleItems() {
998 if (this.mAdapter != null) {
999 this.mAdapter.selectedAllVisibleItems();
1007 public void onDeselectAllVisibleItems() {
1008 if (this.mAdapter != null) {
1009 this.mAdapter.deselectedAllVisibleItems();
1017 public List<FileSystemObject> onRequestSelectedFiles() {
1018 return this.getSelectedFiles();
1025 public List<FileSystemObject> onRequestCurrentItems() {
1026 return this.getFiles();
1033 public String onRequestCurrentDir() {
1034 return this.mCurrentDir;
1038 * Method that creates a ChRooted environment, protecting the user to break anything
1042 public void createChRooted() {
1043 // If we are in a ChRooted environment, then do nothing
1044 if (this.mChRooted) return;
1045 this.mChRooted = true;
1047 //Change to first storage volume
1048 StorageVolume[] volumes =
1049 StorageHelper.getStorageVolumes(getContext());
1050 if (volumes != null && volumes.length > 0) {
1051 changeCurrentDir(volumes[0].getPath(), false, true, false, null, null);
1056 * Method that exits from a ChRooted environment
1059 public void exitChRooted() {
1060 // If we aren't in a ChRooted environment, then do nothing
1061 if (!this.mChRooted) return;
1062 this.mChRooted = false;
1069 * Method that ensures that the user don't go outside the ChRooted environment
1071 * @param newDir The new directory to navigate to
1074 private String checkChRootedNavigation(String newDir) {
1075 // If we aren't in ChRooted environment, then there is nothing to check
1076 if (!this.mChRooted) return newDir;
1078 // Check if the path is owned by one of the storage volumes
1079 if (!StorageHelper.isPathInStorageVolume(newDir)) {
1080 StorageVolume[] volumes = StorageHelper.getStorageVolumes(getContext());
1081 if (volumes != null && volumes.length > 0) {
1082 return volumes[0].getPath();