OSDN Git Service

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