2 * Copyright (C) 2012 The CyanogenMod Project
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 package com.cyanogenmod.filemanager.activities;
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;
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;
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;
132 import static com.cyanogenmod.filemanager.util.MimeTypeHelper.MimeTypeCategory.*;
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
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.
146 public class NavigationActivity extends Activity
147 implements OnHistoryListener, OnRequestRefreshListener,
148 OnNavigationRequestMenuListener, OnNavigationSelectionChangedListener {
150 private static final String TAG = "NavigationActivity"; //$NON-NLS-1$
152 private static boolean DEBUG = false;
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$
158 private static final String STR_USB = "usb"; // $NON-NLS-1$
161 * Intent code for request a search.
163 public static final int INTENT_REQUEST_SEARCH = 10001;
166 * Intent code for request a search.
168 public static final int INTENT_REQUEST_SETTINGS = 20001;
171 * Constant for extra information about selected search entry.
173 public static final String EXTRA_SEARCH_ENTRY_SELECTION =
174 "extra_search_entry_selection"; //$NON-NLS-1$
177 * Constant for extra information about last search data.
179 public static final String EXTRA_SEARCH_LAST_SEARCH_DATA =
180 "extra_search_last_search_data"; //$NON-NLS-1$
183 * Constant for extra information for request a navigation to the passed path.
185 public static final String EXTRA_NAVIGATE_TO =
186 "extra_navigate_to"; //$NON-NLS-1$
189 * Constant for extra information for request to add navigation to the history
191 public static final String EXTRA_ADD_TO_HISTORY =
192 "extra_add_to_history"; //$NON-NLS-1$
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;
200 private Toolbar mToolBar;
201 private SearchView mSearchView;
202 private NavigationCustomTitleView mCustomTitleView;
203 private InputMethodManager mImm;
205 private final BroadcastReceiver mNotificationReceiver = new BroadcastReceiver() {
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);
213 // Disk usage warning level
214 if (key.compareTo(FileManagerSettings.
215 SETTINGS_DISK_USAGE_WARNING_LEVEL.getId()) == 0) {
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();
228 // Case sensitive sort
229 if (key.compareTo(FileManagerSettings.
230 SETTINGS_CASE_SENSITIVE_SORT.getId()) == 0) {
231 getCurrentNavigationView().refresh();
236 if (key.compareTo(FileManagerSettings.
237 SETTINGS_DISPLAY_THUMBS.getId()) == 0) {
238 // Clean the icon cache applying the current theme
244 if (key.compareTo(FileManagerSettings.
245 SETTINGS_USE_FLINGER.getId()) == 0) {
247 Preferences.getSharedPreferences().getBoolean(
248 FileManagerSettings.SETTINGS_USE_FLINGER.getId(),
249 ((Boolean)FileManagerSettings.
250 SETTINGS_USE_FLINGER.
251 getDefaultValue()).booleanValue());
252 getCurrentNavigationView().setUseFlinger(useFlinger);
257 if (key.compareTo(FileManagerSettings.
258 SETTINGS_ACCESS_MODE.getId()) == 0) {
259 // Is it necessary to create or exit of the ChRooted?
261 FileManagerApplication.
262 getAccessMode().compareTo(AccessMode.SAFE) == 0;
263 if (chRooted != NavigationActivity.this.mChRooted) {
273 if (key.compareTo(FileManagerSettings.
274 SETTINGS_RESTRICT_SECONDARY_USERS_ACCESS.getId()) == 0) {
275 if (AndroidHelper.isSecondaryUser(context)) {
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$
283 ConsoleBuilder.changeToNonPrivilegedConsole(context);
288 // Filetime format mode
289 if (key.compareTo(FileManagerSettings.
290 SETTINGS_FILETIME_FORMAT_MODE.getId()) == 0) {
292 synchronized (FileHelper.DATETIME_SYNC) {
293 FileHelper.sReloadDateTimeFormats = true;
294 NavigationActivity.this.getCurrentNavigationView().refresh();
299 } else if (intent.getAction().compareTo(
300 FileManagerSettings.INTENT_FILE_CHANGED) == 0) {
301 // Retrieve the file that was changed
303 intent.getStringExtra(FileManagerSettings.EXTRA_FILE_CHANGED_KEY);
305 FileSystemObject fso = CommandHelper.getFileInfo(context, file, null);
307 getCurrentNavigationView().refresh(fso);
309 } catch (Exception e) {
310 ExceptionUtil.translateException(context, e, true, false);
313 } else if (intent.getAction().compareTo(
314 FileManagerSettings.INTENT_THEME_CHANGED) == 0) {
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) {
322 synchronized (FileHelper.DATETIME_SYNC) {
323 FileHelper.sReloadDateTimeFormats = true;
324 NavigationActivity.this.getCurrentNavigationView().refresh();
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();
340 private OnClickListener mOnClickDrawerTabListener = new OnClickListener() {
342 public void onClick(View v) {
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);
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$
363 mClearHistory.setVisibility(View.GONE);
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);
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$
385 mClearHistory.setVisibility(mHistory.size() > 0 ? View.VISIBLE : View.GONE);
394 private OnClickListener mOnClickDrawerActionBarListener = new OnClickListener() {
396 public void onClick(View v) {
398 case R.id.ab_settings:
399 mDrawerLayout.closeDrawer(Gravity.START);
402 case R.id.ab_clear_history:
404 mClearHistory.setVisibility(View.GONE);
412 static String MIME_TYPE_LOCALIZED_NAMES[];
416 static Map<MimeTypeCategory, Drawable> EASY_MODE_ICONS = new
417 HashMap<MimeTypeCategory, Drawable>();
422 NavigationView[] mNavigationViews;
426 ListView mEasyModeListView;
427 private List<History> mHistory;
429 private static final List<MimeTypeCategory> EASY_MODE_LIST = new ArrayList<MimeTypeCategory>() {
440 private ArrayAdapter<MimeTypeCategory> mEasyModeAdapter;
441 private View.OnClickListener mEasyModeItemClickListener = new View.OnClickListener() {
443 public void onClick(View view) {
444 Integer position = (Integer) view.getTag();
449 private int mCurrentNavigationView;
451 private ViewGroup mActionBar;
452 private SelectionView mSelectionBar;
454 private DrawerLayout mDrawerLayout;
455 private ViewGroup mDrawer;
456 private ActionBarDrawerToggle mDrawerToggle;
457 private LinearLayout mDrawerHistory;
458 private TextView mDrawerHistoryEmpty;
460 private TextView mBookmarksTab;
461 private TextView mHistoryTab;
462 private View mBookmarksLayout;
463 private View mHistoryLayout;
465 private ButtonItem mSettings;
466 private ButtonItem mClearHistory;
468 private List<Bookmark> mBookmarks;
469 private List<Bookmark> mSdBookmarks;
470 private LinearLayout mDrawerBookmarks;
472 private boolean mExitFlag = false;
473 private long mExitBackTimeout = -1;
475 private Dialog mActiveDialog = null;
477 private int mOrientation;
479 private boolean mNeedsEasyMode = false;
481 private boolean mDisplayingSearchResults;
493 private AsyncTask<Void, Void, Boolean> mBookmarksTask;
499 protected void onCreate(Bundle state) {
502 Log.d(TAG, "NavigationActivity.onCreate"); //$NON-NLS-1$
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);
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);
524 //the input manager service
525 mImm = (InputMethodManager) this.getSystemService(
526 Context.INPUT_METHOD_SERVICE);
528 // Set the theme before setContentView
529 Theme theme = ThemeManager.getCurrentTheme(this);
530 theme.setBaseThemeNoActionBar(this);
532 //Set the main layout of the activity
533 setContentView(R.layout.navigation);
535 //Initialize nfc adapter
536 NfcAdapter mNfcAdapter = NfcAdapter.getDefaultAdapter(this);
537 if (mNfcAdapter != null) {
538 mNfcAdapter.setBeamPushUrisCallback(new NfcAdapter.CreateBeamUrisCallback() {
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())));
551 if (fileUri.size() > 0) {
552 return fileUri.toArray(new Uri[fileUri.size()]);
560 //Initialize activity
564 initNavigationViews();
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);
571 //Initialize action bars
572 initTitleActionBar();
573 initStatusActionBar();
576 // Initialize navigation drawer
580 // Adjust layout (only when start on landscape mode)
581 int orientation = getResources().getConfiguration().orientation;
582 if (orientation == Configuration.ORIENTATION_LANDSCAPE) {
585 this.mOrientation = orientation;
590 // Show welcome message
593 this.mHandler = new Handler();
594 this.mHandler.post(new Runnable() {
597 // Initialize console
600 //Initialize navigation
601 int cc = NavigationActivity.this.mNavigationViews.length;
602 for (int i = 0; i < cc; i++) {
603 initNavigation(i, false, getIntent());
606 //Check the intent action
607 checkIntent(getIntent());
611 MIME_TYPE_LOCALIZED_NAMES = MimeTypeCategory.getFriendlyLocalizedNames(NavigationActivity
614 EASY_MODE_ICONS.put(MimeTypeCategory.NONE, getResources().getDrawable(R.drawable
616 EASY_MODE_ICONS.put(MimeTypeCategory.IMAGE, getResources().getDrawable(R.drawable
618 EASY_MODE_ICONS.put(MimeTypeCategory.VIDEO, getResources().getDrawable(R.drawable
620 EASY_MODE_ICONS.put(MimeTypeCategory.AUDIO, getResources().getDrawable(R.drawable
622 EASY_MODE_ICONS.put(MimeTypeCategory.DOCUMENT, getResources().getDrawable(R.drawable
624 EASY_MODE_ICONS.put(MimeTypeCategory.APP, getResources().getDrawable(R.drawable
625 .ic_em_application));
628 super.onCreate(state);
632 protected void onStart() {
635 // Check restrictions
636 if (!FileManagerApplication.checkRestrictSecondaryUsersAccess(this, mChRooted)) {
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();
651 if (mDisplayingSearchResults) {
652 mDisplayingSearchResults = false;
655 getCurrentNavigationView().refresh(true);
660 protected void onPostCreate(Bundle savedInstanceState) {
661 super.onPostCreate(savedInstanceState);
662 // Sync the toggle state after onRestoreInstanceState has occurred.
663 mDrawerToggle.syncState();
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);
675 //Initialize navigation
676 initNavigation(this.mCurrentNavigationView, restore, intent);
678 //Check the intent action
686 public void onConfigurationChanged(Configuration newConfig) {
687 super.onConfigurationChanged(newConfig);
689 mDrawerToggle.onConfigurationChanged(newConfig);
696 public boolean onOptionsItemSelected(MenuItem item) {
697 if (mDrawerToggle.onOptionsItemSelected(item)) {
701 if (mNeedsEasyMode) {
702 if (item.getItemId() == android.R.id.home) {
703 if (mHistory.size() == 0 && !isEasyModeVisible()) {
704 performShowEasyMode();
710 return super.onOptionsItemSelected(item);
717 protected void onDestroy() {
719 Log.d(TAG, "NavigationActivity.onDestroy"); //$NON-NLS-1$
722 if (mActiveDialog != null && mActiveDialog.isShowing()) {
723 mActiveDialog.dismiss();
726 // Unregister the receiver
728 unregisterReceiver(this.mNotificationReceiver);
729 } catch (Throwable ex) {
734 //All destroy. Continue
739 * Method that returns the current navigation view.
741 * @return NavigationView The current navigation view
743 public NavigationView getCurrentNavigationView() {
744 return getNavigationView(this.mCurrentNavigationView);
748 * Method that returns the current navigation view.
750 * @param viewId The view to return
751 * @return NavigationView The current navigation view
753 public NavigationView getNavigationView(int viewId) {
754 if (this.mNavigationViews == null) return null;
755 return this.mNavigationViews[viewId];
759 * Method that initializes the activity.
761 private void init() {
762 this.mHistory = new ArrayList<History>();
763 this.mChRooted = FileManagerApplication.getAccessMode().compareTo(AccessMode.SAFE) == 0;
767 * Method that displays a welcome message the first time the user
768 * access the application
770 private void showWelcomeMsg() {
771 boolean firstUse = Preferences.getSharedPreferences().getBoolean(
772 FileManagerSettings.SETTINGS_FIRST_USE.getId(),
773 ((Boolean)FileManagerSettings.SETTINGS_FIRST_USE.getDefaultValue()).booleanValue());
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);
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);
785 // Don't display again this dialog
787 Preferences.savePreference(
788 FileManagerSettings.SETTINGS_FIRST_USE, Boolean.FALSE, true);
789 } catch (Exception e) {/**NON BLOCK**/}
794 * Method that initializes the titlebar of the activity.
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);
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));
819 //Configure the action bar options
820 getActionBar().setBackgroundDrawable(
821 getResources().getDrawable(R.drawable.bg_material_titlebar));
822 mToolBar.addView(titleLayout);
826 * Method that initializes the statusbar of the activity.
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() {
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();
843 //Wake through children calculation his dimensions
844 int bw = (int)getResources().getDimension(R.dimen.default_buttom_width);
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);
856 // Have overflow menu? Actually no. There is only a search action, so just hide
858 View overflow = findViewById(R.id.ab_overflow);
859 overflow.setVisibility(View.GONE);
861 // Show the status bar
862 View statusBar = findViewById(R.id.navigation_statusbar_portrait_holder);
863 statusBar.setVisibility(View.VISIBLE);
867 * Method that initializes the selectionbar of the activity.
869 private void initSelectionBar() {
870 this.mSelectionBar = (SelectionView)findViewById(R.id.navigation_selectionbar);
874 * Method that initializes the navigation drawer of the activity.
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);
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);
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);
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
902 mOnClickDrawerTabListener.onClick(lastTab == 0 ? mBookmarksTab : mHistoryTab);
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) {
909 /** Called when a drawer has settled in a completely closed state. */
910 public void onDrawerClosed(View view) {
911 super.onDrawerClosed(view);
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);
920 getActionBar().setDisplayHomeAsUpEnabled(true);
922 // Set the drawer toggle as the DrawerListener
923 mDrawerLayout.setDrawerListener(mDrawerToggle);
927 * Method that do something when the DrawerLayout opened.
929 private void onDrawerLayoutOpened(View drawerView){
930 if (mSearchView != null && mSearchView.getVisibility() == View.VISIBLE) {
932 hideSoftInput(drawerView);
937 * Method that hide the software when the software showing.
940 private void hideSoftInput(View view){
942 mImm.hideSoftInputFromWindow(view.getWindowToken(), 0);
947 * Method that adds a history entry to the history list in the drawer
949 private void addHistoryToDrawer(int index, HistoryNavigable navigable) {
950 // hide empty message
951 mDrawerHistoryEmpty.setVisibility(View.GONE);
953 Theme theme = ThemeManager.getCurrentTheme(this);
954 IconHolder iconholder = new IconHolder(this, false);
956 // inflate single bookmark layout item and fill it
957 LinearLayout view = (LinearLayout) getLayoutInflater().inflate(
958 R.layout.history_item, null);
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);
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$
970 iconView.setImageDrawable(icon);
972 String title = navigable.getTitle();
973 if (title == null || title.trim().length() == 0) {
974 title = getString(R.string.root_directory_name);
978 directory.setText(navigable.getDescription());
980 theme.setTextColor(this, name, "text_color");
981 theme.setTextColor(this, directory, "text_color");
984 view.setOnClickListener(new OnClickListener() {
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);
991 navigateToHistory(history);
992 mDrawerLayout.closeDrawer(Gravity.START);
996 // add as first child
997 mDrawerHistory.addView(view, 0);
999 // Show clear button if history tab is selected
1000 mClearHistory.setVisibility(mHistoryTab.isSelected() ? View.VISIBLE : View.GONE);
1004 * Method takes a bookmark as argument and adds it to mBookmarks and the
1005 * list in the drawer
1007 public void addBookmark(Bookmark bookmark) {
1008 mBookmarks.add(bookmark);
1009 addBookmarkToDrawer(bookmark);
1013 * Show the easy mode view
1015 private void performShowEasyMode() {
1016 mEasyModeListView.setVisibility(View.VISIBLE);
1017 getCurrentNavigationView().setVisibility(View.GONE);
1018 performShowBackArrow(false);
1022 * Hide the easy mode view
1024 private void performHideEasyMode() {
1025 mEasyModeListView.setVisibility(View.GONE);
1026 getCurrentNavigationView().setVisibility(View.VISIBLE);
1029 private void performShowBackArrow(boolean showBackArrow) {
1030 if (mNeedsEasyMode) {
1031 mDrawerToggle.setDrawerIndicatorEnabled(!showBackArrow);
1035 private boolean isEasyModeVisible() {
1036 return mEasyModeListView.getVisibility() != View.GONE;
1040 * Method takes a bookmark as argument and adds it to the bookmark list in
1043 private void addBookmarkToDrawer(Bookmark bookmark) {
1044 Theme theme = ThemeManager.getCurrentTheme(this);
1045 IconHolder iconholder = new IconHolder(this, false);
1047 // inflate single bookmark layout item and fill it
1048 LinearLayout view = (LinearLayout) getLayoutInflater().inflate(
1049 R.layout.bookmarks_item, null);
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);
1058 name.setText(bookmark.mName);
1059 path.setText(bookmark.mPath);
1061 theme.setTextColor(this, name, "text_color");
1062 theme.setTextColor(this, path, "text_color");
1064 icon.setImageDrawable(iconholder.getDrawable(BookmarksHelper
1065 .getIcon(bookmark)));
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);
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);
1080 actionButton.setImageDrawable(action);
1081 actionButton.setVisibility(action != null ? View.VISIBLE : View.GONE);
1082 actionButton.setOnClickListener(new OnClickListener() {
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);
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() {
1096 public void onValueChanged(String newInitialDir) {
1097 bookmark.mPath = newInitialDir;
1099 // reset drawer bookmarks list
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);
1117 mBookmarks.remove(bookmark);
1118 mDrawerBookmarks.removeView(v);
1123 actionButton.setContentDescription(actionCd);
1125 // handle item click
1126 view.setOnClickListener(new OnClickListener() {
1128 public void onClick(View v) {
1129 final int index = mDrawerBookmarks.indexOfChild(v);
1130 final Bookmark bookmark = mBookmarks.get(index);
1132 boolean showEasyMode = (mSdBookmarks.contains(bookmark)) &&
1133 getResources().getBoolean(R.bool.cmcc_show_easy_mode);
1135 // try to navigate to the bookmark path
1137 FileSystemObject fso = CommandHelper.getFileInfo(
1138 getApplicationContext(), bookmark.mPath, null);
1141 performShowEasyMode();
1143 performHideEasyMode();
1145 performShowBackArrow(!mDrawerToggle.isDrawerIndicatorEnabled());
1146 getCurrentNavigationView().open(fso);
1147 mDrawerLayout.closeDrawer(Gravity.START);
1150 // The bookmark does not exist, delete the user-defined
1153 Bookmarks.removeBookmark(getApplicationContext(),
1156 // reset bookmarks list to default
1159 catch (Exception ex) {
1163 catch (Exception e) { // Capture the exception
1165 .translateException(NavigationActivity.this, e);
1166 if (e instanceof NoSuchFileOrDirectory
1167 || e instanceof FileNotFoundException) {
1168 // The bookmark does not exist, delete the user-defined
1171 Bookmarks.removeBookmark(getApplicationContext(),
1174 // reset bookmarks list to default
1177 catch (Exception ex) {
1185 mDrawerBookmarks.addView(view);
1189 * Method that initializes the bookmarks.
1191 private synchronized void initBookmarks() {
1192 if (mBookmarksTask != null &&
1193 !mBookmarksTask.getStatus().equals(AsyncTask.Status.FINISHED)) {
1197 // Retrieve the loading view
1198 final View waiting = findViewById(R.id.bookmarks_loading);
1200 // Load bookmarks in background
1201 mBookmarksTask = new AsyncTask<Void, Void, Boolean>() {
1205 protected Boolean doInBackground(Void... params) {
1207 mBookmarks = loadBookmarks();
1208 return Boolean.TRUE;
1211 catch (Exception e) {
1213 return Boolean.FALSE;
1218 protected void onPreExecute() {
1219 waiting.setVisibility(View.VISIBLE);
1220 mDrawerBookmarks.removeAllViews();
1224 protected void onPostExecute(Boolean result) {
1225 waiting.setVisibility(View.GONE);
1226 if (result.booleanValue()) {
1227 for (Bookmark bookmark : mBookmarks) {
1228 addBookmarkToDrawer(bookmark);
1232 if (this.mCause != null) {
1233 ExceptionUtil.translateException(
1234 NavigationActivity.this, this.mCause);
1237 mBookmarksTask = null;
1241 protected void onCancelled() {
1242 waiting.setVisibility(View.GONE);
1243 mBookmarksTask = null;
1246 mBookmarksTask.execute();
1250 * Method that loads all kind of bookmarks and join in an array to be used
1251 * in the listview adapter.
1253 * @return List<Bookmark>
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());
1264 mSdBookmarks = loadSdStorageBookmarks();
1265 bookmarks.addAll(mSdBookmarks);
1266 bookmarks.addAll(loadVirtualBookmarks());
1267 bookmarks.addAll(loadUserBookmarks());
1272 * Method that loads the home bookmark from the user preference.
1274 * @return Bookmark The bookmark loaded
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);
1286 * Method that loads the filesystem bookmarks from the internal xml file.
1287 * (defined by this application)
1289 * @return List<Bookmark> The bookmarks loaded
1291 private List<Bookmark> loadFilesystemBookmarks() {
1293 // Initialize the bookmarks
1294 List<Bookmark> bookmarks = new ArrayList<Bookmark>();
1296 // Read the command list xml file
1297 XmlResourceParser parser = getResources().getXml(
1298 R.xml.filesystem_bookmarks);
1301 // Find the root element
1302 XmlUtils.beginDocument(parser, TAG_BOOKMARKS);
1304 XmlUtils.nextElement(parser);
1305 String element = parser.getName();
1306 if (element == null) {
1310 if (TAG_BOOKMARK.equals(element)) {
1311 CharSequence name = null;
1312 CharSequence directory = null;
1315 name = getString(parser.getAttributeResourceValue(
1316 R.styleable.Bookmark_name, 0));
1318 catch (Exception e) {
1322 directory = getString(parser
1323 .getAttributeResourceValue(
1324 R.styleable.Bookmark_directory, 0));
1326 catch (Exception e) {
1329 if (directory == null) {
1331 .getAttributeValue(R.styleable.Bookmark_directory);
1333 if (name != null && directory != null) {
1334 bookmarks.add(new Bookmark(
1335 BOOKMARK_TYPE.FILESYSTEM, name.toString(),
1336 directory.toString()));
1341 // Return the bookmarks
1349 catch (Throwable ex) {
1350 Log.e(TAG, "Load filesystem bookmarks failed", ex); //$NON-NLS-1$
1354 return new ArrayList<Bookmark>();
1358 * Method that loads the secure digital card storage bookmarks from the
1361 * @return List<Bookmark> The bookmarks loaded
1363 private List<Bookmark> loadSdStorageBookmarks() {
1364 // Initialize the bookmarks
1365 List<Bookmark> bookmarks = new ArrayList<Bookmark>();
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 + "'");
1380 if (!TextUtils.isEmpty(path)) {
1381 String lowerPath = path.toLowerCase(Locale.ROOT);
1383 if (lowerPath.contains(STR_USB)) {
1384 bookmark = new Bookmark(BOOKMARK_TYPE.USB, StorageHelper
1385 .getStorageVolumeDescription(getApplication(), volume), path);
1387 bookmark = new Bookmark(BOOKMARK_TYPE.SDCARD, StorageHelper
1388 .getStorageVolumeDescription(getApplication(), volume), path);
1390 bookmarks.add(bookmark);
1395 // Return the bookmarks
1398 catch (Throwable ex) {
1399 Log.e(TAG, "Load filesystem bookmarks failed", ex); //$NON-NLS-1$
1403 return new ArrayList<Bookmark>();
1407 * Method that loads all virtual mount points.
1409 * @return List<Bookmark> The bookmarks loaded
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;
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);
1427 bookmarks.add(new Bookmark(type, name, mp.getMountPoint()));
1433 * Method that loads the user bookmarks (added by the user).
1435 * @return List<Bookmark> The bookmarks loaded
1437 private List<Bookmark> loadUserBookmarks() {
1438 List<Bookmark> bookmarks = new ArrayList<Bookmark>();
1439 Cursor cursor = Bookmarks.getAllBookmarks(this.getContentResolver());
1441 if (cursor != null && cursor.moveToFirst()) {
1443 Bookmark bm = new Bookmark(cursor);
1445 && !StorageHelper.isPathInStorageVolume(bm.mPath)) {
1450 while (cursor.moveToNext());
1455 if (cursor != null) {
1459 catch (Exception e) {
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);
1478 * Method that initializes the navigation views of the activity
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;
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) {
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);
1509 mEasyModeAdapter.addAll(EASY_MODE_LIST);
1510 mEasyModeListView.setAdapter(mEasyModeAdapter);
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 '*'
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);
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);
1535 intent.putExtra(SearchActivity.EXTRA_SEARCH_MIMETYPE, searchCategories);
1538 startActivity(intent);
1542 * Method that initialize the console
1545 void initConsole() {
1546 //Create the default console (from the preferences)
1548 Console console = ConsoleBuilder.getConsole(NavigationActivity.this);
1549 if (console == null) {
1550 throw new ConsoleAllocException("console == null"); //$NON-NLS-1$
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);
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
1574 * Method that initializes the navigation.
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
1581 void initNavigation(final int viewId, final boolean restore, final Intent intent) {
1582 if (mDisplayingSearchResults || restore) {
1586 final NavigationView navigationView = getNavigationView(viewId);
1587 this.mHandler.post(new Runnable() {
1590 //Is necessary navigate?
1591 applyInitialDir(navigationView, intent);
1597 * Method that applies the user-defined initial directory
1599 * @param navigationView The navigation view
1600 * @param intent The current intent
1603 void applyInitialDir(final NavigationView navigationView, final Intent intent) {
1604 //Load the user-defined initial directory
1606 Preferences.getSharedPreferences().getString(
1607 FileManagerSettings.SETTINGS_INITIAL_DIR.getId(),
1608 (String)FileManagerSettings.
1609 SETTINGS_INITIAL_DIR.getDefaultValue());
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();
1630 final boolean addToHistory = intent.getBooleanExtra(EXTRA_ADD_TO_HISTORY, true);
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;
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();
1653 //Ensure that initial directory is an absolute directory
1654 initialDir = FileHelper.getAbsPath(initialDir);
1656 // Show exception and exit
1657 DialogHelper.showToast(
1659 R.string.msgs_cant_create_console, Toast.LENGTH_LONG);
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();
1672 // Fix for /data/media/0. Libcore doesn't detect it correctly.
1674 exists = CommandHelper.getFileInfo(this, initialDir, false, null) != null;
1675 } catch (InsufficientPermissionsException ipex) {
1676 ExceptionUtil.translateException(
1677 this, ipex, false, true, new OnRelaunchCommandResult() {
1679 public void onSuccess() {
1680 navigationView.changeCurrentDir(absInitialDir, addToHistory);
1683 public void onFailed(Throwable cause) {
1684 showInitialInvalidDirectoryMsg(userInitialDir);
1685 navigationView.changeCurrentDir(FileHelper.ROOT_DIRECTORY,
1689 public void onCancelled() {
1690 showInitialInvalidDirectoryMsg(userInitialDir);
1691 navigationView.changeCurrentDir(FileHelper.ROOT_DIRECTORY,
1696 // Asynchronous mode
1698 } catch (Exception ex) {
1699 // We are not interested in other exceptions
1700 ExceptionUtil.translateException(this, ex, true, false);
1703 // Check again the initial directory
1705 showInitialInvalidDirectoryMsg(userInitialDir);
1706 initialDir = FileHelper.ROOT_DIRECTORY;
1709 // Weird, but we have a valid initial directory
1713 boolean needsEasyMode = false;
1714 if (mSdBookmarks != null ) {
1715 for (Bookmark bookmark :mSdBookmarks) {
1716 if (bookmark.mPath.equalsIgnoreCase(initialDir)) {
1717 needsEasyMode = true;
1723 mNeedsEasyMode = getResources().getBoolean(R.bool.cmcc_show_easy_mode);
1725 needsEasyMode = needsEasyMode && mNeedsEasyMode;
1726 if (needsEasyMode) {
1727 performShowEasyMode();
1729 performHideEasyMode();
1731 // Change the current directory to the user-defined initial directory
1732 navigationView.changeCurrentDir(initialDir, addToHistory);
1736 * Displays a message reporting invalid directory
1738 * @param initialDir The initial directory
1741 void showInitialInvalidDirectoryMsg(String initialDir) {
1742 // Change to root directory
1743 DialogHelper.showToast(
1746 R.string.msgs_settings_invalid_initial_directory,
1748 Toast.LENGTH_SHORT);
1752 * Method that verifies the intent passed to the activity, and checks
1753 * if a request is made like Search.
1755 * @param intent The intent to check
1758 void checkIntent(Intent intent) {
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);
1773 //-- SearchManager.QUERY
1774 String query = intent.getStringExtra(SearchManager.QUERY);
1775 if (query != null) {
1776 searchIntent.putExtra(SearchManager.QUERY, query);
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);
1785 startActivityForResult(searchIntent, INTENT_REQUEST_SEARCH);
1794 public boolean onKeyUp(int keyCode, KeyEvent event) {
1795 if (keyCode == KeyEvent.KEYCODE_MENU) {
1796 if (mDrawerLayout.isDrawerOpen(mDrawer)) {
1797 mDrawerLayout.closeDrawer(Gravity.START);
1799 mDrawerLayout.openDrawer(Gravity.START);
1803 return super.onKeyUp(keyCode, event);
1807 public void onBackPressed() {
1808 if (mDrawerLayout.isDrawerOpen(Gravity.START)) {
1809 mDrawerLayout.closeDrawer(Gravity.START);
1813 boolean upToParent = mHistory.size() > 0;
1815 if (mNeedsEasyMode && !isEasyModeVisible() && !upToParent) {
1816 performShowEasyMode();
1819 if (checkBackAction()) {
1824 // An exit event has occurred, force the destroy the consoles
1829 * Method invoked when an action item is clicked.
1831 * @param view The button pushed
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();
1843 //Hide navigation view configuration toolbar
1844 getCurrentNavigationView().getCustomTitle().hideConfigurationView();
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);
1857 //######################
1858 //Navigation view options
1859 //######################
1860 case R.id.ab_sort_mode:
1861 showSettingsPopUp(view,
1863 new FileManagerSettings[]{
1864 FileManagerSettings.SETTINGS_SORT_MODE}));
1866 case R.id.ab_layout_mode:
1867 showSettingsPopUp(view,
1869 new FileManagerSettings[]{
1870 FileManagerSettings.SETTINGS_LAYOUT_MODE}));
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}));
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}));
1889 //######################
1891 //######################
1892 case R.id.ab_selection_done:
1893 //Show information of the filesystem
1894 getCurrentNavigationView().onDeselectAll();
1897 //######################
1898 //Action Bar buttons
1899 //######################
1900 case R.id.ab_actions:
1901 openActionsDialog(getCurrentNavigationView().getCurrentDir(),
1905 case R.id.ab_search:
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
1928 switch (requestCode) {
1929 case INTENT_REQUEST_SEARCH:
1930 if (resultCode == RESULT_OK) {
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);
1939 //Goto to new directory
1940 getCurrentNavigationView().open(fso, searchInfo);
1941 performHideEasyMode();
1942 mDisplayingSearchResults = true;
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
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);
1957 // reset bookmarks list to default as the user could have set a
1958 // new bookmark in the search activity
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);
1983 public void onCheckHistory() {
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) {
1996 getCurrentNavigationView().refresh();
1998 if (clearSelection) {
1999 this.getCurrentNavigationView().onDeselectAll();
2004 public void onClearCache(Object o) {
2005 getCurrentNavigationView().onClearCache(o);
2012 public void onRequestBookmarksRefresh() {
2020 public void onRequestRemove(Object o, boolean clearSelection) {
2021 if (o instanceof FileSystemObject) {
2023 this.getCurrentNavigationView().removeItem((FileSystemObject)o);
2025 //Remove from history
2026 removeFromHistory((FileSystemObject)o);
2028 onRequestRefresh(null, clearSelection);
2030 if (clearSelection) {
2031 this.getCurrentNavigationView().onDeselectAll();
2039 public void onNavigateTo(Object o) {
2044 public void onCancel(){
2052 public void onSelectionChanged(NavigationView navView, List<FileSystemObject> selectedItems) {
2053 this.mSelectionBar.setSelection(selectedItems);
2060 public void onRequestMenu(NavigationView navView, FileSystemObject item) {
2061 // Show the actions dialog
2062 openActionsDialog(item, false);
2066 * Method that shows a popup with a menu associated a {@link FileManagerSettings}.
2068 * @param anchor The action button that was pressed
2069 * @param settings The array of settings associated with the action button
2071 private void showSettingsPopUp(View anchor, List<FileManagerSettings> settings) {
2072 //Create the adapter
2073 final MenuSettingsAdapter adapter = new MenuSettingsAdapter(this, settings);
2075 //Create a show the popup menu
2076 final ListPopupWindow popup = DialogHelper.createListPopupWindow(this, adapter, anchor);
2077 popup.setOnItemClickListener(new OnItemClickListener() {
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);
2085 if (setting.compareTo(FileManagerSettings.SETTINGS_LAYOUT_MODE) == 0) {
2086 //Need to change the layout
2087 getCurrentNavigationView().changeViewMode(
2088 NavigationLayoutMode.fromId(value));
2091 if (setting.getDefaultValue() instanceof Enum<?>) {
2093 Preferences.savePreference(setting, new ObjectIdentifier() {
2095 public int getId() {
2102 Preferences.getSharedPreferences().
2105 ((Boolean)setting.getDefaultValue()).booleanValue());
2106 Preferences.savePreference(setting, Boolean.valueOf(!newval), false);
2108 getCurrentNavigationView().refresh();
2110 } catch (Exception e) {
2111 Log.e(TAG, "Error applying navigation option", e); //$NON-NLS-1$
2112 NavigationActivity.this.mHandler.post(new Runnable() {
2115 DialogHelper.showToast(
2116 NavigationActivity.this,
2117 R.string.msgs_settings_save_failure, Toast.LENGTH_SHORT);
2123 getCurrentNavigationView().getCustomTitle().restoreView();
2128 popup.setOnDismissListener(new PopupWindow.OnDismissListener() {
2130 public void onDismiss() {
2138 * Method that show the information of a filesystem mount point.
2140 * @param mp The mount point info
2141 * @param du The disk usage of the mount point
2143 private void showMountPointInfo(MountPoint mp, DiskUsage du) {
2144 //Has mount point info?
2146 //There is no information
2148 DialogHelper.createWarningDialog(
2150 R.string.filesystem_info_warning_title,
2151 R.string.filesystem_info_warning_msg);
2152 DialogHelper.delegateDialogShow(this, alert);
2156 //Show a the filesystem info dialog
2157 FilesystemInfoDialog dialog = new FilesystemInfoDialog(this, mp, du);
2158 dialog.setOnMountListener(new OnMountListener() {
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();
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);
2179 * Method that checks the action that must be realized when the
2180 * back button is pushed.
2182 * @return boolean Indicates if the action must be intercepted
2184 private boolean checkBackAction() {
2185 // We need a basic structure to check this
2186 if (getCurrentNavigationView() == null) return false;
2188 if (mSearchView.getVisibility() == View.VISIBLE) {
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();
2199 //Do back operation over the navigation history
2200 boolean flag = this.mExitFlag;
2202 this.mExitFlag = !back();
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);
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();
2221 //Back action not applied
2222 return !this.mExitFlag;
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());
2233 super.startActivity(intent);
2237 * Method that returns the history size.
2239 private void clearHistory() {
2240 this.mHistory.clear();
2241 mDrawerHistory.removeAllViews();
2242 mDrawerHistoryEmpty.setVisibility(View.VISIBLE);
2246 * Method that navigates to the passed history reference.
2248 * @param history The history reference
2249 * @return boolean A problem occurs while navigate
2251 public synchronized boolean navigateToHistory(History history) {
2254 History realHistory = this.mHistory.get(history.getPosition());
2256 //Navigate to item. Check what kind of history is
2257 if (realHistory.getItem() instanceof NavigationViewInfoParcelable) {
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)) {
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);
2277 //The type is unknown
2278 throw new IllegalArgumentException("Unknown history type"); //$NON-NLS-1$
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);
2288 if (mDrawerHistory.getChildCount() == 0) {
2289 mDrawerHistoryEmpty.setVisibility(View.VISIBLE);
2293 boolean clearHistory = mHistoryTab.isSelected() && mHistory.size() > 0;
2294 mClearHistory.setVisibility(clearHistory ? View.VISIBLE : View.GONE);
2297 } catch (Throwable ex) {
2298 if (history != null) {
2300 String.format("Failed to navigate to history %d: %s", //$NON-NLS-1$
2301 Integer.valueOf(history.getPosition()),
2302 history.getItem().getTitle()), ex);
2305 String.format("Failed to navigate to history: null", ex)); //$NON-NLS-1$
2307 this.mHandler.post(new Runnable() {
2310 DialogHelper.showToast(
2311 NavigationActivity.this,
2312 R.string.msgs_history_unknown, Toast.LENGTH_LONG);
2316 //Not change directory
2322 * Method that request a back action over the navigation history.
2324 * @return boolean If a back action was applied
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();
2335 FileSystemObject info = CommandHelper.getFileInfo(this, path, null);
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);
2349 //Navigate to history
2350 if (this.mHistory.size() > 0) {
2351 return navigateToHistory(this.mHistory.get(this.mHistory.size() - 1));
2355 mClearHistory.setVisibility(View.GONE);
2359 private void openActionsDialog(String path, boolean global) {
2360 FileSystemObject fso = null;
2362 fso = CommandHelper.getFileInfo(this, path, false, null);
2364 throw new NoSuchFileOrDirectory(path);
2366 openActionsDialog(fso, global);
2367 } catch (Exception e) {
2369 ExceptionUtil.translateException(this, e);
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);
2382 * Method that opens the actions dialog
2384 * @param item The path or the {@link FileSystemObject}
2385 * @param global If the menu to display is the one with global actions
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.
2393 ActionsDialog dialog = new ActionsDialog(this, this, item, global, false);
2394 dialog.setOnRequestRefreshListener(this);
2395 dialog.setOnSelectionListener(getCurrentNavigationView());
2400 * Method that opens the search view.
2405 mSearchView.setVisibility(View.VISIBLE);
2406 mSearchView.onActionViewExpanded();
2407 mCustomTitleView.setVisibility(View.GONE);
2410 void closeSearch() {
2411 mSearchView.setVisibility(View.GONE);
2412 mSearchView.onActionViewCollapsed();
2413 mCustomTitleView.setVisibility(View.VISIBLE);
2417 * Method that opens the settings activity.
2421 void openSettings() {
2422 Intent settingsIntent = new Intent(NavigationActivity.this,
2423 SettingsPreferences.class);
2424 startActivityForResult(settingsIntent, INTENT_REQUEST_SETTINGS);
2428 * Method that remove the {@link FileSystemObject} from the history
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();
2451 * Update the history positions after one of the history is removed from drawer
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);
2462 * Method that ask the user to change the access mode prior to crash.
2466 //Show a dialog asking the user
2467 AlertDialog dialog =
2468 DialogHelper.createYesNoDialog(
2470 R.string.msgs_change_to_prompt_access_mode_title,
2471 R.string.msgs_change_to_prompt_access_mode_msg,
2472 new DialogInterface.OnClickListener() {
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);
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.
2489 ConsoleBuilder.changeToNonPrivilegedConsole(NavigationActivity.this);
2492 Preferences.savePreference(
2493 FileManagerSettings.SETTINGS_ACCESS_MODE,
2494 AccessMode.PROMPT, true);
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);
2506 DialogHelper.delegateDialogShow(this, dialog);
2510 * Method that creates a ChRooted environment, protecting the user to break anything in
2514 void createChRooted() {
2515 // If we are in a ChRooted mode, then do nothing
2516 if (this.mChRooted) return;
2517 this.mChRooted = true;
2519 int cc = this.mNavigationViews.length;
2520 for (int i = 0; i < cc; i++) {
2521 this.mNavigationViews[i].createChRooted();
2524 // Remove the selection
2525 cc = this.mNavigationViews.length;
2526 for (int i = 0; i < cc; i++) {
2527 getCurrentNavigationView().onDeselectAll();
2530 // Remove the history (don't allow to access to previous data)
2535 * Method that exits from a ChRooted
2538 void exitChRooted() {
2539 // If we aren't in a ChRooted mode, then do nothing
2540 if (!this.mChRooted) return;
2541 this.mChRooted = false;
2543 int cc = this.mNavigationViews.length;
2544 for (int i = 0; i < cc; i++) {
2545 this.mNavigationViews[i].exitChRooted();
2550 * Method called when a controlled exit is required
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();
2564 FileManagerApplication.destroyBackgroundConsole();
2565 } catch (Throwable ex) {
2569 ConsoleBuilder.destroyConsole();
2570 } catch (Throwable ex) {
2576 * Method that reconfigures the layout for better fit in portrait and landscape modes
2578 private void onLayoutChanged() {
2579 Theme theme = ThemeManager.getCurrentTheme(this);
2580 boolean drawerOpen = mDrawerLayout.isDrawerOpen(Gravity.START);
2582 // Apply only when the orientation was changed
2583 int orientation = getResources().getConfiguration().orientation;
2584 if (this.mOrientation == orientation) return;
2585 this.mOrientation = orientation;
2587 // imitate a closed drawer while layout is rebuilt to avoid NullPointerException
2589 mDrawerLayout.closeDrawer(Gravity.START);
2592 if (this.mOrientation == Configuration.ORIENTATION_LANDSCAPE) {
2594 ViewGroup statusBar = (ViewGroup)findViewById(R.id.navigation_statusbar);
2595 if (statusBar.getParent() != null) {
2596 ViewGroup parent = (ViewGroup) statusBar.getParent();
2597 parent.removeView(statusBar);
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;
2604 int cc = statusBar.getChildCount();
2605 for (int i = 0; i < cc; i++) {
2606 View child = statusBar.getChildAt(i);
2607 if (child instanceof ButtonItem) {
2611 // Currently there isn't overflow menu
2612 int w = abw + rbw - bw;
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(
2619 ViewGroup.LayoutParams.MATCH_PARENT);
2620 statusBar.setLayoutParams(params);
2621 newParent.addView(statusBar);
2624 theme.setBackgroundDrawable(this, statusBar, "titlebar_drawable"); //$NON-NLS-1$
2627 View holder = findViewById(R.id.navigation_statusbar_portrait_holder);
2628 holder.setVisibility(View.GONE);
2632 ViewGroup statusBar = (ViewGroup)findViewById(R.id.navigation_statusbar);
2633 if (statusBar.getParent() != null) {
2634 ViewGroup parent = (ViewGroup) statusBar.getParent();
2635 parent.removeView(statusBar);
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);
2649 theme.setBackgroundDrawable(this, statusBar, "statusbar_drawable"); //$NON-NLS-1$
2652 newParent.setVisibility(View.VISIBLE);
2655 // if drawer was open, imitate reopening
2657 mDrawerToggle.onDrawerOpened(mDrawer);
2662 * Method that removes all the history items that refers to virtual unmounted filesystems
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()) {
2676 mDrawerHistory.removeViewAt(mDrawerHistory.getChildCount() - i - 1);
2680 mDrawerHistoryEmpty.setVisibility(
2681 mDrawerHistory.getChildCount() == 0 ? View.VISIBLE : View.GONE);
2682 updateHistoryPositions();
2686 * Method that removes all the selection items that refers to virtual unmounted filesystems
2688 private void removeUnmountedSelection() {
2689 for (NavigationView view : mNavigationViews) {
2690 view.removeUnmountedSelection();
2692 mSelectionBar.setSelection(getNavigationView(mCurrentNavigationView).getSelectedFiles());
2696 * Method that applies the current theme to the activity
2700 int orientation = getResources().getConfiguration().orientation;
2701 Theme theme = ThemeManager.getCurrentTheme(this);
2702 theme.setBaseThemeNoActionBar(this);
2705 // imitate a closed drawer while layout is rebuilt to avoid NullPointerException
2706 boolean drawerOpen = mDrawerLayout.isDrawerOpen(Gravity.START);
2708 mDrawerLayout.closeDrawer(Gravity.START);
2712 View v = findViewById(R.id.navigation_layout);
2713 theme.setBackgroundDrawable(this, v, "background_drawable"); //$NON-NLS-1$
2716 theme.setTitlebarDrawable(this, getActionBar(), "titlebar_drawable"); //$NON-NLS-1$
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);
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));
2739 SearchManager searchManager = (SearchManager) getSystemService(Context.SEARCH_SERVICE);
2740 mSearchView.setSearchableInfo(searchManager.getSearchableInfo(getComponentName()));
2741 mSearchView.setIconifiedByDefault(false);
2743 mCustomTitleView = (NavigationCustomTitleView) findViewById(R.id.navigation_title_flipper);
2744 mCustomTitleView.setVisibility(View.VISIBLE);
2747 v = findViewById(R.id.navigation_statusbar);
2748 if (orientation == Configuration.ORIENTATION_LANDSCAPE) {
2749 theme.setBackgroundDrawable(this, v, "titlebar_drawable"); //$NON-NLS-1$
2751 theme.setBackgroundDrawable(this, v, "statusbar_drawable"); //$NON-NLS-1$
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$
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$
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$
2780 // - Navigation drawer
2781 v = findViewById(R.id.history_empty);
2782 theme.setTextColor(this, (TextView)v, "text_color"); //$NON-NLS-1$
2784 for (int i=0; i<mDrawerHistory.getChildCount(); i++) {
2785 View item = mDrawerHistory.getChildAt(i);
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$
2794 int cc = this.mNavigationViews.length;
2795 for (int i = 0; i < cc; i++) {
2796 getNavigationView(i).applyTheme();
2799 // if drawer was open, imitate reopening
2801 mDrawerToggle.onDrawerOpened(mDrawer);
2806 * Method that applies the current theme to the tab host
2808 private void applyTabTheme() {
2810 Theme theme = ThemeManager.getCurrentTheme(this);
2812 View v = findViewById(R.id.drawer);
2813 theme.setBackgroundDrawable(this, v, "background_drawable"); //$NON-NLS-1$
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$
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$
2826 public void updateActiveDialog(Dialog dialog) {
2827 mActiveDialog = dialog;