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.SearchManager;
22 import android.content.BroadcastReceiver;
23 import android.content.Context;
24 import android.content.DialogInterface;
25 import android.content.Intent;
26 import android.content.IntentFilter;
27 import android.content.res.Configuration;
28 import android.content.res.XmlResourceParser;
29 import android.database.Cursor;
30 import android.graphics.Color;
31 import android.graphics.drawable.Drawable;
32 import android.net.Uri;
33 import android.nfc.NfcAdapter;
34 import android.nfc.NfcEvent;
35 import android.os.AsyncTask;
36 import android.os.Bundle;
37 import android.os.Environment;
38 import android.os.Handler;
39 import android.os.Parcelable;
40 import android.os.storage.StorageVolume;
41 import android.support.v4.app.ActionBarDrawerToggle;
42 import android.support.v4.widget.DrawerLayout;
43 import android.text.TextUtils;
44 import android.util.Log;
45 import android.view.Gravity;
46 import android.view.KeyEvent;
47 import android.view.MenuItem;
48 import android.view.View;
49 import android.view.View.OnClickListener;
50 import android.view.ViewGroup;
51 import android.widget.AdapterView;
52 import android.widget.AdapterView.OnItemClickListener;
53 import android.widget.ImageButton;
54 import android.widget.ImageView;
55 import android.widget.LinearLayout;
56 import android.widget.ListPopupWindow;
57 import android.widget.ListView;
58 import android.widget.PopupWindow;
59 import android.widget.SearchView;
60 import android.widget.TextView;
61 import android.widget.Toast;
62 import android.widget.Toolbar;
63 import android.widget.ArrayAdapter;
65 import com.android.internal.util.XmlUtils;
66 import com.cyanogenmod.filemanager.FileManagerApplication;
67 import com.cyanogenmod.filemanager.R;
68 import com.cyanogenmod.filemanager.activities.preferences.SettingsPreferences;
69 import com.cyanogenmod.filemanager.adapters.MenuSettingsAdapter;
70 import com.cyanogenmod.filemanager.console.Console;
71 import com.cyanogenmod.filemanager.console.ConsoleAllocException;
72 import com.cyanogenmod.filemanager.console.ConsoleBuilder;
73 import com.cyanogenmod.filemanager.console.InsufficientPermissionsException;
74 import com.cyanogenmod.filemanager.console.NoSuchFileOrDirectory;
75 import com.cyanogenmod.filemanager.console.VirtualConsole;
76 import com.cyanogenmod.filemanager.console.VirtualMountPointConsole;
77 import com.cyanogenmod.filemanager.console.secure.SecureConsole;
78 import com.cyanogenmod.filemanager.listeners.OnHistoryListener;
79 import com.cyanogenmod.filemanager.listeners.OnRequestRefreshListener;
80 import com.cyanogenmod.filemanager.model.Bookmark;
81 import com.cyanogenmod.filemanager.model.DiskUsage;
82 import com.cyanogenmod.filemanager.model.FileSystemObject;
83 import com.cyanogenmod.filemanager.model.History;
84 import com.cyanogenmod.filemanager.model.MountPoint;
85 import com.cyanogenmod.filemanager.model.Bookmark.BOOKMARK_TYPE;
86 import com.cyanogenmod.filemanager.parcelables.HistoryNavigable;
87 import com.cyanogenmod.filemanager.parcelables.NavigationViewInfoParcelable;
88 import com.cyanogenmod.filemanager.parcelables.SearchInfoParcelable;
89 import com.cyanogenmod.filemanager.preferences.AccessMode;
90 import com.cyanogenmod.filemanager.preferences.Bookmarks;
91 import com.cyanogenmod.filemanager.preferences.FileManagerSettings;
92 import com.cyanogenmod.filemanager.preferences.NavigationLayoutMode;
93 import com.cyanogenmod.filemanager.preferences.ObjectIdentifier;
94 import com.cyanogenmod.filemanager.preferences.Preferences;
95 import com.cyanogenmod.filemanager.ui.IconHolder;
96 import com.cyanogenmod.filemanager.ui.ThemeManager;
97 import com.cyanogenmod.filemanager.ui.ThemeManager.Theme;
98 import com.cyanogenmod.filemanager.ui.dialogs.ActionsDialog;
99 import com.cyanogenmod.filemanager.ui.dialogs.FilesystemInfoDialog;
100 import com.cyanogenmod.filemanager.ui.dialogs.InitialDirectoryDialog;
101 import com.cyanogenmod.filemanager.ui.dialogs.FilesystemInfoDialog.OnMountListener;
102 import com.cyanogenmod.filemanager.ui.widgets.Breadcrumb;
103 import com.cyanogenmod.filemanager.ui.widgets.ButtonItem;
104 import com.cyanogenmod.filemanager.ui.widgets.NavigationCustomTitleView;
105 import com.cyanogenmod.filemanager.ui.widgets.NavigationView;
106 import com.cyanogenmod.filemanager.ui.widgets.NavigationView.OnNavigationRequestMenuListener;
107 import com.cyanogenmod.filemanager.ui.widgets.NavigationView.OnNavigationSelectionChangedListener;
108 import com.cyanogenmod.filemanager.ui.widgets.SelectionView;
109 import com.cyanogenmod.filemanager.util.AndroidHelper;
110 import com.cyanogenmod.filemanager.util.BookmarksHelper;
111 import com.cyanogenmod.filemanager.util.CommandHelper;
112 import com.cyanogenmod.filemanager.util.DialogHelper;
113 import com.cyanogenmod.filemanager.util.ExceptionUtil;
114 import com.cyanogenmod.filemanager.util.ExceptionUtil.OnRelaunchCommandResult;
115 import com.cyanogenmod.filemanager.util.FileHelper;
116 import com.cyanogenmod.filemanager.util.MimeTypeHelper.MimeTypeCategory;
117 import com.cyanogenmod.filemanager.util.StorageHelper;
120 import java.io.FileNotFoundException;
121 import java.util.ArrayList;
122 import java.util.Arrays;
123 import java.util.HashMap;
124 import java.util.List;
125 import java.util.Locale;
126 import java.util.Map;
128 import static com.cyanogenmod.filemanager.util.MimeTypeHelper.MimeTypeCategory.*;
131 * The main navigation activity. This activity is the center of the application.
132 * From this the user can navigate, search, make actions.<br/>
133 * This activity is singleTop, so when it is displayed no other activities exists in
135 * This cause an issue with the saved instance of this class, because if another activity
136 * is displayed, and the process is killed, NavigationActivity is started and the saved
137 * instance gets corrupted.<br/>
138 * For this reason the methods {link {@link Activity#onSaveInstanceState(Bundle)} and
139 * {@link Activity#onRestoreInstanceState(Bundle)} are not implemented, and every time
140 * the app is killed, is restarted from his initial state.
142 public class NavigationActivity extends Activity
143 implements OnHistoryListener, OnRequestRefreshListener,
144 OnNavigationRequestMenuListener, OnNavigationSelectionChangedListener {
146 private static final String TAG = "NavigationActivity"; //$NON-NLS-1$
148 private static boolean DEBUG = false;
150 // Bookmark list XML tags
151 private static final String TAG_BOOKMARKS = "Bookmarks"; //$NON-NLS-1$
152 private static final String TAG_BOOKMARK = "bookmark"; //$NON-NLS-1$
154 private static final String STR_USB = "usb"; // $NON-NLS-1$
157 * Intent code for request a search.
159 public static final int INTENT_REQUEST_SEARCH = 10001;
162 * Intent code for request a search.
164 public static final int INTENT_REQUEST_SETTINGS = 20001;
167 * Constant for extra information about selected search entry.
169 public static final String EXTRA_SEARCH_ENTRY_SELECTION =
170 "extra_search_entry_selection"; //$NON-NLS-1$
173 * Constant for extra information about last search data.
175 public static final String EXTRA_SEARCH_LAST_SEARCH_DATA =
176 "extra_search_last_search_data"; //$NON-NLS-1$
179 * Constant for extra information for request a navigation to the passed path.
181 public static final String EXTRA_NAVIGATE_TO =
182 "extra_navigate_to"; //$NON-NLS-1$
185 * Constant for extra information for request to add navigation to the history
187 public static final String EXTRA_ADD_TO_HISTORY =
188 "extra_add_to_history"; //$NON-NLS-1$
190 // The timeout needed to reset the exit status for back button
191 // After this time user need to tap 2 times the back button to
192 // exit, and the toast is shown again after the first tap.
193 private static final int RELEASE_EXIT_CHECK_TIMEOUT = 3500;
196 private Toolbar mToolBar;
197 private SearchView mSearchView;
198 private NavigationCustomTitleView mCustomTitleView;
200 private final BroadcastReceiver mNotificationReceiver = new BroadcastReceiver() {
202 public void onReceive(Context context, Intent intent) {
203 if (intent != null) {
204 if (intent.getAction().compareTo(FileManagerSettings.INTENT_SETTING_CHANGED) == 0) {
205 // The settings has changed
206 String key = intent.getStringExtra(FileManagerSettings.EXTRA_SETTING_CHANGED_KEY);
208 // Disk usage warning level
209 if (key.compareTo(FileManagerSettings.
210 SETTINGS_DISK_USAGE_WARNING_LEVEL.getId()) == 0) {
212 // Set the free disk space warning level of the breadcrumb widget
213 Breadcrumb breadcrumb = getCurrentNavigationView().getBreadcrumb();
214 String fds = Preferences.getSharedPreferences().getString(
215 FileManagerSettings.SETTINGS_DISK_USAGE_WARNING_LEVEL.getId(),
216 (String)FileManagerSettings.
217 SETTINGS_DISK_USAGE_WARNING_LEVEL.getDefaultValue());
218 breadcrumb.setFreeDiskSpaceWarningLevel(Integer.parseInt(fds));
219 breadcrumb.updateMountPointInfo();
223 // Case sensitive sort
224 if (key.compareTo(FileManagerSettings.
225 SETTINGS_CASE_SENSITIVE_SORT.getId()) == 0) {
226 getCurrentNavigationView().refresh();
231 if (key.compareTo(FileManagerSettings.
232 SETTINGS_DISPLAY_THUMBS.getId()) == 0) {
233 // Clean the icon cache applying the current theme
239 if (key.compareTo(FileManagerSettings.
240 SETTINGS_USE_FLINGER.getId()) == 0) {
242 Preferences.getSharedPreferences().getBoolean(
243 FileManagerSettings.SETTINGS_USE_FLINGER.getId(),
244 ((Boolean)FileManagerSettings.
245 SETTINGS_USE_FLINGER.
246 getDefaultValue()).booleanValue());
247 getCurrentNavigationView().setUseFlinger(useFlinger);
252 if (key.compareTo(FileManagerSettings.
253 SETTINGS_ACCESS_MODE.getId()) == 0) {
254 // Is it necessary to create or exit of the ChRooted?
256 FileManagerApplication.
257 getAccessMode().compareTo(AccessMode.SAFE) == 0;
258 if (chRooted != NavigationActivity.this.mChRooted) {
268 if (key.compareTo(FileManagerSettings.
269 SETTINGS_RESTRICT_SECONDARY_USERS_ACCESS.getId()) == 0) {
270 if (AndroidHelper.isSecondaryUser(context)) {
272 Preferences.savePreference(
273 FileManagerSettings.SETTINGS_ACCESS_MODE,
274 AccessMode.SAFE, true);
275 } catch (Throwable ex) {
276 Log.w(TAG, "can't save console preference", ex); //$NON-NLS-1$
278 ConsoleBuilder.changeToNonPrivilegedConsole(context);
283 // Filetime format mode
284 if (key.compareTo(FileManagerSettings.
285 SETTINGS_FILETIME_FORMAT_MODE.getId()) == 0) {
287 synchronized (FileHelper.DATETIME_SYNC) {
288 FileHelper.sReloadDateTimeFormats = true;
289 NavigationActivity.this.getCurrentNavigationView().refresh();
294 } else if (intent.getAction().compareTo(
295 FileManagerSettings.INTENT_FILE_CHANGED) == 0) {
296 // Retrieve the file that was changed
298 intent.getStringExtra(FileManagerSettings.EXTRA_FILE_CHANGED_KEY);
300 FileSystemObject fso = CommandHelper.getFileInfo(context, file, null);
302 getCurrentNavigationView().refresh(fso);
304 } catch (Exception e) {
305 ExceptionUtil.translateException(context, e, true, false);
308 } else if (intent.getAction().compareTo(
309 FileManagerSettings.INTENT_THEME_CHANGED) == 0) {
312 } else if (intent.getAction().compareTo(Intent.ACTION_TIME_CHANGED) == 0 ||
313 intent.getAction().compareTo(Intent.ACTION_DATE_CHANGED) == 0 ||
314 intent.getAction().compareTo(Intent.ACTION_TIMEZONE_CHANGED) == 0) {
316 synchronized (FileHelper.DATETIME_SYNC) {
317 FileHelper.sReloadDateTimeFormats = true;
318 NavigationActivity.this.getCurrentNavigationView().refresh();
320 } else if (intent.getAction().compareTo(
321 FileManagerSettings.INTENT_MOUNT_STATUS_CHANGED) == 0) {
322 onRequestBookmarksRefresh();
323 removeUnmountedHistory();
324 removeUnmountedSelection();
325 } else if(intent.getAction().equals(Intent.ACTION_MEDIA_MOUNTED)) {
326 onRequestBookmarksRefresh();
327 removeUnmountedHistory();
328 removeUnmountedSelection();
334 private OnClickListener mOnClickDrawerTabListener = new OnClickListener() {
336 public void onClick(View v) {
338 case R.id.drawer_bookmarks_tab:
339 if (!mBookmarksTab.isSelected()) {
340 mBookmarksTab.setSelected(true);
341 mHistoryTab.setSelected(false);
342 mBookmarksTab.setTextAppearance(
343 NavigationActivity.this, R.style.primary_text_appearance);
344 mHistoryTab.setTextAppearance(
345 NavigationActivity.this, R.style.secondary_text_appearance);
346 mHistoryLayout.setVisibility(View.GONE);
347 mBookmarksLayout.setVisibility(View.VISIBLE);
351 Preferences.savePreference(FileManagerSettings.USER_PREF_LAST_DRAWER_TAB,
352 Integer.valueOf(0), true);
353 } catch (Exception ex) {
354 Log.e(TAG, "Can't save last drawer tab", ex); //$NON-NLS-1$
357 mClearHistory.setVisibility(View.GONE);
360 case R.id.drawer_history_tab:
361 if (!mHistoryTab.isSelected()) {
362 mHistoryTab.setSelected(true);
363 mBookmarksTab.setSelected(false);
364 mHistoryTab.setTextAppearance(
365 NavigationActivity.this, R.style.primary_text_appearance);
366 mBookmarksTab.setTextAppearance(
367 NavigationActivity.this, R.style.secondary_text_appearance);
368 mBookmarksLayout.setVisibility(View.GONE);
369 mHistoryLayout.setVisibility(View.VISIBLE);
373 Preferences.savePreference(FileManagerSettings.USER_PREF_LAST_DRAWER_TAB,
374 Integer.valueOf(1), true);
375 } catch (Exception ex) {
376 Log.e(TAG, "Can't save last drawer tab", ex); //$NON-NLS-1$
379 mClearHistory.setVisibility(mHistory.size() > 0 ? View.VISIBLE : View.GONE);
388 private OnClickListener mOnClickDrawerActionBarListener = new OnClickListener() {
390 public void onClick(View v) {
392 case R.id.ab_settings:
393 mDrawerLayout.closeDrawer(Gravity.START);
396 case R.id.ab_clear_history:
398 mClearHistory.setVisibility(View.GONE);
406 static String MIME_TYPE_LOCALIZED_NAMES[];
410 static Map<MimeTypeCategory, Drawable> EASY_MODE_ICONS = new
411 HashMap<MimeTypeCategory, Drawable>();
416 NavigationView[] mNavigationViews;
420 ListView mEasyModeListView;
421 private List<History> mHistory;
423 private static final List<MimeTypeCategory> EASY_MODE_LIST = new ArrayList<MimeTypeCategory>() {
434 private ArrayAdapter<MimeTypeCategory> mEasyModeAdapter;
435 private View.OnClickListener mEasyModeItemClickListener = new View.OnClickListener() {
437 public void onClick(View view) {
438 Integer position = (Integer) view.getTag();
443 private int mCurrentNavigationView;
445 private ViewGroup mActionBar;
446 private SelectionView mSelectionBar;
448 private DrawerLayout mDrawerLayout;
449 private ViewGroup mDrawer;
450 private ActionBarDrawerToggle mDrawerToggle;
451 private LinearLayout mDrawerHistory;
452 private TextView mDrawerHistoryEmpty;
454 private TextView mBookmarksTab;
455 private TextView mHistoryTab;
456 private View mBookmarksLayout;
457 private View mHistoryLayout;
459 private ButtonItem mSettings;
460 private ButtonItem mClearHistory;
462 private List<Bookmark> mBookmarks;
463 private List<Bookmark> mSdBookmarks;
464 private LinearLayout mDrawerBookmarks;
466 private boolean mExitFlag = false;
467 private long mExitBackTimeout = -1;
469 private int mOrientation;
481 private AsyncTask<Void, Void, Boolean> mBookmarksTask;
487 protected void onCreate(Bundle state) {
490 Log.d(TAG, "NavigationActivity.onCreate"); //$NON-NLS-1$
493 // Register the broadcast receiver
494 IntentFilter filter = new IntentFilter();
495 filter.addAction(FileManagerSettings.INTENT_SETTING_CHANGED);
496 filter.addAction(FileManagerSettings.INTENT_FILE_CHANGED);
497 filter.addAction(FileManagerSettings.INTENT_THEME_CHANGED);
498 filter.addAction(Intent.ACTION_DATE_CHANGED);
499 filter.addAction(Intent.ACTION_TIME_CHANGED);
500 filter.addAction(Intent.ACTION_TIMEZONE_CHANGED);
501 filter.addAction(FileManagerSettings.INTENT_MOUNT_STATUS_CHANGED);
502 filter.addAction(Intent.ACTION_MEDIA_MOUNTED);
503 registerReceiver(this.mNotificationReceiver, filter);
505 // Set the theme before setContentView
506 Theme theme = ThemeManager.getCurrentTheme(this);
507 theme.setBaseThemeNoActionBar(this);
509 //Set the main layout of the activity
510 setContentView(R.layout.navigation);
512 //Initialize nfc adapter
513 NfcAdapter mNfcAdapter = NfcAdapter.getDefaultAdapter(this);
514 if (mNfcAdapter != null) {
515 mNfcAdapter.setBeamPushUrisCallback(new NfcAdapter.CreateBeamUrisCallback() {
517 public Uri[] createBeamUris(NfcEvent event) {
518 List<FileSystemObject> selectedFiles =
519 getCurrentNavigationView().getSelectedFiles();
520 if (selectedFiles.size() > 0) {
521 List<Uri> fileUri = new ArrayList<Uri>();
522 for (FileSystemObject f : selectedFiles) {
523 //Beam ignores folders and system files
524 if (!FileHelper.isDirectory(f) && !FileHelper.isSystemFile(f)) {
525 fileUri.add(Uri.fromFile(new File(f.getFullPath())));
528 if (fileUri.size() > 0) {
529 return fileUri.toArray(new Uri[fileUri.size()]);
537 //Initialize activity
541 initNavigationViews();
543 // As we're using a Toolbar, we should retrieve it and set it
544 // to be our ActionBar
545 mToolBar = (Toolbar) findViewById(R.id.material_toolbar);
546 setActionBar(mToolBar);
548 //Initialize action bars
549 initTitleActionBar();
550 initStatusActionBar();
553 // Initialize navigation drawer
557 // Adjust layout (only when start on landscape mode)
558 int orientation = getResources().getConfiguration().orientation;
559 if (orientation == Configuration.ORIENTATION_LANDSCAPE) {
562 this.mOrientation = orientation;
567 // Show welcome message
570 this.mHandler = new Handler();
571 this.mHandler.post(new Runnable() {
574 // Initialize console
577 //Initialize navigation
578 int cc = NavigationActivity.this.mNavigationViews.length;
579 for (int i = 0; i < cc; i++) {
580 initNavigation(i, false, getIntent());
583 //Check the intent action
584 checkIntent(getIntent());
588 MIME_TYPE_LOCALIZED_NAMES = MimeTypeCategory.getFriendlyLocalizedNames(NavigationActivity
591 EASY_MODE_ICONS.put(MimeTypeCategory.NONE, getResources().getDrawable(R.drawable
593 EASY_MODE_ICONS.put(MimeTypeCategory.IMAGE, getResources().getDrawable(R.drawable
595 EASY_MODE_ICONS.put(MimeTypeCategory.VIDEO, getResources().getDrawable(R.drawable
597 EASY_MODE_ICONS.put(MimeTypeCategory.AUDIO, getResources().getDrawable(R.drawable
599 EASY_MODE_ICONS.put(MimeTypeCategory.DOCUMENT, getResources().getDrawable(R.drawable
601 EASY_MODE_ICONS.put(MimeTypeCategory.APP, getResources().getDrawable(R.drawable
602 .ic_em_application));
605 super.onCreate(state);
609 protected void onResume() {
612 if (mSearchView.getVisibility() == View.VISIBLE) {
616 // Check restrictions
617 if (!FileManagerApplication.checkRestrictSecondaryUsersAccess(this, mChRooted)) {
621 // Check that the current dir is mounted (for virtual filesystems)
622 String curDir = mNavigationViews[mCurrentNavigationView].getCurrentDir();
623 if (curDir != null) {
624 VirtualMountPointConsole vc = VirtualMountPointConsole.getVirtualConsoleForPath(
625 mNavigationViews[mCurrentNavigationView].getCurrentDir());
626 if (vc != null && !vc.isMounted()) {
627 onRequestBookmarksRefresh();
628 removeUnmountedHistory();
629 removeUnmountedSelection();
631 Intent intent = new Intent();
632 intent.putExtra(EXTRA_ADD_TO_HISTORY, false);
633 initNavigation(NavigationActivity.this.mCurrentNavigationView, false, intent);
639 protected void onPostCreate(Bundle savedInstanceState) {
640 super.onPostCreate(savedInstanceState);
641 // Sync the toggle state after onRestoreInstanceState has occurred.
642 mDrawerToggle.syncState();
649 protected void onNewIntent(Intent intent) {
650 //Initialize navigation
651 initNavigation(this.mCurrentNavigationView, true, intent);
653 //Check the intent action
661 public void onConfigurationChanged(Configuration newConfig) {
662 super.onConfigurationChanged(newConfig);
664 mDrawerToggle.onConfigurationChanged(newConfig);
671 public boolean onOptionsItemSelected(MenuItem item) {
672 if (mDrawerToggle.onOptionsItemSelected(item)) {
675 return super.onOptionsItemSelected(item);
682 protected void onDestroy() {
684 Log.d(TAG, "NavigationActivity.onDestroy"); //$NON-NLS-1$
687 // Unregister the receiver
689 unregisterReceiver(this.mNotificationReceiver);
690 } catch (Throwable ex) {
694 //All destroy. Continue
699 * Method that returns the current navigation view.
701 * @return NavigationView The current navigation view
703 public NavigationView getCurrentNavigationView() {
704 return getNavigationView(this.mCurrentNavigationView);
708 * Method that returns the current navigation view.
710 * @param viewId The view to return
711 * @return NavigationView The current navigation view
713 public NavigationView getNavigationView(int viewId) {
714 if (this.mNavigationViews == null) return null;
715 return this.mNavigationViews[viewId];
719 * Method that initializes the activity.
721 private void init() {
722 this.mHistory = new ArrayList<History>();
723 this.mChRooted = FileManagerApplication.getAccessMode().compareTo(AccessMode.SAFE) == 0;
727 * Method that displays a welcome message the first time the user
728 * access the application
730 private void showWelcomeMsg() {
731 boolean firstUse = Preferences.getSharedPreferences().getBoolean(
732 FileManagerSettings.SETTINGS_FIRST_USE.getId(),
733 ((Boolean)FileManagerSettings.SETTINGS_FIRST_USE.getDefaultValue()).booleanValue());
735 //Display the welcome message?
736 if (firstUse && FileManagerApplication.hasShellCommands()) {
737 // open navigation drawer to show user that it exists
738 mDrawerLayout.openDrawer(Gravity.START);
740 AlertDialog dialog = DialogHelper.createAlertDialog(this,
741 R.mipmap.ic_launcher_filemanager, R.string.welcome_title,
742 getString(R.string.welcome_msg), false);
743 DialogHelper.delegateDialogShow(this, dialog);
745 // Don't display again this dialog
747 Preferences.savePreference(
748 FileManagerSettings.SETTINGS_FIRST_USE, Boolean.FALSE, true);
749 } catch (Exception e) {/**NON BLOCK**/}
754 * Method that initializes the titlebar of the activity.
756 private void initTitleActionBar() {
757 //Inflate the view and associate breadcrumb
758 View titleLayout = getLayoutInflater().inflate(
759 R.layout.navigation_view_customtitle, null, false);
760 NavigationCustomTitleView title =
761 (NavigationCustomTitleView)titleLayout.findViewById(R.id.navigation_title_flipper);
762 title.setOnHistoryListener(this);
763 Breadcrumb breadcrumb = (Breadcrumb)title.findViewById(R.id.breadcrumb_view);
764 int cc = this.mNavigationViews.length;
765 for (int i = 0; i < cc; i++) {
766 this.mNavigationViews[i].setBreadcrumb(breadcrumb);
767 this.mNavigationViews[i].setOnHistoryListener(this);
768 this.mNavigationViews[i].setOnNavigationSelectionChangedListener(this);
769 this.mNavigationViews[i].setOnNavigationOnRequestMenuListener(this);
770 this.mNavigationViews[i].setCustomTitle(title);
773 // Set the free disk space warning level of the breadcrumb widget
774 String fds = Preferences.getSharedPreferences().getString(
775 FileManagerSettings.SETTINGS_DISK_USAGE_WARNING_LEVEL.getId(),
776 (String)FileManagerSettings.SETTINGS_DISK_USAGE_WARNING_LEVEL.getDefaultValue());
777 breadcrumb.setFreeDiskSpaceWarningLevel(Integer.parseInt(fds));
779 //Configure the action bar options
780 getActionBar().setBackgroundDrawable(
781 getResources().getDrawable(R.drawable.bg_material_titlebar));
782 mToolBar.addView(titleLayout);
786 * Method that initializes the statusbar of the activity.
788 private void initStatusActionBar() {
789 //Performs a width calculation of buttons. Buttons exceeds the width
790 //of the action bar should be hidden
791 //This application not use android ActionBar because the application
792 //make uses of the title and bottom areas, and wants to force to show
793 //the overflow button (without care of physical buttons)
794 this.mActionBar = (ViewGroup)findViewById(R.id.navigation_actionbar);
795 this.mActionBar.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
797 public void onLayoutChange(
798 View v, int left, int top, int right, int bottom, int oldLeft,
799 int oldTop, int oldRight, int oldBottom) {
800 //Get the width of the action bar
801 int w = v.getMeasuredWidth();
803 //Wake through children calculation his dimensions
804 int bw = (int)getResources().getDimension(R.dimen.default_buttom_width);
806 final ViewGroup abView = ((ViewGroup)v);
807 int cc = abView.getChildCount();
808 for (int i = 0; i < cc; i++) {
809 View child = abView.getChildAt(i);
810 child.setVisibility(cw + bw > w ? View.INVISIBLE : View.VISIBLE);
816 // Have overflow menu? Actually no. There is only a search action, so just hide
818 View overflow = findViewById(R.id.ab_overflow);
819 overflow.setVisibility(View.GONE);
821 // Show the status bar
822 View statusBar = findViewById(R.id.navigation_statusbar_portrait_holder);
823 statusBar.setVisibility(View.VISIBLE);
827 * Method that initializes the selectionbar of the activity.
829 private void initSelectionBar() {
830 this.mSelectionBar = (SelectionView)findViewById(R.id.navigation_selectionbar);
834 * Method that initializes the navigation drawer of the activity.
836 private void initDrawer() {
837 mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
838 //Set our status bar color
839 mDrawerLayout.setStatusBarBackgroundColor(R.color.material_palette_blue_primary_dark);
840 mDrawer = (ViewGroup) findViewById(R.id.drawer);
841 mDrawerBookmarks = (LinearLayout) findViewById(R.id.bookmarks_list);
842 mDrawerHistory = (LinearLayout) findViewById(R.id.history_list);
843 mDrawerHistoryEmpty = (TextView) findViewById(R.id.history_empty);
845 mBookmarksLayout = findViewById(R.id.drawer_bookmarks);
846 mHistoryLayout = findViewById(R.id.drawer_history);
847 mBookmarksTab = (TextView) findViewById(R.id.drawer_bookmarks_tab);
848 mHistoryTab = (TextView) findViewById(R.id.drawer_history_tab);
849 mBookmarksTab.setOnClickListener(mOnClickDrawerTabListener);
850 mHistoryTab.setOnClickListener(mOnClickDrawerTabListener);
852 mSettings = (ButtonItem) findViewById(R.id.ab_settings);
853 mSettings.setOnClickListener(mOnClickDrawerActionBarListener);
854 mClearHistory = (ButtonItem) findViewById(R.id.ab_clear_history);
855 mClearHistory.setOnClickListener(mOnClickDrawerActionBarListener);
857 // Restore the last tab pressed
858 Integer lastTab = Preferences.getSharedPreferences().getInt(
859 FileManagerSettings.USER_PREF_LAST_DRAWER_TAB.getId(),
860 (Integer) FileManagerSettings.USER_PREF_LAST_DRAWER_TAB
862 mOnClickDrawerTabListener.onClick(lastTab == 0 ? mBookmarksTab : mHistoryTab);
864 // Set the navigation drawer "hamburger" icon
865 mDrawerToggle = new ActionBarDrawerToggle(this, mDrawerLayout,
866 R.drawable.ic_material_light_navigation_drawer,
867 R.string.drawer_open, R.string.drawer_close) {
869 /** Called when a drawer has settled in a completely closed state. */
870 public void onDrawerClosed(View view) {
871 super.onDrawerClosed(view);
874 /** Called when a drawer has settled in a completely open state. */
875 public void onDrawerOpened(View drawerView) {
876 super.onDrawerOpened(drawerView);
880 // Set the drawer toggle as the DrawerListener
881 mDrawerLayout.setDrawerListener(mDrawerToggle);
885 * Method that adds a history entry to the history list in the drawer
887 private void addHistoryToDrawer(int index, HistoryNavigable navigable) {
888 // hide empty message
889 mDrawerHistoryEmpty.setVisibility(View.GONE);
891 Theme theme = ThemeManager.getCurrentTheme(this);
892 IconHolder iconholder = new IconHolder(this, false);
894 // inflate single bookmark layout item and fill it
895 LinearLayout view = (LinearLayout) getLayoutInflater().inflate(
896 R.layout.history_item, null);
898 ImageView iconView = (ImageView) view
899 .findViewById(R.id.history_item_icon);
900 TextView name = (TextView) view.findViewById(R.id.history_item_name);
901 TextView directory = (TextView) view
902 .findViewById(R.id.history_item_directory);
904 Drawable icon = iconholder.getDrawable("ic_fso_folder_drawable"); //$NON-NLS-1$
905 if (navigable instanceof SearchInfoParcelable) {
906 icon = iconholder.getDrawable("ic_history_search_drawable"); //$NON-NLS-1$
908 iconView.setImageDrawable(icon);
910 String title = navigable.getTitle();
911 if (title == null || title.trim().length() == 0) {
912 title = getString(R.string.root_directory_name);
916 directory.setText(navigable.getDescription());
918 theme.setTextColor(this, name, "text_color");
919 theme.setTextColor(this, directory, "text_color");
922 view.setOnClickListener(new OnClickListener() {
924 public void onClick(View v) {
925 final int index = mDrawerHistory.indexOfChild(v);
926 final int count = mDrawerHistory.getChildCount();
927 final History history = mHistory.get(count - index - 1);
929 navigateToHistory(history);
930 mDrawerLayout.closeDrawer(Gravity.START);
934 // add as first child
935 mDrawerHistory.addView(view, 0);
937 // Show clear button if history tab is selected
938 mClearHistory.setVisibility(mHistoryTab.isSelected() ? View.VISIBLE : View.GONE);
942 * Method takes a bookmark as argument and adds it to mBookmarks and the
945 public void addBookmark(Bookmark bookmark) {
946 mBookmarks.add(bookmark);
947 addBookmarkToDrawer(bookmark);
951 * Show the easy mode view
953 private void performShowEasyMode() {
954 mEasyModeListView.setVisibility(View.VISIBLE);
955 getCurrentNavigationView().setVisibility(View.GONE);
959 * Hide the easy mode view
961 private void performHideEasyMode() {
962 mEasyModeListView.setVisibility(View.GONE);
963 getCurrentNavigationView().setVisibility(View.VISIBLE);
967 * Method takes a bookmark as argument and adds it to the bookmark list in
970 private void addBookmarkToDrawer(Bookmark bookmark) {
971 Theme theme = ThemeManager.getCurrentTheme(this);
972 IconHolder iconholder = new IconHolder(this, false);
974 // inflate single bookmark layout item and fill it
975 LinearLayout view = (LinearLayout) getLayoutInflater().inflate(
976 R.layout.bookmarks_item, null);
978 ImageView icon = (ImageView) view
979 .findViewById(R.id.bookmarks_item_icon);
980 TextView name = (TextView) view.findViewById(R.id.bookmarks_item_name);
981 TextView path = (TextView) view.findViewById(R.id.bookmarks_item_path);
982 ImageButton actionButton = (ImageButton) view
983 .findViewById(R.id.bookmarks_item_action);
985 name.setText(bookmark.mName);
986 path.setText(bookmark.mPath);
988 theme.setTextColor(this, name, "text_color");
989 theme.setTextColor(this, path, "text_color");
991 icon.setImageDrawable(iconholder.getDrawable(BookmarksHelper
992 .getIcon(bookmark)));
994 Drawable action = null;
995 String actionCd = null;
996 if (bookmark.mType.compareTo(BOOKMARK_TYPE.HOME) == 0) {
997 action = iconholder.getDrawable("ic_edit_home_bookmark_drawable"); //$NON-NLS-1$
998 actionCd = getApplicationContext().getString(
999 R.string.bookmarks_button_config_cd);
1001 else if (bookmark.mType.compareTo(BOOKMARK_TYPE.USER_DEFINED) == 0) {
1002 action = iconholder.getDrawable("ic_close_drawable"); //$NON-NLS-1$
1003 actionCd = getApplicationContext().getString(
1004 R.string.bookmarks_button_remove_bookmark_cd);
1007 actionButton.setImageDrawable(action);
1008 actionButton.setVisibility(action != null ? View.VISIBLE : View.GONE);
1009 actionButton.setOnClickListener(new OnClickListener() {
1011 public void onClick(View view) {
1012 final View v = (View) view.getParent();
1013 final int index = mDrawerBookmarks.indexOfChild(v);
1014 final Bookmark bookmark = mBookmarks.get(index);
1017 if (bookmark.mType.compareTo(BOOKMARK_TYPE.HOME) == 0) {
1018 // Show a dialog for configure initial directory
1019 InitialDirectoryDialog dialog = new InitialDirectoryDialog(
1020 NavigationActivity.this);
1021 dialog.setOnValueChangedListener(new InitialDirectoryDialog.OnValueChangedListener() {
1023 public void onValueChanged(String newInitialDir) {
1024 bookmark.mPath = newInitialDir;
1026 // reset drawer bookmarks list
1035 if (bookmark.mType.compareTo(BOOKMARK_TYPE.USER_DEFINED) == 0) {
1036 boolean result = Bookmarks.removeBookmark(
1037 getApplicationContext(), bookmark);
1038 if (!result) { // Show warning
1039 DialogHelper.showToast(getApplicationContext(),
1040 R.string.msgs_operation_failure,
1041 Toast.LENGTH_SHORT);
1044 mBookmarks.remove(bookmark);
1045 mDrawerBookmarks.removeView(v);
1050 actionButton.setContentDescription(actionCd);
1052 // handle item click
1053 view.setOnClickListener(new OnClickListener() {
1055 public void onClick(View v) {
1056 final int index = mDrawerBookmarks.indexOfChild(v);
1057 final Bookmark bookmark = mBookmarks.get(index);
1059 boolean showEasyMode = (mSdBookmarks.contains(bookmark)) &&
1060 getResources().getBoolean(R.bool.cmcc_show_easy_mode);
1062 // try to navigate to the bookmark path
1064 FileSystemObject fso = CommandHelper.getFileInfo(
1065 getApplicationContext(), bookmark.mPath, null);
1068 performShowEasyMode();
1070 performHideEasyMode();
1072 getCurrentNavigationView().open(fso);
1073 mDrawerLayout.closeDrawer(Gravity.START);
1076 // The bookmark does not exist, delete the user-defined
1079 Bookmarks.removeBookmark(getApplicationContext(),
1082 // reset bookmarks list to default
1085 catch (Exception ex) {
1089 catch (Exception e) { // Capture the exception
1091 .translateException(NavigationActivity.this, e);
1092 if (e instanceof NoSuchFileOrDirectory
1093 || e instanceof FileNotFoundException) {
1094 // The bookmark does not exist, delete the user-defined
1097 Bookmarks.removeBookmark(getApplicationContext(),
1100 // reset bookmarks list to default
1103 catch (Exception ex) {
1111 mDrawerBookmarks.addView(view);
1115 * Method that initializes the bookmarks.
1117 private synchronized void initBookmarks() {
1118 if (mBookmarksTask != null &&
1119 !mBookmarksTask.getStatus().equals(AsyncTask.Status.FINISHED)) {
1123 // Retrieve the loading view
1124 final View waiting = findViewById(R.id.bookmarks_loading);
1126 // Load bookmarks in background
1127 mBookmarksTask = new AsyncTask<Void, Void, Boolean>() {
1131 protected Boolean doInBackground(Void... params) {
1133 mBookmarks = loadBookmarks();
1134 return Boolean.TRUE;
1137 catch (Exception e) {
1139 return Boolean.FALSE;
1144 protected void onPreExecute() {
1145 waiting.setVisibility(View.VISIBLE);
1146 mDrawerBookmarks.removeAllViews();
1150 protected void onPostExecute(Boolean result) {
1151 waiting.setVisibility(View.GONE);
1152 if (result.booleanValue()) {
1153 for (Bookmark bookmark : mBookmarks) {
1154 addBookmarkToDrawer(bookmark);
1158 if (this.mCause != null) {
1159 ExceptionUtil.translateException(
1160 NavigationActivity.this, this.mCause);
1163 mBookmarksTask = null;
1167 protected void onCancelled() {
1168 waiting.setVisibility(View.GONE);
1169 mBookmarksTask = null;
1172 mBookmarksTask.execute();
1176 * Method that loads all kind of bookmarks and join in an array to be used
1177 * in the listview adapter.
1179 * @return List<Bookmark>
1182 List<Bookmark> loadBookmarks() {
1183 // Bookmarks = HOME + FILESYSTEM + SD STORAGES + USER DEFINED
1184 // In ChRooted mode = SD STORAGES + USER DEFINED (from SD STORAGES)
1185 List<Bookmark> bookmarks = new ArrayList<Bookmark>();
1186 if (!this.mChRooted) {
1187 bookmarks.add(loadHomeBookmarks());
1188 bookmarks.addAll(loadFilesystemBookmarks());
1190 mSdBookmarks = loadSdStorageBookmarks();
1191 bookmarks.addAll(mSdBookmarks);
1192 bookmarks.addAll(loadVirtualBookmarks());
1193 bookmarks.addAll(loadUserBookmarks());
1198 * Method that loads the home bookmark from the user preference.
1200 * @return Bookmark The bookmark loaded
1202 private Bookmark loadHomeBookmarks() {
1203 String initialDir = Preferences.getSharedPreferences().getString(
1204 FileManagerSettings.SETTINGS_INITIAL_DIR.getId(),
1205 (String) FileManagerSettings.SETTINGS_INITIAL_DIR
1206 .getDefaultValue());
1207 return new Bookmark(BOOKMARK_TYPE.HOME,
1208 getString(R.string.bookmarks_home), initialDir);
1212 * Method that loads the filesystem bookmarks from the internal xml file.
1213 * (defined by this application)
1215 * @return List<Bookmark> The bookmarks loaded
1217 private List<Bookmark> loadFilesystemBookmarks() {
1219 // Initialize the bookmarks
1220 List<Bookmark> bookmarks = new ArrayList<Bookmark>();
1222 // Read the command list xml file
1223 XmlResourceParser parser = getResources().getXml(
1224 R.xml.filesystem_bookmarks);
1227 // Find the root element
1228 XmlUtils.beginDocument(parser, TAG_BOOKMARKS);
1230 XmlUtils.nextElement(parser);
1231 String element = parser.getName();
1232 if (element == null) {
1236 if (TAG_BOOKMARK.equals(element)) {
1237 CharSequence name = null;
1238 CharSequence directory = null;
1241 name = getString(parser.getAttributeResourceValue(
1242 R.styleable.Bookmark_name, 0));
1244 catch (Exception e) {
1248 directory = getString(parser
1249 .getAttributeResourceValue(
1250 R.styleable.Bookmark_directory, 0));
1252 catch (Exception e) {
1255 if (directory == null) {
1257 .getAttributeValue(R.styleable.Bookmark_directory);
1259 if (name != null && directory != null) {
1260 bookmarks.add(new Bookmark(
1261 BOOKMARK_TYPE.FILESYSTEM, name.toString(),
1262 directory.toString()));
1267 // Return the bookmarks
1275 catch (Throwable ex) {
1276 Log.e(TAG, "Load filesystem bookmarks failed", ex); //$NON-NLS-1$
1280 return new ArrayList<Bookmark>();
1284 * Method that loads the secure digital card storage bookmarks from the
1287 * @return List<Bookmark> The bookmarks loaded
1289 private List<Bookmark> loadSdStorageBookmarks() {
1290 // Initialize the bookmarks
1291 List<Bookmark> bookmarks = new ArrayList<Bookmark>();
1294 // Recovery sdcards from storage manager
1295 StorageVolume[] volumes = StorageHelper
1296 .getStorageVolumes(getApplication());
1297 for (StorageVolume volume: volumes) {
1298 if (volume != null) {
1299 String mountedState = volume.getState();
1300 String path = volume.getPath();
1301 if (!Environment.MEDIA_MOUNTED.equalsIgnoreCase(mountedState) &&
1302 !Environment.MEDIA_MOUNTED_READ_ONLY.equalsIgnoreCase(mountedState)) {
1303 Log.w(TAG, "Ignoring '" + path + "' with state of '"+ mountedState + "'");
1306 if (!TextUtils.isEmpty(path)) {
1307 String lowerPath = path.toLowerCase(Locale.ROOT);
1309 if (lowerPath.contains(STR_USB)) {
1310 bookmark = new Bookmark(BOOKMARK_TYPE.USB, StorageHelper
1311 .getStorageVolumeDescription(getApplication(), volume), path);
1313 bookmark = new Bookmark(BOOKMARK_TYPE.SDCARD, StorageHelper
1314 .getStorageVolumeDescription(getApplication(), volume), path);
1316 bookmarks.add(bookmark);
1321 // Return the bookmarks
1324 catch (Throwable ex) {
1325 Log.e(TAG, "Load filesystem bookmarks failed", ex); //$NON-NLS-1$
1329 return new ArrayList<Bookmark>();
1333 * Method that loads all virtual mount points.
1335 * @return List<Bookmark> The bookmarks loaded
1337 private List<Bookmark> loadVirtualBookmarks() {
1338 // Initialize the bookmarks
1339 List<Bookmark> bookmarks = new ArrayList<Bookmark>();
1340 List<MountPoint> mps = VirtualMountPointConsole.getVirtualMountPoints();
1341 for (MountPoint mp : mps) {
1342 BOOKMARK_TYPE type = null;
1344 if (mp.isSecure()) {
1345 type = BOOKMARK_TYPE.SECURE;
1346 name = getString(R.string.bookmarks_secure);
1347 } else if (mp.isRemote()) {
1348 type = BOOKMARK_TYPE.REMOTE;
1349 name = getString(R.string.bookmarks_remote);
1353 bookmarks.add(new Bookmark(type, name, mp.getMountPoint()));
1359 * Method that loads the user bookmarks (added by the user).
1361 * @return List<Bookmark> The bookmarks loaded
1363 private List<Bookmark> loadUserBookmarks() {
1364 List<Bookmark> bookmarks = new ArrayList<Bookmark>();
1365 Cursor cursor = Bookmarks.getAllBookmarks(this.getContentResolver());
1367 if (cursor != null && cursor.moveToFirst()) {
1369 Bookmark bm = new Bookmark(cursor);
1371 && !StorageHelper.isPathInStorageVolume(bm.mPath)) {
1376 while (cursor.moveToNext());
1381 if (cursor != null) {
1385 catch (Exception e) {
1390 // Remove bookmarks from virtual storage if the filesystem is not mount
1391 int c = bookmarks.size() - 1;
1392 for (int i = c; i >= 0; i--) {
1393 VirtualMountPointConsole vc =
1394 VirtualMountPointConsole.getVirtualConsoleForPath(bookmarks.get(i).mPath);
1395 if (vc != null && !vc.isMounted()) {
1396 bookmarks.remove(i);
1404 * Method that initializes the navigation views of the activity
1406 private void initNavigationViews() {
1407 //Get the navigation views (wishlist: multiple view; for now only one view)
1408 this.mNavigationViews = new NavigationView[1];
1409 this.mCurrentNavigationView = 0;
1411 this.mNavigationViews[0] = (NavigationView)findViewById(R.id.navigation_view);
1412 this.mNavigationViews[0].setId(0);
1413 this.mEasyModeListView = (ListView) findViewById(R.id.lv_easy_mode);
1414 mEasyModeAdapter = new ArrayAdapter<MimeTypeCategory>(this, R.layout
1415 .navigation_view_simple_item) {
1417 public View getView(int position, View convertView, ViewGroup parent) {
1418 convertView = (convertView == null) ?getLayoutInflater().inflate(R.layout
1419 .navigation_view_simple_item, parent, false) : convertView;
1420 MimeTypeCategory item = getItem(position);
1421 String typeTitle = MIME_TYPE_LOCALIZED_NAMES[item.ordinal()];
1422 TextView typeTitleTV = (TextView) convertView
1423 .findViewById(R.id.navigation_view_item_name);
1424 ImageView typeIconIV = (ImageView) convertView
1425 .findViewById(R.id.navigation_view_item_icon);
1426 View checkBoxView = convertView.findViewById(R.id.navigation_view_item_check);
1427 checkBoxView.setVisibility(View.GONE);
1428 typeTitleTV.setText(typeTitle);
1429 typeIconIV.setImageDrawable(EASY_MODE_ICONS.get(item));
1430 convertView.setOnClickListener(mEasyModeItemClickListener);
1431 convertView.setTag(position);
1435 mEasyModeAdapter.addAll(EASY_MODE_LIST);
1436 mEasyModeListView.setAdapter(mEasyModeAdapter);
1439 private void onClicked(int position) {
1440 Intent intent = new Intent(this, SearchActivity.class);
1441 intent.setAction(Intent.ACTION_SEARCH);
1442 intent.putExtra(SearchActivity.EXTRA_SEARCH_DIRECTORY,
1443 getCurrentNavigationView().getCurrentDir());
1444 intent.putExtra(SearchManager.QUERY, "*"); // Use wild-card '*'
1446 if (position == 0) {
1447 performHideEasyMode();
1451 ArrayList<MimeTypeCategory> searchCategories = new ArrayList<MimeTypeCategory>();
1452 MimeTypeCategory selectedCategory = EASY_MODE_LIST.get(position);
1453 searchCategories.add(selectedCategory);
1454 // a one off case where we implicitly want to also search for TEXT mimetypes when the
1455 // DOCUMENTS category is selected
1456 if (selectedCategory == MimeTypeCategory.DOCUMENT) {
1457 searchCategories.add(MimeTypeCategory.TEXT);
1459 intent.putExtra(SearchActivity.EXTRA_SEARCH_MIMETYPE, searchCategories);
1462 startActivity(intent);
1466 * Method that initialize the console
1469 void initConsole() {
1470 //Create the default console (from the preferences)
1472 Console console = ConsoleBuilder.getConsole(NavigationActivity.this);
1473 if (console == null) {
1474 throw new ConsoleAllocException("console == null"); //$NON-NLS-1$
1476 } catch (Throwable ex) {
1477 if (!NavigationActivity.this.mChRooted) {
1478 //Show exception and exit
1479 Log.e(TAG, getString(R.string.msgs_cant_create_console), ex);
1480 // We don't have any console
1481 // Show exception and exit
1482 DialogHelper.showToast(
1483 NavigationActivity.this,
1484 R.string.msgs_cant_create_console, Toast.LENGTH_LONG);
1489 // We are in a trouble (something is not allowing creating the console)
1490 // Ask the user to return to prompt or root access mode mode with a
1491 // non-privileged console, prior to make crash the application
1498 * Method that initializes the navigation.
1500 * @param viewId The navigation view identifier where apply the navigation
1501 * @param restore Initialize from a restore info
1502 * @param intent The current intent
1505 void initNavigation(final int viewId, final boolean restore, final Intent intent) {
1506 final NavigationView navigationView = getNavigationView(viewId);
1507 this.mHandler.post(new Runnable() {
1510 //Is necessary navigate?
1512 applyInitialDir(navigationView, intent);
1519 * Method that applies the user-defined initial directory
1521 * @param navigationView The navigation view
1522 * @param intent The current intent
1525 void applyInitialDir(final NavigationView navigationView, final Intent intent) {
1526 //Load the user-defined initial directory
1528 Preferences.getSharedPreferences().getString(
1529 FileManagerSettings.SETTINGS_INITIAL_DIR.getId(),
1530 (String)FileManagerSettings.
1531 SETTINGS_INITIAL_DIR.getDefaultValue());
1533 // Check if request navigation to directory (use as default), and
1534 // ensure chrooted and absolute path
1535 String navigateTo = intent.getStringExtra(EXTRA_NAVIGATE_TO);
1536 if (navigateTo != null && navigateTo.length() > 0) {
1537 initialDir = navigateTo;
1538 } else if (intent.getAction().equals(Intent.ACTION_VIEW)) {
1539 Uri data = intent.getData();
1540 if (data != null && (FileHelper.FILE_URI_SCHEME.equals(data.getScheme())
1541 || FileHelper.FOLDER_URI_SCHEME.equals(data.getScheme())
1542 || FileHelper.DIRECTORY_URI_SCHEME.equals(data.getScheme()))) {
1543 File path = new File(data.getPath());
1544 if (path.isDirectory()) {
1545 initialDir = path.getAbsolutePath();
1551 final boolean addToHistory = intent.getBooleanExtra(EXTRA_ADD_TO_HISTORY, true);
1553 // We cannot navigate to a secure console if is unmount, go to root in that case
1554 VirtualConsole vc = VirtualMountPointConsole.getVirtualConsoleForPath(initialDir);
1555 if (vc != null && vc instanceof SecureConsole && !((SecureConsole) vc).isMounted()) {
1556 initialDir = FileHelper.ROOT_DIRECTORY;
1559 if (this.mChRooted) {
1560 // Initial directory is the first external sdcard (sdcard, emmc, usb, ...)
1561 if (!StorageHelper.isPathInStorageVolume(initialDir)) {
1562 StorageVolume[] volumes =
1563 StorageHelper.getStorageVolumes(this);
1564 if (volumes != null && volumes.length > 0) {
1565 initialDir = volumes[0].getPath();
1566 //Ensure that initial directory is an absolute directory
1567 initialDir = FileHelper.getAbsPath(initialDir);
1569 // Show exception and exit
1570 DialogHelper.showToast(
1572 R.string.msgs_cant_create_console, Toast.LENGTH_LONG);
1578 //Ensure that initial directory is an absolute directory
1579 final String userInitialDir = initialDir;
1580 initialDir = FileHelper.getAbsPath(initialDir);
1581 final String absInitialDir = initialDir;
1582 File f = new File(initialDir);
1583 boolean exists = f.exists();
1585 // Fix for /data/media/0. Libcore doesn't detect it correctly.
1587 exists = CommandHelper.getFileInfo(this, initialDir, false, null) != null;
1588 } catch (InsufficientPermissionsException ipex) {
1589 ExceptionUtil.translateException(
1590 this, ipex, false, true, new OnRelaunchCommandResult() {
1592 public void onSuccess() {
1593 navigationView.changeCurrentDir(absInitialDir, addToHistory);
1596 public void onFailed(Throwable cause) {
1597 showInitialInvalidDirectoryMsg(userInitialDir);
1598 navigationView.changeCurrentDir(FileHelper.ROOT_DIRECTORY,
1602 public void onCancelled() {
1603 showInitialInvalidDirectoryMsg(userInitialDir);
1604 navigationView.changeCurrentDir(FileHelper.ROOT_DIRECTORY,
1609 // Asynchronous mode
1611 } catch (Exception ex) {
1612 // We are not interested in other exceptions
1613 ExceptionUtil.translateException(this, ex, true, false);
1616 // Check again the initial directory
1618 showInitialInvalidDirectoryMsg(userInitialDir);
1619 initialDir = FileHelper.ROOT_DIRECTORY;
1622 // Weird, but we have a valid initial directory
1626 boolean needsEasyMode = false;
1627 if (mSdBookmarks != null ) {
1628 for (Bookmark bookmark :mSdBookmarks) {
1629 if (bookmark.mPath.equalsIgnoreCase(initialDir)) {
1630 needsEasyMode = true;
1636 needsEasyMode = needsEasyMode
1637 && getResources().getBoolean(R.bool.cmcc_show_easy_mode);
1638 if (needsEasyMode) {
1639 performShowEasyMode();
1641 performHideEasyMode();
1643 // Change the current directory to the user-defined initial directory
1644 navigationView.changeCurrentDir(initialDir, addToHistory);
1648 * Displays a message reporting invalid directory
1650 * @param initialDir The initial directory
1653 void showInitialInvalidDirectoryMsg(String initialDir) {
1654 // Change to root directory
1655 DialogHelper.showToast(
1658 R.string.msgs_settings_invalid_initial_directory,
1660 Toast.LENGTH_SHORT);
1664 * Method that verifies the intent passed to the activity, and checks
1665 * if a request is made like Search.
1667 * @param intent The intent to check
1670 void checkIntent(Intent intent) {
1672 if (Intent.ACTION_SEARCH.equals(intent.getAction())) {
1673 Intent searchIntent = new Intent(this, SearchActivity.class);
1674 searchIntent.setAction(Intent.ACTION_SEARCH);
1675 //- SearchActivity.EXTRA_SEARCH_DIRECTORY
1676 searchIntent.putExtra(
1677 SearchActivity.EXTRA_SEARCH_DIRECTORY,
1678 getCurrentNavigationView().getCurrentDir());
1679 //- SearchManager.APP_DATA
1680 if (intent.getBundleExtra(SearchManager.APP_DATA) != null) {
1681 Bundle bundle = new Bundle();
1682 bundle.putAll(intent.getBundleExtra(SearchManager.APP_DATA));
1683 searchIntent.putExtra(SearchManager.APP_DATA, bundle);
1685 //-- SearchManager.QUERY
1686 String query = intent.getStringExtra(SearchManager.QUERY);
1687 if (query != null) {
1688 searchIntent.putExtra(SearchManager.QUERY, query);
1690 //- android.speech.RecognizerIntent.EXTRA_RESULTS
1691 ArrayList<String> extraResults =
1692 intent.getStringArrayListExtra(android.speech.RecognizerIntent.EXTRA_RESULTS);
1693 if (extraResults != null) {
1694 searchIntent.putStringArrayListExtra(
1695 android.speech.RecognizerIntent.EXTRA_RESULTS, extraResults);
1697 startActivityForResult(searchIntent, INTENT_REQUEST_SEARCH);
1706 public boolean onKeyUp(int keyCode, KeyEvent event) {
1707 if (keyCode == KeyEvent.KEYCODE_MENU) {
1708 if (mDrawerLayout.isDrawerOpen(mDrawer)) {
1709 mDrawerLayout.closeDrawer(Gravity.START);
1711 mDrawerLayout.openDrawer(Gravity.START);
1715 return super.onKeyUp(keyCode, event);
1719 public void onBackPressed() {
1720 if (checkBackAction()) {
1721 performHideEasyMode();
1725 // An exit event has occurred, force the destroy the consoles
1730 * Method invoked when an action item is clicked.
1732 * @param view The button pushed
1734 public void onActionBarItemClick(View view) {
1735 switch (view.getId()) {
1736 //######################
1737 //Navigation Custom Title
1738 //######################
1739 case R.id.ab_configuration:
1740 //Show navigation view configuration toolbar
1741 getCurrentNavigationView().getCustomTitle().showConfigurationView();
1744 //Hide navigation view configuration toolbar
1745 getCurrentNavigationView().getCustomTitle().hideConfigurationView();
1748 //######################
1749 //Breadcrumb Actions
1750 //######################
1751 case R.id.ab_filesystem_info:
1752 //Show information of the filesystem
1753 MountPoint mp = getCurrentNavigationView().getBreadcrumb().getMountPointInfo();
1754 DiskUsage du = getCurrentNavigationView().getBreadcrumb().getDiskUsageInfo();
1755 showMountPointInfo(mp, du);
1758 //######################
1759 //Navigation view options
1760 //######################
1761 case R.id.ab_sort_mode:
1762 showSettingsPopUp(view,
1764 new FileManagerSettings[]{
1765 FileManagerSettings.SETTINGS_SORT_MODE}));
1767 case R.id.ab_layout_mode:
1768 showSettingsPopUp(view,
1770 new FileManagerSettings[]{
1771 FileManagerSettings.SETTINGS_LAYOUT_MODE}));
1773 case R.id.ab_view_options:
1774 // If we are in ChRooted mode, then don't show non-secure items
1775 if (this.mChRooted) {
1776 showSettingsPopUp(view,
1777 Arrays.asList(new FileManagerSettings[]{
1778 FileManagerSettings.SETTINGS_SHOW_DIRS_FIRST}));
1780 showSettingsPopUp(view,
1781 Arrays.asList(new FileManagerSettings[]{
1782 FileManagerSettings.SETTINGS_SHOW_DIRS_FIRST,
1783 FileManagerSettings.SETTINGS_SHOW_HIDDEN,
1784 FileManagerSettings.SETTINGS_SHOW_SYSTEM,
1785 FileManagerSettings.SETTINGS_SHOW_SYMLINKS}));
1790 //######################
1792 //######################
1793 case R.id.ab_selection_done:
1794 //Show information of the filesystem
1795 getCurrentNavigationView().onDeselectAll();
1798 //######################
1799 //Action Bar buttons
1800 //######################
1801 case R.id.ab_actions:
1802 openActionsDialog(getCurrentNavigationView().getCurrentDir(),
1806 case R.id.ab_search:
1820 protected void onActivityResult(int requestCode, int resultCode, Intent data) {
1821 if (requestCode == INTENT_REQUEST_SETTINGS) {
1822 // reset bookmarks list to default as the user could changed the
1823 // root mode which changes the system bookmarks
1829 switch (requestCode) {
1830 case INTENT_REQUEST_SEARCH:
1831 if (resultCode == RESULT_OK) {
1833 Bundle bundle = data.getExtras();
1834 if (bundle != null) {
1835 FileSystemObject fso = (FileSystemObject) bundle.getSerializable(
1836 EXTRA_SEARCH_ENTRY_SELECTION);
1837 SearchInfoParcelable searchInfo =
1838 bundle.getParcelable(EXTRA_SEARCH_LAST_SEARCH_DATA);
1840 //Goto to new directory
1841 getCurrentNavigationView().open(fso, searchInfo);
1842 performHideEasyMode();
1845 } else if (resultCode == RESULT_CANCELED) {
1846 SearchInfoParcelable searchInfo =
1847 data.getParcelableExtra(EXTRA_SEARCH_LAST_SEARCH_DATA);
1848 if (searchInfo != null && searchInfo.isSuccessNavigation()) {
1849 //Navigate to previous history
1852 // I don't know is the search view was changed, so try to do a refresh
1853 // of the navigation view
1854 getCurrentNavigationView().refresh(true);
1857 // reset bookmarks list to default as the user could have set a
1858 // new bookmark in the search activity
1872 public void onNewHistory(HistoryNavigable navigable) {
1873 addHistoryToDrawer(this.mHistory.size(), navigable);
1874 //Recollect information about current status
1875 History history = new History(this.mHistory.size(), navigable);
1876 this.mHistory.add(history);
1883 public void onCheckHistory() {
1890 public void onRequestRefresh(Object o, boolean clearSelection) {
1891 if (o instanceof FileSystemObject) {
1892 // Refresh only the item
1893 this.getCurrentNavigationView().refresh((FileSystemObject)o);
1894 } else if (o == null) {
1896 getCurrentNavigationView().refresh();
1898 if (clearSelection) {
1899 this.getCurrentNavigationView().onDeselectAll();
1907 public void onRequestBookmarksRefresh() {
1915 public void onRequestRemove(Object o, boolean clearSelection) {
1916 if (o instanceof FileSystemObject) {
1918 this.getCurrentNavigationView().removeItem((FileSystemObject)o);
1920 //Remove from history
1921 removeFromHistory((FileSystemObject)o);
1923 onRequestRefresh(null, clearSelection);
1925 if (clearSelection) {
1926 this.getCurrentNavigationView().onDeselectAll();
1934 public void onNavigateTo(Object o) {
1942 public void onSelectionChanged(NavigationView navView, List<FileSystemObject> selectedItems) {
1943 this.mSelectionBar.setSelection(selectedItems);
1950 public void onRequestMenu(NavigationView navView, FileSystemObject item) {
1951 // Show the actions dialog
1952 openActionsDialog(item, false);
1956 * Method that shows a popup with a menu associated a {@link FileManagerSettings}.
1958 * @param anchor The action button that was pressed
1959 * @param settings The array of settings associated with the action button
1961 private void showSettingsPopUp(View anchor, List<FileManagerSettings> settings) {
1962 //Create the adapter
1963 final MenuSettingsAdapter adapter = new MenuSettingsAdapter(this, settings);
1965 //Create a show the popup menu
1966 final ListPopupWindow popup = DialogHelper.createListPopupWindow(this, adapter, anchor);
1967 popup.setOnItemClickListener(new OnItemClickListener() {
1969 public void onItemClick(AdapterView<?> parent, View v, int position, long id) {
1970 FileManagerSettings setting =
1971 ((MenuSettingsAdapter)parent.getAdapter()).getSetting(position);
1972 final int value = ((MenuSettingsAdapter)parent.getAdapter()).getId(position);
1975 if (setting.compareTo(FileManagerSettings.SETTINGS_LAYOUT_MODE) == 0) {
1976 //Need to change the layout
1977 getCurrentNavigationView().changeViewMode(
1978 NavigationLayoutMode.fromId(value));
1981 if (setting.getDefaultValue() instanceof Enum<?>) {
1983 Preferences.savePreference(setting, new ObjectIdentifier() {
1985 public int getId() {
1992 Preferences.getSharedPreferences().
1995 ((Boolean)setting.getDefaultValue()).booleanValue());
1996 Preferences.savePreference(setting, Boolean.valueOf(!newval), false);
1998 getCurrentNavigationView().refresh();
2000 } catch (Exception e) {
2001 Log.e(TAG, "Error applying navigation option", e); //$NON-NLS-1$
2002 NavigationActivity.this.mHandler.post(new Runnable() {
2005 DialogHelper.showToast(
2006 NavigationActivity.this,
2007 R.string.msgs_settings_save_failure, Toast.LENGTH_SHORT);
2013 getCurrentNavigationView().getCustomTitle().restoreView();
2018 popup.setOnDismissListener(new PopupWindow.OnDismissListener() {
2020 public void onDismiss() {
2028 * Method that show the information of a filesystem mount point.
2030 * @param mp The mount point info
2031 * @param du The disk usage of the mount point
2033 private void showMountPointInfo(MountPoint mp, DiskUsage du) {
2034 //Has mount point info?
2036 //There is no information
2038 DialogHelper.createWarningDialog(
2040 R.string.filesystem_info_warning_title,
2041 R.string.filesystem_info_warning_msg);
2042 DialogHelper.delegateDialogShow(this, alert);
2046 //Show a the filesystem info dialog
2047 FilesystemInfoDialog dialog = new FilesystemInfoDialog(this, mp, du);
2048 dialog.setOnMountListener(new OnMountListener() {
2050 public void onRemount(MountPoint mountPoint) {
2051 //Update the statistics of breadcrumb, only if mount point is the same
2052 Breadcrumb breadcrumb = getCurrentNavigationView().getBreadcrumb();
2053 if (breadcrumb.getMountPointInfo().compareTo(mountPoint) == 0) {
2054 breadcrumb.updateMountPointInfo();
2056 if (mountPoint.isSecure()) {
2057 // Secure mountpoints only can be unmount, so we need to move the navigation
2058 // to a secure storage (do not add to history)
2059 Intent intent = new Intent();
2060 intent.putExtra(EXTRA_ADD_TO_HISTORY, false);
2061 initNavigation(NavigationActivity.this.mCurrentNavigationView, false, intent);
2069 * Method that checks the action that must be realized when the
2070 * back button is pushed.
2072 * @return boolean Indicates if the action must be intercepted
2074 private boolean checkBackAction() {
2075 // We need a basic structure to check this
2076 if (getCurrentNavigationView() == null) return false;
2078 if (mSearchView.getVisibility() == View.VISIBLE) {
2082 //Check if the configuration view is showing. In this case back
2083 //action must be "close configuration"
2084 if (getCurrentNavigationView().getCustomTitle().isConfigurationViewShowing()) {
2085 getCurrentNavigationView().getCustomTitle().restoreView();
2089 //Do back operation over the navigation history
2090 boolean flag = this.mExitFlag;
2092 this.mExitFlag = !back();
2094 // Retrieve if the exit status timeout has expired
2095 long now = System.currentTimeMillis();
2096 boolean timeout = (this.mExitBackTimeout == -1 ||
2097 (now - this.mExitBackTimeout) > RELEASE_EXIT_CHECK_TIMEOUT);
2099 //Check if there no history and if the user was advised in the last back action
2100 if (this.mExitFlag && (this.mExitFlag != flag || timeout)) {
2101 //Communicate the user that the next time the application will be closed
2102 this.mExitBackTimeout = System.currentTimeMillis();
2103 DialogHelper.showToast(this, R.string.msgs_push_again_to_exit, Toast.LENGTH_SHORT);
2107 //Back action not applied
2108 return !this.mExitFlag;
2112 public void startActivity(Intent intent) {
2113 // check if search intent
2114 if (Intent.ACTION_SEARCH.equals(intent.getAction())) {
2115 intent.putExtra(SearchActivity.EXTRA_SEARCH_DIRECTORY,
2116 getCurrentNavigationView().getCurrentDir());
2119 super.startActivity(intent);
2123 * Method that returns the history size.
2125 private void clearHistory() {
2126 this.mHistory.clear();
2127 mDrawerHistory.removeAllViews();
2128 mDrawerHistoryEmpty.setVisibility(View.VISIBLE);
2132 * Method that navigates to the passed history reference.
2134 * @param history The history reference
2135 * @return boolean A problem occurs while navigate
2137 public synchronized boolean navigateToHistory(History history) {
2140 History realHistory = this.mHistory.get(history.getPosition());
2142 //Navigate to item. Check what kind of history is
2143 if (realHistory.getItem() instanceof NavigationViewInfoParcelable) {
2145 NavigationViewInfoParcelable info =
2146 (NavigationViewInfoParcelable)realHistory.getItem();
2147 int viewId = info.getId();
2148 NavigationView view = getNavigationView(viewId);
2149 // Selected items must not be restored from on history navigation
2150 info.setSelectedFiles(view.getSelectedFiles());
2151 if (!view.onRestoreState(info)) {
2155 } else if (realHistory.getItem() instanceof SearchInfoParcelable) {
2156 //Search (open search with the search results)
2157 SearchInfoParcelable info = (SearchInfoParcelable)realHistory.getItem();
2158 Intent searchIntent = new Intent(this, SearchActivity.class);
2159 searchIntent.setAction(SearchActivity.ACTION_RESTORE);
2160 searchIntent.putExtra(SearchActivity.EXTRA_SEARCH_RESTORE, (Parcelable)info);
2161 startActivityForResult(searchIntent, INTENT_REQUEST_SEARCH);
2163 //The type is unknown
2164 throw new IllegalArgumentException("Unknown history type"); //$NON-NLS-1$
2167 //Remove the old history
2168 int cc = realHistory.getPosition();
2169 for (int i = this.mHistory.size() - 1; i >= cc; i--) {
2170 this.mHistory.remove(i);
2171 mDrawerHistory.removeViewAt(0);
2174 if (mDrawerHistory.getChildCount() == 0) {
2175 mDrawerHistoryEmpty.setVisibility(View.VISIBLE);
2179 boolean clearHistory = mHistoryTab.isSelected() && mHistory.size() > 0;
2180 mClearHistory.setVisibility(clearHistory ? View.VISIBLE : View.GONE);
2183 } catch (Throwable ex) {
2184 if (history != null) {
2186 String.format("Failed to navigate to history %d: %s", //$NON-NLS-1$
2187 Integer.valueOf(history.getPosition()),
2188 history.getItem().getTitle()), ex);
2191 String.format("Failed to navigate to history: null", ex)); //$NON-NLS-1$
2193 this.mHandler.post(new Runnable() {
2196 DialogHelper.showToast(
2197 NavigationActivity.this,
2198 R.string.msgs_history_unknown, Toast.LENGTH_LONG);
2202 //Not change directory
2208 * Method that request a back action over the navigation history.
2210 * @return boolean If a back action was applied
2212 public boolean back() {
2213 // Check that has valid history
2214 while (this.mHistory.size() > 0) {
2215 History h = this.mHistory.get(this.mHistory.size() - 1);
2216 if (h.getItem() instanceof NavigationViewInfoParcelable) {
2217 // Verify that the path exists
2218 String path = ((NavigationViewInfoParcelable)h.getItem()).getCurrentDir();
2221 FileSystemObject info = CommandHelper.getFileInfo(this, path, null);
2225 this.mHistory.remove(this.mHistory.size() - 1);
2226 } catch (Exception e) {
2227 ExceptionUtil.translateException(this, e, true, false);
2228 this.mHistory.remove(this.mHistory.size() - 1);
2235 //Navigate to history
2236 if (this.mHistory.size() > 0) {
2237 return navigateToHistory(this.mHistory.get(this.mHistory.size() - 1));
2241 mClearHistory.setVisibility(View.GONE);
2246 * Method that opens the actions dialog
2248 * @param item The path or the {@link FileSystemObject}
2249 * @param global If the menu to display is the one with global actions
2251 private void openActionsDialog(Object item, boolean global) {
2252 // Resolve the full path
2253 String path = String.valueOf(item);
2254 if (item instanceof FileSystemObject) {
2255 path = ((FileSystemObject)item).getFullPath();
2258 // Prior to show the dialog, refresh the item reference
2259 FileSystemObject fso = null;
2261 fso = CommandHelper.getFileInfo(this, path, false, null);
2263 throw new NoSuchFileOrDirectory(path);
2266 } catch (Exception e) {
2268 ExceptionUtil.translateException(this, e);
2270 // Remove the object
2271 if (e instanceof FileNotFoundException || e instanceof NoSuchFileOrDirectory) {
2272 // If have a FileSystemObject reference then there is no need to search
2273 // the path (less resources used)
2274 if (item instanceof FileSystemObject) {
2275 getCurrentNavigationView().removeItem((FileSystemObject)item);
2277 getCurrentNavigationView().removeItem((String)item);
2284 ActionsDialog dialog = new ActionsDialog(this, this, fso, global, false);
2285 dialog.setOnRequestRefreshListener(this);
2286 dialog.setOnSelectionListener(getCurrentNavigationView());
2291 * Method that opens the search view.
2296 mSearchView.setVisibility(View.VISIBLE);
2297 mSearchView.onActionViewExpanded();
2298 mCustomTitleView.setVisibility(View.GONE);
2301 void closeSearch() {
2302 mSearchView.setVisibility(View.GONE);
2303 mSearchView.onActionViewCollapsed();
2304 mCustomTitleView.setVisibility(View.VISIBLE);
2308 * Method that opens the settings activity.
2312 void openSettings() {
2313 Intent settingsIntent = new Intent(NavigationActivity.this,
2314 SettingsPreferences.class);
2315 startActivityForResult(settingsIntent, INTENT_REQUEST_SETTINGS);
2319 * Method that remove the {@link FileSystemObject} from the history
2321 private void removeFromHistory(FileSystemObject fso) {
2322 if (this.mHistory != null) {
2323 int cc = this.mHistory.size() - 1;
2324 for (int i = cc; i >= 0 ; i--) {
2325 History history = this.mHistory.get(i);
2326 if (history.getItem() instanceof NavigationViewInfoParcelable) {
2327 String p0 = fso.getFullPath();
2328 String p1 = ((NavigationViewInfoParcelable) history.getItem()).getCurrentDir();
2329 if (p0.compareTo(p1) == 0) {
2330 this.mHistory.remove(i);
2331 mDrawerHistory.removeViewAt(mDrawerHistory.getChildCount() - i - 1);
2332 mDrawerHistoryEmpty.setVisibility(
2333 mDrawerHistory.getChildCount() == 0 ? View.VISIBLE : View.GONE);
2334 updateHistoryPositions();
2342 * Update the history positions after one of the history is removed from drawer
2344 private void updateHistoryPositions() {
2345 int cc = this.mHistory.size() - 1;
2346 for (int i = 0; i <= cc ; i++) {
2347 History history = this.mHistory.get(i);
2348 history.setPosition(i + 1);
2353 * Method that ask the user to change the access mode prior to crash.
2357 //Show a dialog asking the user
2358 AlertDialog dialog =
2359 DialogHelper.createYesNoDialog(
2361 R.string.msgs_change_to_prompt_access_mode_title,
2362 R.string.msgs_change_to_prompt_access_mode_msg,
2363 new DialogInterface.OnClickListener() {
2365 public void onClick(DialogInterface alertDialog, int which) {
2366 if (which == DialogInterface.BUTTON_NEGATIVE) {
2367 // We don't have any console
2368 // Show exception and exit
2369 DialogHelper.showToast(
2370 NavigationActivity.this,
2371 R.string.msgs_cant_create_console, Toast.LENGTH_LONG);
2376 // Ok. Now try to change to prompt mode. Any crash
2377 // here is a fatal error. We won't have any console to operate.
2380 ConsoleBuilder.changeToNonPrivilegedConsole(NavigationActivity.this);
2383 Preferences.savePreference(
2384 FileManagerSettings.SETTINGS_ACCESS_MODE,
2385 AccessMode.PROMPT, true);
2387 } catch (Exception e) {
2388 // Displays an exception and exit
2389 Log.e(TAG, getString(R.string.msgs_cant_create_console), e);
2390 DialogHelper.showToast(
2391 NavigationActivity.this,
2392 R.string.msgs_cant_create_console, Toast.LENGTH_LONG);
2397 DialogHelper.delegateDialogShow(this, dialog);
2401 * Method that creates a ChRooted environment, protecting the user to break anything in
2405 void createChRooted() {
2406 // If we are in a ChRooted mode, then do nothing
2407 if (this.mChRooted) return;
2408 this.mChRooted = true;
2410 int cc = this.mNavigationViews.length;
2411 for (int i = 0; i < cc; i++) {
2412 this.mNavigationViews[i].createChRooted();
2415 // Remove the selection
2416 cc = this.mNavigationViews.length;
2417 for (int i = 0; i < cc; i++) {
2418 getCurrentNavigationView().onDeselectAll();
2421 // Remove the history (don't allow to access to previous data)
2426 * Method that exits from a ChRooted
2429 void exitChRooted() {
2430 // If we aren't in a ChRooted mode, then do nothing
2431 if (!this.mChRooted) return;
2432 this.mChRooted = false;
2434 int cc = this.mNavigationViews.length;
2435 for (int i = 0; i < cc; i++) {
2436 this.mNavigationViews[i].exitChRooted();
2441 * Method called when a controlled exit is required
2445 // Recycle the navigation views
2446 int cc = this.mNavigationViews.length;
2447 for (int i = 0; i < cc; i++) {
2448 this.mNavigationViews[i].recycle();
2451 FileManagerApplication.destroyBackgroundConsole();
2452 } catch (Throwable ex) {
2456 ConsoleBuilder.destroyConsole();
2457 } catch (Throwable ex) {
2464 * Method that reconfigures the layout for better fit in portrait and landscape modes
2466 private void onLayoutChanged() {
2467 Theme theme = ThemeManager.getCurrentTheme(this);
2468 boolean drawerOpen = mDrawerLayout.isDrawerOpen(Gravity.START);
2470 // Apply only when the orientation was changed
2471 int orientation = getResources().getConfiguration().orientation;
2472 if (this.mOrientation == orientation) return;
2473 this.mOrientation = orientation;
2475 // imitate a closed drawer while layout is rebuilt to avoid NullPointerException
2477 mDrawerLayout.closeDrawer(Gravity.START);
2480 if (this.mOrientation == Configuration.ORIENTATION_LANDSCAPE) {
2482 ViewGroup statusBar = (ViewGroup)findViewById(R.id.navigation_statusbar);
2483 if (statusBar.getParent() != null) {
2484 ViewGroup parent = (ViewGroup) statusBar.getParent();
2485 parent.removeView(statusBar);
2488 // Calculate the action button size (all the buttons must fit in the title bar)
2489 int bw = (int)getResources().getDimension(R.dimen.default_buttom_width);
2490 int abw = this.mActionBar.getChildCount() * bw;
2492 int cc = statusBar.getChildCount();
2493 for (int i = 0; i < cc; i++) {
2494 View child = statusBar.getChildAt(i);
2495 if (child instanceof ButtonItem) {
2499 // Currently there isn't overflow menu
2500 int w = abw + rbw - bw;
2502 // Add to the new location
2503 ViewGroup newParent = (ViewGroup)findViewById(R.id.navigation_title_landscape_holder);
2504 LinearLayout.LayoutParams params =
2505 new LinearLayout.LayoutParams(
2507 ViewGroup.LayoutParams.MATCH_PARENT);
2508 statusBar.setLayoutParams(params);
2509 newParent.addView(statusBar);
2512 theme.setBackgroundDrawable(this, statusBar, "titlebar_drawable"); //$NON-NLS-1$
2515 View holder = findViewById(R.id.navigation_statusbar_portrait_holder);
2516 holder.setVisibility(View.GONE);
2520 ViewGroup statusBar = (ViewGroup)findViewById(R.id.navigation_statusbar);
2521 if (statusBar.getParent() != null) {
2522 ViewGroup parent = (ViewGroup) statusBar.getParent();
2523 parent.removeView(statusBar);
2526 // Add to the new location
2527 ViewGroup newParent = (ViewGroup)findViewById(
2528 R.id.navigation_statusbar_portrait_holder);
2529 LinearLayout.LayoutParams params =
2530 new LinearLayout.LayoutParams(
2531 ViewGroup.LayoutParams.MATCH_PARENT,
2532 ViewGroup.LayoutParams.MATCH_PARENT);
2533 statusBar.setLayoutParams(params);
2534 newParent.addView(statusBar);
2537 theme.setBackgroundDrawable(this, statusBar, "statusbar_drawable"); //$NON-NLS-1$
2540 newParent.setVisibility(View.VISIBLE);
2543 // if drawer was open, imitate reopening
2545 mDrawerToggle.onDrawerOpened(mDrawer);
2550 * Method that removes all the history items that refers to virtual unmounted filesystems
2552 private void removeUnmountedHistory() {
2553 int cc = mHistory.size() - 1;
2554 for (int i = cc; i >= 0; i--) {
2555 History history = mHistory.get(i);
2556 if (history.getItem() instanceof NavigationViewInfoParcelable) {
2557 NavigationViewInfoParcelable navigableInfo =
2558 ((NavigationViewInfoParcelable) history.getItem());
2559 VirtualMountPointConsole vc =
2560 VirtualMountPointConsole.getVirtualConsoleForPath(
2561 navigableInfo.getCurrentDir());
2562 if (vc != null && !vc.isMounted()) {
2564 mDrawerHistory.removeViewAt(mDrawerHistory.getChildCount() - i - 1);
2568 mDrawerHistoryEmpty.setVisibility(
2569 mDrawerHistory.getChildCount() == 0 ? View.VISIBLE : View.GONE);
2570 updateHistoryPositions();
2574 * Method that removes all the selection items that refers to virtual unmounted filesystems
2576 private void removeUnmountedSelection() {
2577 for (NavigationView view : mNavigationViews) {
2578 view.removeUnmountedSelection();
2580 mSelectionBar.setSelection(getNavigationView(mCurrentNavigationView).getSelectedFiles());
2584 * Method that applies the current theme to the activity
2588 int orientation = getResources().getConfiguration().orientation;
2589 Theme theme = ThemeManager.getCurrentTheme(this);
2590 theme.setBaseThemeNoActionBar(this);
2593 // imitate a closed drawer while layout is rebuilt to avoid NullPointerException
2594 boolean drawerOpen = mDrawerLayout.isDrawerOpen(Gravity.START);
2596 mDrawerLayout.closeDrawer(Gravity.START);
2600 View v = findViewById(R.id.navigation_layout);
2601 theme.setBackgroundDrawable(this, v, "background_drawable"); //$NON-NLS-1$
2604 theme.setTitlebarDrawable(this, getActionBar(), "titlebar_drawable"); //$NON-NLS-1$
2606 // Hackery to theme search view
2607 mSearchView = (SearchView) findViewById(R.id.navigation_search_bar);
2608 int searchPlateId = mSearchView.getContext().getResources()
2609 .getIdentifier("android:id/search_plate", null, null);
2610 View searchPlate = mSearchView.findViewById(searchPlateId);
2611 if (searchPlate != null) {
2612 int searchTextId = searchPlate.getContext().getResources()
2613 .getIdentifier("android:id/search_src_text", null, null);
2614 TextView searchText = (TextView) searchPlate.findViewById(searchTextId);
2615 if (searchText != null) {
2616 searchText.setTextColor(Color.WHITE);
2617 searchText.setHintTextColor(Color.WHITE);
2620 int magId = getResources().getIdentifier("android:id/search_mag_icon", null, null);
2621 ImageView magImage = (ImageView) mSearchView.findViewById(magId);
2622 if (magImage != null) {
2623 magImage.setLayoutParams(new LinearLayout.LayoutParams(0, 0));
2627 SearchManager searchManager = (SearchManager) getSystemService(Context.SEARCH_SERVICE);
2628 mSearchView.setSearchableInfo(searchManager.getSearchableInfo(getComponentName()));
2629 mSearchView.setIconifiedByDefault(false);
2631 mCustomTitleView = (NavigationCustomTitleView) findViewById(R.id.navigation_title_flipper);
2632 mCustomTitleView.setVisibility(View.VISIBLE);
2635 v = findViewById(R.id.navigation_statusbar);
2636 if (orientation == Configuration.ORIENTATION_LANDSCAPE) {
2637 theme.setBackgroundDrawable(this, v, "titlebar_drawable"); //$NON-NLS-1$
2639 theme.setBackgroundDrawable(this, v, "statusbar_drawable"); //$NON-NLS-1$
2641 v = findViewById(R.id.ab_overflow);
2642 theme.setImageDrawable(this, (ImageView)v, "ab_overflow_drawable"); //$NON-NLS-1$
2643 v = findViewById(R.id.ab_actions);
2644 theme.setImageDrawable(this, (ImageView)v, "ab_actions_drawable"); //$NON-NLS-1$
2645 v = findViewById(R.id.ab_search);
2646 theme.setImageDrawable(this, (ImageView)v, "ab_search_drawable"); //$NON-NLS-1$
2649 v = findViewById(R.id.ab_configuration);
2650 theme.setImageDrawable(this, (ImageView)v, "expander_open_drawable"); //$NON-NLS-1$
2651 v = findViewById(R.id.ab_close);
2652 theme.setImageDrawable(this, (ImageView)v, "expander_close_drawable"); //$NON-NLS-1$
2653 v = findViewById(R.id.ab_sort_mode);
2654 theme.setImageDrawable(this, (ImageView)v, "ab_sort_mode_drawable"); //$NON-NLS-1$
2655 v = findViewById(R.id.ab_layout_mode);
2656 theme.setImageDrawable(this, (ImageView)v, "ab_layout_mode_drawable"); //$NON-NLS-1$
2657 v = findViewById(R.id.ab_view_options);
2658 theme.setImageDrawable(this, (ImageView)v, "ab_view_options_drawable"); //$NON-NLS-1$
2661 v = findViewById(R.id.navigation_selectionbar);
2662 theme.setBackgroundDrawable(this, v, "selectionbar_drawable"); //$NON-NLS-1$
2663 v = findViewById(R.id.ab_selection_done);
2664 theme.setImageDrawable(this, (ImageView)v, "ab_selection_done_drawable"); //$NON-NLS-1$
2665 v = findViewById(R.id.navigation_status_selection_label);
2666 theme.setTextColor(this, (TextView)v, "text_color"); //$NON-NLS-1$
2668 // - Navigation drawer
2669 v = findViewById(R.id.history_empty);
2670 theme.setTextColor(this, (TextView)v, "text_color"); //$NON-NLS-1$
2672 for (int i=0; i<mDrawerHistory.getChildCount(); i++) {
2673 View item = mDrawerHistory.getChildAt(i);
2675 v = item.findViewById(R.id.history_item_name);
2676 theme.setTextColor(this, (TextView)v, "text_color"); //$NON-NLS-1$
2677 v = item.findViewById(R.id.history_item_directory);
2678 theme.setTextColor(this, (TextView)v, "text_color"); //$NON-NLS-1$
2682 int cc = this.mNavigationViews.length;
2683 for (int i = 0; i < cc; i++) {
2684 getNavigationView(i).applyTheme();
2687 // if drawer was open, imitate reopening
2689 mDrawerToggle.onDrawerOpened(mDrawer);
2694 * Method that applies the current theme to the tab host
2696 private void applyTabTheme() {
2698 Theme theme = ThemeManager.getCurrentTheme(this);
2700 View v = findViewById(R.id.drawer);
2701 theme.setBackgroundDrawable(this, v, "background_drawable"); //$NON-NLS-1$
2703 v = findViewById(R.id.drawer_bookmarks_tab);
2704 theme.setTextColor(this, (TextView)v, "text_color"); //$NON-NLS-1$
2705 v = findViewById(R.id.drawer_history_tab);
2706 theme.setTextColor(this, (TextView)v, "text_color"); //$NON-NLS-1$
2708 v = findViewById(R.id.ab_settings);
2709 theme.setImageDrawable(this, (ButtonItem) v, "ab_settings_drawable"); //$NON-NLS-1$
2710 v = findViewById(R.id.ab_clear_history);
2711 theme.setImageDrawable(this, (ButtonItem) v, "ab_delete_drawable"); //$NON-NLS-1$