/* * Copyright 2014 Yaroslav Mytkalyk * 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.docd.purefm.ui.activities; import android.app.ActionBar; import android.app.Activity; import android.app.AlertDialog; import android.app.Dialog; import android.app.Fragment; import android.app.FragmentManager; import android.content.ComponentName; import android.content.DialogInterface; import android.content.Intent; import android.content.ServiceConnection; import android.content.res.Configuration; import android.graphics.drawable.Drawable; import android.os.Bundle; import android.os.IBinder; import android.os.Parcelable; import android.support.v4.app.ActionBarDrawerToggle; import android.support.v4.view.GravityCompat; import android.support.v4.view.ViewPager; import android.support.v4.widget.DrawerLayout; import android.view.KeyEvent; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.widget.ListView; import com.docd.purefm.Environment; import com.docd.purefm.Extras; import com.docd.purefm.PureFM; import com.docd.purefm.R; import com.docd.purefm.browser.Browser; import com.docd.purefm.adapters.BookmarksAdapter; import com.docd.purefm.adapters.BrowserTabsAdapter; import com.docd.purefm.file.GenericFile; import com.docd.purefm.operations.OperationsService; import com.docd.purefm.ui.dialogs.MessageDialogBuilder; import com.docd.purefm.ui.dialogs.ProgressAlertDialogBuilder; import com.docd.purefm.ui.fragments.BrowserFragment; import com.docd.purefm.utils.ClipBoard; import com.docd.purefm.utils.PFMTextUtils; import com.docd.purefm.utils.PreviewHolder; import com.docd.purefm.ui.view.BreadCrumbTextView; import com.docd.purefm.utils.ThemeUtils; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.widget.Toast; import java.util.ArrayList; /** * Activity that holds ViewPager with BrowserFragments * and manages ActionBar and Key events * * @author Doctoror */ public final class BrowserPagerActivity extends AbstractBrowserActivity implements ServiceConnection, OperationsService.OperationListener { /** * Saved fragment state. This saving mechanism is used for restoring * the state when Activity is recreated because of theme change */ private static final String EXTRA_SAVED_FRAGMENT_ADAPTER_STATE = "BrowserPagerActivity.extras.SAVED_FRAGMENT_STATE"; private ActionBar mActionBar; private BreadCrumbTextView mBreadCrumbView; private boolean isDrawerOpened; private DrawerLayout mDrawerLayout; private ActionBarDrawerToggle mDrawerToggle; private boolean mShowHomeAsUp; private ListView mDrawerList; private BookmarksAdapter mBookmarksAdapter; private GenericFile currentPath; private BrowserTabsAdapter mPagerAdapter; private BrowserFragment mCurrentlyDisplayedFragment; private Dialog mOperationProgressDialog; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); if (savedInstanceState == null) { savedInstanceState = getIntent().getBundleExtra(EXTRA_SAVED_STATE); } this.setContentView(R.layout.activity_browser); this.initActionBar(); this.initView(); this.restoreSavedState(savedInstanceState); } @Override protected void onPause() { super.onPause(); final FragmentManager fm = getFragmentManager(); final Fragment f = fm.findFragmentByTag(TAG_DIALOG); if (f != null) { fm.beginTransaction().remove(f).commit(); fm.executePendingTransactions(); } } @Override protected void onResume() { super.onResume(); this.invalidateOptionsMenu(); } @Override protected void setActionBarIcon(final Drawable icon) { final ActionBar actionBar = getActionBar(); if (actionBar == null) { throw new RuntimeException("Should have ActionBar"); } actionBar.setIcon(icon); } @Override protected void onSaveInstanceState(@NonNull final Bundle outState) { super.onSaveInstanceState(outState); outState.putParcelable(EXTRA_SAVED_FRAGMENT_ADAPTER_STATE, mPagerAdapter.saveManualState()); } private void restoreSavedState(final Bundle savedState) { if (savedState != null) { final Parcelable adapterState = savedState.getParcelable(EXTRA_SAVED_FRAGMENT_ADAPTER_STATE); if (adapterState != null) { if (mPagerAdapter != null) { mPagerAdapter.restoreManualState(adapterState); } } } } @Override public void onTrimMemory(int level) { super.onTrimMemory(level); PreviewHolder.getInstance(this).recycle(); } private void initActionBar() { mActionBar = this.getActionBar(); if (mActionBar == null) { throw new RuntimeException("BrowserPagerActivity should have an ActionBar"); } mActionBar.setDisplayOptions(ActionBar.DISPLAY_SHOW_HOME | ActionBar.DISPLAY_SHOW_CUSTOM | ActionBar.DISPLAY_USE_LOGO | ActionBar.DISPLAY_HOME_AS_UP); //noinspection InflateParams final View custom = LayoutInflater.from(this).inflate( R.layout.activity_browser_actionbar, null); if (custom == null) { throw new RuntimeException("Inflated View is null"); } mActionBar.setCustomView(custom); mBreadCrumbView = (BreadCrumbTextView) custom .findViewById(R.id.bread_crumb_view); } private void initView() { final ViewPager pager = (ViewPager) this.findViewById(R.id.pager); mPagerAdapter = new BrowserTabsAdapter(getFragmentManager()); pager.setAdapter(mPagerAdapter); mPagerAdapter.setViewPager(pager); pager.setOffscreenPageLimit(2); mDrawerLayout = (DrawerLayout) this.findViewById(R.id.drawer); mDrawerLayout.setDrawerShadow(R.drawable.drawer_shadow, GravityCompat.START); final int themeId = ThemeUtils.getInteger(getTheme(), R.attr.themeId, PureFM.THEME_ID_DARK); mDrawerToggle = new BrowserActivityDrawerToggle(this, this.mDrawerLayout, themeId == PureFM.THEME_ID_LIGHT ? R.drawable.holo_light_ic_drawer : R.drawable.holo_dark_ic_drawer, R.string.menu_bookmarks, R.string.app_name); mDrawerLayout.setDrawerListener(mDrawerToggle); mDrawerList = (ListView) this.findViewById(R.id.drawerList); mDrawerList.setAdapter(mBookmarksAdapter = new BookmarksAdapter(this)); } @Override protected void onPostCreate(Bundle savedInstanceState) { super.onPostCreate(savedInstanceState); mDrawerToggle.syncState(); } @Override protected void onStart() { super.onStart(); bindService(new Intent(this, OperationsService.class), this, BIND_AUTO_CREATE); } @Override protected void onStop() { super.onStop(); unbindService(this); if (mBookmarksAdapter.isModified()) { getSettings().setBookmarks(mBookmarksAdapter.getData()); } } @Override public boolean onOptionsItemSelected(MenuItem item) { // Pass the event to ActionBarDrawerToggle, if it returns // true, then it has handled the app icon touch event //noinspection SimplifiableIfStatement if (mDrawerToggle.isDrawerIndicatorEnabled() && mDrawerToggle.onOptionsItemSelected(item)) { return true; } return super.onOptionsItemSelected(item); } public void invalidateList() { mPagerAdapter.notifyDataSetChanged(); } @Override public boolean isHistoryEnabled() { return true; } @Override protected BrowserFragment getCurrentlyDisplayedFragment() { return mCurrentlyDisplayedFragment; } @Override public void setOnSequenceClickListener(BreadCrumbTextView.OnSequenceClickListener sequenceListener) { if (mBreadCrumbView != null) { mBreadCrumbView.setOnSequenceClickListener(sequenceListener); } } @Override public boolean shouldShowBrowserFragmentMenu() { return !isDrawerOpened; } @Override public void setCurrentlyDisplayedFragment(final BrowserFragment fragment) { mCurrentlyDisplayedFragment = fragment; } /** * Toggles between using up button or navigation drawer icon by setting the DrawerListener */ void setDrawerIndicatorEnabled(final boolean showUpButton) { mShowHomeAsUp = showUpButton; mDrawerToggle.setDrawerIndicatorEnabled(!showUpButton); } @Override public void onNavigate(GenericFile path) { invalidateOptionsMenu(); } @Override public void onNavigationCompleted(GenericFile path) { currentPath = path; mBreadCrumbView.setFile(path.toFile()); setDrawerIndicatorEnabled(!path.toFile().equals(Environment.sRootDirectory)); invalidateOptionsMenu(); } @Override public boolean onKeyUp(int keyCode, @NonNull KeyEvent event) { if (event.getKeyCode() == KeyEvent.KEYCODE_SEARCH) { final Intent searchIntent = new Intent(this, SearchActivity.class); searchIntent.putExtra(Extras.EXTRA_PATH, currentPath.getAbsolutePath()); startActivity(searchIntent); return true; } return super.onKeyUp(keyCode, event); } @Override public boolean onCreateOptionsMenu(final Menu menu) { if (this.isDrawerOpened) { this.getMenuInflater().inflate(R.menu.activity_bookmarks, menu); return true; } return super.onCreateOptionsMenu(menu); } @Override public boolean onMenuItemSelected(final int featureId, @NonNull final MenuItem item) { switch (item.getItemId()) { case R.id.menu_bookmarks_new: if (currentPath != null) { final String path = currentPath.getAbsolutePath(); this.mBookmarksAdapter.addItem(path); } return true; default: return super.onMenuItemSelected(featureId, item); } } /** * Should be called by BookmarksAdapter to set current path and close the Drawer */ public void setCurrentPath(GenericFile path) { if (this.mDrawerLayout.isDrawerOpen(this.mDrawerList)) { this.mDrawerLayout.closeDrawer(this.mDrawerList); } if (this.mCurrentlyDisplayedFragment != null) { final Browser browser = this.mCurrentlyDisplayedFragment.getBrowser(); if (browser != null) { browser.navigate(path, true); } } } @Override public void onBackPressed() { final boolean onFragmentBackPressed; onFragmentBackPressed = this.mCurrentlyDisplayedFragment != null && this.mCurrentlyDisplayedFragment.onBackPressed(); if (!onFragmentBackPressed) { final AlertDialog.Builder b = new AlertDialog.Builder(this); b.setMessage(R.string.dialog_quit_message); b.setCancelable(true); b.setPositiveButton(R.string.yes, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { dialog.dismiss(); PreviewHolder.getInstance(BrowserPagerActivity.this).recycle(); finish(); } }); b.setNegativeButton(R.string.no, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { dialog.dismiss(); } }); final Dialog dialog = b.create(); if (!this.isFinishing()) { dialog.show(); } } } @Override public void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); mDrawerToggle.onConfigurationChanged(newConfig); mBreadCrumbView.fullScrollRight(); } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { if (requestCode == REQUEST_CODE_SETTINGS) { if (resultCode == Activity.RESULT_OK) { mPagerAdapter.notifyDataSetChanged(); } } } // =================== SERVICE CONNECTION ================== @Override public void onServiceConnected(ComponentName name, IBinder service) { ((OperationsService.LocalBinder) service).setOperationListener(this); } @Override public void onServiceDisconnected(ComponentName name) { if (mOperationProgressDialog != null) { mOperationProgressDialog.dismiss(); mOperationProgressDialog = null; } } // ================= OPERATION LISTENER ==================== @Override public void onOperationStarted(@NonNull final String action, @Nullable final CharSequence operationMessage, @NonNull final Intent cancelIntent) { if (mOperationProgressDialog == null || !mOperationProgressDialog.isShowing()) { mOperationProgressDialog = ProgressAlertDialogBuilder.create(this, operationMessage, new View.OnClickListener() { @Override public void onClick(final View view) { startService(cancelIntent); } }); if (!isFinishing()) { mOperationProgressDialog.show(); } } } @Override public void onOperationEnded(@Nullable final String operation, @Nullable final Object result) { if (mOperationProgressDialog != null) { mOperationProgressDialog.dismiss(); mOperationProgressDialog = null; } if (operation != null) { switch (operation) { case OperationsService.ACTION_DELETE: { @SuppressWarnings("unchecked") final ArrayList<GenericFile> failed = (ArrayList<GenericFile>) result; if (failed != null && !failed.isEmpty() && !isFinishing()) { MessageDialogBuilder.create(this, R.string.dialog_delete_failed, PFMTextUtils.fileListToDashList( failed) ).show(); } break; } case OperationsService.ACTION_PASTE: { @SuppressWarnings("unchecked") final ArrayList<GenericFile> failed = (ArrayList<GenericFile>) result; if (failed != null && !failed.isEmpty() && !isFinishing()) { MessageDialogBuilder.create(this, ClipBoard.isMove() ? R.string.dialog_move_failed : R.string.dialog_copy_failed, PFMTextUtils.fileListToDashList(failed) ).show(); } invalidateOptionsMenu(); break; } case OperationsService.ACTION_RENAME: case OperationsService.ACTION_CREATE_FILE: case OperationsService.ACTION_CREATE_DIRECTORY: if (result != null) { Toast.makeText(this, (CharSequence) result, Toast.LENGTH_SHORT).show(); } break; } } } /** * ActionBarDrawerToggle that manages display options and title */ private final class BrowserActivityDrawerToggle extends ActionBarDrawerToggle { private BrowserActivityDrawerToggle(Activity activity, DrawerLayout drawerLayout, int drawerImageRes, int openDrawerContentDescRes, int closeDrawerContentDescRes) { super(activity, drawerLayout, drawerImageRes, openDrawerContentDescRes, closeDrawerContentDescRes); } @Override public void onDrawerOpened(final View drawerView) { super.onDrawerOpened(drawerView); isDrawerOpened = true; mActionBar.setDisplayOptions(ActionBar.DISPLAY_SHOW_HOME | ActionBar.DISPLAY_HOME_AS_UP | ActionBar.DISPLAY_USE_LOGO | ActionBar.DISPLAY_SHOW_TITLE); mActionBar.setTitle(R.string.menu_bookmarks); mDrawerToggle.setDrawerIndicatorEnabled(true); invalidateOptionsMenu(); } @Override public void onDrawerClosed(final View drawerView) { super.onDrawerClosed(drawerView); isDrawerOpened = false; mActionBar.setDisplayOptions(ActionBar.DISPLAY_SHOW_HOME | ActionBar.DISPLAY_HOME_AS_UP | ActionBar.DISPLAY_SHOW_CUSTOM | ActionBar.DISPLAY_USE_LOGO); mDrawerToggle.setDrawerIndicatorEnabled(!mShowHomeAsUp); invalidateOptionsMenu(); } } }