Java tutorial
/* * Copyright 2011 The Android Open Source 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.holo.fileexplorer; import java.io.File; import java.util.ArrayList; import android.app.AlertDialog; import android.app.Dialog; import android.content.DialogInterface; import android.content.Intent; import android.content.DialogInterface.OnClickListener; import android.content.SharedPreferences; import android.content.SharedPreferences.OnSharedPreferenceChangeListener; import android.os.Build; import android.os.Bundle; import android.preference.PreferenceManager; import com.actionbarsherlock.app.ActionBar; import com.actionbarsherlock.app.SherlockFragmentActivity; import com.actionbarsherlock.view.Menu; import com.actionbarsherlock.view.MenuInflater; import com.actionbarsherlock.view.MenuItem; import com.holo.fileexplorer.R; import com.holo.root.ExtendedMount; import com.holo.root.RootSupport; import com.holo.actions.FileActionSupport; import com.stericson.RootTools.*; import com.viewpagerindicator.UnderlinePageIndicator; import android.support.v4.view.ViewPager; import android.support.v4.view.ViewPager.OnPageChangeListener; import android.util.Log; import android.view.KeyEvent; import android.view.LayoutInflater; import android.view.View; import android.view.inputmethod.EditorInfo; import android.widget.EditText; import android.widget.TextView; import android.widget.Toast; public class MainActivity extends SherlockFragmentActivity implements OnPageChangeListener { private MenuItem mUp; private MenuItem mBookmarks; private MenuItem mSearch; private MenuItem mNewFolder; private MenuItem mSort; private MenuItem mRefresh; private MenuItem mSettings; private MenuItem mExit; private MenuItem mReadOnly; private MenuItem mReadWrite; // Dialog Codes public static final int DIALOG_NEW_FOLDER = 1; public static final int DIALOG_DELETE = 2; public static final int DIALOG_RENAME = 3; public static final int DIALOG_MULTI_DELETE = 4; public static final int DIALOG_FILTER = 5; public static final int DIALOG_DETAILS = 6; public static final int DIALOG_BOOKMARKS = 7; public static final int DIALOG_ZIP = 8; public static final int DIALOG_WARNING_EXISTS = 9; public static final int DIALOG_CHANGE_FILE_EXTENSION = 10; public static final int DIALOG_MULTI_COMPRESS_ZIP = 11; // Used to pass parameters to onCreateDialog method private String mDialogArgument; // ViewPager variables public FileFragmentPagerAdapter mViewPager; public ViewPager mPager; private UnderlinePageIndicator mPageIndicator; // Preference variables private OnSharedPreferenceChangeListener listener; private Menu mMainOptionsMenu; private boolean shouldRestartApp = false; private int mThemeId = -1; public boolean firstRun = true; private String newZipName = ""; // Root and Busybox availability flags public boolean rootEnabled = false; public boolean busyBoxIsAvailable = false; public boolean rootIsAvailable = false; public ArrayList<ExtendedMount> mounts = null; /** * Where all of the magic starts. This is run when the application first * opens. It determines the current theme and instantiates the ViewPager * object. * * @param savedInstanceState * the freeze-dried state of the app before it was put into * hibernation (unless this is the initial start-up. * @return nothing */ public void onCreate(Bundle savedInstanceState) { // android.os.Debug.startMethodTracing("lsd"); SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this); String themeTest = prefs.getString("theme", "identity"); if (themeTest.equalsIgnoreCase("light")) { mThemeId = R.style.AppTheme_Light; } else if (themeTest.equalsIgnoreCase("dark")) { mThemeId = R.style.AppTheme_Dark; } else if (themeTest.equalsIgnoreCase("darkactionbar")) { mThemeId = R.style.AppTheme_Light_DarkActionBar; } else if (themeTest.equalsIgnoreCase("identity")) { mThemeId = R.style.AppTheme_Identity; } this.setTheme(mThemeId); // This must be called after setTheme() on pre-Honeycomb devices in // order for the correct theme background to show up properly. If this // is called first, the background from the theme defined in the // manifest will always be used regardless of new themes set via // setTheme(). super.onCreate(savedInstanceState); setContentView(R.layout.fragment_pager); ActionBar bar = getSupportActionBar(); bar.setTitle(""); mViewPager = new FileFragmentPagerAdapter(this, getSupportFragmentManager()); mPager = (ViewPager) findViewById(R.id.pager); mPager.setAdapter(mViewPager); mPager.setHorizontalScrollBarEnabled(true); // TODO this is a pretty much a hack job for now, and proper state // retaining needs to be implemented for tablets mPager.setOffscreenPageLimit(mViewPager.getCount()); // Set the drawable for the divider between each page in the ViewPager mPager.setPageMargin(FileActionSupport.convertDip2Pixels(this, 3)); mPager.setPageMarginDrawable(R.color.icsblue); mPageIndicator = (UnderlinePageIndicator) findViewById(R.id.indicator); mPageIndicator.setViewPager(mPager); rootEnabled = prefs.getBoolean("rootEnabled", false); if (rootEnabled) { if (RootTools.isRootAvailable()) { // su exists, so we can actually see if busybox is installed. // Unrooted users cannot use any of the root features, so lets // not // bother them with busybox // Check to see if busybox is available if (RootTools.isBusyboxAvailable()) { busyBoxIsAvailable = true; } else { // TODO change to RootTools method "2" to in order to // determine // what the User did in the market RootTools.offerBusyBox(this); } // Check to see if root access has been granted if (RootTools.isAccessGiven()) { // We're good to go! rootIsAvailable = true; try { mounts = RootSupport.getMounts(); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } } else { // Not rooted. This line should never be reached since the root // preferences options should be disabled on non-rooted devices. } } else { // Root functionality is not enabled in the preferences } } // private void checkRoot() { // SharedPreferences prefs = PreferenceManager // .getDefaultSharedPreferences(this); // try { // if (prefs.getBoolean("rootEnabled", false) // && (RootManager.Default == null || !RootManager.Default // .isRoot())) { // requestRoot(); // rootEnabled = true; // } else if (RootManager.Default != null) { // exitRoot(); // } // // } catch (Exception e) { // // Logger.LogWarning("Couldn't get root.", e); // } // // } // // private void requestRoot() { // // new Thread(new Runnable(){public void run(){ // RootManager.Default.requestRoot(); // // }}).start(); // } // // private void exitRoot() { // if (RootManager.Default == null) // return; // new Thread(new Runnable() { // public void run() { // RootManager.Default.exitRoot(); // } // }).start(); // } /** * This is basically run whenever the app is closed and then reopened. */ public void onResume() { super.onResume(); if (shouldRestartApp) { shouldRestartApp = false; Intent i = getBaseContext().getPackageManager() .getLaunchIntentForPackage(getBaseContext().getPackageName()); i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); startActivity(i); } listenForThemeChange(); mPageIndicator.setOnPageChangeListener(this); } @Override public void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); outState.putInt("theme", mThemeId); } @Override public boolean onCreateOptionsMenu(Menu menu) { mMainOptionsMenu = menu; MenuInflater menuInflater = getSupportMenuInflater(); menuInflater.inflate(R.menu.message_list_main, menu); mUp = menu.findItem(R.id.action_up); mBookmarks = menu.findItem(R.id.action_open_bookmarks); mSearch = menu.findItem(R.id.action_search); mNewFolder = menu.findItem(R.id.action_new_folder); mSort = menu.findItem(R.id.action_sort); mRefresh = menu.findItem(R.id.action_refresh); mSettings = menu.findItem(R.id.action_settings); mExit = menu.findItem(R.id.action_exit); mReadOnly = menu.findItem(R.id.action_ro); mReadWrite = menu.findItem(R.id.action_rw); // Calling super after populating the menu is necessary here to ensure // that the action bar helpers have a chance to handle this event. return super.onCreateOptionsMenu(menu); } @Override public boolean onPrepareOptionsMenu(Menu menu) { mUp.setVisible(true); mBookmarks.setVisible(true); mSearch.setVisible(true); mNewFolder.setVisible(true); mSort.setVisible(true); mRefresh.setVisible(true); mSettings.setVisible(true); mExit.setVisible(true); mReadOnly.setVisible(false); mReadWrite.setVisible(false); return super.onPrepareOptionsMenu(menu); } @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case android.R.id.home: Toast.makeText(this, "Tapped home", Toast.LENGTH_SHORT).show(); break; case R.id.action_rw: String currentPath = mViewPager.getFragment(mPager, mPager.getCurrentItem()).getCurrentDir() .getAbsolutePath(); boolean result = RootTools.remount(currentPath, "rw"); ArrayList<Mount> mounts = new ArrayList<Mount>(); try { mounts = RootTools.getMounts(); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } mounts.clear(); Log.v("MOUNT RW?", "RW WRITABLE? " + new File(currentPath).canWrite()); break; case R.id.action_ro: RootTools.remount( mViewPager.getFragment(mPager, mPager.getCurrentItem()).getCurrentDir().getAbsolutePath(), "ro"); break; case R.id.action_up: mViewPager.getFragment(mPager, mPager.getCurrentItem()).upOneLevel(); break; case R.id.action_new_folder: LayoutInflater inflater = LayoutInflater.from(this); View view = inflater.inflate(R.layout.dialog_new_folder, null); final EditText et = (EditText) view.findViewById(R.id.foldername); et.setText(""); new AlertDialog.Builder(this).setTitle(R.string.create_new_folder).setView(view) .setPositiveButton(android.R.string.ok, new OnClickListener() { public void onClick(DialogInterface dialog, int which) { mViewPager.getFragment(mPager, mPager.getCurrentItem()) .createNewFolder(et.getText().toString()); } }).setNegativeButton(android.R.string.cancel, new OnClickListener() { public void onClick(DialogInterface dialog, int which) { // Cancel should not do anything beyond // closing the dialog. } }).show(); break; case R.id.action_open_bookmarks: Toast.makeText(this, "Tapped bookmarks (Not implemented yet. Patience.)", Toast.LENGTH_SHORT).show(); break; case R.id.action_refresh: // getSupportActionBarHelper().setRefreshActionItemState(true); refreshCurrentPage(); // TODO: preserve scroll position and show // progress // getSupportActionBarHelper().setRefreshActionItemState(false); Toast.makeText(this, "Folder Refreshed", Toast.LENGTH_SHORT).show(); break; case R.id.action_search: Toast.makeText(this, "Tapped search (Not implemented yet. Patience.)", Toast.LENGTH_SHORT).show(); break; // case R.id.action_storage_summary: // Toast.makeText(this, // "Tapped storage summary (Not implemented yet. It'll be good though.)", // Toast.LENGTH_SHORT).show(); // break; case R.id.action_sort: // Do nothing. This has a submenu break; case R.id.sort_alphabetical: item.setChecked(true); mViewPager.getFragment(mPager, mPager.getCurrentItem()).sort(FileListFragment.SORT_ALPHABETICAL); break; case R.id.sort_last_modified: item.setChecked(true); mViewPager.getFragment(mPager, mPager.getCurrentItem()).sort(FileListFragment.SORT_LAST_MODIFIED); break; case R.id.sort_reverse: // Toggle the checked state Boolean newState = !item.isChecked(); item.setChecked(newState); mViewPager.getFragment(mPager, mPager.getCurrentItem()).sortDirection(newState); break; case R.id.action_settings: if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) { Intent intent = new Intent(this, EditPreferences.class); intent.putExtra("themeid", mThemeId); startActivity(new Intent(this, EditPreferences.class)); } else { startActivity(new Intent(this, EditPreferencesHC.class)); } break; case R.id.action_exit: // finish(); android.os.Process.killProcess(android.os.Process.myPid()); break; } return super.onOptionsItemSelected(item); } // This triggers an activity reload after a theme change so that the new // styles and assets can be pulled in private void listenForThemeChange() { listener = new OnSharedPreferenceChangeListener() { @Override public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { if (key.equals("theme")) { shouldRestartApp = true; } } }; PreferenceManager.getDefaultSharedPreferences(this).registerOnSharedPreferenceChangeListener(listener); } /** * Since Dialogs are (almost always) attached to an activity, they are all * defined here to provide simple, combined access. Courtesy of OpenIntents: * <p> * http://code.google.com/p/openintents/source/browse/#svn/trunk/samples/ * TestFileManager * <p> * *Note: commented code is straight from OI, and uncommented has been * modified to work with HFE * * @param id * id code of the desired dialog. Defined as a set of constants * within MainActivity * @param bundle * the bundle containing any parameters to be used by the dialog * @return a reference to the open dialog */ // @Override protected Dialog onCreateDialog(int id, Bundle bundle) { switch (id) { case DIALOG_NEW_FOLDER: LayoutInflater inflater = LayoutInflater.from(this); View view = inflater.inflate(R.layout.dialog_new_folder, null); final EditText et = (EditText) view.findViewById(R.id.foldername); et.setText(""); // accept "return" key TextView.OnEditorActionListener returnListener = new TextView.OnEditorActionListener() { public boolean onEditorAction(TextView exampleView, int actionId, KeyEvent event) { if (actionId == EditorInfo.IME_NULL && event.getAction() == KeyEvent.ACTION_DOWN) { // match this behavior to your OK button // createNewFolder(et.getText().toString()); dismissDialog(DIALOG_NEW_FOLDER); } return true; } }; // et.setOnEditorActionListener(returnListener); // // end of code regarding "return key" // // return new AlertDialog.Builder(this) // .setIcon(android.R.drawable.ic_dialog_alert) // .setTitle(R.string.create_new_folder) // .setView(view) // .setPositiveButton(android.R.string.ok, // new OnClickListener() { // // public void onClick(DialogInterface dialog, // int which) { // createNewFolder(et.getText().toString()); // } // // }) // .setNegativeButton(android.R.string.cancel, // new OnClickListener() { // // public void onClick(DialogInterface dialog, // int which) { // // Cancel should not do anything. // } // // }).create(); // case DIALOG_RENAME: // inflater = LayoutInflater.from(this); // view = inflater.inflate(R.layout.dialog_new_folder, null); // final EditText et2 = (EditText) // view.findViewById(R.id.foldername); // // accept "return" key // TextView.OnEditorActionListener returnListener2 = new // TextView.OnEditorActionListener() { // public boolean onEditorAction(TextView exampleView, // int actionId, KeyEvent event) { // if (actionId == EditorInfo.IME_NULL // && event.getAction() == KeyEvent.ACTION_DOWN) { // renameFileOrFolder(mContextFile, et2.getText() // .toString()); // match this behavior to your OK // // button // dismissDialog(DIALOG_RENAME); // } // return true; // } // // }; // et2.setOnEditorActionListener(returnListener2); // // end of code regarding "return key" // return new AlertDialog.Builder(this) // .setTitle(R.string.menu_rename) // .setView(view) // .setPositiveButton(android.R.string.ok, // new OnClickListener() { // // public void onClick(DialogInterface dialog, // int which) { // // renameFileOrFolder(mContextFile, et2 // .getText().toString()); // } // // }) // .setNegativeButton(android.R.string.cancel, // new OnClickListener() { // // public void onClick(DialogInterface dialog, // int which) { // // Cancel should not do anything. // } // // }).create(); case DIALOG_ZIP: inflater = LayoutInflater.from(this); view = inflater.inflate(R.layout.dialog_new_folder, null); final EditText editText = (EditText) view.findViewById(R.id.foldername); // accept "return" key TextView.OnEditorActionListener returnListener3 = new TextView.OnEditorActionListener() { public boolean onEditorAction(TextView exampleView, int actionId, KeyEvent event) { if (actionId == EditorInfo.IME_NULL && event.getAction() == KeyEvent.ACTION_DOWN) { mViewPager.getFragment(mPager, mPager.getCurrentItem()) .zipInit(editText.getText().toString()); // if (new File(mContextFile.getParent() + // File.separator // + editText.getText().toString()).exists()) { // mDialogArgument = editText.getText().toString(); // showDialog(DIALOG_WARNING_EXISTS); // } else { // new CompressManager(FileManagerActivity.this) // .compress(mContextFile, editText.getText() // .toString()); // } // match this behavior to your OK button dismissDialog(DIALOG_ZIP); } return true; } }; editText.setOnEditorActionListener(returnListener3); // end of code regarding "return key" return new AlertDialog.Builder(this).setTitle(R.string.zip_dialog).setView(view) .setPositiveButton(android.R.string.ok, new OnClickListener() { public void onClick(DialogInterface dialog, int which) { mViewPager.getFragment(mPager, mPager.getCurrentItem()) .zipInit(editText.getText().toString()); // if (new File(mContextFile.getParent() // + File.separator // + editText.getText().toString()) // .exists()) { // mDialogArgument = editText.getText() // .toString(); // showDialog(DIALOG_WARNING_EXISTS); // } else { // new CompressManager( // FileManagerActivity.this) // .compress(mContextFile, // editText.getText() // .toString()); // } } }).setNegativeButton(android.R.string.cancel, new OnClickListener() { public void onClick(DialogInterface dialog, int which) { // Cancel should not do anything. } }).create(); } return super.onCreateDialog(id, bundle); } /** * A part of the PageChangeListener interface. Not currently in use here. */ @Override public void onPageScrollStateChanged(int arg0) { // TODO Auto-generated method stub } /** * A part of the PageChangeListener interface. Not currently in use here. */ @Override public void onPageScrolled(int arg0, float arg1, int arg2) { // TODO Auto-generated method stub } /** * A part of the PageChangeListener interface. Since there are numerous UI * elements that are contextually based on the currently selected page, we * need to trigger UI updates after the user swipes to a new page. The pager * is contained within the main activity, but the relevant data must be * pushed from the currently selected list fragment. Therefore, the takeOver * method is called on the fragment, which then reaches back up and updates * the action bar, etc. * * @param position * the integer index of the currently selected page * @return nothing * */ @Override public void onPageSelected(int position) { Log.i("MainActivity: ", "onPageSelected: " + position); // Toast.makeText(this, "selected " + position, // Toast.LENGTH_SHORT).show(); FileListFragment fragment = mViewPager.getFragment(mPager, position); if (fragment != null) fragment.takeOver(mMainOptionsMenu); } /** * Used by the Action Mode to reset which viewPager page is in focus. Useful * for when an out-of-focus page list has checked items and the user presses * one of the action mode buttons (only one page can have checked items at a * time). Active page is set back to the one with the checked items so that * there is no confusion over what selection the action mode button is * operating on. * * @param pageNum * the integer index of the page we want to select * @return nothing */ public void setPage(int pageNum) { mPager.setCurrentItem(pageNum); } /** * Used by the Action Mode to get the directory of the current folder view. * Main activity is able to determine this, whereas the Action Mode has no * way of determining this. Used with the Paste action. After a file has * been copied or cut, this allows the Action Bar to enable swiping to a * different file view and pasting there. * * @return a file referencing the directory displayed within the currently * selected ViewPager page */ public File getCurrentDir() { return mViewPager.getFragment(mPager, mPager.getCurrentItem()).getCurrentDir(); } /** * Used by the Action Mode to refresh the current folder view. Main activity * is able to determine this, whereas the Action Mode has no way of * determining this. * * @return nothing */ public void refreshCurrentPage() { mViewPager.getFragment(mPager, mPager.getCurrentItem()).refresh(); } /** * KeyDown/KeyUp code derived from * http://developer.android.com/sdk/android-2.0.html (read very bottom of * page) * <p> * The user may tap the back button, but then drag off of the button to * avoid a button press * * @see android.support.v4.app.FragmentActivity#onKeyDown(int, * android.view.KeyEvent) * * */ public boolean onKeyDown(int keyCode, KeyEvent event) { if (keyCode == KeyEvent.KEYCODE_BACK && event.getRepeatCount() == 0) { event.startTracking(); return true; } return super.onKeyDown(keyCode, event); } /** * */ public boolean onKeyUp(int keyCode, KeyEvent event) { if (keyCode == KeyEvent.KEYCODE_BACK && event.isTracking() && !event.isCanceled()) { // *** DO ACTION HERE *** if (mViewPager.getFragment(mPager, mPager.getCurrentItem()).backOneLevel()) { return true; } else { new AlertDialog.Builder(this).setIcon(android.R.drawable.ic_dialog_alert) .setMessage("Quit the application?") .setPositiveButton("Yes", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { // android.os.Debug.stopMethodTracing(); finish(); } }).setNegativeButton("No", null).show(); } return true; } return super.onKeyUp(keyCode, event); } public void setFirstRun(boolean firstRun) { this.firstRun = firstRun; } public void setNewZipName(String newZipName) { this.newZipName = newZipName; } public String getNewZipName() { return this.newZipName; } }