OSDN Git Service

Fix Navigation back from Search
[android-x86/packages-apps-CMFileManager.git] / src / com / cyanogenmod / filemanager / ui / widgets / NavigationView.java
1 /*
2  * Copyright (C) 2012 The CyanogenMod Project
3  *
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
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16
17 package com.cyanogenmod.filemanager.ui.widgets;
18
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.view.animation.AccelerateInterpolator;
29 import android.view.animation.AlphaAnimation;
30 import android.view.animation.Animation;
31 import android.widget.AdapterView;
32 import android.widget.ListAdapter;
33 import android.widget.ListView;
34 import android.widget.RelativeLayout;
35 import android.widget.Toast;
36
37 import com.cyanogenmod.filemanager.FileManagerApplication;
38 import com.cyanogenmod.filemanager.R;
39 import com.cyanogenmod.filemanager.adapters.FileSystemObjectAdapter;
40 import com.cyanogenmod.filemanager.adapters.FileSystemObjectAdapter.OnSelectionChangedListener;
41 import com.cyanogenmod.filemanager.console.CancelledOperationException;
42 import com.cyanogenmod.filemanager.console.ConsoleAllocException;
43 import com.cyanogenmod.filemanager.console.VirtualMountPointConsole;
44 import com.cyanogenmod.filemanager.listeners.OnHistoryListener;
45 import com.cyanogenmod.filemanager.listeners.OnRequestRefreshListener;
46 import com.cyanogenmod.filemanager.listeners.OnSelectionListener;
47 import com.cyanogenmod.filemanager.model.Directory;
48 import com.cyanogenmod.filemanager.model.FileSystemObject;
49 import com.cyanogenmod.filemanager.model.ParentDirectory;
50 import com.cyanogenmod.filemanager.model.Symlink;
51 import com.cyanogenmod.filemanager.parcelables.NavigationViewInfoParcelable;
52 import com.cyanogenmod.filemanager.parcelables.SearchInfoParcelable;
53 import com.cyanogenmod.filemanager.preferences.AccessMode;
54 import com.cyanogenmod.filemanager.preferences.DisplayRestrictions;
55 import com.cyanogenmod.filemanager.preferences.FileManagerSettings;
56 import com.cyanogenmod.filemanager.preferences.NavigationLayoutMode;
57 import com.cyanogenmod.filemanager.preferences.ObjectIdentifier;
58 import com.cyanogenmod.filemanager.preferences.Preferences;
59 import com.cyanogenmod.filemanager.ui.ThemeManager;
60 import com.cyanogenmod.filemanager.ui.ThemeManager.Theme;
61 import com.cyanogenmod.filemanager.ui.policy.DeleteActionPolicy;
62 import com.cyanogenmod.filemanager.ui.policy.IntentsActionPolicy;
63 import com.cyanogenmod.filemanager.ui.widgets.FlingerListView.OnItemFlingerListener;
64 import com.cyanogenmod.filemanager.ui.widgets.FlingerListView.OnItemFlingerResponder;
65 import com.cyanogenmod.filemanager.util.CommandHelper;
66 import com.cyanogenmod.filemanager.util.DialogHelper;
67 import com.cyanogenmod.filemanager.util.ExceptionUtil;
68 import com.cyanogenmod.filemanager.util.ExceptionUtil.OnRelaunchCommandResult;
69 import com.cyanogenmod.filemanager.util.FileHelper;
70 import com.cyanogenmod.filemanager.util.StorageHelper;
71
72 import java.io.File;
73 import java.util.ArrayList;
74 import java.util.HashMap;
75 import java.util.List;
76 import java.util.Map;
77
78 /**
79  * The file manager implementation view (contains the graphical representation and the input
80  * management for a file manager; shows the folders/files, the mode view, react touch events,
81  * navigate, ...).
82  */
83 public class NavigationView extends RelativeLayout implements
84 AdapterView.OnItemClickListener, AdapterView.OnItemLongClickListener,
85 BreadcrumbListener, OnSelectionChangedListener, OnSelectionListener, OnRequestRefreshListener {
86
87     private static final String TAG = "NavigationView"; //$NON-NLS-1$
88
89     /**
90      * An interface to communicate selection changes events.
91      */
92     public interface OnNavigationSelectionChangedListener {
93         /**
94          * Method invoked when the selection changed.
95          *
96          * @param navView The navigation view that generate the event
97          * @param selectedItems The new selected items
98          */
99         void onSelectionChanged(NavigationView navView, List<FileSystemObject> selectedItems);
100     }
101
102     /**
103      * An interface to communicate a request for show the menu associated
104      * with an item.
105      */
106     public interface OnNavigationRequestMenuListener {
107         /**
108          * Method invoked when a request to show the menu associated
109          * with an item is started.
110          *
111          * @param navView The navigation view that generate the event
112          * @param item The item for which the request was started
113          */
114         void onRequestMenu(NavigationView navView, FileSystemObject item);
115     }
116
117     /**
118      * An interface to communicate a request when the user choose a file.
119      */
120     public interface OnFilePickedListener {
121         /**
122          * Method invoked when a request when the user choose a file.
123          *
124          * @param item The item choose
125          */
126         void onFilePicked(FileSystemObject item);
127     }
128
129     /**
130      * An interface to communicate a change of the current directory
131      */
132     public interface OnDirectoryChangedListener {
133         /**
134          * Method invoked when the current directory changes
135          *
136          * @param item The newly active directory
137          */
138         void onDirectoryChanged(FileSystemObject item);
139     }
140
141     /**
142      * The navigation view mode
143      * @hide
144      */
145     public enum NAVIGATION_MODE {
146         /**
147          * The navigation view acts as a browser, and allow open files itself.
148          */
149         BROWSABLE,
150         /**
151          * The navigation view acts as a picker of files
152          */
153         PICKABLE,
154     }
155
156     /**
157      * A listener for flinging events from {@link FlingerListView}
158      */
159     private final OnItemFlingerListener mOnItemFlingerListener = new OnItemFlingerListener() {
160
161         @Override
162         public boolean onItemFlingerStart(
163                 AdapterView<?> parent, View view, int position, long id) {
164             try {
165                 // Response if the item can be removed
166                 FileSystemObjectAdapter adapter = (FileSystemObjectAdapter)parent.getAdapter();
167
168                 // Short circuit to protect OOBE
169                 if (position < 0 || position >= adapter.getCount()) {
170                     return false;
171                 }
172
173                 FileSystemObject fso = adapter.getItem(position);
174                 if (fso != null) {
175                     if (fso instanceof ParentDirectory) {
176                         return false;
177                     }
178                     return true;
179                 }
180             } catch (Exception e) {
181                 ExceptionUtil.translateException(getContext(), e, true, false);
182             }
183             return false;
184         }
185
186         @Override
187         public void onItemFlingerEnd(OnItemFlingerResponder responder,
188                 AdapterView<?> parent, View view, int position, long id) {
189
190             try {
191                 // Response if the item can be removed
192                 FileSystemObjectAdapter adapter = (FileSystemObjectAdapter)parent.getAdapter();
193                 FileSystemObject fso = adapter.getItem(position);
194                 if (fso != null) {
195                     DeleteActionPolicy.removeFileSystemObject(
196                             getContext(),
197                             fso,
198                             NavigationView.this,
199                             NavigationView.this,
200                             responder);
201                     return;
202                 }
203
204                 // Cancels the flinger operation
205                 responder.cancel();
206
207             } catch (Exception e) {
208                 ExceptionUtil.translateException(getContext(), e, true, false);
209                 responder.cancel();
210             }
211         }
212     };
213
214     private class NavigationTask extends AsyncTask<String, Integer, List<FileSystemObject>> {
215         private final boolean mUseCurrent;
216         private final boolean mAddToHistory;
217         private final boolean mReload;
218         private boolean mHasChanged;
219         private boolean mIsNewHistory;
220         private String mNewDirChecked;
221         private final SearchInfoParcelable mSearchInfo;
222         private final FileSystemObject mScrollTo;
223         private final Map<DisplayRestrictions, Object> mRestrictions;
224         private final boolean mChRooted;
225
226         public NavigationTask(boolean useCurrent, boolean addToHistory, boolean reload,
227                 SearchInfoParcelable searchInfo, FileSystemObject scrollTo,
228                 Map<DisplayRestrictions, Object> restrictions, boolean chRooted) {
229             super();
230             this.mUseCurrent = useCurrent;
231             this.mAddToHistory = addToHistory;
232             this.mSearchInfo = searchInfo;
233             this.mReload = reload;
234             this.mScrollTo = scrollTo;
235             this.mRestrictions = restrictions;
236             this.mChRooted = chRooted;
237         }
238
239         /**
240          * {@inheritDoc}
241          */
242         @Override
243         protected List<FileSystemObject> doInBackground(String... params) {
244             // Check navigation security (don't allow to go outside the ChRooted environment if one
245             // is created)
246             mNewDirChecked = checkChRootedNavigation(params[0]);
247
248             mHasChanged = !(NavigationView.this.mPreviousDir != null &&
249                     NavigationView.this.mPreviousDir.compareTo(mNewDirChecked) == 0);
250             mIsNewHistory = (NavigationView.this.mPreviousDir != null);
251
252             try {
253                 //Reset the custom title view and returns to breadcrumb
254                 if (NavigationView.this.mTitle != null) {
255                     NavigationView.this.mTitle.post(new Runnable() {
256                         @Override
257                         public void run() {
258                             try {
259                                 NavigationView.this.mTitle.restoreView();
260                             } catch (Exception e) {
261                                 e.printStackTrace();
262                             }
263                         }
264                     });
265                 }
266
267
268                 //Start of loading data
269                 if (NavigationView.this.mBreadcrumb != null) {
270                     try {
271                         NavigationView.this.mBreadcrumb.startLoading();
272                     } catch (Throwable ex) {
273                         /**NON BLOCK**/
274                     }
275                 }
276
277                 //Get the files, resolve links and apply configuration
278                 //(sort, hidden, ...)
279                 List<FileSystemObject> files = NavigationView.this.mFiles;
280                 if (!mUseCurrent) {
281                     files = CommandHelper.listFiles(getContext(), mNewDirChecked, null);
282                 }
283
284                 //Apply user preferences
285                 List<FileSystemObject> sortedFiles =
286                         FileHelper.applyUserPreferences(files, this.mRestrictions, this.mChRooted);
287
288                 return sortedFiles;
289
290             } catch (final ConsoleAllocException e) {
291                 //Show exception and exists
292                 NavigationView.this.post(new Runnable() {
293                     @Override
294                     public void run() {
295                         Context ctx = getContext();
296                         Log.e(TAG, ctx.getString(
297                                 R.string.msgs_cant_create_console), e);
298                         DialogHelper.showToast(ctx,
299                                 R.string.msgs_cant_create_console,
300                                 Toast.LENGTH_LONG);
301                         ((Activity)ctx).finish();
302                     }
303                 });
304
305             } catch (Exception ex) {
306                 //End of loading data
307                 if (NavigationView.this.mBreadcrumb != null) {
308                     try {
309                         NavigationView.this.mBreadcrumb.endLoading();
310                     } catch (Throwable ex2) {
311                         /**NON BLOCK**/
312                     }
313                 }
314                 if (ex instanceof CancelledOperationException) {
315                     return null;
316                 }
317
318                 //Capture exception (attach task, and use listener to do the anim)
319                 ExceptionUtil.attachAsyncTask(
320                         ex,
321                         new AsyncTask<Object, Integer, Boolean>() {
322                             private List<FileSystemObject> mTaskFiles = null;
323                             @Override
324                             @SuppressWarnings({
325                                 "unchecked", "unqualified-field-access"
326                             })
327                             protected Boolean doInBackground(Object... taskParams) {
328                                 mTaskFiles = (List<FileSystemObject>)taskParams[0];
329                                 return Boolean.TRUE;
330                             }
331
332                             @Override
333                             @SuppressWarnings("unqualified-field-access")
334                             protected void onPostExecute(Boolean result) {
335                                 if (!result.booleanValue()) {
336                                     return;
337                                 }
338                                 onPostExecuteTask(
339                                         mTaskFiles, mAddToHistory, mIsNewHistory, mHasChanged,
340                                         mSearchInfo, mNewDirChecked, mScrollTo);
341                             }
342                         });
343                 final OnRelaunchCommandResult exListener =
344                         new OnRelaunchCommandResult() {
345                     @Override
346                     public void onSuccess() {
347                         done();
348                     }
349                     @Override
350                     public void onFailed(Throwable cause) {
351                         done();
352                     }
353                     @Override
354                     public void onCancelled() {
355                         done();
356                     }
357                     private void done() {
358                         // Do animation
359                         fadeEfect(false);
360                     }
361                 };
362                 ExceptionUtil.translateException(
363                         getContext(), ex, false, true, exListener);
364             }
365             return null;
366         }
367
368         /**
369          * {@inheritDoc}
370          */
371         @Override
372         protected void onCancelled(List<FileSystemObject> result) {
373             onCancelled();
374         }
375
376         /**
377          * {@inheritDoc}
378          */
379         @Override
380         protected void onPostExecute(List<FileSystemObject> files) {
381             // This means an exception. This method will be recalled then
382             onPostExecuteTask(files, mAddToHistory, mIsNewHistory, mHasChanged,
383                         mSearchInfo, mNewDirChecked, mScrollTo);
384
385             // Do animation
386             fadeEfect(false);
387         }
388
389         /**
390          * Method that performs a fade animation.
391          *
392          * @param out Fade out (true); Fade in (false)
393          */
394         void fadeEfect(final boolean out) {
395             Activity activity = (Activity)getContext();
396             activity.runOnUiThread(new Runnable() {
397                 @Override
398                 public void run() {
399                     Animation fadeAnim = out ?
400                             new AlphaAnimation(1, 0) :
401                                 new AlphaAnimation(0, 1);
402                             fadeAnim.setDuration(50L);
403                             fadeAnim.setFillAfter(true);
404                             fadeAnim.setInterpolator(new AccelerateInterpolator());
405                             NavigationView.this.startAnimation(fadeAnim);
406                 }
407             });
408         }
409     };
410
411     private int mId;
412     private String mCurrentDir;
413     private String mPreviousDir;
414     private NavigationLayoutMode mCurrentMode;
415     /**
416      * @hide
417      */
418     List<FileSystemObject> mFiles;
419     private FileSystemObjectAdapter mAdapter;
420
421     private OnHistoryListener mOnHistoryListener;
422     private OnNavigationSelectionChangedListener mOnNavigationSelectionChangedListener;
423     private OnNavigationRequestMenuListener mOnNavigationRequestMenuListener;
424     private OnFilePickedListener mOnFilePickedListener;
425     private OnDirectoryChangedListener mOnDirectoryChangedListener;
426
427     private boolean mChRooted;
428
429     private NAVIGATION_MODE mNavigationMode;
430
431     // Restrictions
432     private Map<DisplayRestrictions, Object> mRestrictions;
433
434     private NavigationTask mNavigationTask;
435
436     /**
437      * @hide
438      */
439     Breadcrumb mBreadcrumb;
440     /**
441      * @hide
442      */
443     NavigationCustomTitleView mTitle;
444     /**
445      * @hide
446      */
447     AdapterView<?> mAdapterView;
448
449     //The layout for icons mode
450     private static final int RESOURCE_MODE_ICONS_LAYOUT = R.layout.navigation_view_icons;
451     private static final int RESOURCE_MODE_ICONS_ITEM = R.layout.navigation_view_icons_item;
452     //The layout for simple mode
453     private static final int RESOURCE_MODE_SIMPLE_LAYOUT = R.layout.navigation_view_simple;
454     private static final int RESOURCE_MODE_SIMPLE_ITEM = R.layout.navigation_view_simple_item;
455     //The layout for details mode
456     private static final int RESOURCE_MODE_DETAILS_LAYOUT = R.layout.navigation_view_details;
457     private static final int RESOURCE_MODE_DETAILS_ITEM = R.layout.navigation_view_details_item;
458
459     //The current layout identifier (is shared for all the mode layout)
460     private static final int RESOURCE_CURRENT_LAYOUT = R.id.navigation_view_layout;
461
462     /**
463      * Constructor of <code>NavigationView</code>.
464      *
465      * @param context The current context
466      * @param attrs The attributes of the XML tag that is inflating the view.
467      */
468     public NavigationView(Context context, AttributeSet attrs) {
469         super(context, attrs);
470         TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.Navigable);
471         try {
472             init(a);
473         } finally {
474             a.recycle();
475         }
476     }
477
478     /**
479      * Constructor of <code>NavigationView</code>.
480      *
481      * @param context The current context
482      * @param attrs The attributes of the XML tag that is inflating the view.
483      * @param defStyle The default style to apply to this view. If 0, no style
484      *        will be applied (beyond what is included in the theme). This may
485      *        either be an attribute resource, whose value will be retrieved
486      *        from the current theme, or an explicit style resource.
487      */
488     public NavigationView(Context context, AttributeSet attrs, int defStyle) {
489         super(context, attrs, defStyle);
490         TypedArray a = context.obtainStyledAttributes(
491                 attrs, R.styleable.Navigable, defStyle, 0);
492         try {
493             init(a);
494         } finally {
495             a.recycle();
496         }
497     }
498
499     /**
500      * Invoked when the instance need to be saved.
501      *
502      * @return NavigationViewInfoParcelable The serialized info
503      */
504     public NavigationViewInfoParcelable onSaveState() {
505         //Return the persistent the data
506         NavigationViewInfoParcelable parcel = new NavigationViewInfoParcelable();
507         parcel.setId(this.mId);
508         parcel.setCurrentDir(this.mPreviousDir);
509         parcel.setChRooted(this.mChRooted);
510         parcel.setSelectedFiles(this.mAdapter.getSelectedItems());
511         parcel.setFiles(this.mFiles);
512
513         int firstVisiblePosition = mAdapterView.getFirstVisiblePosition();
514         if (firstVisiblePosition >= 0 && firstVisiblePosition < mAdapter.getCount()) {
515             FileSystemObject firstVisible = mAdapter
516                     .getItem(firstVisiblePosition);
517             parcel.setFirstVisible(firstVisible);
518         }
519
520         return parcel;
521     }
522
523     /**
524      * Invoked when the instance need to be restored.
525      *
526      * @param info The serialized info
527      * @return boolean If can restore
528      */
529     public boolean onRestoreState(NavigationViewInfoParcelable info) {
530         //Restore the data
531         this.mId = info.getId();
532         this.mCurrentDir = info.getCurrentDir();
533         this.mChRooted = info.getChRooted();
534         this.mFiles = info.getFiles();
535         this.mAdapter.setSelectedItems(info.getSelectedFiles());
536
537         final FileSystemObject firstVisible = info.getFirstVisible();
538
539         //Update the views
540         refresh(firstVisible);
541         return true;
542     }
543
544     /**
545      * Method that initializes the view. This method loads all the necessary
546      * information and create an appropriate layout for the view.
547      *
548      * @param tarray The type array
549      */
550     private void init(TypedArray tarray) {
551         // Retrieve the mode
552         this.mNavigationMode = NAVIGATION_MODE.BROWSABLE;
553         int mode = tarray.getInteger(
554                 R.styleable.Navigable_navigation,
555                 NAVIGATION_MODE.BROWSABLE.ordinal());
556         if (mode >= 0 && mode < NAVIGATION_MODE.values().length) {
557             this.mNavigationMode = NAVIGATION_MODE.values()[mode];
558         }
559
560         // Initialize default restrictions (no restrictions)
561         this.mRestrictions = new HashMap<DisplayRestrictions, Object>();
562
563         //Initialize variables
564         this.mFiles = new ArrayList<FileSystemObject>();
565
566         // Is ChRooted environment?
567         if (this.mNavigationMode.compareTo(NAVIGATION_MODE.PICKABLE) == 0) {
568             // Pick mode is always ChRooted
569             this.mChRooted = true;
570         } else {
571             this.mChRooted =
572                     FileManagerApplication.getAccessMode().compareTo(AccessMode.SAFE) == 0;
573         }
574
575         //Retrieve the default configuration
576         if (this.mNavigationMode.compareTo(NAVIGATION_MODE.BROWSABLE) == 0) {
577             SharedPreferences preferences = Preferences.getSharedPreferences();
578             int viewMode = preferences.getInt(
579                     FileManagerSettings.SETTINGS_LAYOUT_MODE.getId(),
580                     ((ObjectIdentifier)FileManagerSettings.
581                             SETTINGS_LAYOUT_MODE.getDefaultValue()).getId());
582             changeViewMode(NavigationLayoutMode.fromId(viewMode));
583         } else {
584             // Pick mode has always a details layout
585             changeViewMode(NavigationLayoutMode.DETAILS);
586         }
587     }
588
589     /**
590      * Method that returns the display restrictions to apply to this view.
591      *
592      * @return Map<DisplayRestrictions, Object> The restrictions to apply
593      */
594     public Map<DisplayRestrictions, Object> getRestrictions() {
595         return this.mRestrictions;
596     }
597
598     /**
599      * Method that sets the display restrictions to apply to this view.
600      *
601      * @param mRestrictions The restrictions to apply
602      */
603     public void setRestrictions(Map<DisplayRestrictions, Object> mRestrictions) {
604         this.mRestrictions = mRestrictions;
605     }
606
607     /**
608      * Method that returns the current file list of the navigation view.
609      *
610      * @return List<FileSystemObject> The current file list of the navigation view
611      */
612     public List<FileSystemObject> getFiles() {
613         if (this.mFiles == null) {
614             return null;
615         }
616         return new ArrayList<FileSystemObject>(this.mFiles);
617     }
618
619     /**
620      * Method that returns the current file list of the navigation view.
621      *
622      * @return List<FileSystemObject> The current file list of the navigation view
623      */
624     public List<FileSystemObject> getSelectedFiles() {
625         if (this.mAdapter != null && this.mAdapter.getSelectedItems() != null) {
626             return new ArrayList<FileSystemObject>(this.mAdapter.getSelectedItems());
627         }
628         return null;
629     }
630
631     /**
632      * Method that returns the custom title fragment associated with this navigation view.
633      *
634      * @return NavigationCustomTitleView The custom title view fragment
635      */
636     public NavigationCustomTitleView getCustomTitle() {
637         return this.mTitle;
638     }
639
640     /**
641      * Method that associates the custom title fragment with this navigation view.
642      *
643      * @param title The custom title view fragment
644      */
645     public void setCustomTitle(NavigationCustomTitleView title) {
646         this.mTitle = title;
647     }
648
649     /**
650      * Method that returns the breadcrumb associated with this navigation view.
651      *
652      * @return Breadcrumb The breadcrumb view fragment
653      */
654     public Breadcrumb getBreadcrumb() {
655         return this.mBreadcrumb;
656     }
657
658     /**
659      * Method that associates the breadcrumb with this navigation view.
660      *
661      * @param breadcrumb The breadcrumb view fragment
662      */
663     public void setBreadcrumb(Breadcrumb breadcrumb) {
664         this.mBreadcrumb = breadcrumb;
665         this.mBreadcrumb.addBreadcrumbListener(this);
666     }
667
668     /**
669      * Method that sets the listener for communicate history changes.
670      *
671      * @param onHistoryListener The listener for communicate history changes
672      */
673     public void setOnHistoryListener(OnHistoryListener onHistoryListener) {
674         this.mOnHistoryListener = onHistoryListener;
675     }
676
677     /**
678      * Method that sets the listener which communicates selection changes.
679      *
680      * @param onNavigationSelectionChangedListener The listener reference
681      */
682     public void setOnNavigationSelectionChangedListener(
683             OnNavigationSelectionChangedListener onNavigationSelectionChangedListener) {
684         this.mOnNavigationSelectionChangedListener = onNavigationSelectionChangedListener;
685     }
686
687     /**
688      * Method that sets the listener for menu item requests.
689      *
690      * @param onNavigationRequestMenuListener The listener reference
691      */
692     public void setOnNavigationOnRequestMenuListener(
693             OnNavigationRequestMenuListener onNavigationRequestMenuListener) {
694         this.mOnNavigationRequestMenuListener = onNavigationRequestMenuListener;
695     }
696
697     /**
698      * @return the mOnFilePickedListener
699      */
700     public OnFilePickedListener getOnFilePickedListener() {
701         return this.mOnFilePickedListener;
702     }
703
704     /**
705      * Method that sets the listener for picked items
706      *
707      * @param onFilePickedListener The listener reference
708      */
709     public void setOnFilePickedListener(OnFilePickedListener onFilePickedListener) {
710         this.mOnFilePickedListener = onFilePickedListener;
711     }
712
713     /**
714      * Method that sets the listener for directory changes
715      *
716      * @param onDirectoryChangedListener The listener reference
717      */
718     public void setOnDirectoryChangedListener(
719             OnDirectoryChangedListener onDirectoryChangedListener) {
720         this.mOnDirectoryChangedListener = onDirectoryChangedListener;
721     }
722
723     /**
724      * Method that sets if the view should use flinger gesture detection.
725      *
726      * @param useFlinger If the view should use flinger gesture detection
727      */
728     public void setUseFlinger(boolean useFlinger) {
729         if (this.mCurrentMode.compareTo(NavigationLayoutMode.ICONS) == 0) {
730             // Not supported
731             return;
732         }
733         // Set the flinger listener (only when navigate)
734         if (this.mNavigationMode.compareTo(NAVIGATION_MODE.BROWSABLE) == 0) {
735             if (this.mAdapterView instanceof FlingerListView) {
736                 if (useFlinger) {
737                     ((FlingerListView)this.mAdapterView).
738                     setOnItemFlingerListener(this.mOnItemFlingerListener);
739                 } else {
740                     ((FlingerListView)this.mAdapterView).setOnItemFlingerListener(null);
741                 }
742             }
743         }
744     }
745
746     /**
747      * Method that forces the view to scroll to the file system object passed.
748      *
749      * @param fso The file system object
750      */
751     public void scrollTo(final FileSystemObject fso) {
752
753         this.mAdapterView.post(new Runnable() {
754
755             @Override
756             public void run() {
757                 if (fso != null) {
758                     try {
759                         int position = mAdapter.getPosition(fso);
760                         mAdapterView.setSelection(position);
761
762                         // Make the scrollbar appear
763                         if (position > 0) {
764                             mAdapterView.scrollBy(0, 1);
765                             mAdapterView.scrollBy(0, -1);
766                         }
767
768                     } catch (Exception e) {
769                         mAdapterView.setSelection(0);
770                     }
771                 } else {
772                     mAdapterView.setSelection(0);
773                 }
774             }
775         });
776
777     }
778
779     /**
780      * Method that refresh the view data.
781      */
782     public void refresh() {
783         refresh(false);
784     }
785
786     /**
787      * Method that refresh the view data.
788      *
789      * @param restore Restore previous position
790      */
791     public void refresh(boolean restore) {
792         FileSystemObject fso = null;
793         // Try to restore the previous scroll position
794         if (restore) {
795             try {
796                 if (this.mAdapterView != null && this.mAdapter != null) {
797                     int position = this.mAdapterView.getFirstVisiblePosition();
798                     fso = this.mAdapter.getItem(position);
799                 }
800             } catch (Throwable _throw) {/**NON BLOCK**/}
801         }
802         refresh(fso);
803     }
804
805     /**
806      * Method that refresh the view data.
807      *
808      * @param scrollTo Scroll to object
809      */
810     public void refresh(FileSystemObject scrollTo) {
811         //Check that current directory was set
812         if (this.mCurrentDir == null || this.mFiles == null) {
813             return;
814         }
815
816         boolean addToHistory = false;
817         boolean reload = true;
818         boolean useCurrent = false;
819         SearchInfoParcelable searchInfo = null;
820
821         String newDir = this.mCurrentDir;
822         if (this.mNavigationTask != null) {
823             addToHistory = this.mNavigationTask.mAddToHistory;
824             reload = this.mNavigationTask.mReload;
825             useCurrent = this.mNavigationTask.mUseCurrent;
826             searchInfo = this.mNavigationTask.mSearchInfo;
827             this.mNavigationTask.cancel(true);
828             this.mNavigationTask = null;
829             this.mCurrentDir = this.mPreviousDir;
830             this.mPreviousDir = null;
831         }
832
833         //Reload data
834         changeCurrentDir(newDir, addToHistory, reload, useCurrent, searchInfo, scrollTo);
835     }
836
837     /**
838      * Method that recycles this object
839      */
840     public void recycle() {
841         if (this.mAdapter != null) {
842             this.mAdapter.dispose();
843         }
844     }
845
846     /**
847      * Method that change the view mode.
848      *
849      * @param newMode The new mode
850      */
851     @SuppressWarnings("unchecked")
852     public void changeViewMode(final NavigationLayoutMode newMode) {
853         //Check that it is really necessary change the mode
854         if (this.mCurrentMode != null && this.mCurrentMode.compareTo(newMode) == 0) {
855             return;
856         }
857
858         // If we should set the listview to response to flinger gesture detection
859         boolean useFlinger =
860                 Preferences.getSharedPreferences().getBoolean(
861                         FileManagerSettings.SETTINGS_USE_FLINGER.getId(),
862                         ((Boolean)FileManagerSettings.
863                                 SETTINGS_USE_FLINGER.
864                                 getDefaultValue()).booleanValue());
865
866         //Creates the new layout
867         AdapterView<ListAdapter> newView = null;
868         int itemResourceId = -1;
869         if (newMode.compareTo(NavigationLayoutMode.ICONS) == 0) {
870             newView = (AdapterView<ListAdapter>)inflate(
871                     getContext(), RESOURCE_MODE_ICONS_LAYOUT, null);
872             itemResourceId = RESOURCE_MODE_ICONS_ITEM;
873
874         } else if (newMode.compareTo(NavigationLayoutMode.SIMPLE) == 0) {
875             newView =  (AdapterView<ListAdapter>)inflate(
876                     getContext(), RESOURCE_MODE_SIMPLE_LAYOUT, null);
877             itemResourceId = RESOURCE_MODE_SIMPLE_ITEM;
878
879             // Set the flinger listener (only when navigate)
880             if (this.mNavigationMode.compareTo(NAVIGATION_MODE.BROWSABLE) == 0) {
881                 if (useFlinger && newView instanceof FlingerListView) {
882                     ((FlingerListView)newView).
883                     setOnItemFlingerListener(this.mOnItemFlingerListener);
884                 }
885             }
886
887         } else if (newMode.compareTo(NavigationLayoutMode.DETAILS) == 0) {
888             newView =  (AdapterView<ListAdapter>)inflate(
889                     getContext(), RESOURCE_MODE_DETAILS_LAYOUT, null);
890             itemResourceId = RESOURCE_MODE_DETAILS_ITEM;
891
892             // Set the flinger listener (only when navigate)
893             if (this.mNavigationMode.compareTo(NAVIGATION_MODE.BROWSABLE) == 0) {
894                 if (useFlinger && newView instanceof FlingerListView) {
895                     ((FlingerListView)newView).
896                     setOnItemFlingerListener(this.mOnItemFlingerListener);
897                 }
898             }
899         }
900
901         //Get the current adapter and its adapter list
902         List<FileSystemObject> files = new ArrayList<FileSystemObject>(this.mFiles);
903         final AdapterView<ListAdapter> current =
904                 (AdapterView<ListAdapter>)findViewById(RESOURCE_CURRENT_LAYOUT);
905         FileSystemObjectAdapter adapter =
906                 new FileSystemObjectAdapter(
907                         getContext(),
908                         new ArrayList<FileSystemObject>(),
909                         itemResourceId,
910                         this.mNavigationMode.compareTo(NAVIGATION_MODE.PICKABLE) == 0);
911         adapter.setOnSelectionChangedListener(this);
912
913         //Remove current layout
914         if (current != null) {
915             if (current.getAdapter() != null) {
916                 //Save selected items before dispose adapter
917                 FileSystemObjectAdapter currentAdapter =
918                         ((FileSystemObjectAdapter)current.getAdapter());
919                 adapter.setSelectedItems(currentAdapter.getSelectedItems());
920                 currentAdapter.dispose();
921             }
922             removeView(current);
923         }
924         this.mFiles = files;
925         adapter.addAll(files);
926
927         //Set the adapter
928         this.mAdapter = adapter;
929         newView.setAdapter(this.mAdapter);
930         newView.setOnItemClickListener(NavigationView.this);
931
932         //Add the new layout
933         this.mAdapterView = newView;
934         addView(newView, 0);
935         this.mCurrentMode = newMode;
936
937         // Pick mode doesn't implements the onlongclick
938         if (this.mNavigationMode.compareTo(NAVIGATION_MODE.BROWSABLE) == 0) {
939             this.mAdapterView.setOnItemLongClickListener(this);
940         } else {
941             this.mAdapterView.setOnItemLongClickListener(null);
942         }
943
944         //Save the preference (only in navigation browse mode)
945         if (this.mNavigationMode.compareTo(NAVIGATION_MODE.BROWSABLE) == 0) {
946             try {
947                 Preferences.savePreference(
948                         FileManagerSettings.SETTINGS_LAYOUT_MODE, newMode, true);
949             } catch (Exception ex) {
950                 Log.e(TAG, "Save of view mode preference fails", ex); //$NON-NLS-1$
951             }
952         }
953     }
954
955     /**
956      * Method that removes a {@link FileSystemObject} from the view
957      *
958      * @param fso The file system object
959      */
960     public void removeItem(FileSystemObject fso) {
961         // Delete also from internal list
962         if (fso != null) {
963             int cc = this.mFiles.size()-1;
964             for (int i = cc; i >= 0; i--) {
965                 FileSystemObject f = this.mFiles.get(i);
966                 if (f != null && f.compareTo(fso) == 0) {
967                     this.mFiles.remove(i);
968                     break;
969                 }
970             }
971         }
972         this.mAdapter.remove(fso);
973     }
974
975     /**
976      * Method that removes a file system object from his path from the view
977      *
978      * @param path The file system object path
979      */
980     public void removeItem(String path) {
981         FileSystemObject fso = this.mAdapter.getItem(path);
982         if (fso != null) {
983             this.mAdapter.remove(fso);
984         }
985     }
986
987     /**
988      * Method that returns the current directory.
989      *
990      * @return String The current directory
991      */
992     public String getCurrentDir() {
993         return this.mCurrentDir;
994     }
995
996     /**
997      * Method that changes the current directory of the view.
998      *
999      * @param newDir The new directory location
1000      */
1001     public void changeCurrentDir(final String newDir) {
1002         changeCurrentDir(newDir, true, false, false, null, null);
1003     }
1004
1005     /**
1006      * Method that changes the current directory of the view.
1007      *
1008      * @param newDir The new directory location
1009      * @param addToHistory Add the directory to history
1010      */
1011     public void changeCurrentDir(final String newDir, boolean addToHistory) {
1012         changeCurrentDir(newDir, addToHistory, false, false, null, null);
1013     }
1014
1015     /**
1016      * Method that changes the current directory of the view.
1017      *
1018      * @param newDir The new directory location
1019      * @param searchInfo The search information (if calling activity is {@link "SearchActivity"})
1020      */
1021     public void changeCurrentDir(final String newDir, SearchInfoParcelable searchInfo) {
1022         changeCurrentDir(newDir, true, false, false, searchInfo, null);
1023     }
1024
1025     /**
1026      * Method that changes the current directory of the view.
1027      *
1028      * @param newDir The new directory location
1029      * @param addToHistory Add the directory to history
1030      * @param reload Force the reload of the data
1031      * @param useCurrent If this method must use the actual data (for back actions)
1032      * @param searchInfo The search information (if calling activity is {@link "SearchActivity"})
1033      * @param scrollTo If not null, then listview must scroll to this item
1034      */
1035     private void changeCurrentDir(
1036             final String newDir, final boolean addToHistory,
1037             final boolean reload, final boolean useCurrent,
1038             final SearchInfoParcelable searchInfo, final FileSystemObject scrollTo) {
1039         this.mPreviousDir = this.mCurrentDir;
1040         this.mCurrentDir = newDir;
1041         mNavigationTask = new NavigationTask(useCurrent, addToHistory, reload,
1042                 searchInfo, scrollTo, mRestrictions, mChRooted);
1043         mNavigationTask.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR, newDir);
1044     }
1045
1046     /**
1047      * Remove all unmounted files in the current selection
1048      */
1049     public void removeUnmountedSelection() {
1050         List<FileSystemObject> selection = mAdapter.getSelectedItems();
1051         int cc = selection.size() - 1;
1052         for (int i = cc; i >= 0; i--) {
1053             FileSystemObject item = selection.get(i);
1054             VirtualMountPointConsole vc =
1055                     VirtualMountPointConsole.getVirtualConsoleForPath(item.getFullPath());
1056             if (vc != null && !vc.isMounted()) {
1057                 selection.remove(i);
1058             }
1059         }
1060         mAdapter.setSelectedItems(selection);
1061         mAdapter.notifyDataSetChanged();
1062
1063         // Do not call the selection listener. This method is supposed to be called by the
1064         // listener itself
1065     }
1066
1067
1068     /**
1069      * Method invoked when a execution ends.
1070      *
1071      * @param files The files obtains from the list
1072      * @param addToHistory If add path to history
1073      * @param isNewHistory If is new history
1074      * @param hasChanged If current directory was changed
1075      * @param searchInfo The search information (if calling activity is {@link "SearchActivity"})
1076      * @param newDir The new directory
1077      * @param scrollTo If not null, then listview must scroll to this item
1078      * @hide
1079      */
1080     void onPostExecuteTask(
1081             List<FileSystemObject> files, boolean addToHistory, boolean isNewHistory,
1082             boolean hasChanged, SearchInfoParcelable searchInfo,
1083             String newDir, final FileSystemObject scrollTo) {
1084         try {
1085             //Check that there is not errors and have some data
1086             if (files == null) {
1087                 this.mCurrentDir = this.mPreviousDir;
1088                 return;
1089             }
1090
1091             //Remove parent directory if we are in the root of a chrooted environment
1092             if (this.mChRooted && StorageHelper.isStorageVolume(newDir)) {
1093                 if (files.size() > 0 && files.get(0) instanceof ParentDirectory) {
1094                     files.remove(0);
1095                 }
1096             }
1097
1098             //Add to history?
1099             if (addToHistory && hasChanged && isNewHistory) {
1100                 if (this.mOnHistoryListener != null) {
1101                     //Communicate the need of a history change
1102                     this.mOnHistoryListener.onNewHistory(onSaveState());
1103                 }
1104             }
1105
1106             //Load the data
1107             loadData(files);
1108             this.mFiles = files;
1109             if (searchInfo != null) {
1110                 searchInfo.setSuccessNavigation(true);
1111             }
1112
1113             //Change the breadcrumb
1114             if (this.mBreadcrumb != null) {
1115                 this.mBreadcrumb.changeBreadcrumbPath(newDir, this.mChRooted);
1116             }
1117
1118             //If scrollTo is null, the position will be set to 0
1119             scrollTo(scrollTo);
1120
1121             //The current directory is now the "newDir"
1122             if (this.mOnDirectoryChangedListener != null) {
1123                 FileSystemObject dir = FileHelper.createFileSystemObject(new File(newDir));
1124                 this.mOnDirectoryChangedListener.onDirectoryChanged(dir);
1125             }
1126
1127         } finally {
1128             //If calling activity is search, then save the search history
1129             if (searchInfo != null) {
1130                 this.mOnHistoryListener.onNewHistory(searchInfo);
1131             }
1132
1133             this.mPreviousDir = null;
1134             mNavigationTask = null;
1135
1136             //End of loading data
1137             try {
1138                 NavigationView.this.mBreadcrumb.endLoading();
1139             } catch (Throwable ex) {
1140                 /**NON BLOCK**/
1141             }
1142         }
1143     }
1144
1145     /**
1146      * Method that loads the files in the adapter.
1147      *
1148      * @param files The files to load in the adapter
1149      * @hide
1150      */
1151     @SuppressWarnings("unchecked")
1152     private void loadData(final List<FileSystemObject> files) {
1153         //Notify data to adapter view
1154         final AdapterView<ListAdapter> view =
1155                 (AdapterView<ListAdapter>)findViewById(RESOURCE_CURRENT_LAYOUT);
1156         FileSystemObjectAdapter adapter = (FileSystemObjectAdapter)view.getAdapter();
1157         adapter.setNotifyOnChange(false);
1158         adapter.clear();
1159         adapter.addAll(files);
1160         adapter.notifyDataSetChanged();
1161     }
1162
1163     /**
1164      * {@inheritDoc}
1165      */
1166     @Override
1167     public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
1168         // Different actions depending on user preference
1169
1170         // Get the adapter and the fso
1171         FileSystemObjectAdapter adapter = ((FileSystemObjectAdapter)parent.getAdapter());
1172         if (adapter == null || position < 0 || (position >= adapter.getCount())) {
1173             return false;
1174         }
1175         FileSystemObject fso = adapter.getItem(position);
1176
1177         // Parent directory hasn't actions
1178         if (fso instanceof ParentDirectory) {
1179             return false;
1180         }
1181
1182         // Pick mode doesn't implements the onlongclick
1183         if (this.mNavigationMode.compareTo(NAVIGATION_MODE.PICKABLE) == 0) {
1184             return false;
1185         }
1186
1187         onRequestMenu(fso);
1188         return true; //Always consume the event
1189     }
1190
1191     /**
1192      * Method that opens or navigates to the {@link FileSystemObject}
1193      *
1194      * @param fso The file system object
1195      */
1196     public void open(FileSystemObject fso) {
1197         open(fso, null);
1198     }
1199
1200     /**
1201      * Method that opens or navigates to the {@link FileSystemObject}
1202      *
1203      * @param fso The file system object
1204      * @param searchInfo The search info
1205      */
1206     public void open(FileSystemObject fso, SearchInfoParcelable searchInfo) {
1207         // If is a folder, then navigate to
1208         if (FileHelper.isDirectory(fso)) {
1209             changeCurrentDir(fso.getFullPath(), searchInfo);
1210         } else {
1211             // Open the file with the preferred registered app
1212             IntentsActionPolicy.openFileSystemObject(getContext(), fso, false, null, null);
1213         }
1214     }
1215
1216     /**
1217      * {@inheritDoc}
1218      */
1219     @Override
1220     public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
1221         try {
1222             FileSystemObject fso = ((FileSystemObjectAdapter)parent.getAdapter()).getItem(position);
1223             if (fso instanceof ParentDirectory) {
1224                 changeCurrentDir(fso.getParent(), true, false, false, null, null);
1225                 return;
1226             } else if (fso instanceof Directory) {
1227                 changeCurrentDir(fso.getFullPath(), true, false, false, null, null);
1228                 return;
1229             } else if (fso instanceof Symlink) {
1230                 Symlink symlink = (Symlink)fso;
1231                 if (symlink.getLinkRef() != null && symlink.getLinkRef() instanceof Directory) {
1232                     changeCurrentDir(
1233                             symlink.getLinkRef().getFullPath(), true, false, false, null, null);
1234                     return;
1235                 }
1236
1237                 // Open the link ref
1238                 fso = symlink.getLinkRef();
1239             }
1240
1241             // Open the file (edit or pick)
1242             if (this.mNavigationMode.compareTo(NAVIGATION_MODE.BROWSABLE) == 0) {
1243                 // Open the file with the preferred registered app
1244                 IntentsActionPolicy.openFileSystemObject(getContext(), fso, false, null, null);
1245             } else {
1246                 // Request a file pick selection
1247                 if (this.mOnFilePickedListener != null) {
1248                     this.mOnFilePickedListener.onFilePicked(fso);
1249                 }
1250             }
1251         } catch (Throwable ex) {
1252             ExceptionUtil.translateException(getContext(), ex);
1253         }
1254     }
1255
1256     /**
1257      * {@inheritDoc}
1258      */
1259     @Override
1260     public void onRequestRefresh(Object o, boolean clearSelection) {
1261         if (o instanceof FileSystemObject) {
1262             refresh((FileSystemObject)o);
1263         } else if (o == null) {
1264             refresh();
1265         }
1266         if (clearSelection) {
1267             onDeselectAll();
1268         }
1269     }
1270
1271     /**
1272      * {@inheritDoc}
1273      */
1274     @Override
1275     public void onRequestBookmarksRefresh() {
1276         // Ignore
1277     }
1278
1279     /**
1280      * {@inheritDoc}
1281      */
1282     @Override
1283     public void onRequestRemove(Object o, boolean clearSelection) {
1284         if (o != null && o instanceof FileSystemObject) {
1285             removeItem((FileSystemObject)o);
1286         } else {
1287             onRequestRefresh(null, clearSelection);
1288         }
1289         if (clearSelection) {
1290             onDeselectAll();
1291         }
1292     }
1293
1294     /**
1295      * {@inheritDoc}
1296      */
1297     @Override
1298     public void onNavigateTo(Object o) {
1299         // Ignored
1300     }
1301
1302     @Override
1303     public void onCancel() {
1304         // nop
1305     }
1306
1307     /**
1308      * {@inheritDoc}
1309      */
1310     @Override
1311     public void onBreadcrumbItemClick(BreadcrumbItem item) {
1312         changeCurrentDir(item.getItemPath(), true, true, false, null, null);
1313     }
1314
1315     /**
1316      * {@inheritDoc}
1317      */
1318     @Override
1319     public void onSelectionChanged(final List<FileSystemObject> selectedItems) {
1320         if (this.mOnNavigationSelectionChangedListener != null) {
1321             this.mOnNavigationSelectionChangedListener.onSelectionChanged(this, selectedItems);
1322         }
1323     }
1324
1325     /**
1326      * Method invoked when a request to show the menu associated
1327      * with an item is started.
1328      *
1329      * @param item The item for which the request was started
1330      */
1331     public void onRequestMenu(final FileSystemObject item) {
1332         if (this.mOnNavigationRequestMenuListener != null) {
1333             this.mOnNavigationRequestMenuListener.onRequestMenu(this, item);
1334         }
1335     }
1336
1337     /**
1338      * {@inheritDoc}
1339      */
1340     @Override
1341     public void onToggleSelection(FileSystemObject fso) {
1342         if (this.mAdapter != null) {
1343             this.mAdapter.toggleSelection(fso);
1344         }
1345     }
1346
1347     /**
1348      * {@inheritDoc}
1349      */
1350     @Override
1351     public void onDeselectAll() {
1352         if (this.mAdapter != null) {
1353             this.mAdapter.deselectedAll();
1354         }
1355     }
1356
1357     /**
1358      * {@inheritDoc}
1359      */
1360     @Override
1361     public void onSelectAllVisibleItems() {
1362         if (this.mAdapter != null) {
1363             this.mAdapter.selectedAllVisibleItems();
1364         }
1365     }
1366
1367     /**
1368      * {@inheritDoc}
1369      */
1370     @Override
1371     public void onDeselectAllVisibleItems() {
1372         if (this.mAdapter != null) {
1373             this.mAdapter.deselectedAllVisibleItems();
1374         }
1375     }
1376
1377     /**
1378      * {@inheritDoc}
1379      */
1380     @Override
1381     public List<FileSystemObject> onRequestSelectedFiles() {
1382         return this.getSelectedFiles();
1383     }
1384
1385     /**
1386      * {@inheritDoc}
1387      */
1388     @Override
1389     public List<FileSystemObject> onRequestCurrentItems() {
1390         return this.getFiles();
1391     }
1392
1393     /**
1394      * {@inheritDoc}
1395      */
1396     @Override
1397     public String onRequestCurrentDir() {
1398         return this.mCurrentDir;
1399     }
1400
1401     /**
1402      * Method that creates a ChRooted environment, protecting the user to break anything
1403      * in the device
1404      * @hide
1405      */
1406     public void createChRooted() {
1407         // If we are in a ChRooted environment, then do nothing
1408         if (this.mChRooted) return;
1409         this.mChRooted = true;
1410
1411         //Change to first storage volume
1412         StorageVolume[] volumes =
1413                 StorageHelper.getStorageVolumes(getContext(), false);
1414         if (volumes != null && volumes.length > 0) {
1415             changeCurrentDir(volumes[0].getPath(), false, true, false, null, null);
1416         }
1417     }
1418
1419     /**
1420      * Method that exits from a ChRooted environment
1421      * @hide
1422      */
1423     public void exitChRooted() {
1424         // If we aren't in a ChRooted environment, then do nothing
1425         if (!this.mChRooted) return;
1426         this.mChRooted = false;
1427
1428         // Refresh
1429         refresh();
1430     }
1431
1432     /**
1433      * Method that ensures that the user don't go outside the ChRooted environment
1434      *
1435      * @param newDir The new directory to navigate to
1436      * @return String
1437      */
1438     private String checkChRootedNavigation(String newDir) {
1439         // If we aren't in ChRooted environment, then there is nothing to check
1440         if (!this.mChRooted) return newDir;
1441
1442         // Check if the path is owned by one of the storage volumes
1443         if (!StorageHelper.isPathInStorageVolume(newDir)) {
1444             StorageVolume[] volumes = StorageHelper.getStorageVolumes(getContext(), false);
1445             if (volumes != null && volumes.length > 0) {
1446                 return volumes[0].getPath();
1447             }
1448         }
1449         return newDir;
1450     }
1451
1452     /**
1453      * Method that applies the current theme to the activity
1454      */
1455     public void applyTheme() {
1456         //- Breadcrumb
1457         if (getBreadcrumb() != null) {
1458             getBreadcrumb().applyTheme();
1459         }
1460
1461         //- Redraw the adapter view
1462         Theme theme = ThemeManager.getCurrentTheme(getContext());
1463         theme.setBackgroundDrawable(getContext(), this, "background_drawable"); //$NON-NLS-1$
1464         if (this.mAdapter != null) {
1465             this.mAdapter.notifyThemeChanged();
1466         }
1467         if (this.mAdapterView instanceof ListView) {
1468             ((ListView)this.mAdapterView).setDivider(
1469                     theme.getDrawable(getContext(), "horizontal_divider_drawable")); //$NON-NLS-1$
1470         }
1471         refresh();
1472     }
1473
1474 }