Java tutorial
/***************************************************************************** * MainActivity.java ***************************************************************************** * Copyright 2011-2012 VLC authors and VideoLAN * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. *****************************************************************************/ package the.joevlc; import org.videolan.vlc.AudioServiceController; import org.videolan.vlc.LibVLC; import org.videolan.vlc.LibVlcException; import org.videolan.vlc.MediaLibrary; import org.videolan.vlc.ThumbnailerManager; import org.videolan.vlc.Util; import org.videolan.vlc.VLCCallbackTask; import org.videolan.vlc.gui.DirectoryViewFragment; import org.videolan.vlc.gui.HistoryFragment; import org.videolan.vlc.gui.SidebarAdapter; import org.videolan.vlc.gui.SidebarEntry; import org.videolan.vlc.gui.video.VideoListAdapter; import org.videolan.vlc.interfaces.ISortable; import org.videolan.vlc.widget.AudioMiniPlayer; import the.joevlc.R; import the.joevlc.R.id; import the.joevlc.R.layout; import the.joevlc.R.menu; import the.joevlc.R.string; import the.joevlc.R.style; import android.app.AlertDialog; import android.app.Dialog; import android.content.BroadcastReceiver; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.content.IntentFilter; import android.content.SharedPreferences; import android.content.SharedPreferences.Editor; import android.content.pm.PackageInfo; import android.content.pm.PackageManager.NameNotFoundException; import android.content.res.Configuration; import android.os.Bundle; import android.os.Handler; import android.preference.PreferenceManager; import android.support.v4.app.Fragment; import android.support.v4.app.FragmentTransaction; import android.util.Log; import android.view.Display; import android.view.LayoutInflater; import android.view.View; import android.view.View.OnClickListener; import android.view.WindowManager; import android.widget.AdapterView; import android.widget.AdapterView.OnItemClickListener; import android.widget.Button; import android.widget.CheckBox; import android.widget.EditText; import android.widget.ImageView; import android.widget.ListView; import android.widget.ProgressBar; import android.widget.TextView; 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.actionbarsherlock.view.Window; import com.slidingmenu.lib.SlidingMenu; public class MainActivity extends SherlockFragmentActivity { public final static String TAG = "VLC/MainActivity"; protected static final String ACTION_SHOW_PROGRESSBAR = "org.videolan.vlc.gui.ShowProgressBar"; protected static final String ACTION_HIDE_PROGRESSBAR = "org.videolan.vlc.gui.HideProgressBar"; protected static final String ACTION_SHOW_TEXTINFO = "org.videolan.vlc.gui.ShowTextInfo"; private static final String PREF_SHOW_INFO = "show_info"; private static final String PREF_FIRST_RUN = "first_run"; private static final int ACTIVITY_RESULT_PREFERENCES = 1; private ActionBar mActionBar; private SlidingMenu mMenu; private SidebarAdapter mSidebarAdapter; private AudioMiniPlayer mAudioPlayer; private AudioServiceController mAudioController; private ThumbnailerManager mThumbnailerManager; private View mInfoLayout; private ProgressBar mInfoProgress; private TextView mInfoText; private String mCurrentFragment; private SharedPreferences mSettings; private int mVersionNumber = -1; private boolean mFirstRun = false; private boolean mScanNeeded = true; @Override protected void onCreate(Bundle savedInstanceState) { if (!Util.hasCompatibleCPU()) { Log.e(TAG, Util.getErrorMsg()); Intent i = new Intent(this, CompatErrorActivity.class); startActivity(i); finish(); super.onCreate(savedInstanceState); return; } /* Get the current version from package */ PackageInfo pinfo = null; try { pinfo = getPackageManager().getPackageInfo(getPackageName(), 0); } catch (NameNotFoundException e) { Log.e(TAG, "package info not found."); } if (pinfo != null) mVersionNumber = pinfo.versionCode; /* Get settings */ mSettings = PreferenceManager.getDefaultSharedPreferences(this); /* Check if it's the first run */ mFirstRun = mSettings.getInt(PREF_FIRST_RUN, -1) != mVersionNumber; if (mFirstRun) { Editor editor = mSettings.edit(); editor.putInt(PREF_FIRST_RUN, mVersionNumber); editor.commit(); } try { // Start LibVLC LibVLC.getInstance(); } catch (LibVlcException e) { e.printStackTrace(); Intent i = new Intent(this, CompatErrorActivity.class); i.putExtra("runtimeError", true); i.putExtra("message", "LibVLC failed to initialize (LibVlcException)"); startActivity(i); finish(); super.onCreate(savedInstanceState); return; } super.onCreate(savedInstanceState); /*** Start initializing the UI ***/ /* Enable the indeterminate progress feature */ requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS); // Set up the sliding menu setContentView(R.layout.sliding_menu); mMenu = (SlidingMenu) findViewById(R.id.sliding_menu); changeMenuOffset(); View v_main = LayoutInflater.from(this).inflate(R.layout.main, null); mMenu.setContent(v_main); View sidebar = LayoutInflater.from(this).inflate(R.layout.sidebar, null); final ListView listView = (ListView) sidebar.findViewById(android.R.id.list); listView.setFooterDividersEnabled(true); mSidebarAdapter = new SidebarAdapter(); listView.setAdapter(mSidebarAdapter); mMenu.setMenu(sidebar); /* Initialize UI variables */ mInfoLayout = v_main.findViewById(R.id.info_layout); mInfoProgress = (ProgressBar) v_main.findViewById(R.id.info_progress); mInfoText = (TextView) v_main.findViewById(R.id.info_text); /* Set up the action bar */ mActionBar = getSupportActionBar(); mActionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD); mActionBar.setDisplayOptions(0, ActionBar.DISPLAY_SHOW_TITLE); mActionBar.setDisplayHomeAsUpEnabled(true); /* Add padding between the home button and the arrow */ ImageView home = (ImageView) findViewById(Util.isHoneycombOrLater() ? android.R.id.home : R.id.abs__home); if (home != null) home.setPadding(20, 0, 0, 0); /* Set up the sidebar click listener */ listView.setOnItemClickListener(new OnItemClickListener() { @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { SidebarEntry entry = (SidebarEntry) listView.getItemAtPosition(position); Fragment current = getSupportFragmentManager().findFragmentById(R.id.fragment_placeholder); if (current == null || current.getTag() == entry.id) { /* Already selected */ mMenu.showAbove(); return; } /* * Clear any backstack before switching tabs. This avoids * activating an old backstack, when a user hits the back button * to quit */ for (int i = 0; i < getSupportFragmentManager().getBackStackEntryCount(); i++) { getSupportFragmentManager().popBackStack(); } FragmentTransaction ft = getSupportFragmentManager().beginTransaction(); ft.detach(current); ft.attach(getFragment(entry.id)); ft.commit(); mCurrentFragment = entry.id; mMenu.showAbove(); } }); /* Set up the mini audio player */ mAudioPlayer = new AudioMiniPlayer(); mAudioController = AudioServiceController.getInstance(); mAudioPlayer.setAudioPlayerControl(mAudioController); mAudioPlayer.update(); getSupportFragmentManager().beginTransaction().replace(R.id.audio_mini_player, mAudioPlayer).commit(); /* Show info/alpha/beta Warning */ if (mSettings.getInt(PREF_SHOW_INFO, -1) != mVersionNumber) showInfoDialog(); else if (mFirstRun) { /* * The sliding menu is automatically opened when the user closes * the info dialog. If (for any reason) the dialog is not shown, * open the menu after a short delay. */ final Handler handler = new Handler(); handler.postDelayed(new Runnable() { @Override public void run() { mMenu.showBehind(); } }, 500); } /* Prepare the progressBar */ IntentFilter filter = new IntentFilter(); filter.addAction(ACTION_SHOW_PROGRESSBAR); filter.addAction(ACTION_HIDE_PROGRESSBAR); filter.addAction(ACTION_SHOW_TEXTINFO); registerReceiver(messageReceiver, filter); /* Reload the latest preferences */ reloadPreferences(); /* Load the thumbnailer */ mThumbnailerManager = new ThumbnailerManager(this, getWindowManager().getDefaultDisplay()); } private void changeMenuOffset() { WindowManager wm = (WindowManager) getSystemService(WINDOW_SERVICE); Display display = wm.getDefaultDisplay(); @SuppressWarnings("deprecation") int behindOffset_dp = Util.convertPxToDp(display.getWidth()) - 208; mMenu.setBehindOffset(Util.convertDpToPx(behindOffset_dp)); } @Override protected void onResume() { super.onResume(); mAudioController.addAudioPlayer(mAudioPlayer); AudioServiceController.getInstance().bindAudioService(this); /* FIXME: this is used to avoid having MainActivity twice in the backstack */ if (getIntent().hasExtra(AudioService.START_FROM_NOTIFICATION)) getIntent().removeExtra(AudioService.START_FROM_NOTIFICATION); /* Load media items from database and storage */ if (mScanNeeded) MediaLibrary.getInstance(this).loadMediaItems(this); } @Override protected void onResumeFragments() { super.onResumeFragments(); /* Restore last view */ Fragment current = getSupportFragmentManager().findFragmentById(R.id.fragment_placeholder); boolean found = false; if (current != null) { for (int i = 0; i < SidebarAdapter.entries.size(); i++) { if (SidebarAdapter.entries.get(i).id.equals(current.getTag())) { found = true; break; } } } else { found = true; } /* Don't call replace() on a non-sidebar fragment, since replace() will * remove() the currently displayed fragment and replace it with a * blank screen. */ if (found) { FragmentTransaction ft = getSupportFragmentManager().beginTransaction(); ft.replace(R.id.fragment_placeholder, getFragment(mCurrentFragment)); ft.commit(); } } /** * Stop audio player and save opened tab */ @Override protected void onPause() { super.onPause(); /* Check for an ongoing scan that needs to be resumed during onResume */ mScanNeeded = MediaLibrary.getInstance(this).isWorking(); /* Stop scanning for files */ MediaLibrary.getInstance(this).stop(); /* Stop the thumbnailer */ mThumbnailerManager.stop(); /* Save the tab status in pref */ SharedPreferences.Editor editor = getSharedPreferences("MainActivity", MODE_PRIVATE).edit(); editor.putString("fragment", mCurrentFragment); editor.commit(); mAudioController.removeAudioPlayer(mAudioPlayer); AudioServiceController.getInstance().unbindAudioService(this); } @Override protected void onDestroy() { super.onDestroy(); try { unregisterReceiver(messageReceiver); } catch (IllegalArgumentException e) { } if (mThumbnailerManager != null) mThumbnailerManager.clearJobs(); } @Override protected void onRestart() { super.onRestart(); /* Reload the latest preferences */ reloadPreferences(); } @Override public void onBackPressed() { if (mMenu.isBehindShowing()) { /* Close the menu first */ mMenu.showAbove(); return; } // If it's the directory view, a "backpressed" action shows a parent. if (mCurrentFragment.equals("directories")) { DirectoryViewFragment directoryView = (DirectoryViewFragment) getFragment(mCurrentFragment); if (!directoryView.isRootDirectory()) { directoryView.showParentDirectory(); return; } } super.onBackPressed(); } private Fragment getFragment(String id) { Fragment fragment = mSidebarAdapter.fetchFragment(id); if (!fragment.isAdded()) getSupportFragmentManager().beginTransaction().add(R.id.fragment_placeholder, fragment, id) .commitAllowingStateLoss(); /* Start the thumbnailer */ if (id.equals("video")) mThumbnailerManager.start((VideoGridFragment) fragment); return fragment; } /** Create menu from XML */ @Override public boolean onCreateOptionsMenu(Menu menu) { /* Note: on Android 3.0+ with an action bar this method * is called while the view is created. This can happen * any time after onCreate. */ MenuInflater inflater = getSupportMenuInflater(); inflater.inflate(R.menu.media_library, menu); return super.onCreateOptionsMenu(menu); } @Override public void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); changeMenuOffset(); } @Override public boolean onSearchRequested() { Intent intent = new Intent(this, SearchActivity.class); startActivity(intent); return false; } /** * Handle onClick form menu buttons */ @Override public boolean onOptionsItemSelected(MenuItem item) { // Intent to start a new Activity Intent intent; // Handle item selection switch (item.getItemId()) { case R.id.ml_menu_sortby_name: case R.id.ml_menu_sortby_length: Fragment current = getSupportFragmentManager().findFragmentById(R.id.fragment_placeholder); if (current == null) break; if (current instanceof ISortable) ((ISortable) current) .sortBy(item.getItemId() == R.id.ml_menu_sortby_name ? VideoListAdapter.SORT_BY_TITLE : VideoListAdapter.SORT_BY_LENGTH); break; // About case R.id.ml_menu_about: intent = new Intent(this, AboutActivity.class); startActivity(intent); break; // Preferences case R.id.ml_menu_preferences: intent = new Intent(this, PreferencesActivity.class); startActivityForResult(intent, ACTIVITY_RESULT_PREFERENCES); break; // Refresh case R.id.ml_menu_refresh: // TODO: factor this into each fragment if (mCurrentFragment.equals("directories")) { DirectoryViewFragment directoryView = (DirectoryViewFragment) getFragment(mCurrentFragment); directoryView.refresh(); } else if (mCurrentFragment.equals("history")) ((HistoryFragment) getFragment(mCurrentFragment)).refresh(); else MediaLibrary.getInstance(this).loadMediaItems(this, true); break; // Restore last playlist case R.id.ml_menu_last_playlist: Intent i = new Intent(AudioService.ACTION_REMOTE_LAST_PLAYLIST); sendBroadcast(i); break; // Open MRL case R.id.ml_menu_open_mrl: onOpenMRL(); break; case R.id.ml_menu_search: onSearchRequested(); break; case android.R.id.home: /* Toggle the sidebar */ if (mMenu.isBehindShowing()) mMenu.showAbove(); else mMenu.showBehind(); break; } return super.onOptionsItemSelected(item); } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if (requestCode == ACTIVITY_RESULT_PREFERENCES) { if (resultCode == PreferencesActivity.RESULT_RESCAN) MediaLibrary.getInstance(this).loadMediaItems(this, true); } } private void reloadPreferences() { SharedPreferences sharedPrefs = getSharedPreferences("MainActivity", MODE_PRIVATE); mCurrentFragment = sharedPrefs.getString("fragment", "video"); } private void showInfoDialog() { final Dialog infoDialog = new Dialog(this, R.style.info_dialog); infoDialog.setContentView(R.layout.info_dialog); Button okButton = (Button) infoDialog.findViewById(R.id.ok); okButton.setOnClickListener(new OnClickListener() { @Override public void onClick(View view) { CheckBox notShowAgain = (CheckBox) infoDialog.findViewById(R.id.not_show_again); if (notShowAgain.isChecked() && mSettings != null) { Editor editor = mSettings.edit(); editor.putInt(PREF_SHOW_INFO, mVersionNumber); editor.commit(); } /* Close the dialog */ infoDialog.dismiss(); /* and finally open the sliding menu if first run */ if (mFirstRun) mMenu.showBehind(); } }); infoDialog.show(); } /** * onClick event from xml * @param view */ public void searchClick(View view) { onSearchRequested(); } private final BroadcastReceiver messageReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { String action = intent.getAction(); if (action.equalsIgnoreCase(ACTION_SHOW_PROGRESSBAR)) { setSupportProgressBarIndeterminateVisibility(true); getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); } else if (action.equalsIgnoreCase(ACTION_HIDE_PROGRESSBAR)) { setSupportProgressBarIndeterminateVisibility(false); getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); } else if (action.equalsIgnoreCase(ACTION_SHOW_TEXTINFO)) { String info = intent.getStringExtra("info"); int max = intent.getIntExtra("max", 0); int progress = intent.getIntExtra("progress", 100); mInfoText.setText(info); mInfoProgress.setMax(max); mInfoProgress.setProgress(progress); mInfoLayout.setVisibility(info != null ? View.VISIBLE : View.GONE); } } }; public static void showProgressBar(Context context) { if (context == null) return; Intent intent = new Intent(); intent.setAction(ACTION_SHOW_PROGRESSBAR); context.getApplicationContext().sendBroadcast(intent); } public static void hideProgressBar(Context context) { if (context == null) return; Intent intent = new Intent(); intent.setAction(ACTION_HIDE_PROGRESSBAR); context.getApplicationContext().sendBroadcast(intent); } public static void sendTextInfo(Context context, String info, int progress, int max) { if (context == null) return; Intent intent = new Intent(); intent.setAction(ACTION_SHOW_TEXTINFO); intent.putExtra("info", info); intent.putExtra("progress", progress); intent.putExtra("max", max); context.getApplicationContext().sendBroadcast(intent); } public static void clearTextInfo(Context context) { sendTextInfo(context, null, 0, 100); } private void onOpenMRL() { AlertDialog.Builder b = new AlertDialog.Builder(this); final EditText input = new EditText(this); b.setTitle(R.string.open_mrl_dialog_title); b.setMessage(R.string.open_mrl_dialog_msg); b.setView(input); b.setPositiveButton(R.string.open, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int button) { /* Start this in a new thread as to not block the UI thread */ VLCCallbackTask task = new VLCCallbackTask(MainActivity.this) { @Override public void run() { AudioServiceController c = AudioServiceController.getInstance(); String s = input.getText().toString(); /* Use the audio player by default. If a video track is * detected, then it will automatically switch to the video * player. This allows us to support more types of streams * (for example, RTSP and TS streaming) where ES can be * dynamically adapted rather than a simple scan. */ c.append(s); } }; task.execute(); } }); b.setNegativeButton("Cancel", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface arg0, int arg1) { return; } }); b.show(); } }