OSDN Git Service

Implement a dialog that warns the user that we must expose the content of the file
[android-x86/packages-apps-CMFileManager.git] / src / com / cyanogenmod / filemanager / activities / NavigationActivity.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.activities;
18
19 import android.app.Activity;
20 import android.app.AlertDialog;
21 import android.app.Dialog;
22 import android.app.SearchManager;
23 import android.content.BroadcastReceiver;
24 import android.content.ContentResolver;
25 import android.content.Context;
26 import android.content.DialogInterface;
27 import android.content.Intent;
28 import android.content.IntentFilter;
29 import android.content.res.Configuration;
30 import android.content.res.XmlResourceParser;
31 import android.database.Cursor;
32 import android.graphics.Color;
33 import android.graphics.drawable.Drawable;
34 import android.net.Uri;
35 import android.nfc.NfcAdapter;
36 import android.nfc.NfcEvent;
37 import android.os.AsyncTask;
38 import android.os.Bundle;
39 import android.os.Environment;
40 import android.os.Handler;
41 import android.os.Parcelable;
42 import android.os.storage.StorageVolume;
43 import android.support.v4.app.ActionBarDrawerToggle;
44 import android.support.v4.widget.DrawerLayout;
45 import android.text.TextUtils;
46 import android.util.Log;
47 import android.view.Gravity;
48 import android.view.KeyEvent;
49 import android.view.MenuItem;
50 import android.view.View;
51 import android.view.View.OnClickListener;
52 import android.view.ViewGroup;
53 import android.widget.AdapterView;
54 import android.widget.AdapterView.OnItemClickListener;
55 import android.widget.ImageButton;
56 import android.widget.ImageView;
57 import android.widget.LinearLayout;
58 import android.widget.ListPopupWindow;
59 import android.widget.ListView;
60 import android.widget.PopupWindow;
61 import android.widget.SearchView;
62 import android.widget.TextView;
63 import android.widget.Toast;
64 import android.widget.Toolbar;
65 import android.widget.ArrayAdapter;
66
67 import com.android.internal.util.XmlUtils;
68 import com.cyanogenmod.filemanager.FileManagerApplication;
69 import com.cyanogenmod.filemanager.R;
70 import com.cyanogenmod.filemanager.activities.preferences.SettingsPreferences;
71 import com.cyanogenmod.filemanager.adapters.MenuSettingsAdapter;
72 import com.cyanogenmod.filemanager.console.Console;
73 import com.cyanogenmod.filemanager.console.ConsoleAllocException;
74 import com.cyanogenmod.filemanager.console.ConsoleBuilder;
75 import com.cyanogenmod.filemanager.console.InsufficientPermissionsException;
76 import com.cyanogenmod.filemanager.console.NoSuchFileOrDirectory;
77 import com.cyanogenmod.filemanager.console.VirtualConsole;
78 import com.cyanogenmod.filemanager.console.VirtualMountPointConsole;
79 import com.cyanogenmod.filemanager.console.secure.SecureConsole;
80 import com.cyanogenmod.filemanager.listeners.OnHistoryListener;
81 import com.cyanogenmod.filemanager.listeners.OnRequestRefreshListener;
82 import com.cyanogenmod.filemanager.model.Bookmark;
83 import com.cyanogenmod.filemanager.model.DiskUsage;
84 import com.cyanogenmod.filemanager.model.FileSystemObject;
85 import com.cyanogenmod.filemanager.model.History;
86 import com.cyanogenmod.filemanager.model.MountPoint;
87 import com.cyanogenmod.filemanager.model.Bookmark.BOOKMARK_TYPE;
88 import com.cyanogenmod.filemanager.parcelables.HistoryNavigable;
89 import com.cyanogenmod.filemanager.parcelables.NavigationViewInfoParcelable;
90 import com.cyanogenmod.filemanager.parcelables.SearchInfoParcelable;
91 import com.cyanogenmod.filemanager.preferences.AccessMode;
92 import com.cyanogenmod.filemanager.preferences.Bookmarks;
93 import com.cyanogenmod.filemanager.preferences.FileManagerSettings;
94 import com.cyanogenmod.filemanager.preferences.NavigationLayoutMode;
95 import com.cyanogenmod.filemanager.preferences.ObjectIdentifier;
96 import com.cyanogenmod.filemanager.preferences.Preferences;
97 import com.cyanogenmod.filemanager.ui.IconHolder;
98 import com.cyanogenmod.filemanager.ui.ThemeManager;
99 import com.cyanogenmod.filemanager.ui.ThemeManager.Theme;
100 import com.cyanogenmod.filemanager.ui.dialogs.ActionsDialog;
101 import com.cyanogenmod.filemanager.ui.dialogs.FilesystemInfoDialog;
102 import com.cyanogenmod.filemanager.ui.dialogs.InitialDirectoryDialog;
103 import com.cyanogenmod.filemanager.ui.dialogs.FilesystemInfoDialog.OnMountListener;
104 import com.cyanogenmod.filemanager.ui.widgets.Breadcrumb;
105 import com.cyanogenmod.filemanager.ui.widgets.ButtonItem;
106 import com.cyanogenmod.filemanager.ui.widgets.NavigationCustomTitleView;
107 import com.cyanogenmod.filemanager.ui.widgets.NavigationView;
108 import com.cyanogenmod.filemanager.ui.widgets.NavigationView.OnNavigationRequestMenuListener;
109 import com.cyanogenmod.filemanager.ui.widgets.NavigationView.OnNavigationSelectionChangedListener;
110 import com.cyanogenmod.filemanager.ui.widgets.SelectionView;
111 import com.cyanogenmod.filemanager.util.AndroidHelper;
112 import com.cyanogenmod.filemanager.util.BookmarksHelper;
113 import com.cyanogenmod.filemanager.util.CommandHelper;
114 import com.cyanogenmod.filemanager.util.DialogHelper;
115 import com.cyanogenmod.filemanager.util.ExceptionUtil;
116 import com.cyanogenmod.filemanager.util.ExceptionUtil.OnRelaunchCommandResult;
117 import com.cyanogenmod.filemanager.util.FileHelper;
118 import com.cyanogenmod.filemanager.util.MimeTypeHelper.MimeTypeCategory;
119 import com.cyanogenmod.filemanager.util.StorageHelper;
120
121 import java.io.File;
122 import java.io.FileNotFoundException;
123 import java.util.ArrayList;
124 import java.util.Arrays;
125 import java.util.HashMap;
126 import java.util.List;
127 import java.util.Locale;
128 import java.util.Map;
129
130 import static com.cyanogenmod.filemanager.util.MimeTypeHelper.MimeTypeCategory.*;
131
132 /**
133  * The main navigation activity. This activity is the center of the application.
134  * From this the user can navigate, search, make actions.<br/>
135  * This activity is singleTop, so when it is displayed no other activities exists in
136  * the stack.<br/>
137  * This cause an issue with the saved instance of this class, because if another activity
138  * is displayed, and the process is killed, NavigationActivity is started and the saved
139  * instance gets corrupted.<br/>
140  * For this reason the methods {link {@link Activity#onSaveInstanceState(Bundle)} and
141  * {@link Activity#onRestoreInstanceState(Bundle)} are not implemented, and every time
142  * the app is killed, is restarted from his initial state.
143  */
144 public class NavigationActivity extends Activity
145     implements OnHistoryListener, OnRequestRefreshListener,
146     OnNavigationRequestMenuListener, OnNavigationSelectionChangedListener {
147
148     private static final String TAG = "NavigationActivity"; //$NON-NLS-1$
149
150     private static boolean DEBUG = false;
151
152     // Bookmark list XML tags
153     private static final String TAG_BOOKMARKS = "Bookmarks"; //$NON-NLS-1$
154     private static final String TAG_BOOKMARK = "bookmark"; //$NON-NLS-1$
155
156     private static final String STR_USB = "usb"; // $NON-NLS-1$
157
158     /**
159      * Intent code for request a search.
160      */
161     public static final int INTENT_REQUEST_SEARCH = 10001;
162
163     /**
164      * Intent code for request a search.
165      */
166     public static final int INTENT_REQUEST_SETTINGS = 20001;
167
168     /**
169      * Constant for extra information about selected search entry.
170      */
171     public static final String EXTRA_SEARCH_ENTRY_SELECTION =
172             "extra_search_entry_selection"; //$NON-NLS-1$
173
174     /**
175      * Constant for extra information about last search data.
176      */
177     public static final String EXTRA_SEARCH_LAST_SEARCH_DATA =
178             "extra_search_last_search_data"; //$NON-NLS-1$
179
180     /**
181      * Constant for extra information for request a navigation to the passed path.
182      */
183     public static final String EXTRA_NAVIGATE_TO =
184             "extra_navigate_to"; //$NON-NLS-1$
185
186     /**
187      * Constant for extra information for request to add navigation to the history
188      */
189     public static final String EXTRA_ADD_TO_HISTORY =
190             "extra_add_to_history"; //$NON-NLS-1$
191
192     // The timeout needed to reset the exit status for back button
193     // After this time user need to tap 2 times the back button to
194     // exit, and the toast is shown again after the first tap.
195     private static final int RELEASE_EXIT_CHECK_TIMEOUT = 3500;
196
197
198     private Toolbar mToolBar;
199     private SearchView mSearchView;
200     private NavigationCustomTitleView mCustomTitleView;
201
202     private final BroadcastReceiver mNotificationReceiver = new BroadcastReceiver() {
203         @Override
204         public void onReceive(Context context, Intent intent) {
205             if (intent != null) {
206                 if (intent.getAction().compareTo(FileManagerSettings.INTENT_SETTING_CHANGED) == 0) {
207                     // The settings has changed
208                     String key = intent.getStringExtra(FileManagerSettings.EXTRA_SETTING_CHANGED_KEY);
209                     if (key != null) {
210                         // Disk usage warning level
211                         if (key.compareTo(FileManagerSettings.
212                                 SETTINGS_DISK_USAGE_WARNING_LEVEL.getId()) == 0) {
213
214                             // Set the free disk space warning level of the breadcrumb widget
215                             Breadcrumb breadcrumb = getCurrentNavigationView().getBreadcrumb();
216                             String fds = Preferences.getSharedPreferences().getString(
217                                     FileManagerSettings.SETTINGS_DISK_USAGE_WARNING_LEVEL.getId(),
218                                     (String)FileManagerSettings.
219                                         SETTINGS_DISK_USAGE_WARNING_LEVEL.getDefaultValue());
220                             breadcrumb.setFreeDiskSpaceWarningLevel(Integer.parseInt(fds));
221                             breadcrumb.updateMountPointInfo();
222                             return;
223                         }
224
225                         // Case sensitive sort
226                         if (key.compareTo(FileManagerSettings.
227                                 SETTINGS_CASE_SENSITIVE_SORT.getId()) == 0) {
228                             getCurrentNavigationView().refresh();
229                             return;
230                         }
231
232                         // Display thumbs
233                         if (key.compareTo(FileManagerSettings.
234                                 SETTINGS_DISPLAY_THUMBS.getId()) == 0) {
235                             // Clean the icon cache applying the current theme
236                             applyTheme();
237                             return;
238                         }
239
240                         // Use flinger
241                         if (key.compareTo(FileManagerSettings.
242                                 SETTINGS_USE_FLINGER.getId()) == 0) {
243                             boolean useFlinger =
244                                     Preferences.getSharedPreferences().getBoolean(
245                                             FileManagerSettings.SETTINGS_USE_FLINGER.getId(),
246                                                 ((Boolean)FileManagerSettings.
247                                                         SETTINGS_USE_FLINGER.
248                                                             getDefaultValue()).booleanValue());
249                             getCurrentNavigationView().setUseFlinger(useFlinger);
250                             return;
251                         }
252
253                         // Access mode
254                         if (key.compareTo(FileManagerSettings.
255                                 SETTINGS_ACCESS_MODE.getId()) == 0) {
256                             // Is it necessary to create or exit of the ChRooted?
257                             boolean chRooted =
258                                     FileManagerApplication.
259                                         getAccessMode().compareTo(AccessMode.SAFE) == 0;
260                             if (chRooted != NavigationActivity.this.mChRooted) {
261                                 if (chRooted) {
262                                     createChRooted();
263                                 } else {
264                                     exitChRooted();
265                                 }
266                             }
267                         }
268
269                         // Restricted access
270                         if (key.compareTo(FileManagerSettings.
271                                 SETTINGS_RESTRICT_SECONDARY_USERS_ACCESS.getId()) == 0) {
272                             if (AndroidHelper.isSecondaryUser(context)) {
273                                 try {
274                                     Preferences.savePreference(
275                                             FileManagerSettings.SETTINGS_ACCESS_MODE,
276                                             AccessMode.SAFE, true);
277                                 } catch (Throwable ex) {
278                                     Log.w(TAG, "can't save console preference", ex); //$NON-NLS-1$
279                                 }
280                                 ConsoleBuilder.changeToNonPrivilegedConsole(context);
281                                 createChRooted();
282                             }
283                         }
284
285                         // Filetime format mode
286                         if (key.compareTo(FileManagerSettings.
287                                 SETTINGS_FILETIME_FORMAT_MODE.getId()) == 0) {
288                             // Refresh the data
289                             synchronized (FileHelper.DATETIME_SYNC) {
290                                 FileHelper.sReloadDateTimeFormats = true;
291                                 NavigationActivity.this.getCurrentNavigationView().refresh();
292                             }
293                         }
294                     }
295
296                 } else if (intent.getAction().compareTo(
297                         FileManagerSettings.INTENT_FILE_CHANGED) == 0) {
298                     // Retrieve the file that was changed
299                     String file =
300                             intent.getStringExtra(FileManagerSettings.EXTRA_FILE_CHANGED_KEY);
301                     try {
302                         FileSystemObject fso = CommandHelper.getFileInfo(context, file, null);
303                         if (fso != null) {
304                             getCurrentNavigationView().refresh(fso);
305                         }
306                     } catch (Exception e) {
307                         ExceptionUtil.translateException(context, e, true, false);
308                     }
309
310                 } else if (intent.getAction().compareTo(
311                         FileManagerSettings.INTENT_THEME_CHANGED) == 0) {
312                     applyTheme();
313
314                 } else if (intent.getAction().compareTo(Intent.ACTION_TIME_CHANGED) == 0 ||
315                            intent.getAction().compareTo(Intent.ACTION_DATE_CHANGED) == 0 ||
316                            intent.getAction().compareTo(Intent.ACTION_TIMEZONE_CHANGED) == 0) {
317                     // Refresh the data
318                     synchronized (FileHelper.DATETIME_SYNC) {
319                         FileHelper.sReloadDateTimeFormats = true;
320                         NavigationActivity.this.getCurrentNavigationView().refresh();
321                     }
322                 } else if (intent.getAction().compareTo(
323                         FileManagerSettings.INTENT_MOUNT_STATUS_CHANGED) == 0 ||
324                             intent.getAction().equals(Intent.ACTION_MEDIA_MOUNTED) ||
325                             intent.getAction().equals(Intent.ACTION_MEDIA_UNMOUNTED)) {
326                     onRequestBookmarksRefresh();
327                     removeUnmountedHistory();
328                     removeUnmountedSelection();
329                 }
330             }
331         }
332     };
333
334     private OnClickListener mOnClickDrawerTabListener = new OnClickListener() {
335         @Override
336         public void onClick(View v) {
337             switch (v.getId()) {
338                 case R.id.drawer_bookmarks_tab:
339                     if (!mBookmarksTab.isSelected()) {
340                         mBookmarksTab.setSelected(true);
341                         mHistoryTab.setSelected(false);
342                         mBookmarksTab.setTextAppearance(
343                                 NavigationActivity.this, R.style.primary_text_appearance);
344                         mHistoryTab.setTextAppearance(
345                                 NavigationActivity.this, R.style.secondary_text_appearance);
346                         mHistoryLayout.setVisibility(View.GONE);
347                         mBookmarksLayout.setVisibility(View.VISIBLE);
348                         applyTabTheme();
349
350                         try {
351                             Preferences.savePreference(FileManagerSettings.USER_PREF_LAST_DRAWER_TAB,
352                                     Integer.valueOf(0), true);
353                         } catch (Exception ex) {
354                             Log.e(TAG, "Can't save last drawer tab", ex); //$NON-NLS-1$
355                         }
356
357                         mClearHistory.setVisibility(View.GONE);
358                     }
359                     break;
360                 case R.id.drawer_history_tab:
361                     if (!mHistoryTab.isSelected()) {
362                         mHistoryTab.setSelected(true);
363                         mBookmarksTab.setSelected(false);
364                         mHistoryTab.setTextAppearance(
365                                 NavigationActivity.this, R.style.primary_text_appearance);
366                         mBookmarksTab.setTextAppearance(
367                                 NavigationActivity.this, R.style.secondary_text_appearance);
368                         mBookmarksLayout.setVisibility(View.GONE);
369                         mHistoryLayout.setVisibility(View.VISIBLE);
370                         applyTabTheme();
371
372                         try {
373                             Preferences.savePreference(FileManagerSettings.USER_PREF_LAST_DRAWER_TAB,
374                                     Integer.valueOf(1), true);
375                         } catch (Exception ex) {
376                             Log.e(TAG, "Can't save last drawer tab", ex); //$NON-NLS-1$
377                         }
378
379                         mClearHistory.setVisibility(mHistory.size() > 0 ? View.VISIBLE : View.GONE);
380                     }
381                     break;
382                 default:
383                     break;
384             }
385         }
386     };
387
388     private OnClickListener mOnClickDrawerActionBarListener = new OnClickListener() {
389         @Override
390         public void onClick(View v) {
391             switch (v.getId()) {
392                 case R.id.ab_settings:
393                     mDrawerLayout.closeDrawer(Gravity.START);
394                     openSettings();
395                     break;
396                 case R.id.ab_clear_history:
397                     clearHistory();
398                     mClearHistory.setVisibility(View.GONE);
399                     break;
400                 default:
401                     break;
402             }
403         }
404     };
405
406     static String MIME_TYPE_LOCALIZED_NAMES[];
407     /**
408      * @hide
409      */
410     static Map<MimeTypeCategory, Drawable> EASY_MODE_ICONS = new
411             HashMap<MimeTypeCategory, Drawable>();
412
413     /**
414      * @hide
415      */
416     NavigationView[] mNavigationViews;
417     /**
418      * @hide
419      */
420     ListView mEasyModeListView;
421     private List<History> mHistory;
422
423     private static final List<MimeTypeCategory> EASY_MODE_LIST = new ArrayList<MimeTypeCategory>() {
424         {
425             add(NONE);
426             add(IMAGE);
427             add(VIDEO);
428             add(AUDIO);
429             add(DOCUMENT);
430             add(APP);
431         }
432     };
433
434     private ArrayAdapter<MimeTypeCategory> mEasyModeAdapter;
435     private View.OnClickListener mEasyModeItemClickListener = new View.OnClickListener() {
436         @Override
437         public void onClick(View view) {
438             Integer position = (Integer) view.getTag();
439             onClicked(position);
440         }
441     };
442
443     private int mCurrentNavigationView;
444
445     private ViewGroup mActionBar;
446     private SelectionView mSelectionBar;
447
448     private DrawerLayout mDrawerLayout;
449     private ViewGroup mDrawer;
450     private ActionBarDrawerToggle mDrawerToggle;
451     private LinearLayout mDrawerHistory;
452     private TextView mDrawerHistoryEmpty;
453
454     private TextView mBookmarksTab;
455     private TextView mHistoryTab;
456     private View mBookmarksLayout;
457     private View mHistoryLayout;
458
459     private ButtonItem mSettings;
460     private ButtonItem mClearHistory;
461
462     private List<Bookmark> mBookmarks;
463     private List<Bookmark> mSdBookmarks;
464     private LinearLayout mDrawerBookmarks;
465
466     private boolean mExitFlag = false;
467     private long mExitBackTimeout = -1;
468
469     private Dialog mActiveDialog = null;
470
471     private int mOrientation;
472
473     /**
474      * @hide
475      */
476     boolean mChRooted;
477
478     /**
479      * @hide
480      */
481     Handler mHandler;
482
483     private AsyncTask<Void, Void, Boolean> mBookmarksTask;
484
485     /**
486      * {@inheritDoc}
487      */
488     @Override
489     protected void onCreate(Bundle state) {
490
491         if (DEBUG) {
492             Log.d(TAG, "NavigationActivity.onCreate"); //$NON-NLS-1$
493         }
494
495         // Register the broadcast receiver
496         IntentFilter filter = new IntentFilter();
497         filter.addAction(FileManagerSettings.INTENT_SETTING_CHANGED);
498         filter.addAction(FileManagerSettings.INTENT_FILE_CHANGED);
499         filter.addAction(FileManagerSettings.INTENT_THEME_CHANGED);
500         filter.addAction(Intent.ACTION_DATE_CHANGED);
501         filter.addAction(Intent.ACTION_TIME_CHANGED);
502         filter.addAction(Intent.ACTION_TIMEZONE_CHANGED);
503         filter.addAction(FileManagerSettings.INTENT_MOUNT_STATUS_CHANGED);
504         registerReceiver(this.mNotificationReceiver, filter);
505
506         // This filter needs the file data scheme, so it must be defined separately.
507         IntentFilter newFilter = new IntentFilter();
508         newFilter.addAction(Intent.ACTION_MEDIA_MOUNTED);
509         newFilter.addAction(Intent.ACTION_MEDIA_UNMOUNTED);
510         newFilter.addDataScheme(ContentResolver.SCHEME_FILE);
511         registerReceiver(mNotificationReceiver, newFilter);
512
513         // Set the theme before setContentView
514         Theme theme = ThemeManager.getCurrentTheme(this);
515         theme.setBaseThemeNoActionBar(this);
516
517         //Set the main layout of the activity
518         setContentView(R.layout.navigation);
519
520         //Initialize nfc adapter
521         NfcAdapter mNfcAdapter = NfcAdapter.getDefaultAdapter(this);
522         if (mNfcAdapter != null) {
523             mNfcAdapter.setBeamPushUrisCallback(new NfcAdapter.CreateBeamUrisCallback() {
524                 @Override
525                 public Uri[] createBeamUris(NfcEvent event) {
526                     List<FileSystemObject> selectedFiles =
527                             getCurrentNavigationView().getSelectedFiles();
528                     if (selectedFiles.size() > 0) {
529                         List<Uri> fileUri = new ArrayList<Uri>();
530                         for (FileSystemObject f : selectedFiles) {
531                             //Beam ignores folders and system files
532                             if (!FileHelper.isDirectory(f) && !FileHelper.isSystemFile(f)) {
533                                 fileUri.add(Uri.fromFile(new File(f.getFullPath())));
534                             }
535                         }
536                         if (fileUri.size() > 0) {
537                             return fileUri.toArray(new Uri[fileUri.size()]);
538                         }
539                     }
540                     return null;
541                 }
542             }, this);
543         }
544
545         //Initialize activity
546         init();
547
548         //Navigation views
549         initNavigationViews();
550
551         // As we're using a Toolbar, we should retrieve it and set it
552         // to be our ActionBar
553         mToolBar = (Toolbar) findViewById(R.id.material_toolbar);
554         setActionBar(mToolBar);
555
556         //Initialize action bars
557         initTitleActionBar();
558         initStatusActionBar();
559         initSelectionBar();
560
561         // Initialize navigation drawer
562         initDrawer();
563         initBookmarks();
564
565         // Adjust layout (only when start on landscape mode)
566         int orientation = getResources().getConfiguration().orientation;
567         if (orientation == Configuration.ORIENTATION_LANDSCAPE) {
568             onLayoutChanged();
569         }
570         this.mOrientation = orientation;
571
572         // Apply the theme
573         applyTheme();
574
575         // Show welcome message
576         showWelcomeMsg();
577
578         this.mHandler = new Handler();
579         this.mHandler.post(new Runnable() {
580             @Override
581             public void run() {
582                 // Initialize console
583                 initConsole();
584
585                 //Initialize navigation
586                 int cc = NavigationActivity.this.mNavigationViews.length;
587                 for (int i = 0; i < cc; i++) {
588                     initNavigation(i, false, getIntent());
589                 }
590
591                 //Check the intent action
592                 checkIntent(getIntent());
593             }
594         });
595
596         MIME_TYPE_LOCALIZED_NAMES = MimeTypeCategory.getFriendlyLocalizedNames(NavigationActivity
597             .this);
598
599         EASY_MODE_ICONS.put(MimeTypeCategory.NONE, getResources().getDrawable(R.drawable
600                 .ic_em_all));
601         EASY_MODE_ICONS.put(MimeTypeCategory.IMAGE, getResources().getDrawable(R.drawable
602                 .ic_em_image));
603         EASY_MODE_ICONS.put(MimeTypeCategory.VIDEO, getResources().getDrawable(R.drawable
604                 .ic_em_video));
605         EASY_MODE_ICONS.put(MimeTypeCategory.AUDIO, getResources().getDrawable(R.drawable
606                 .ic_em_music));
607         EASY_MODE_ICONS.put(MimeTypeCategory.DOCUMENT, getResources().getDrawable(R.drawable
608                 .ic_em_document));
609         EASY_MODE_ICONS.put(MimeTypeCategory.APP, getResources().getDrawable(R.drawable
610                 .ic_em_application));
611
612         //Save state
613         super.onCreate(state);
614     }
615
616     @Override
617     protected void onResume() {
618         super.onResume();
619
620         if (mSearchView.getVisibility() == View.VISIBLE) {
621             closeSearch();
622         }
623
624         // Check restrictions
625         if (!FileManagerApplication.checkRestrictSecondaryUsersAccess(this, mChRooted)) {
626             return;
627         }
628
629         // Check that the current dir is mounted (for virtual filesystems)
630         String curDir = mNavigationViews[mCurrentNavigationView].getCurrentDir();
631         if (curDir != null) {
632             VirtualMountPointConsole vc = VirtualMountPointConsole.getVirtualConsoleForPath(
633                     mNavigationViews[mCurrentNavigationView].getCurrentDir());
634             if (vc != null && !vc.isMounted()) {
635                 onRequestBookmarksRefresh();
636                 removeUnmountedHistory();
637                 removeUnmountedSelection();
638
639                 Intent intent = new Intent();
640                 intent.putExtra(EXTRA_ADD_TO_HISTORY, false);
641                 initNavigation(NavigationActivity.this.mCurrentNavigationView, false, intent);
642             }
643         }
644     }
645
646     @Override
647     protected void onPostCreate(Bundle savedInstanceState) {
648         super.onPostCreate(savedInstanceState);
649         // Sync the toggle state after onRestoreInstanceState has occurred.
650         mDrawerToggle.syncState();
651     }
652
653     /**
654      * {@inheritDoc}
655      */
656     @Override
657     protected void onNewIntent(Intent intent) {
658         //Initialize navigation
659         initNavigation(this.mCurrentNavigationView, true, intent);
660
661         //Check the intent action
662         checkIntent(intent);
663     }
664
665     /**
666      * {@inheritDoc}
667      */
668     @Override
669     public void onConfigurationChanged(Configuration newConfig) {
670         super.onConfigurationChanged(newConfig);
671         onLayoutChanged();
672         mDrawerToggle.onConfigurationChanged(newConfig);
673     }
674
675     /**
676      * {@inheritDoc}
677      */
678     @Override
679     public boolean onOptionsItemSelected(MenuItem item) {
680         if (mDrawerToggle.onOptionsItemSelected(item)) {
681           return true;
682         }
683         return super.onOptionsItemSelected(item);
684     }
685
686     /**
687      * {@inheritDoc}
688      */
689     @Override
690     protected void onDestroy() {
691         if (DEBUG) {
692             Log.d(TAG, "NavigationActivity.onDestroy"); //$NON-NLS-1$
693         }
694
695         if (mActiveDialog != null && mActiveDialog.isShowing()) {
696             mActiveDialog.dismiss();
697         }
698
699         // Unregister the receiver
700         try {
701             unregisterReceiver(this.mNotificationReceiver);
702         } catch (Throwable ex) {
703             /**NON BLOCK**/
704         }
705
706         //All destroy. Continue
707         super.onDestroy();
708     }
709
710     /**
711      * Method that returns the current navigation view.
712      *
713      * @return NavigationView The current navigation view
714      */
715     public NavigationView getCurrentNavigationView() {
716         return getNavigationView(this.mCurrentNavigationView);
717     }
718
719     /**
720      * Method that returns the current navigation view.
721      *
722      * @param viewId The view to return
723      * @return NavigationView The current navigation view
724      */
725     public NavigationView getNavigationView(int viewId) {
726         if (this.mNavigationViews == null) return null;
727         return this.mNavigationViews[viewId];
728     }
729
730     /**
731      * Method that initializes the activity.
732      */
733     private void init() {
734         this.mHistory = new ArrayList<History>();
735         this.mChRooted = FileManagerApplication.getAccessMode().compareTo(AccessMode.SAFE) == 0;
736     }
737
738     /**
739      * Method that displays a welcome message the first time the user
740      * access the application
741      */
742     private void showWelcomeMsg() {
743         boolean firstUse = Preferences.getSharedPreferences().getBoolean(
744                 FileManagerSettings.SETTINGS_FIRST_USE.getId(),
745                 ((Boolean)FileManagerSettings.SETTINGS_FIRST_USE.getDefaultValue()).booleanValue());
746
747         //Display the welcome message?
748         if (firstUse && FileManagerApplication.hasShellCommands()) {
749             // open navigation drawer to show user that it exists
750             mDrawerLayout.openDrawer(Gravity.START);
751
752             AlertDialog dialog = DialogHelper.createAlertDialog(this,
753                     R.mipmap.ic_launcher_filemanager, R.string.welcome_title,
754                     getString(R.string.welcome_msg), false);
755             DialogHelper.delegateDialogShow(this, dialog);
756
757             // Don't display again this dialog
758             try {
759                 Preferences.savePreference(
760                         FileManagerSettings.SETTINGS_FIRST_USE, Boolean.FALSE, true);
761             } catch (Exception e) {/**NON BLOCK**/}
762         }
763     }
764
765     /**
766      * Method that initializes the titlebar of the activity.
767      */
768     private void initTitleActionBar() {
769         //Inflate the view and associate breadcrumb
770         View titleLayout = getLayoutInflater().inflate(
771                 R.layout.navigation_view_customtitle, null, false);
772         NavigationCustomTitleView title =
773                 (NavigationCustomTitleView)titleLayout.findViewById(R.id.navigation_title_flipper);
774         title.setOnHistoryListener(this);
775         Breadcrumb breadcrumb = (Breadcrumb)title.findViewById(R.id.breadcrumb_view);
776         int cc = this.mNavigationViews.length;
777         for (int i = 0; i < cc; i++) {
778             this.mNavigationViews[i].setBreadcrumb(breadcrumb);
779             this.mNavigationViews[i].setOnHistoryListener(this);
780             this.mNavigationViews[i].setOnNavigationSelectionChangedListener(this);
781             this.mNavigationViews[i].setOnNavigationOnRequestMenuListener(this);
782             this.mNavigationViews[i].setCustomTitle(title);
783         }
784
785         // Set the free disk space warning level of the breadcrumb widget
786         String fds = Preferences.getSharedPreferences().getString(
787                 FileManagerSettings.SETTINGS_DISK_USAGE_WARNING_LEVEL.getId(),
788                 (String)FileManagerSettings.SETTINGS_DISK_USAGE_WARNING_LEVEL.getDefaultValue());
789         breadcrumb.setFreeDiskSpaceWarningLevel(Integer.parseInt(fds));
790
791         //Configure the action bar options
792         getActionBar().setBackgroundDrawable(
793                 getResources().getDrawable(R.drawable.bg_material_titlebar));
794         mToolBar.addView(titleLayout);
795     }
796
797     /**
798      * Method that initializes the statusbar of the activity.
799      */
800     private void initStatusActionBar() {
801         //Performs a width calculation of buttons. Buttons exceeds the width
802         //of the action bar should be hidden
803         //This application not use android ActionBar because the application
804         //make uses of the title and bottom areas, and wants to force to show
805         //the overflow button (without care of physical buttons)
806         this.mActionBar = (ViewGroup)findViewById(R.id.navigation_actionbar);
807         this.mActionBar.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
808             @Override
809             public void onLayoutChange(
810                     View v, int left, int top, int right, int bottom, int oldLeft,
811                     int oldTop, int oldRight, int oldBottom) {
812                 //Get the width of the action bar
813                 int w = v.getMeasuredWidth();
814
815                 //Wake through children calculation his dimensions
816                 int bw = (int)getResources().getDimension(R.dimen.default_buttom_width);
817                 int cw = 0;
818                 final ViewGroup abView = ((ViewGroup)v);
819                 int cc = abView.getChildCount();
820                 for (int i = 0; i < cc; i++) {
821                     View child = abView.getChildAt(i);
822                     child.setVisibility(cw + bw > w ? View.INVISIBLE : View.VISIBLE);
823                     cw += bw;
824                 }
825             }
826         });
827
828         // Have overflow menu? Actually no. There is only a search action, so just hide
829         // the overflow
830         View overflow = findViewById(R.id.ab_overflow);
831         overflow.setVisibility(View.GONE);
832
833         // Show the status bar
834         View statusBar = findViewById(R.id.navigation_statusbar_portrait_holder);
835         statusBar.setVisibility(View.VISIBLE);
836     }
837
838     /**
839      * Method that initializes the selectionbar of the activity.
840      */
841     private void initSelectionBar() {
842         this.mSelectionBar = (SelectionView)findViewById(R.id.navigation_selectionbar);
843     }
844
845     /**
846      * Method that initializes the navigation drawer of the activity.
847      */
848     private void initDrawer() {
849         mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
850         //Set our status bar color
851         mDrawerLayout.setStatusBarBackgroundColor(R.color.material_palette_blue_primary_dark);
852         mDrawer = (ViewGroup) findViewById(R.id.drawer);
853         mDrawerBookmarks = (LinearLayout) findViewById(R.id.bookmarks_list);
854         mDrawerHistory = (LinearLayout) findViewById(R.id.history_list);
855         mDrawerHistoryEmpty = (TextView) findViewById(R.id.history_empty);
856
857         mBookmarksLayout = findViewById(R.id.drawer_bookmarks);
858         mHistoryLayout = findViewById(R.id.drawer_history);
859         mBookmarksTab = (TextView) findViewById(R.id.drawer_bookmarks_tab);
860         mHistoryTab = (TextView) findViewById(R.id.drawer_history_tab);
861         mBookmarksTab.setOnClickListener(mOnClickDrawerTabListener);
862         mHistoryTab.setOnClickListener(mOnClickDrawerTabListener);
863
864         mSettings = (ButtonItem) findViewById(R.id.ab_settings);
865         mSettings.setOnClickListener(mOnClickDrawerActionBarListener);
866         mClearHistory = (ButtonItem) findViewById(R.id.ab_clear_history);
867         mClearHistory.setOnClickListener(mOnClickDrawerActionBarListener);
868
869         // Restore the last tab pressed
870         Integer lastTab = Preferences.getSharedPreferences().getInt(
871                 FileManagerSettings.USER_PREF_LAST_DRAWER_TAB.getId(),
872                 (Integer) FileManagerSettings.USER_PREF_LAST_DRAWER_TAB
873                         .getDefaultValue());
874         mOnClickDrawerTabListener.onClick(lastTab == 0 ? mBookmarksTab : mHistoryTab);
875
876         // Set the navigation drawer "hamburger" icon
877         mDrawerToggle = new ActionBarDrawerToggle(this, mDrawerLayout,
878                 R.drawable.ic_material_light_navigation_drawer,
879                 R.string.drawer_open, R.string.drawer_close) {
880
881             /** Called when a drawer has settled in a completely closed state. */
882             public void onDrawerClosed(View view) {
883                 super.onDrawerClosed(view);
884             }
885
886             /** Called when a drawer has settled in a completely open state. */
887             public void onDrawerOpened(View drawerView) {
888                 super.onDrawerOpened(drawerView);
889             }
890         };
891         getActionBar().setDisplayHomeAsUpEnabled(true);
892
893         // Set the drawer toggle as the DrawerListener
894         mDrawerLayout.setDrawerListener(mDrawerToggle);
895     }
896
897     /**
898      * Method that adds a history entry to the history list in the drawer
899      */
900     private void addHistoryToDrawer(int index, HistoryNavigable navigable) {
901         // hide empty message
902         mDrawerHistoryEmpty.setVisibility(View.GONE);
903
904         Theme theme = ThemeManager.getCurrentTheme(this);
905         IconHolder iconholder = new IconHolder(this, false);
906
907         // inflate single bookmark layout item and fill it
908         LinearLayout view = (LinearLayout) getLayoutInflater().inflate(
909                 R.layout.history_item, null);
910
911         ImageView iconView = (ImageView) view
912                 .findViewById(R.id.history_item_icon);
913         TextView name = (TextView) view.findViewById(R.id.history_item_name);
914         TextView directory = (TextView) view
915                 .findViewById(R.id.history_item_directory);
916
917         Drawable icon = iconholder.getDrawable("ic_fso_folder_drawable"); //$NON-NLS-1$
918         if (navigable instanceof SearchInfoParcelable) {
919             icon = iconholder.getDrawable("ic_history_search_drawable"); //$NON-NLS-1$
920         }
921         iconView.setImageDrawable(icon);
922
923         String title = navigable.getTitle();
924         if (title == null || title.trim().length() == 0) {
925             title = getString(R.string.root_directory_name);
926         }
927
928         name.setText(title);
929         directory.setText(navigable.getDescription());
930
931         theme.setTextColor(this, name, "text_color");
932         theme.setTextColor(this, directory, "text_color");
933
934         // handle item click
935         view.setOnClickListener(new OnClickListener() {
936             @Override
937             public void onClick(View v) {
938                 final int index = mDrawerHistory.indexOfChild(v);
939                 final int count = mDrawerHistory.getChildCount();
940                 final History history = mHistory.get(count - index - 1);
941
942                 navigateToHistory(history);
943                 mDrawerLayout.closeDrawer(Gravity.START);
944             }
945         });
946
947         // add as first child
948         mDrawerHistory.addView(view, 0);
949
950         // Show clear button if history tab is selected
951         mClearHistory.setVisibility(mHistoryTab.isSelected() ? View.VISIBLE : View.GONE);
952     }
953
954     /**
955      * Method takes a bookmark as argument and adds it to mBookmarks and the
956      * list in the drawer
957      */
958     public void addBookmark(Bookmark bookmark) {
959         mBookmarks.add(bookmark);
960         addBookmarkToDrawer(bookmark);
961     }
962
963     /**
964      * Show the easy mode view
965      */
966     private void performShowEasyMode() {
967         mEasyModeListView.setVisibility(View.VISIBLE);
968         getCurrentNavigationView().setVisibility(View.GONE);
969     }
970
971     /**
972      * Hide the easy mode view
973      */
974     private void performHideEasyMode() {
975         mEasyModeListView.setVisibility(View.GONE);
976         getCurrentNavigationView().setVisibility(View.VISIBLE);
977     }
978
979     /**
980      * Method takes a bookmark as argument and adds it to the bookmark list in
981      * the drawer
982      */
983     private void addBookmarkToDrawer(Bookmark bookmark) {
984         Theme theme = ThemeManager.getCurrentTheme(this);
985         IconHolder iconholder = new IconHolder(this, false);
986
987         // inflate single bookmark layout item and fill it
988         LinearLayout view = (LinearLayout) getLayoutInflater().inflate(
989                 R.layout.bookmarks_item, null);
990
991         ImageView icon = (ImageView) view
992                 .findViewById(R.id.bookmarks_item_icon);
993         TextView name = (TextView) view.findViewById(R.id.bookmarks_item_name);
994         TextView path = (TextView) view.findViewById(R.id.bookmarks_item_path);
995         ImageButton actionButton = (ImageButton) view
996                 .findViewById(R.id.bookmarks_item_action);
997
998         name.setText(bookmark.mName);
999         path.setText(bookmark.mPath);
1000
1001         theme.setTextColor(this, name, "text_color");
1002         theme.setTextColor(this, path, "text_color");
1003
1004         icon.setImageDrawable(iconholder.getDrawable(BookmarksHelper
1005                 .getIcon(bookmark)));
1006
1007         Drawable action = null;
1008         String actionCd = null;
1009         if (bookmark.mType.compareTo(BOOKMARK_TYPE.HOME) == 0) {
1010             action = iconholder.getDrawable("ic_edit_home_bookmark_drawable"); //$NON-NLS-1$
1011             actionCd = getApplicationContext().getString(
1012                     R.string.bookmarks_button_config_cd);
1013         }
1014         else if (bookmark.mType.compareTo(BOOKMARK_TYPE.USER_DEFINED) == 0) {
1015             action = iconholder.getDrawable("ic_close_drawable"); //$NON-NLS-1$
1016             actionCd = getApplicationContext().getString(
1017                     R.string.bookmarks_button_remove_bookmark_cd);
1018         }
1019
1020         actionButton.setImageDrawable(action);
1021         actionButton.setVisibility(action != null ? View.VISIBLE : View.GONE);
1022         actionButton.setOnClickListener(new OnClickListener() {
1023             @Override
1024             public void onClick(View view) {
1025                 final View v = (View) view.getParent();
1026                 final int index = mDrawerBookmarks.indexOfChild(v);
1027                 final Bookmark bookmark = mBookmarks.get(index);
1028
1029                 // Configure home
1030                 if (bookmark.mType.compareTo(BOOKMARK_TYPE.HOME) == 0) {
1031                     // Show a dialog for configure initial directory
1032                     InitialDirectoryDialog dialog = new InitialDirectoryDialog(
1033                             NavigationActivity.this);
1034                     dialog.setOnValueChangedListener(new InitialDirectoryDialog.OnValueChangedListener() {
1035                         @Override
1036                         public void onValueChanged(String newInitialDir) {
1037                             bookmark.mPath = newInitialDir;
1038
1039                             // reset drawer bookmarks list
1040                             initBookmarks();
1041                         }
1042                     });
1043                     dialog.show();
1044                     return;
1045                 }
1046
1047                 // Remove bookmark
1048                 if (bookmark.mType.compareTo(BOOKMARK_TYPE.USER_DEFINED) == 0) {
1049                     boolean result = Bookmarks.removeBookmark(
1050                             getApplicationContext(), bookmark);
1051                     if (!result) { // Show warning
1052                         DialogHelper.showToast(getApplicationContext(),
1053                                 R.string.msgs_operation_failure,
1054                                 Toast.LENGTH_SHORT);
1055                         return;
1056                     }
1057                     mBookmarks.remove(bookmark);
1058                     mDrawerBookmarks.removeView(v);
1059                     return;
1060                 }
1061             }
1062         });
1063         actionButton.setContentDescription(actionCd);
1064
1065         // handle item click
1066         view.setOnClickListener(new OnClickListener() {
1067             @Override
1068             public void onClick(View v) {
1069                 final int index = mDrawerBookmarks.indexOfChild(v);
1070                 final Bookmark bookmark = mBookmarks.get(index);
1071
1072                 boolean showEasyMode = (mSdBookmarks.contains(bookmark)) &&
1073                         getResources().getBoolean(R.bool.cmcc_show_easy_mode);
1074
1075                 // try to navigate to the bookmark path
1076                 try {
1077                     FileSystemObject fso = CommandHelper.getFileInfo(
1078                             getApplicationContext(), bookmark.mPath, null);
1079                     if (fso != null) {
1080                         if (showEasyMode) {
1081                             performShowEasyMode();
1082                         } else {
1083                             performHideEasyMode();
1084                         }
1085                         getCurrentNavigationView().open(fso);
1086                         mDrawerLayout.closeDrawer(Gravity.START);
1087                     }
1088                     else {
1089                         // The bookmark does not exist, delete the user-defined
1090                         // bookmark
1091                         try {
1092                             Bookmarks.removeBookmark(getApplicationContext(),
1093                                     bookmark);
1094
1095                             // reset bookmarks list to default
1096                             initBookmarks();
1097                         }
1098                         catch (Exception ex) {
1099                         }
1100                     }
1101                 }
1102                 catch (Exception e) { // Capture the exception
1103                     ExceptionUtil
1104                             .translateException(NavigationActivity.this, e);
1105                     if (e instanceof NoSuchFileOrDirectory
1106                             || e instanceof FileNotFoundException) {
1107                         // The bookmark does not exist, delete the user-defined
1108                         // bookmark
1109                         try {
1110                             Bookmarks.removeBookmark(getApplicationContext(),
1111                                     bookmark);
1112
1113                             // reset bookmarks list to default
1114                             initBookmarks();
1115                         }
1116                         catch (Exception ex) {
1117                         }
1118                     }
1119                     return;
1120                 }
1121             }
1122         });
1123
1124         mDrawerBookmarks.addView(view);
1125     }
1126
1127     /**
1128      * Method that initializes the bookmarks.
1129      */
1130     private synchronized void initBookmarks() {
1131         if (mBookmarksTask != null &&
1132                 !mBookmarksTask.getStatus().equals(AsyncTask.Status.FINISHED)) {
1133             return;
1134         }
1135
1136         // Retrieve the loading view
1137         final View waiting = findViewById(R.id.bookmarks_loading);
1138
1139         // Load bookmarks in background
1140         mBookmarksTask = new AsyncTask<Void, Void, Boolean>() {
1141             Exception mCause;
1142
1143             @Override
1144             protected Boolean doInBackground(Void... params) {
1145                 try {
1146                     mBookmarks = loadBookmarks();
1147                     return Boolean.TRUE;
1148
1149                 }
1150                 catch (Exception e) {
1151                     this.mCause = e;
1152                     return Boolean.FALSE;
1153                 }
1154             }
1155
1156             @Override
1157             protected void onPreExecute() {
1158                 waiting.setVisibility(View.VISIBLE);
1159                 mDrawerBookmarks.removeAllViews();
1160             }
1161
1162             @Override
1163             protected void onPostExecute(Boolean result) {
1164                 waiting.setVisibility(View.GONE);
1165                 if (result.booleanValue()) {
1166                     for (Bookmark bookmark : mBookmarks) {
1167                         addBookmarkToDrawer(bookmark);
1168                     }
1169                 }
1170                 else {
1171                     if (this.mCause != null) {
1172                         ExceptionUtil.translateException(
1173                                 NavigationActivity.this, this.mCause);
1174                     }
1175                 }
1176                 mBookmarksTask = null;
1177             }
1178
1179             @Override
1180             protected void onCancelled() {
1181                 waiting.setVisibility(View.GONE);
1182                 mBookmarksTask = null;
1183             }
1184         };
1185         mBookmarksTask.execute();
1186     }
1187
1188     /**
1189      * Method that loads all kind of bookmarks and join in an array to be used
1190      * in the listview adapter.
1191      *
1192      * @return List<Bookmark>
1193      * @hide
1194      */
1195     List<Bookmark> loadBookmarks() {
1196         // Bookmarks = HOME + FILESYSTEM + SD STORAGES + USER DEFINED
1197         // In ChRooted mode = SD STORAGES + USER DEFINED (from SD STORAGES)
1198         List<Bookmark> bookmarks = new ArrayList<Bookmark>();
1199         if (!this.mChRooted) {
1200             bookmarks.add(loadHomeBookmarks());
1201             bookmarks.addAll(loadFilesystemBookmarks());
1202         }
1203         mSdBookmarks = loadSdStorageBookmarks();
1204         bookmarks.addAll(mSdBookmarks);
1205         bookmarks.addAll(loadVirtualBookmarks());
1206         bookmarks.addAll(loadUserBookmarks());
1207         return bookmarks;
1208     }
1209
1210     /**
1211      * Method that loads the home bookmark from the user preference.
1212      *
1213      * @return Bookmark The bookmark loaded
1214      */
1215     private Bookmark loadHomeBookmarks() {
1216         String initialDir = Preferences.getSharedPreferences().getString(
1217                 FileManagerSettings.SETTINGS_INITIAL_DIR.getId(),
1218                 (String) FileManagerSettings.SETTINGS_INITIAL_DIR
1219                         .getDefaultValue());
1220         return new Bookmark(BOOKMARK_TYPE.HOME,
1221                 getString(R.string.bookmarks_home), initialDir);
1222     }
1223
1224     /**
1225      * Method that loads the filesystem bookmarks from the internal xml file.
1226      * (defined by this application)
1227      *
1228      * @return List<Bookmark> The bookmarks loaded
1229      */
1230     private List<Bookmark> loadFilesystemBookmarks() {
1231         try {
1232             // Initialize the bookmarks
1233             List<Bookmark> bookmarks = new ArrayList<Bookmark>();
1234
1235             // Read the command list xml file
1236             XmlResourceParser parser = getResources().getXml(
1237                     R.xml.filesystem_bookmarks);
1238
1239             try {
1240                 // Find the root element
1241                 XmlUtils.beginDocument(parser, TAG_BOOKMARKS);
1242                 while (true) {
1243                     XmlUtils.nextElement(parser);
1244                     String element = parser.getName();
1245                     if (element == null) {
1246                         break;
1247                     }
1248
1249                     if (TAG_BOOKMARK.equals(element)) {
1250                         CharSequence name = null;
1251                         CharSequence directory = null;
1252
1253                         try {
1254                             name = getString(parser.getAttributeResourceValue(
1255                                     R.styleable.Bookmark_name, 0));
1256                         }
1257                         catch (Exception e) {
1258                             /** NON BLOCK **/
1259                         }
1260                         try {
1261                             directory = getString(parser
1262                                     .getAttributeResourceValue(
1263                                             R.styleable.Bookmark_directory, 0));
1264                         }
1265                         catch (Exception e) {
1266                             /** NON BLOCK **/
1267                         }
1268                         if (directory == null) {
1269                             directory = parser
1270                                     .getAttributeValue(R.styleable.Bookmark_directory);
1271                         }
1272                         if (name != null && directory != null) {
1273                             bookmarks.add(new Bookmark(
1274                                     BOOKMARK_TYPE.FILESYSTEM, name.toString(),
1275                                     directory.toString()));
1276                         }
1277                     }
1278                 }
1279
1280                 // Return the bookmarks
1281                 return bookmarks;
1282
1283             }
1284             finally {
1285                 parser.close();
1286             }
1287         }
1288         catch (Throwable ex) {
1289             Log.e(TAG, "Load filesystem bookmarks failed", ex); //$NON-NLS-1$
1290         }
1291
1292         // No data
1293         return new ArrayList<Bookmark>();
1294     }
1295
1296     /**
1297      * Method that loads the secure digital card storage bookmarks from the
1298      * system.
1299      *
1300      * @return List<Bookmark> The bookmarks loaded
1301      */
1302     private List<Bookmark> loadSdStorageBookmarks() {
1303         // Initialize the bookmarks
1304         List<Bookmark> bookmarks = new ArrayList<Bookmark>();
1305
1306         try {
1307             // Recovery sdcards from storage manager
1308             StorageVolume[] volumes = StorageHelper
1309                     .getStorageVolumes(getApplication(), true);
1310             for (StorageVolume volume: volumes) {
1311                 if (volume != null) {
1312                     String mountedState = volume.getState();
1313                     String path = volume.getPath();
1314                     if (!Environment.MEDIA_MOUNTED.equalsIgnoreCase(mountedState) &&
1315                             !Environment.MEDIA_MOUNTED_READ_ONLY.equalsIgnoreCase(mountedState)) {
1316                         Log.w(TAG, "Ignoring '" + path + "' with state of '"+ mountedState + "'");
1317                         continue;
1318                     }
1319                     if (!TextUtils.isEmpty(path)) {
1320                         String lowerPath = path.toLowerCase(Locale.ROOT);
1321                         Bookmark bookmark;
1322                         if (lowerPath.contains(STR_USB)) {
1323                             bookmark = new Bookmark(BOOKMARK_TYPE.USB, StorageHelper
1324                                     .getStorageVolumeDescription(getApplication(), volume), path);
1325                         } else {
1326                             bookmark = new Bookmark(BOOKMARK_TYPE.SDCARD, StorageHelper
1327                                     .getStorageVolumeDescription(getApplication(), volume), path);
1328                         }
1329                         bookmarks.add(bookmark);
1330                     }
1331                 }
1332             }
1333
1334             // Return the bookmarks
1335             return bookmarks;
1336         }
1337         catch (Throwable ex) {
1338             Log.e(TAG, "Load filesystem bookmarks failed", ex); //$NON-NLS-1$
1339         }
1340
1341         // No data
1342         return new ArrayList<Bookmark>();
1343     }
1344
1345     /**
1346      * Method that loads all virtual mount points.
1347      *
1348      * @return List<Bookmark> The bookmarks loaded
1349      */
1350     private List<Bookmark> loadVirtualBookmarks() {
1351         // Initialize the bookmarks
1352         List<Bookmark> bookmarks = new ArrayList<Bookmark>();
1353         List<MountPoint> mps = VirtualMountPointConsole.getVirtualMountPoints();
1354         for (MountPoint mp : mps) {
1355             BOOKMARK_TYPE type = null;
1356             String name = null;
1357             if (mp.isSecure()) {
1358                 type = BOOKMARK_TYPE.SECURE;
1359                 name = getString(R.string.bookmarks_secure);
1360             } else if (mp.isRemote()) {
1361                 type = BOOKMARK_TYPE.REMOTE;
1362                 name = getString(R.string.bookmarks_remote);
1363             } else {
1364                 continue;
1365             }
1366             bookmarks.add(new Bookmark(type, name, mp.getMountPoint()));
1367         }
1368         return bookmarks;
1369     }
1370
1371     /**
1372      * Method that loads the user bookmarks (added by the user).
1373      *
1374      * @return List<Bookmark> The bookmarks loaded
1375      */
1376     private List<Bookmark> loadUserBookmarks() {
1377         List<Bookmark> bookmarks = new ArrayList<Bookmark>();
1378         Cursor cursor = Bookmarks.getAllBookmarks(this.getContentResolver());
1379         try {
1380             if (cursor != null && cursor.moveToFirst()) {
1381                 do {
1382                     Bookmark bm = new Bookmark(cursor);
1383                     if (this.mChRooted
1384                             && !StorageHelper.isPathInStorageVolume(bm.mPath)) {
1385                         continue;
1386                     }
1387                     bookmarks.add(bm);
1388                 }
1389                 while (cursor.moveToNext());
1390             }
1391         }
1392         finally {
1393             try {
1394                 if (cursor != null) {
1395                     cursor.close();
1396                 }
1397             }
1398             catch (Exception e) {
1399                 /** NON BLOCK **/
1400             }
1401         }
1402
1403         // Remove bookmarks from virtual storage if the filesystem is not mount
1404         int c = bookmarks.size() - 1;
1405         for (int i = c; i >= 0; i--) {
1406             VirtualMountPointConsole vc =
1407                     VirtualMountPointConsole.getVirtualConsoleForPath(bookmarks.get(i).mPath);
1408             if (vc != null && !vc.isMounted()) {
1409                 bookmarks.remove(i);
1410             }
1411         }
1412
1413         return bookmarks;
1414     }
1415
1416     /**
1417      * Method that initializes the navigation views of the activity
1418      */
1419     private void initNavigationViews() {
1420         //Get the navigation views (wishlist: multiple view; for now only one view)
1421         this.mNavigationViews = new NavigationView[1];
1422         this.mCurrentNavigationView = 0;
1423         //- 0
1424         this.mNavigationViews[0] = (NavigationView)findViewById(R.id.navigation_view);
1425         this.mNavigationViews[0].setId(0);
1426         this.mEasyModeListView = (ListView) findViewById(R.id.lv_easy_mode);
1427         mEasyModeAdapter = new ArrayAdapter<MimeTypeCategory>(this, R.layout
1428                 .navigation_view_simple_item) {
1429             @Override
1430             public View getView(int position, View convertView, ViewGroup parent) {
1431                 convertView = (convertView == null) ?getLayoutInflater().inflate(R.layout
1432                         .navigation_view_simple_item, parent, false) : convertView;
1433                 MimeTypeCategory item = getItem(position);
1434                 String typeTitle = MIME_TYPE_LOCALIZED_NAMES[item.ordinal()];
1435                 TextView typeTitleTV = (TextView) convertView
1436                         .findViewById(R.id.navigation_view_item_name);
1437                 ImageView typeIconIV = (ImageView) convertView
1438                         .findViewById(R.id.navigation_view_item_icon);
1439                 View checkBoxView = convertView.findViewById(R.id.navigation_view_item_check);
1440                 checkBoxView.setVisibility(View.GONE);
1441                 typeTitleTV.setText(typeTitle);
1442                 typeIconIV.setImageDrawable(EASY_MODE_ICONS.get(item));
1443                 convertView.setOnClickListener(mEasyModeItemClickListener);
1444                 convertView.setTag(position);
1445                 return convertView;
1446             }
1447         };
1448         mEasyModeAdapter.addAll(EASY_MODE_LIST);
1449         mEasyModeListView.setAdapter(mEasyModeAdapter);
1450     }
1451
1452     private void onClicked(int position) {
1453         Intent intent = new Intent(this, SearchActivity.class);
1454         intent.setAction(Intent.ACTION_SEARCH);
1455         intent.putExtra(SearchActivity.EXTRA_SEARCH_DIRECTORY,
1456                 getCurrentNavigationView().getCurrentDir());
1457         intent.putExtra(SearchManager.QUERY, "*"); // Use wild-card '*'
1458
1459         if (position == 0) {
1460             performHideEasyMode();
1461             return;
1462
1463         } else {
1464             ArrayList<MimeTypeCategory> searchCategories = new ArrayList<MimeTypeCategory>();
1465             MimeTypeCategory selectedCategory = EASY_MODE_LIST.get(position);
1466             searchCategories.add(selectedCategory);
1467             // a one off case where we implicitly want to also search for TEXT mimetypes when the
1468             // DOCUMENTS category is selected
1469             if (selectedCategory == MimeTypeCategory.DOCUMENT) {
1470                 searchCategories.add(MimeTypeCategory.TEXT);
1471             }
1472             intent.putExtra(SearchActivity.EXTRA_SEARCH_MIMETYPE, searchCategories);
1473         }
1474
1475         startActivity(intent);
1476     }
1477
1478     /**
1479      * Method that initialize the console
1480      * @hide
1481      */
1482     void initConsole() {
1483         //Create the default console (from the preferences)
1484         try {
1485             Console console = ConsoleBuilder.getConsole(NavigationActivity.this);
1486             if (console == null) {
1487                 throw new ConsoleAllocException("console == null"); //$NON-NLS-1$
1488             }
1489         } catch (Throwable ex) {
1490             if (!NavigationActivity.this.mChRooted) {
1491                 //Show exception and exit
1492                 Log.e(TAG, getString(R.string.msgs_cant_create_console), ex);
1493                 // We don't have any console
1494                 // Show exception and exit
1495                 DialogHelper.showToast(
1496                         NavigationActivity.this,
1497                         R.string.msgs_cant_create_console, Toast.LENGTH_LONG);
1498                 exit();
1499                 return;
1500             }
1501
1502             // We are in a trouble (something is not allowing creating the console)
1503             // Ask the user to return to prompt or root access mode mode with a
1504             // non-privileged console, prior to make crash the application
1505             askOrExit();
1506             return;
1507         }
1508     }
1509
1510     /**
1511      * Method that initializes the navigation.
1512      *
1513      * @param viewId The navigation view identifier where apply the navigation
1514      * @param restore Initialize from a restore info
1515      * @param intent The current intent
1516      * @hide
1517      */
1518     void initNavigation(final int viewId, final boolean restore, final Intent intent) {
1519         final NavigationView navigationView = getNavigationView(viewId);
1520         this.mHandler.post(new Runnable() {
1521             @Override
1522             public void run() {
1523                 //Is necessary navigate?
1524                 if (!restore) {
1525                     applyInitialDir(navigationView, intent);
1526                 }
1527             }
1528         });
1529     }
1530
1531     /**
1532      * Method that applies the user-defined initial directory
1533      *
1534      * @param navigationView The navigation view
1535      * @param intent The current intent
1536      * @hide
1537      */
1538     void applyInitialDir(final NavigationView navigationView, final Intent intent) {
1539         //Load the user-defined initial directory
1540         String initialDir =
1541                 Preferences.getSharedPreferences().getString(
1542                     FileManagerSettings.SETTINGS_INITIAL_DIR.getId(),
1543                     (String)FileManagerSettings.
1544                         SETTINGS_INITIAL_DIR.getDefaultValue());
1545
1546         // Check if request navigation to directory (use as default), and
1547         // ensure chrooted and absolute path
1548         String navigateTo = intent.getStringExtra(EXTRA_NAVIGATE_TO);
1549         String intentAction = intent.getAction();
1550         if (navigateTo != null && navigateTo.length() > 0) {
1551             initialDir = navigateTo;
1552         } else if (intentAction != null && intentAction.equals(Intent.ACTION_VIEW)) {
1553             Uri data = intent.getData();
1554             if (data != null && (FileHelper.FILE_URI_SCHEME.equals(data.getScheme())
1555                     || FileHelper.FOLDER_URI_SCHEME.equals(data.getScheme())
1556                     || FileHelper.DIRECTORY_URI_SCHEME.equals(data.getScheme()))) {
1557                 File path = new File(data.getPath());
1558                 if (path.isDirectory()) {
1559                     initialDir = path.getAbsolutePath();
1560                 }
1561             }
1562         }
1563
1564         // Add to history
1565         final boolean addToHistory = intent.getBooleanExtra(EXTRA_ADD_TO_HISTORY, true);
1566
1567         // We cannot navigate to a secure console if it is unmounted. So go to root in that case
1568         VirtualConsole vc = VirtualMountPointConsole.getVirtualConsoleForPath(initialDir);
1569         if (vc != null && vc instanceof SecureConsole && !((SecureConsole) vc).isMounted()) {
1570             initialDir = FileHelper.ROOT_DIRECTORY;
1571         }
1572
1573         if (this.mChRooted) {
1574             // Initial directory is the first external sdcard (sdcard, emmc, usb, ...)
1575             if (!StorageHelper.isPathInStorageVolume(initialDir)) {
1576                 StorageVolume[] volumes =
1577                         StorageHelper.getStorageVolumes(this, false);
1578                 if (volumes != null && volumes.length > 0) {
1579                     initialDir = volumes[0].getPath();
1580                     //Ensure that initial directory is an absolute directory
1581                     initialDir = FileHelper.getAbsPath(initialDir);
1582                 } else {
1583                     // Show exception and exit
1584                     DialogHelper.showToast(
1585                             this,
1586                             R.string.msgs_cant_create_console, Toast.LENGTH_LONG);
1587                     exit();
1588                     return;
1589                 }
1590             }
1591         } else {
1592             //Ensure that initial directory is an absolute directory
1593             final String userInitialDir = initialDir;
1594             initialDir = FileHelper.getAbsPath(initialDir);
1595             final String absInitialDir = initialDir;
1596             File f = new File(initialDir);
1597             boolean exists = f.exists();
1598             if (!exists) {
1599                 // Fix for /data/media/0. Libcore doesn't detect it correctly.
1600                 try {
1601                     exists = CommandHelper.getFileInfo(this, initialDir, false, null) != null;
1602                 } catch (InsufficientPermissionsException ipex) {
1603                     ExceptionUtil.translateException(
1604                             this, ipex, false, true, new OnRelaunchCommandResult() {
1605                         @Override
1606                         public void onSuccess() {
1607                             navigationView.changeCurrentDir(absInitialDir, addToHistory);
1608                         }
1609                         @Override
1610                         public void onFailed(Throwable cause) {
1611                             showInitialInvalidDirectoryMsg(userInitialDir);
1612                             navigationView.changeCurrentDir(FileHelper.ROOT_DIRECTORY,
1613                                     addToHistory);
1614                         }
1615                         @Override
1616                         public void onCancelled() {
1617                             showInitialInvalidDirectoryMsg(userInitialDir);
1618                             navigationView.changeCurrentDir(FileHelper.ROOT_DIRECTORY,
1619                                     addToHistory);
1620                         }
1621                     });
1622
1623                     // Asynchronous mode
1624                     return;
1625                 } catch (Exception ex) {
1626                     // We are not interested in other exceptions
1627                     ExceptionUtil.translateException(this, ex, true, false);
1628                 }
1629
1630                 // Check again the initial directory
1631                 if (!exists) {
1632                     showInitialInvalidDirectoryMsg(userInitialDir);
1633                     initialDir = FileHelper.ROOT_DIRECTORY;
1634                 }
1635
1636                 // Weird, but we have a valid initial directory
1637             }
1638         }
1639
1640         boolean needsEasyMode = false;
1641         if (mSdBookmarks != null ) {
1642             for (Bookmark bookmark :mSdBookmarks) {
1643                 if (bookmark.mPath.equalsIgnoreCase(initialDir)) {
1644                     needsEasyMode = true;
1645                     break;
1646                 }
1647             }
1648         }
1649
1650         needsEasyMode = needsEasyMode
1651                 && getResources().getBoolean(R.bool.cmcc_show_easy_mode);
1652         if (needsEasyMode) {
1653             performShowEasyMode();
1654         } else {
1655             performHideEasyMode();
1656         }
1657         // Change the current directory to the user-defined initial directory
1658         navigationView.changeCurrentDir(initialDir, addToHistory);
1659     }
1660
1661     /**
1662      * Displays a message reporting invalid directory
1663      *
1664      * @param initialDir The initial directory
1665      * @hide
1666      */
1667     void showInitialInvalidDirectoryMsg(String initialDir) {
1668         // Change to root directory
1669         DialogHelper.showToast(
1670                 this,
1671                 getString(
1672                         R.string.msgs_settings_invalid_initial_directory,
1673                         initialDir),
1674                 Toast.LENGTH_SHORT);
1675     }
1676
1677     /**
1678      * Method that verifies the intent passed to the activity, and checks
1679      * if a request is made like Search.
1680      *
1681      * @param intent The intent to check
1682      * @hide
1683      */
1684     void checkIntent(Intent intent) {
1685         //Search action
1686         if (Intent.ACTION_SEARCH.equals(intent.getAction())) {
1687             Intent searchIntent = new Intent(this, SearchActivity.class);
1688             searchIntent.setAction(Intent.ACTION_SEARCH);
1689             //- SearchActivity.EXTRA_SEARCH_DIRECTORY
1690             searchIntent.putExtra(
1691                     SearchActivity.EXTRA_SEARCH_DIRECTORY,
1692                     getCurrentNavigationView().getCurrentDir());
1693             //- SearchManager.APP_DATA
1694             if (intent.getBundleExtra(SearchManager.APP_DATA) != null) {
1695                 Bundle bundle = new Bundle();
1696                 bundle.putAll(intent.getBundleExtra(SearchManager.APP_DATA));
1697                 searchIntent.putExtra(SearchManager.APP_DATA, bundle);
1698             }
1699             //-- SearchManager.QUERY
1700             String query = intent.getStringExtra(SearchManager.QUERY);
1701             if (query != null) {
1702                 searchIntent.putExtra(SearchManager.QUERY, query);
1703             }
1704             //- android.speech.RecognizerIntent.EXTRA_RESULTS
1705             ArrayList<String> extraResults =
1706                     intent.getStringArrayListExtra(android.speech.RecognizerIntent.EXTRA_RESULTS);
1707             if (extraResults != null) {
1708                 searchIntent.putStringArrayListExtra(
1709                         android.speech.RecognizerIntent.EXTRA_RESULTS, extraResults);
1710             }
1711             startActivityForResult(searchIntent, INTENT_REQUEST_SEARCH);
1712             return;
1713         }
1714     }
1715
1716     /**
1717      * {@inheritDoc}
1718      */
1719     @Override
1720     public boolean onKeyUp(int keyCode, KeyEvent event) {
1721         if (keyCode == KeyEvent.KEYCODE_MENU) {
1722             if (mDrawerLayout.isDrawerOpen(mDrawer)) {
1723                 mDrawerLayout.closeDrawer(Gravity.START);
1724             } else {
1725                 mDrawerLayout.openDrawer(Gravity.START);
1726             }
1727             return true;
1728         }
1729         return super.onKeyUp(keyCode, event);
1730     }
1731
1732     @Override
1733     public void onBackPressed() {
1734         if (checkBackAction()) {
1735             performHideEasyMode();
1736             return;
1737         }
1738
1739         // An exit event has occurred, force the destroy the consoles
1740         exit();
1741     }
1742
1743     /**
1744      * Method invoked when an action item is clicked.
1745      *
1746      * @param view The button pushed
1747      */
1748     public void onActionBarItemClick(View view) {
1749         switch (view.getId()) {
1750             //######################
1751             //Navigation Custom Title
1752             //######################
1753             case R.id.ab_configuration:
1754                 //Show navigation view configuration toolbar
1755                 getCurrentNavigationView().getCustomTitle().showConfigurationView();
1756                 break;
1757             case R.id.ab_close:
1758                 //Hide navigation view configuration toolbar
1759                 getCurrentNavigationView().getCustomTitle().hideConfigurationView();
1760                 break;
1761
1762             //######################
1763             //Breadcrumb Actions
1764             //######################
1765             case R.id.ab_filesystem_info:
1766                 //Show information of the filesystem
1767                 MountPoint mp = getCurrentNavigationView().getBreadcrumb().getMountPointInfo();
1768                 DiskUsage du = getCurrentNavigationView().getBreadcrumb().getDiskUsageInfo();
1769                 showMountPointInfo(mp, du);
1770                 break;
1771
1772             //######################
1773             //Navigation view options
1774             //######################
1775             case R.id.ab_sort_mode:
1776                 showSettingsPopUp(view,
1777                         Arrays.asList(
1778                                 new FileManagerSettings[]{
1779                                         FileManagerSettings.SETTINGS_SORT_MODE}));
1780                 break;
1781             case R.id.ab_layout_mode:
1782                 showSettingsPopUp(view,
1783                         Arrays.asList(
1784                                 new FileManagerSettings[]{
1785                                         FileManagerSettings.SETTINGS_LAYOUT_MODE}));
1786                 break;
1787             case R.id.ab_view_options:
1788                 // If we are in ChRooted mode, then don't show non-secure items
1789                 if (this.mChRooted) {
1790                     showSettingsPopUp(view,
1791                             Arrays.asList(new FileManagerSettings[]{
1792                                     FileManagerSettings.SETTINGS_SHOW_DIRS_FIRST}));
1793                 } else {
1794                     showSettingsPopUp(view,
1795                             Arrays.asList(new FileManagerSettings[]{
1796                                     FileManagerSettings.SETTINGS_SHOW_DIRS_FIRST,
1797                                     FileManagerSettings.SETTINGS_SHOW_HIDDEN,
1798                                     FileManagerSettings.SETTINGS_SHOW_SYSTEM,
1799                                     FileManagerSettings.SETTINGS_SHOW_SYMLINKS}));
1800                 }
1801
1802                 break;
1803
1804             //######################
1805             //Selection Actions
1806             //######################
1807             case R.id.ab_selection_done:
1808                 //Show information of the filesystem
1809                 getCurrentNavigationView().onDeselectAll();
1810                 break;
1811
1812             //######################
1813             //Action Bar buttons
1814             //######################
1815             case R.id.ab_actions:
1816                 openActionsDialog(getCurrentNavigationView().getCurrentDir(),
1817                         true);
1818                 break;
1819
1820             case R.id.ab_search:
1821
1822                 openSearch();
1823                 break;
1824
1825             default:
1826                 break;
1827         }
1828     }
1829
1830     /**
1831      * {@inheritDoc}
1832      */
1833     @Override
1834     protected void onActivityResult(int requestCode, int resultCode, Intent data) {
1835         if (requestCode == INTENT_REQUEST_SETTINGS) {
1836             // reset bookmarks list to default as the user could changed the
1837             // root mode which changes the system bookmarks
1838             initBookmarks();
1839             return;
1840         }
1841
1842         if (data != null) {
1843             switch (requestCode) {
1844                 case INTENT_REQUEST_SEARCH:
1845                     if (resultCode == RESULT_OK) {
1846                         //Change directory?
1847                         Bundle bundle = data.getExtras();
1848                         if (bundle != null) {
1849                             FileSystemObject fso = (FileSystemObject) bundle.getSerializable(
1850                                     EXTRA_SEARCH_ENTRY_SELECTION);
1851                             SearchInfoParcelable searchInfo =
1852                                     bundle.getParcelable(EXTRA_SEARCH_LAST_SEARCH_DATA);
1853                             if (fso != null) {
1854                                 //Goto to new directory
1855                                 getCurrentNavigationView().open(fso, searchInfo);
1856                                 performHideEasyMode();
1857                             }
1858                         }
1859                     } else if (resultCode == RESULT_CANCELED) {
1860                         SearchInfoParcelable searchInfo =
1861                                 data.getParcelableExtra(EXTRA_SEARCH_LAST_SEARCH_DATA);
1862                         if (searchInfo != null && searchInfo.isSuccessNavigation()) {
1863                             //Navigate to previous history
1864                             back();
1865                         } else {
1866                             // I don't know is the search view was changed, so try to do a refresh
1867                             // of the navigation view
1868                             getCurrentNavigationView().refresh(true);
1869                         }
1870                     }
1871                     // reset bookmarks list to default as the user could have set a
1872                     // new bookmark in the search activity
1873                     initBookmarks();
1874                     break;
1875
1876                 default:
1877                     break;
1878             }
1879         }
1880     }
1881
1882     /**
1883      * {@inheritDoc}
1884      */
1885     @Override
1886     public void onNewHistory(HistoryNavigable navigable) {
1887         addHistoryToDrawer(this.mHistory.size(), navigable);
1888         //Recollect information about current status
1889         History history = new History(this.mHistory.size(), navigable);
1890         this.mHistory.add(history);
1891     }
1892
1893     /**
1894      * {@inheritDoc}
1895      */
1896     @Override
1897     public void onCheckHistory() {
1898     }
1899
1900     /**
1901      * {@inheritDoc}
1902      */
1903     @Override
1904     public void onRequestRefresh(Object o, boolean clearSelection) {
1905         if (o instanceof FileSystemObject) {
1906             // Refresh only the item
1907             this.getCurrentNavigationView().refresh((FileSystemObject)o);
1908         } else if (o == null) {
1909             // Refresh all
1910             getCurrentNavigationView().refresh();
1911         }
1912         if (clearSelection) {
1913             this.getCurrentNavigationView().onDeselectAll();
1914         }
1915     }
1916
1917     /**
1918      * {@inheritDoc}
1919      */
1920     @Override
1921     public void onRequestBookmarksRefresh() {
1922         initBookmarks();
1923     }
1924
1925     /**
1926      * {@inheritDoc}
1927      */
1928     @Override
1929     public void onRequestRemove(Object o, boolean clearSelection) {
1930         if (o instanceof FileSystemObject) {
1931             // Remove from view
1932             this.getCurrentNavigationView().removeItem((FileSystemObject)o);
1933
1934             //Remove from history
1935             removeFromHistory((FileSystemObject)o);
1936         } else {
1937             onRequestRefresh(null, clearSelection);
1938         }
1939         if (clearSelection) {
1940             this.getCurrentNavigationView().onDeselectAll();
1941         }
1942     }
1943
1944     /**
1945      * {@inheritDoc}
1946      */
1947     @Override
1948     public void onNavigateTo(Object o) {
1949         // Ignored
1950     }
1951
1952     @Override
1953     public void onCancel(){
1954         // nop
1955     }
1956
1957     /**
1958      * {@inheritDoc}
1959      */
1960     @Override
1961     public void onSelectionChanged(NavigationView navView, List<FileSystemObject> selectedItems) {
1962         this.mSelectionBar.setSelection(selectedItems);
1963     }
1964
1965     /**
1966      * {@inheritDoc}
1967      */
1968     @Override
1969     public void onRequestMenu(NavigationView navView, FileSystemObject item) {
1970         // Show the actions dialog
1971         openActionsDialog(item, false);
1972     }
1973
1974     /**
1975      * Method that shows a popup with a menu associated a {@link FileManagerSettings}.
1976      *
1977      * @param anchor The action button that was pressed
1978      * @param settings The array of settings associated with the action button
1979      */
1980     private void showSettingsPopUp(View anchor, List<FileManagerSettings> settings) {
1981         //Create the adapter
1982         final MenuSettingsAdapter adapter = new MenuSettingsAdapter(this, settings);
1983
1984         //Create a show the popup menu
1985         final ListPopupWindow popup = DialogHelper.createListPopupWindow(this, adapter, anchor);
1986         popup.setOnItemClickListener(new OnItemClickListener() {
1987             @Override
1988             public void onItemClick(AdapterView<?> parent, View v, int position, long id) {
1989                 FileManagerSettings setting =
1990                         ((MenuSettingsAdapter)parent.getAdapter()).getSetting(position);
1991                 final int value = ((MenuSettingsAdapter)parent.getAdapter()).getId(position);
1992                 popup.dismiss();
1993                 try {
1994                     if (setting.compareTo(FileManagerSettings.SETTINGS_LAYOUT_MODE) == 0) {
1995                         //Need to change the layout
1996                         getCurrentNavigationView().changeViewMode(
1997                                 NavigationLayoutMode.fromId(value));
1998                     } else {
1999                         //Save and refresh
2000                         if (setting.getDefaultValue() instanceof Enum<?>) {
2001                             //Enumeration
2002                             Preferences.savePreference(setting, new ObjectIdentifier() {
2003                                 @Override
2004                                 public int getId() {
2005                                     return value;
2006                                 }
2007                             }, false);
2008                         } else {
2009                             //Boolean
2010                             boolean newval =
2011                                     Preferences.getSharedPreferences().
2012                                         getBoolean(
2013                                             setting.getId(),
2014                                             ((Boolean)setting.getDefaultValue()).booleanValue());
2015                             Preferences.savePreference(setting, Boolean.valueOf(!newval), false);
2016                         }
2017                         getCurrentNavigationView().refresh();
2018                     }
2019                 } catch (Exception e) {
2020                     Log.e(TAG, "Error applying navigation option", e); //$NON-NLS-1$
2021                     NavigationActivity.this.mHandler.post(new Runnable() {
2022                         @Override
2023                         public void run() {
2024                             DialogHelper.showToast(
2025                                     NavigationActivity.this,
2026                                     R.string.msgs_settings_save_failure, Toast.LENGTH_SHORT);
2027                         }
2028                     });
2029
2030                 } finally {
2031                     adapter.dispose();
2032                     getCurrentNavigationView().getCustomTitle().restoreView();
2033                 }
2034
2035             }
2036         });
2037         popup.setOnDismissListener(new PopupWindow.OnDismissListener() {
2038             @Override
2039             public void onDismiss() {
2040                 adapter.dispose();
2041             }
2042         });
2043         popup.show();
2044     }
2045
2046     /**
2047      * Method that show the information of a filesystem mount point.
2048      *
2049      * @param mp The mount point info
2050      * @param du The disk usage of the mount point
2051      */
2052     private void showMountPointInfo(MountPoint mp, DiskUsage du) {
2053         //Has mount point info?
2054         if (mp == null) {
2055             //There is no information
2056             AlertDialog alert =
2057                     DialogHelper.createWarningDialog(
2058                             this,
2059                             R.string.filesystem_info_warning_title,
2060                             R.string.filesystem_info_warning_msg);
2061             DialogHelper.delegateDialogShow(this, alert);
2062             return;
2063         }
2064
2065         //Show a the filesystem info dialog
2066         FilesystemInfoDialog dialog = new FilesystemInfoDialog(this, mp, du);
2067         dialog.setOnMountListener(new OnMountListener() {
2068             @Override
2069             public void onRemount(MountPoint mountPoint) {
2070                 //Update the statistics of breadcrumb, only if mount point is the same
2071                 Breadcrumb breadcrumb = getCurrentNavigationView().getBreadcrumb();
2072                 if (breadcrumb.getMountPointInfo().compareTo(mountPoint) == 0) {
2073                     breadcrumb.updateMountPointInfo();
2074                 }
2075                 if (mountPoint.isSecure()) {
2076                     // Secure mountpoints only can be unmount, so we need to move the navigation
2077                     // to a secure storage (do not add to history)
2078                     Intent intent = new Intent();
2079                     intent.putExtra(EXTRA_ADD_TO_HISTORY, false);
2080                     initNavigation(NavigationActivity.this.mCurrentNavigationView, false, intent);
2081                 }
2082             }
2083         });
2084         dialog.show();
2085     }
2086
2087     /**
2088      * Method that checks the action that must be realized when the
2089      * back button is pushed.
2090      *
2091      * @return boolean Indicates if the action must be intercepted
2092      */
2093     private boolean checkBackAction() {
2094         // We need a basic structure to check this
2095         if (getCurrentNavigationView() == null) return false;
2096
2097         if (mSearchView.getVisibility() == View.VISIBLE) {
2098             closeSearch();
2099         }
2100
2101         //Check if the configuration view is showing. In this case back
2102         //action must be "close configuration"
2103         if (getCurrentNavigationView().getCustomTitle().isConfigurationViewShowing()) {
2104             getCurrentNavigationView().getCustomTitle().restoreView();
2105             return true;
2106         }
2107
2108         //Do back operation over the navigation history
2109         boolean flag = this.mExitFlag;
2110
2111         this.mExitFlag = !back();
2112
2113         // Retrieve if the exit status timeout has expired
2114         long now = System.currentTimeMillis();
2115         boolean timeout = (this.mExitBackTimeout == -1 ||
2116                             (now - this.mExitBackTimeout) > RELEASE_EXIT_CHECK_TIMEOUT);
2117
2118         //Check if there no history and if the user was advised in the last back action
2119         if (this.mExitFlag && (this.mExitFlag != flag || timeout)) {
2120             //Communicate the user that the next time the application will be closed
2121             this.mExitBackTimeout = System.currentTimeMillis();
2122             DialogHelper.showToast(this, R.string.msgs_push_again_to_exit, Toast.LENGTH_SHORT);
2123             return true;
2124         }
2125
2126         //Back action not applied
2127         return !this.mExitFlag;
2128     }
2129
2130     @Override
2131     public void startActivity(Intent intent) {
2132         // check if search intent
2133         if (Intent.ACTION_SEARCH.equals(intent.getAction())) {
2134             intent.putExtra(SearchActivity.EXTRA_SEARCH_DIRECTORY,
2135                     getCurrentNavigationView().getCurrentDir());
2136         }
2137
2138         super.startActivity(intent);
2139     }
2140
2141     /**
2142      * Method that returns the history size.
2143      */
2144     private void clearHistory() {
2145         this.mHistory.clear();
2146         mDrawerHistory.removeAllViews();
2147         mDrawerHistoryEmpty.setVisibility(View.VISIBLE);
2148     }
2149
2150     /**
2151      * Method that navigates to the passed history reference.
2152      *
2153      * @param history The history reference
2154      * @return boolean A problem occurs while navigate
2155      */
2156     public synchronized boolean navigateToHistory(History history) {
2157         try {
2158             //Gets the history
2159             History realHistory = this.mHistory.get(history.getPosition());
2160
2161             //Navigate to item. Check what kind of history is
2162             if (realHistory.getItem() instanceof NavigationViewInfoParcelable) {
2163                 //Navigation
2164                 NavigationViewInfoParcelable info =
2165                         (NavigationViewInfoParcelable)realHistory.getItem();
2166                 int viewId = info.getId();
2167                 NavigationView view = getNavigationView(viewId);
2168                 // Selected items must not be restored from on history navigation
2169                 info.setSelectedFiles(view.getSelectedFiles());
2170                 if (!view.onRestoreState(info)) {
2171                     return true;
2172                 }
2173
2174             } else if (realHistory.getItem() instanceof SearchInfoParcelable) {
2175                 //Search (open search with the search results)
2176                 SearchInfoParcelable info = (SearchInfoParcelable)realHistory.getItem();
2177                 Intent searchIntent = new Intent(this, SearchActivity.class);
2178                 searchIntent.setAction(SearchActivity.ACTION_RESTORE);
2179                 searchIntent.putExtra(SearchActivity.EXTRA_SEARCH_RESTORE, (Parcelable)info);
2180                 startActivityForResult(searchIntent, INTENT_REQUEST_SEARCH);
2181             } else {
2182                 //The type is unknown
2183                 throw new IllegalArgumentException("Unknown history type"); //$NON-NLS-1$
2184             }
2185
2186             //Remove the old history
2187             int cc = realHistory.getPosition();
2188             for (int i = this.mHistory.size() - 1; i >= cc; i--) {
2189                 this.mHistory.remove(i);
2190                 mDrawerHistory.removeViewAt(0);
2191             }
2192
2193             if (mDrawerHistory.getChildCount() == 0) {
2194                 mDrawerHistoryEmpty.setVisibility(View.VISIBLE);
2195             }
2196
2197             //Navigate
2198             boolean clearHistory = mHistoryTab.isSelected() && mHistory.size() > 0;
2199             mClearHistory.setVisibility(clearHistory ? View.VISIBLE : View.GONE);
2200             return true;
2201
2202         } catch (Throwable ex) {
2203             if (history != null) {
2204                 Log.e(TAG,
2205                         String.format("Failed to navigate to history %d: %s", //$NON-NLS-1$
2206                                 Integer.valueOf(history.getPosition()),
2207                                 history.getItem().getTitle()), ex);
2208             } else {
2209                 Log.e(TAG,
2210                         String.format("Failed to navigate to history: null", ex)); //$NON-NLS-1$
2211             }
2212             this.mHandler.post(new Runnable() {
2213                 @Override
2214                 public void run() {
2215                     DialogHelper.showToast(
2216                             NavigationActivity.this,
2217                             R.string.msgs_history_unknown, Toast.LENGTH_LONG);
2218                 }
2219             });
2220
2221             //Not change directory
2222             return false;
2223         }
2224     }
2225
2226     /**
2227      * Method that request a back action over the navigation history.
2228      *
2229      * @return boolean If a back action was applied
2230      */
2231     public boolean back() {
2232         // Check that has valid history
2233         while (this.mHistory.size() > 0) {
2234             History h = this.mHistory.get(this.mHistory.size() - 1);
2235             if (h.getItem() instanceof NavigationViewInfoParcelable) {
2236                 // Verify that the path exists
2237                 String path = ((NavigationViewInfoParcelable)h.getItem()).getCurrentDir();
2238
2239                 try {
2240                     FileSystemObject info = CommandHelper.getFileInfo(this, path, null);
2241                     if (info != null) {
2242                         break;
2243                     }
2244                     this.mHistory.remove(this.mHistory.size() - 1);
2245                 } catch (Exception e) {
2246                     ExceptionUtil.translateException(this, e, true, false);
2247                     this.mHistory.remove(this.mHistory.size() - 1);
2248                 }
2249             } else {
2250                 break;
2251             }
2252         }
2253
2254         //Navigate to history
2255         if (this.mHistory.size() > 0) {
2256             return navigateToHistory(this.mHistory.get(this.mHistory.size() - 1));
2257         }
2258
2259         //Nothing to apply
2260         mClearHistory.setVisibility(View.GONE);
2261         return false;
2262     }
2263
2264     /**
2265      * Method that opens the actions dialog
2266      *
2267      * @param item The path or the {@link FileSystemObject}
2268      * @param global If the menu to display is the one with global actions
2269      */
2270     private void openActionsDialog(Object item, boolean global) {
2271         // Resolve the full path
2272         String path = String.valueOf(item);
2273         if (item instanceof FileSystemObject) {
2274             path = ((FileSystemObject)item).getFullPath();
2275         }
2276
2277         // Prior to show the dialog, refresh the item reference
2278         FileSystemObject fso = null;
2279         try {
2280             fso = CommandHelper.getFileInfo(this, path, false, null);
2281             if (fso == null) {
2282                 throw new NoSuchFileOrDirectory(path);
2283             }
2284
2285         } catch (Exception e) {
2286             // Notify the user
2287             ExceptionUtil.translateException(this, e);
2288
2289             // Remove the object
2290             if (e instanceof FileNotFoundException || e instanceof NoSuchFileOrDirectory) {
2291                 // If have a FileSystemObject reference then there is no need to search
2292                 // the path (less resources used)
2293                 if (item instanceof FileSystemObject) {
2294                     getCurrentNavigationView().removeItem((FileSystemObject)item);
2295                 } else {
2296                     getCurrentNavigationView().removeItem((String)item);
2297                 }
2298             }
2299             return;
2300         }
2301
2302         // Show the dialog
2303         ActionsDialog dialog = new ActionsDialog(this, this, fso, global, false);
2304         dialog.setOnRequestRefreshListener(this);
2305         dialog.setOnSelectionListener(getCurrentNavigationView());
2306         dialog.show();
2307     }
2308
2309     /**
2310      * Method that opens the search view.
2311      *
2312      * @hide
2313      */
2314     void openSearch() {
2315         mSearchView.setVisibility(View.VISIBLE);
2316         mSearchView.onActionViewExpanded();
2317         mCustomTitleView.setVisibility(View.GONE);
2318     }
2319
2320     void closeSearch() {
2321         mSearchView.setVisibility(View.GONE);
2322         mSearchView.onActionViewCollapsed();
2323         mCustomTitleView.setVisibility(View.VISIBLE);
2324     }
2325
2326     /**
2327      * Method that opens the settings activity.
2328      *
2329      * @hide
2330      */
2331     void openSettings() {
2332         Intent settingsIntent = new Intent(NavigationActivity.this,
2333                 SettingsPreferences.class);
2334         startActivityForResult(settingsIntent, INTENT_REQUEST_SETTINGS);
2335     }
2336
2337     /**
2338      * Method that remove the {@link FileSystemObject} from the history
2339      */
2340     private void removeFromHistory(FileSystemObject fso) {
2341         if (this.mHistory != null) {
2342             int cc = this.mHistory.size() - 1;
2343             for (int i = cc; i >= 0 ; i--) {
2344                 History history = this.mHistory.get(i);
2345                 if (history.getItem() instanceof NavigationViewInfoParcelable) {
2346                     String p0 = fso.getFullPath();
2347                     String p1 = ((NavigationViewInfoParcelable) history.getItem()).getCurrentDir();
2348                     if (p0.compareTo(p1) == 0) {
2349                         this.mHistory.remove(i);
2350                         mDrawerHistory.removeViewAt(mDrawerHistory.getChildCount() - i - 1);
2351                         mDrawerHistoryEmpty.setVisibility(
2352                                 mDrawerHistory.getChildCount() == 0 ? View.VISIBLE : View.GONE);
2353                         updateHistoryPositions();
2354                     }
2355                 }
2356             }
2357         }
2358     }
2359
2360     /**
2361      * Update the history positions after one of the history is removed from drawer
2362      */
2363     private void updateHistoryPositions() {
2364         int cc = this.mHistory.size() - 1;
2365         for (int i = 0; i <= cc ; i++) {
2366             History history = this.mHistory.get(i);
2367             history.setPosition(i + 1);
2368         }
2369     }
2370
2371     /**
2372      * Method that ask the user to change the access mode prior to crash.
2373      * @hide
2374      */
2375     void askOrExit() {
2376         //Show a dialog asking the user
2377         AlertDialog dialog =
2378             DialogHelper.createYesNoDialog(
2379                 this,
2380                 R.string.msgs_change_to_prompt_access_mode_title,
2381                 R.string.msgs_change_to_prompt_access_mode_msg,
2382                 new DialogInterface.OnClickListener() {
2383                     @Override
2384                     public void onClick(DialogInterface alertDialog, int which) {
2385                         if (which == DialogInterface.BUTTON_NEGATIVE) {
2386                             // We don't have any console
2387                             // Show exception and exit
2388                             DialogHelper.showToast(
2389                                     NavigationActivity.this,
2390                                     R.string.msgs_cant_create_console, Toast.LENGTH_LONG);
2391                             exit();
2392                             return;
2393                         }
2394
2395                         // Ok. Now try to change to prompt mode. Any crash
2396                         // here is a fatal error. We won't have any console to operate.
2397                         try {
2398                             // Change console
2399                             ConsoleBuilder.changeToNonPrivilegedConsole(NavigationActivity.this);
2400
2401                             // Save preferences
2402                             Preferences.savePreference(
2403                                     FileManagerSettings.SETTINGS_ACCESS_MODE,
2404                                     AccessMode.PROMPT, true);
2405
2406                         } catch (Exception e) {
2407                             // Displays an exception and exit
2408                             Log.e(TAG, getString(R.string.msgs_cant_create_console), e);
2409                             DialogHelper.showToast(
2410                                     NavigationActivity.this,
2411                                     R.string.msgs_cant_create_console, Toast.LENGTH_LONG);
2412                             exit();
2413                         }
2414                     }
2415                });
2416         DialogHelper.delegateDialogShow(this, dialog);
2417     }
2418
2419     /**
2420      * Method that creates a ChRooted environment, protecting the user to break anything in
2421      * the device
2422      * @hide
2423      */
2424     void createChRooted() {
2425         // If we are in a ChRooted mode, then do nothing
2426         if (this.mChRooted) return;
2427         this.mChRooted = true;
2428
2429         int cc = this.mNavigationViews.length;
2430         for (int i = 0; i < cc; i++) {
2431             this.mNavigationViews[i].createChRooted();
2432         }
2433
2434         // Remove the selection
2435         cc = this.mNavigationViews.length;
2436         for (int i = 0; i < cc; i++) {
2437             getCurrentNavigationView().onDeselectAll();
2438         }
2439
2440         // Remove the history (don't allow to access to previous data)
2441         clearHistory();
2442     }
2443
2444     /**
2445      * Method that exits from a ChRooted
2446      * @hide
2447      */
2448     void exitChRooted() {
2449         // If we aren't in a ChRooted mode, then do nothing
2450         if (!this.mChRooted) return;
2451         this.mChRooted = false;
2452
2453         int cc = this.mNavigationViews.length;
2454         for (int i = 0; i < cc; i++) {
2455             this.mNavigationViews[i].exitChRooted();
2456         }
2457     }
2458
2459     /**
2460      * Method called when a controlled exit is required
2461      * @hide
2462      */
2463     void exit() {
2464         // Recycle the navigation views
2465         int cc = this.mNavigationViews.length;
2466         for (int i = 0; i < cc; i++) {
2467             this.mNavigationViews[i].recycle();
2468         }
2469         try {
2470             FileManagerApplication.destroyBackgroundConsole();
2471         } catch (Throwable ex) {
2472             /**NON BLOCK**/
2473         }
2474         try {
2475             ConsoleBuilder.destroyConsole();
2476         } catch (Throwable ex) {
2477             /**NON BLOCK**/
2478         }
2479         finish();
2480     }
2481
2482     /**
2483      * Method that reconfigures the layout for better fit in portrait and landscape modes
2484      */
2485     private void onLayoutChanged() {
2486         Theme theme = ThemeManager.getCurrentTheme(this);
2487         boolean drawerOpen = mDrawerLayout.isDrawerOpen(Gravity.START);
2488
2489         // Apply only when the orientation was changed
2490         int orientation = getResources().getConfiguration().orientation;
2491         if (this.mOrientation == orientation) return;
2492         this.mOrientation = orientation;
2493
2494         // imitate a closed drawer while layout is rebuilt to avoid NullPointerException
2495         if (drawerOpen) {
2496             mDrawerLayout.closeDrawer(Gravity.START);
2497         }
2498
2499         if (this.mOrientation == Configuration.ORIENTATION_LANDSCAPE) {
2500             // Landscape mode
2501             ViewGroup statusBar = (ViewGroup)findViewById(R.id.navigation_statusbar);
2502             if (statusBar.getParent() != null) {
2503                 ViewGroup parent = (ViewGroup) statusBar.getParent();
2504                 parent.removeView(statusBar);
2505             }
2506
2507             // Calculate the action button size (all the buttons must fit in the title bar)
2508             int bw = (int)getResources().getDimension(R.dimen.default_buttom_width);
2509             int abw = this.mActionBar.getChildCount() * bw;
2510             int rbw = 0;
2511             int cc = statusBar.getChildCount();
2512             for (int i = 0; i < cc; i++) {
2513                 View child = statusBar.getChildAt(i);
2514                 if (child instanceof ButtonItem) {
2515                     rbw += bw;
2516                 }
2517             }
2518             // Currently there isn't overflow menu
2519             int w = abw + rbw - bw;
2520
2521             // Add to the new location
2522             ViewGroup newParent = (ViewGroup)findViewById(R.id.navigation_title_landscape_holder);
2523             LinearLayout.LayoutParams params =
2524                     new LinearLayout.LayoutParams(
2525                             w,
2526                             ViewGroup.LayoutParams.MATCH_PARENT);
2527             statusBar.setLayoutParams(params);
2528             newParent.addView(statusBar);
2529
2530             // Apply theme
2531             theme.setBackgroundDrawable(this, statusBar, "titlebar_drawable"); //$NON-NLS-1$
2532
2533             // Hide holder
2534             View holder = findViewById(R.id.navigation_statusbar_portrait_holder);
2535             holder.setVisibility(View.GONE);
2536
2537         } else {
2538             // Portrait mode
2539             ViewGroup statusBar = (ViewGroup)findViewById(R.id.navigation_statusbar);
2540             if (statusBar.getParent() != null) {
2541                 ViewGroup parent = (ViewGroup) statusBar.getParent();
2542                 parent.removeView(statusBar);
2543             }
2544
2545             // Add to the new location
2546             ViewGroup newParent = (ViewGroup)findViewById(
2547                     R.id.navigation_statusbar_portrait_holder);
2548             LinearLayout.LayoutParams params =
2549                     new LinearLayout.LayoutParams(
2550                             ViewGroup.LayoutParams.MATCH_PARENT,
2551                             ViewGroup.LayoutParams.MATCH_PARENT);
2552             statusBar.setLayoutParams(params);
2553             newParent.addView(statusBar);
2554
2555             // Apply theme
2556             theme.setBackgroundDrawable(this, statusBar, "statusbar_drawable"); //$NON-NLS-1$
2557
2558             // Show holder
2559             newParent.setVisibility(View.VISIBLE);
2560         }
2561
2562         // if drawer was open, imitate reopening
2563         if (drawerOpen) {
2564             mDrawerToggle.onDrawerOpened(mDrawer);
2565         }
2566     }
2567
2568     /**
2569      * Method that removes all the history items that refers to virtual unmounted filesystems
2570      */
2571     private void removeUnmountedHistory() {
2572         int cc = mHistory.size() - 1;
2573         for (int i = cc; i >= 0; i--) {
2574             History history = mHistory.get(i);
2575             if (history.getItem() instanceof NavigationViewInfoParcelable) {
2576                 NavigationViewInfoParcelable navigableInfo =
2577                         ((NavigationViewInfoParcelable) history.getItem());
2578                 VirtualMountPointConsole vc =
2579                         VirtualMountPointConsole.getVirtualConsoleForPath(
2580                                 navigableInfo.getCurrentDir());
2581                 if (vc != null && !vc.isMounted()) {
2582                     mHistory.remove(i);
2583                     mDrawerHistory.removeViewAt(mDrawerHistory.getChildCount() - i - 1);
2584                 }
2585             }
2586         }
2587         mDrawerHistoryEmpty.setVisibility(
2588                 mDrawerHistory.getChildCount() == 0 ? View.VISIBLE : View.GONE);
2589         updateHistoryPositions();
2590     }
2591
2592     /**
2593      * Method that removes all the selection items that refers to virtual unmounted filesystems
2594      */
2595     private void removeUnmountedSelection() {
2596         for (NavigationView view : mNavigationViews) {
2597             view.removeUnmountedSelection();
2598         }
2599         mSelectionBar.setSelection(getNavigationView(mCurrentNavigationView).getSelectedFiles());
2600     }
2601
2602     /**
2603      * Method that applies the current theme to the activity
2604      * @hide
2605      */
2606     void applyTheme() {
2607         int orientation = getResources().getConfiguration().orientation;
2608         Theme theme = ThemeManager.getCurrentTheme(this);
2609         theme.setBaseThemeNoActionBar(this);
2610         applyTabTheme();
2611
2612         // imitate a closed drawer while layout is rebuilt to avoid NullPointerException
2613         boolean drawerOpen = mDrawerLayout.isDrawerOpen(Gravity.START);
2614         if (drawerOpen) {
2615             mDrawerLayout.closeDrawer(Gravity.START);
2616         }
2617
2618         //- Layout
2619         View v = findViewById(R.id.navigation_layout);
2620         theme.setBackgroundDrawable(this, v, "background_drawable"); //$NON-NLS-1$
2621
2622         //- ActionBar
2623         theme.setTitlebarDrawable(this, getActionBar(), "titlebar_drawable"); //$NON-NLS-1$
2624
2625         // Hackery to theme search view
2626         mSearchView = (SearchView) findViewById(R.id.navigation_search_bar);
2627         int searchPlateId = mSearchView.getContext().getResources()
2628                 .getIdentifier("android:id/search_plate", null, null);
2629         View searchPlate = mSearchView.findViewById(searchPlateId);
2630         if (searchPlate != null) {
2631             int searchTextId = searchPlate.getContext().getResources()
2632                     .getIdentifier("android:id/search_src_text", null, null);
2633             TextView searchText = (TextView) searchPlate.findViewById(searchTextId);
2634             if (searchText != null) {
2635                 searchText.setTextColor(Color.WHITE);
2636                 searchText.setHintTextColor(Color.WHITE);
2637             }
2638
2639             int magId = getResources().getIdentifier("android:id/search_mag_icon", null, null);
2640             ImageView magImage = (ImageView) mSearchView.findViewById(magId);
2641             if (magImage != null) {
2642                 magImage.setLayoutParams(new LinearLayout.LayoutParams(0, 0));
2643             }
2644         }
2645
2646         SearchManager searchManager = (SearchManager) getSystemService(Context.SEARCH_SERVICE);
2647         mSearchView.setSearchableInfo(searchManager.getSearchableInfo(getComponentName()));
2648         mSearchView.setIconifiedByDefault(false);
2649
2650         mCustomTitleView = (NavigationCustomTitleView) findViewById(R.id.navigation_title_flipper);
2651         mCustomTitleView.setVisibility(View.VISIBLE);
2652
2653         //- StatusBar
2654         v = findViewById(R.id.navigation_statusbar);
2655         if (orientation == Configuration.ORIENTATION_LANDSCAPE) {
2656             theme.setBackgroundDrawable(this, v, "titlebar_drawable"); //$NON-NLS-1$
2657         } else {
2658             theme.setBackgroundDrawable(this, v, "statusbar_drawable"); //$NON-NLS-1$
2659         }
2660         v = findViewById(R.id.ab_overflow);
2661         theme.setImageDrawable(this, (ImageView)v, "ab_overflow_drawable"); //$NON-NLS-1$
2662         v = findViewById(R.id.ab_actions);
2663         theme.setImageDrawable(this, (ImageView)v, "ab_actions_drawable"); //$NON-NLS-1$
2664         v = findViewById(R.id.ab_search);
2665         theme.setImageDrawable(this, (ImageView)v, "ab_search_drawable"); //$NON-NLS-1$
2666
2667         //- Expanders
2668         v = findViewById(R.id.ab_configuration);
2669         theme.setImageDrawable(this, (ImageView)v, "expander_open_drawable"); //$NON-NLS-1$
2670         v = findViewById(R.id.ab_close);
2671         theme.setImageDrawable(this, (ImageView)v, "expander_close_drawable"); //$NON-NLS-1$
2672         v = findViewById(R.id.ab_sort_mode);
2673         theme.setImageDrawable(this, (ImageView)v, "ab_sort_mode_drawable"); //$NON-NLS-1$
2674         v = findViewById(R.id.ab_layout_mode);
2675         theme.setImageDrawable(this, (ImageView)v, "ab_layout_mode_drawable"); //$NON-NLS-1$
2676         v = findViewById(R.id.ab_view_options);
2677         theme.setImageDrawable(this, (ImageView)v, "ab_view_options_drawable"); //$NON-NLS-1$
2678
2679         //- SelectionBar
2680         v = findViewById(R.id.navigation_selectionbar);
2681         theme.setBackgroundDrawable(this, v, "selectionbar_drawable"); //$NON-NLS-1$
2682         v = findViewById(R.id.ab_selection_done);
2683         theme.setImageDrawable(this, (ImageView)v, "ab_selection_done_drawable"); //$NON-NLS-1$
2684         v = findViewById(R.id.navigation_status_selection_label);
2685         theme.setTextColor(this, (TextView)v, "text_color"); //$NON-NLS-1$
2686
2687         // - Navigation drawer
2688         v = findViewById(R.id.history_empty);
2689         theme.setTextColor(this, (TextView)v, "text_color"); //$NON-NLS-1$
2690
2691         for (int i=0; i<mDrawerHistory.getChildCount(); i++) {
2692             View item = mDrawerHistory.getChildAt(i);
2693
2694             v = item.findViewById(R.id.history_item_name);
2695             theme.setTextColor(this, (TextView)v, "text_color"); //$NON-NLS-1$
2696             v = item.findViewById(R.id.history_item_directory);
2697             theme.setTextColor(this, (TextView)v, "text_color"); //$NON-NLS-1$
2698         }
2699
2700         //- NavigationView
2701         int cc = this.mNavigationViews.length;
2702         for (int i = 0; i < cc; i++) {
2703             getNavigationView(i).applyTheme();
2704         }
2705
2706         // if drawer was open, imitate reopening
2707         if (drawerOpen) {
2708             mDrawerToggle.onDrawerOpened(mDrawer);
2709         }
2710     }
2711
2712     /**
2713      * Method that applies the current theme to the tab host
2714      */
2715     private void applyTabTheme() {
2716         // Apply the theme
2717         Theme theme = ThemeManager.getCurrentTheme(this);
2718
2719         View v = findViewById(R.id.drawer);
2720         theme.setBackgroundDrawable(this, v, "background_drawable"); //$NON-NLS-1$
2721
2722         v = findViewById(R.id.drawer_bookmarks_tab);
2723         theme.setTextColor(this, (TextView)v, "text_color"); //$NON-NLS-1$
2724         v = findViewById(R.id.drawer_history_tab);
2725         theme.setTextColor(this, (TextView)v, "text_color"); //$NON-NLS-1$
2726
2727         v = findViewById(R.id.ab_settings);
2728         theme.setImageDrawable(this, (ButtonItem) v, "ab_settings_drawable"); //$NON-NLS-1$
2729         v = findViewById(R.id.ab_clear_history);
2730         theme.setImageDrawable(this, (ButtonItem) v, "ab_delete_drawable"); //$NON-NLS-1$
2731     }
2732
2733     public void updateActiveDialog(Dialog dialog) {
2734         mActiveDialog = dialog;
2735     }
2736 }