/* * Copyright (C) 2012 The CyanogenMod Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.cyanogenmod.filemanager.activities; import android.Manifest; import android.app.Activity; import android.app.Dialog; import android.app.SearchManager; import android.content.BroadcastReceiver; import android.content.ContentResolver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.pm.PackageManager; import android.net.Uri; import android.nfc.NfcAdapter; import android.os.Bundle; import android.provider.Settings; import android.support.design.widget.NavigationView; import android.support.design.widget.Snackbar; import android.support.v4.app.Fragment; import android.support.v4.app.FragmentManager; import android.support.v4.app.FragmentManager.OnBackStackChangedListener; import android.support.v4.app.FragmentTransaction; import android.support.v4.graphics.ColorUtils; import android.support.v4.widget.DrawerLayout; import android.support.v7.app.ActionBarActivity; import android.support.v7.widget.CardView; import android.support.v7.widget.Toolbar; import android.text.TextUtils; import android.util.Log; import android.view.Gravity; import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; import android.view.WindowManager; import android.widget.AdapterView; import android.widget.AdapterView.OnItemClickListener; import android.widget.Button; import android.widget.GridView; import android.widget.ImageView; import android.widget.SearchView; import android.widget.TextView; import com.cyanogenmod.filemanager.FileManagerApplication; import com.cyanogenmod.filemanager.R; import com.cyanogenmod.filemanager.activities.preferences.SettingsPreferences; import com.cyanogenmod.filemanager.adapters.QuickSearchAdapter; import com.cyanogenmod.filemanager.controllers.NavigationDrawerController; import com.cyanogenmod.filemanager.model.Bookmark; import com.cyanogenmod.filemanager.model.FileSystemObject; import com.cyanogenmod.filemanager.preferences.FileManagerSettings; import com.cyanogenmod.filemanager.preferences.Preferences; import com.cyanogenmod.filemanager.ui.ThemeManager; import com.cyanogenmod.filemanager.ui.fragments.NavigationFragment; import com.cyanogenmod.filemanager.ui.fragments.NavigationFragment.OnGoHomeRequestListener; import com.cyanogenmod.filemanager.ui.widgets.NavigationView.OnBackRequestListener; import com.cyanogenmod.filemanager.util.FileHelper; import com.cyanogenmod.filemanager.util.StorageHelper; import java.io.File; import java.io.InvalidClassException; import java.util.ArrayList; import java.util.List; /** * The main navigation activity. This activity is the center of the application. * From this the user can navigate, search, make actions.
* This activity is singleTop, so when it is displayed no other activities exists in * the stack.
* This cause an issue with the saved instance of this class, because if another activity * is displayed, and the process is killed, MainActivity is started and the saved * instance gets corrupted.
* For this reason the methods {link {@link Activity#onSaveInstanceState(Bundle)} and * {@link Activity#onRestoreInstanceState(Bundle)} are not implemented, and every time * the app is killed, is restarted from his initial state. */ public class MainActivity extends ActionBarActivity implements OnItemClickListener, OnBackRequestListener, OnGoHomeRequestListener { private static final String TAG = MainActivity.class.getSimpleName(); private static boolean DEBUG = false; // Bookmark list XML tags private static final String TAG_BOOKMARKS = "Bookmarks"; //$NON-NLS-1$ private static final String TAG_BOOKMARK = "bookmark"; //$NON-NLS-1$ private static final String STR_USB = "usb"; // $NON-NLS-1$ /** * Intent code for request a search. */ public static final int INTENT_REQUEST_SETTINGS = 20001; /** * Constant for extra information about selected search entry. */ public static final String EXTRA_SEARCH_ENTRY_SELECTION = "extra_search_entry_selection"; //$NON-NLS-1$ /** * Constant for extra information about last search data. */ public static final String EXTRA_SEARCH_LAST_SEARCH_DATA = "extra_search_last_search_data"; //$NON-NLS-1$ /** * Constant for extra information for request a navigation to the passed path. */ public static final String EXTRA_NAVIGATE_TO = "extra_navigate_to"; //$NON-NLS-1$ /** * Constant for extra information for request to add navigation to the history */ public static final String EXTRA_ADD_TO_HISTORY = "extra_add_to_history"; //$NON-NLS-1$ private Toolbar mToolBar; /** * Fragment types */ private enum FragmentType { // Home fragment HOME, // Navigation fragment NAVIGATION, } private Fragment currentFragment; private DrawerLayout mDrawerLayout; private NavigationDrawerController mNavigationDrawerController; private boolean mPopBackStack = false; private static final int REQUEST_CODE_STORAGE_PERMS = 321; private boolean hasPermissions() { int res = checkCallingOrSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE); return (res == PackageManager.PERMISSION_GRANTED); } private void requestNecessaryPermissions() { String[] permissions = new String[] { Manifest.permission.WRITE_EXTERNAL_STORAGE, }; requestPermissions(permissions, REQUEST_CODE_STORAGE_PERMS); } @Override public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grandResults) { boolean allowed = true; switch (requestCode) { case REQUEST_CODE_STORAGE_PERMS: for (int res : grandResults) { allowed = allowed && (res == PackageManager.PERMISSION_GRANTED); } break; default: allowed = false; break; } if (allowed) { finishOnCreate(); } else { if (shouldShowRequestPermissionRationale(Manifest.permission.WRITE_EXTERNAL_STORAGE)) { String text = getResources().getString(R.string.storage_permissions_denied); final ViewGroup viewGroup = (ViewGroup) ((ViewGroup) this .findViewById(android.R.id.content)).getChildAt(0); if (viewGroup != null) { Snackbar snackbar = Snackbar.make(viewGroup, text, Snackbar.LENGTH_INDEFINITE); snackbar.setAction(android.R.string.ok, new View.OnClickListener() { @Override public void onClick(View v) { requestNecessaryPermissions(); } }); snackbar.show(); } } else { StringBuilder builder = new StringBuilder(getString(R.string .storage_permissions_denied)); builder.append("\n\n"); builder.append(getString(R.string.storage_permissions_explanation)); final ViewGroup viewGroup = (ViewGroup) ((ViewGroup) this .findViewById(android.R.id.content)).getChildAt(0); if (viewGroup != null) { Snackbar snackbar = Snackbar.make(viewGroup, builder.toString(), Snackbar.LENGTH_INDEFINITE); snackbar.setAction(R.string.snackbar_settings, new View.OnClickListener() { @Override public void onClick(View v) { startInstalledAppDetailsActivity(MainActivity.this); finish(); } }); snackbar.show(); } } } } public static void startInstalledAppDetailsActivity(final Activity context) { if (context == null) { return; } final Intent i = new Intent(); i.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS); i.addCategory(Intent.CATEGORY_DEFAULT); i.setData(Uri.parse("package:" + context.getPackageName())); i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); i.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY); i.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS); context.startActivity(i); } private final BroadcastReceiver mNotificationReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { if (intent != null) { if (intent.getAction().equals(Intent.ACTION_MEDIA_MOUNTED) || intent.getAction().equals(Intent.ACTION_MEDIA_UNMOUNTED)) { mNavigationDrawerController.loadNavigationDrawerItems(); } } } }; /** * {@inheritDoc} */ @Override protected void onCreate(Bundle state) { getWindow().addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS); // Set the theme before setContentView ThemeManager.Theme theme = ThemeManager.getCurrentTheme(this); theme.setBaseThemeNoActionBar(this); //Set the main layout of the activity setContentView(R.layout.navigation); //Save state super.onCreate(state); if (!hasPermissions()) { requestNecessaryPermissions(); } else { finishOnCreate(); } } private void finishOnCreate() { IntentFilter newFilter = new IntentFilter(); newFilter.addAction(Intent.ACTION_MEDIA_MOUNTED); newFilter.addAction(Intent.ACTION_MEDIA_UNMOUNTED); newFilter.addDataScheme(ContentResolver.SCHEME_FILE); registerReceiver(mNotificationReceiver, newFilter); mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout); NavigationView navigationDrawer = (NavigationView) findViewById(R.id.navigation_view); mNavigationDrawerController = new NavigationDrawerController(this, navigationDrawer); showWelcomeMsg(); //FragmentManager.OnBackStackChangedListener getSupportFragmentManager().addOnBackStackChangedListener(new OnBackStackChangedListener() { @Override public void onBackStackChanged() { updateCurrentFragment(); } }); handleSearchBar(); initQuickSearch(); setHomeStatusBarColor(); //Initialize nfc adapter NfcAdapter mNfcAdapter = NfcAdapter.getDefaultAdapter(this); if (mNfcAdapter != null) { mNfcAdapter.setBeamPushUrisCallback(new NfcAdapter.CreateBeamUrisCallback() { @Override public android.net.Uri[] createBeamUris(android.nfc.NfcEvent event) { if (currentFragment instanceof NavigationFragment) { List selectedFiles = ((NavigationFragment)currentFragment).getCurrentNavigationView() .getSelectedFiles(); if (selectedFiles.size() > 0) { List fileUri = new ArrayList(); for (FileSystemObject f : selectedFiles) { //Beam ignores folders and system files if (!FileHelper.isDirectory(f) && !FileHelper.isSystemFile(f)) { fileUri.add(Uri.fromFile(new File(f.getFullPath()))); } } if (fileUri.size() > 0) { return fileUri.toArray(new android.net.Uri[fileUri.size()]); } } } return null; } }, this); } handleNavigateIntent(getIntent()); } private void handleSearchBar() { SearchView searchView = (SearchView) findViewById(R.id.homepage_search_bar); SearchManager searchManager = (SearchManager) getSystemService(Context.SEARCH_SERVICE); searchView.setSearchableInfo(searchManager.getSearchableInfo(getComponentName())); searchView.setIconifiedByDefault(false); int searchPlateId = searchView.getContext().getResources() .getIdentifier("android:id/search_plate", null, null); View searchPlate = searchView.findViewById(searchPlateId); if (searchPlate != null) { int searchTextId = searchPlate.getContext().getResources() .getIdentifier("android:id/search_src_text", null, null); TextView searchText = (TextView) searchPlate.findViewById(searchTextId); if (searchText != null) { int searchColor = getResources().getColor(R.color.search_bar_hint_text_color); searchText.setTextColor(searchColor); searchText.setHintTextColor(searchColor); } // Update all the image views to our assets int imageViewId = getResources().getIdentifier("android:id/search_button", null, null); ImageView imageView = (ImageView) searchView.findViewById(imageViewId); if (imageView != null) { imageView.setImageResource(R.drawable.ic_search); } imageViewId = getResources().getIdentifier("android:id/search_mag_icon", null, null); imageView = (ImageView) searchView.findViewById(imageViewId); if (imageView != null) { imageView.setImageResource(R.drawable.ic_search); } imageViewId = getResources().getIdentifier("android:id/search_voice_btn", null, null); imageView = (ImageView) searchView.findViewById(imageViewId); if (imageView != null) { imageView.setImageResource(R.drawable.ic_search_voice); } imageViewId = getResources().getIdentifier("android:id/search_close_btn", null, null); imageView = (ImageView) searchView.findViewById(imageViewId); if (imageView != null) { imageView.setImageResource(R.drawable.ic_cancel_close); } } searchView.setFocusable(false); } /** * {@inheritDoc} */ @Override public void onDestroy() { if (DEBUG) { Log.d(TAG, "MainActivity.onDestroy"); //$NON-NLS-1$ } // Unregister the receiver unregisterReceiver(this.mNotificationReceiver); super.onDestroy(); } public void setCurrentFragment(FragmentType fragmentType) { FragmentManager fragmentManager = getSupportFragmentManager(); String fragmentTag = null; switch (fragmentType) { case NAVIGATION: mPopBackStack = false; currentFragment = new NavigationFragment(); ((NavigationFragment) currentFragment).setOnBackRequestListener(this); ((NavigationFragment) currentFragment).setOnGoHomeRequestListener(this); ((NavigationFragment)currentFragment) .setOnDirectoryChangedListener(mNavigationDrawerController); fragmentTag = fragmentType.name(); break; case HOME: default: mPopBackStack = false; currentFragment = null; int fragmentCount = fragmentManager.getBackStackEntryCount(); for (int i = 0; i < fragmentCount; i++) { FragmentManager.BackStackEntry backStackEntry = fragmentManager.getBackStackEntryAt(i); Fragment fragment = fragmentManager.findFragmentByTag(backStackEntry.getName()); if (fragment != null) { fragmentManager.beginTransaction() .remove(fragment) .commitAllowingStateLoss(); fragmentManager.popBackStack(); } } mNavigationDrawerController.setSelected(R.id.navigation_item_home); setHomeStatusBarColor(); return; } fragmentManager.beginTransaction() .replace(R.id.navigation_fragment_container, currentFragment, fragmentTag) .setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE) .addToBackStack(fragmentTag) .commitAllowingStateLoss(); } private void setHomeStatusBarColor() { int foregroundColor = getResources().getColor(R.color.status_bar_foreground_color); int backgroundColor = getResources().getColor(R.color.default_primary); int statusBarColor = ColorUtils.compositeColors(foregroundColor, backgroundColor); getWindow().setStatusBarColor(statusBarColor); } private void updateCurrentFragment() { FragmentManager fragmentManager = getSupportFragmentManager(); if (fragmentManager.getBackStackEntryCount() > 0) { FragmentManager.BackStackEntry backEntry = fragmentManager.getBackStackEntryAt( fragmentManager.getBackStackEntryCount() - 1); currentFragment = fragmentManager.findFragmentByTag(backEntry.getName()); } else { // current fragment is Home currentFragment = null; mNavigationDrawerController.setSelected(R.id.navigation_item_home); setHomeStatusBarColor(); } } private boolean isCurrentFragment(FragmentType fragmentType) { if (fragmentType == FragmentType.HOME) { return getSupportFragmentManager().getFragments().size() <= 0; } else { Fragment fragment = getSupportFragmentManager().findFragmentByTag(fragmentType.name()); return (fragment != null && fragment.isVisible()); } } public void navigateToPath(String path) { if (isCurrentFragment(FragmentType.NAVIGATION)) { NavigationFragment fragment = (NavigationFragment) currentFragment; fragment.getCurrentNavigationView().changeCurrentDir(path, true); } else { getIntent().putExtra(EXTRA_NAVIGATE_TO, path); setCurrentFragment(FragmentType.NAVIGATION); } } public void addBookmark(Bookmark bookmark) { // stub } public void updateActiveDialog(Dialog dialog) { // stub } /** * {@inheritDoc} */ @Override protected void onNewIntent(Intent intent) { if (!handleNavigateIntent(intent)) { handleSearchIntent(intent); } } private boolean handleNavigateIntent(Intent intent) { if (intent != null) { String path = intent.getStringExtra(EXTRA_NAVIGATE_TO); if (!TextUtils.isEmpty(path)) { navigateToPath(path); return true; } } return false; } public void handleSearchIntent(Intent intent) { if (Intent.ACTION_SEARCH.equals(intent.getAction())) { Intent searchIntent = new Intent(this, SearchActivity.class); searchIntent.setAction(Intent.ACTION_SEARCH); //- SearchActivity.EXTRA_SEARCH_DIRECTORY String extraDir = null; if (currentFragment instanceof NavigationFragment) { extraDir = ((NavigationFragment)currentFragment) .getCurrentNavigationView().getCurrentDir(); } extraDir = TextUtils.isEmpty(extraDir) ? FileHelper.ROOT_DIRECTORY : extraDir; searchIntent.putExtra(SearchActivity.EXTRA_SEARCH_DIRECTORY, extraDir); //- SearchManager.APP_DATA if (intent.getBundleExtra(SearchManager.APP_DATA) != null) { Bundle bundle = new Bundle(); bundle.putAll(intent.getBundleExtra(SearchManager.APP_DATA)); searchIntent.putExtra(SearchManager.APP_DATA, bundle); } //-- SearchManager.QUERY String query = intent.getStringExtra(SearchManager.QUERY); if (query != null) { searchIntent.putExtra(SearchManager.QUERY, query); } //- android.speech.RecognizerIntent.EXTRA_RESULTS ArrayList extraResults = intent.getStringArrayListExtra(android.speech.RecognizerIntent.EXTRA_RESULTS); if (extraResults != null) { searchIntent.putStringArrayListExtra( android.speech.RecognizerIntent.EXTRA_RESULTS, extraResults); } startActivityForResult(searchIntent, NavigationFragment.INTENT_REQUEST_SEARCH); } } @Override protected void onStart() { super.onStart(); mToolBar = (Toolbar) findViewById(R.id.material_toolbar); setSupportActionBar(mToolBar); getSupportActionBar().setDisplayHomeAsUpEnabled(true); getSupportActionBar().setHomeButtonEnabled(true); getSupportActionBar().setHomeAsUpIndicator(R.drawable.ic_menu); } private void initQuickSearch() { GridView gridview = (GridView) findViewById(R.id.quick_search_view); QuickSearchAdapter quickSearchAdapter = new QuickSearchAdapter(this, R.layout.quick_search_item); quickSearchAdapter.addAll(quickSearchAdapter.QUICK_SEARCH_LIST); gridview.setAdapter(quickSearchAdapter); } @Override public void onResume() { super.onResume(); mNavigationDrawerController.loadNavigationDrawerItems(); } /** * {@inheritDoc} */ @Override public void onItemClick(AdapterView parent, View view, int position, long id) { view.setSelected(true); int itemId = view.getId(); switch (itemId) { case R.id.navigation_item_home: if (DEBUG) Log.d(TAG, "onNavigationItemSelected::navigation_item_home"); setCurrentFragment(FragmentType.HOME); mNavigationDrawerController.setSelected(itemId); break; case R.id.navigation_item_favorites: // TODO: Implement this path if (DEBUG) Log.d(TAG, "onNavigationItemSelected::navigation_item_favorites"); mNavigationDrawerController.setSelected(itemId); break; case R.id.navigation_item_internal: if (DEBUG) Log.d(TAG, "onNavigationItemSelected::navigation_item_favorites"); navigateToPath(StorageHelper.getLocalStoragePath(this)); break; case R.id.navigation_item_root_d: if (DEBUG) Log.d(TAG, "onNavigationItemSelected::navigation_item_root_d"); navigateToPath(FileHelper.ROOT_DIRECTORY); break; case R.id.navigation_item_manage: // TODO: Implement this path if (DEBUG) Log.d(TAG, "onNavigationItemSelected::navigation_item_manage"); break; case R.id.navigation_item_settings: if (DEBUG) Log.d(TAG, "onNavigationItemSelected::navigation_item_settings"); openSettings(); break; default: if (DEBUG) { Log.d(TAG, String.format("onNavigationItemSelected::default (%d)", itemId)); } String path = null; // Check for item id in storage bookmarks Bookmark bookmark = mNavigationDrawerController.getBookmarkFromMenuItem(itemId); if (bookmark != null) { path = bookmark.getPath(); } if (!TextUtils.isEmpty(path)) { // Check for item id in remote roots navigateToPath(path); } else { return; } break; } mDrawerLayout.closeDrawers(); } /** * Method invoked when an action item is clicked. * * @param view The button pushed */ public void onActionBarItemClick(android.view.View view) { if (currentFragment instanceof NavigationFragment) { NavigationFragment navigationFragment = ((NavigationFragment)currentFragment); switch (view.getId()) { //###################### //Selection Actions //###################### case R.id.ab_selection_done: //Show information of the filesystem navigationFragment.getCurrentNavigationView().onDeselectAll(); break; case R.id.ab_actions: // Show the actions dialog navigationFragment.openActionsDialog(null, true); default: break; } } } /** * Method that opens the settings activity. * * @hide */ void openSettings() { Intent settingsIntent = new Intent(MainActivity.this, SettingsPreferences.class); startActivityForResult(settingsIntent, INTENT_REQUEST_SETTINGS); } /** * Method that displays a welcome message the first time the user * access the application */ private void showWelcomeMsg() { boolean firstUse = Preferences.getSharedPreferences().getBoolean( FileManagerSettings.SETTINGS_FIRST_USE.getId(), ((Boolean)FileManagerSettings.SETTINGS_FIRST_USE.getDefaultValue()).booleanValue()); //Display the welcome message? if (firstUse && FileManagerApplication.hasShellCommands()) { Intent intent = new Intent(this, WelcomeActivity.class); startActivity(intent); try { Preferences.savePreference(FileManagerSettings.SETTINGS_FIRST_USE, Boolean.FALSE, true); } catch (InvalidClassException e) { e.printStackTrace(); } } } @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case android.R.id.home: if (mPopBackStack) { FragmentManager fm = getSupportFragmentManager(); if (fm.getBackStackEntryCount() > 0) { fm.popBackStack(); } } else { mDrawerLayout.openDrawer(Gravity.START); } return true; default: return false; } } @Override public void onBackPressed() { if (mDrawerLayout.isDrawerOpen(Gravity.START)) { mDrawerLayout.closeDrawer(Gravity.START); return; } if (currentFragment instanceof NavigationFragment) { if (((NavigationFragment)currentFragment).back()) { return; } } if (getSupportFragmentManager().getBackStackEntryCount() == 0) { finish(); } super.onBackPressed(); } @Override public void onBackRequested() { onBackPressed(); } @Override public void onGoHomeRequested(String message) { if (DEBUG) Log.d(TAG, "onGoHomeRequested"); setCurrentFragment(FragmentType.HOME); mNavigationDrawerController.setSelected(R.id.navigation_item_home); if (!TextUtils.isEmpty(message)) { // Alert the user of what happened. final View view = findViewById(R.id.navigation_fragment_container); Snackbar.make(view, message, Snackbar.LENGTH_LONG).show(); } } public int getColorForPath(String path) { return mNavigationDrawerController.getColorForPath(path); } }