OSDN Git Service

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