package edu.mit.mobile.android.locast.ver2.casts; /* * Copyright (C) 2011 MIT Mobile Experience Lab * * 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. */ import android.content.Intent; import android.content.res.Configuration; import android.database.Cursor; import android.graphics.drawable.Drawable; import android.media.MediaPlayer; import android.media.MediaPlayer.OnCompletionListener; import android.media.MediaPlayer.OnErrorListener; import android.media.MediaPlayer.OnPreparedListener; import android.net.Uri; import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.support.v4.app.FragmentActivity; import android.support.v4.app.LoaderManager; import android.support.v4.app.LoaderManager.LoaderCallbacks; import android.support.v4.content.CursorLoader; import android.support.v4.content.Loader; import android.view.View; import android.view.WindowManager; import android.view.animation.AnimationUtils; import android.widget.ImageView; import android.widget.MediaController; import android.widget.TextView; import android.widget.VideoView; import edu.mit.mobile.android.imagecache.ImageCache.OnImageLoadListener; import edu.mit.mobile.android.locast.data.CastMedia; import edu.mit.mobile.android.locast.data.MediaProvider; import edu.mit.mobile.android.locast.ver2.R; /** * @author steve * */ public class VideoPlayer extends FragmentActivity implements LoaderCallbacks<Cursor>, OnPreparedListener, OnCompletionListener, OnErrorListener, OnImageLoadListener { private static final String TAG = VideoPlayer.class.getSimpleName(); private static final long OSD_TIMEOUT = 5000; VideoView mVideoView; MediaPlayer mMediaPlayer; MediaController mMediaController; TextView mDescriptionView; TextView mTitleView; private final int LOADER_CASTMEDIA_DIR = 0, LOADER_CASTMEDIA_ITEM = 1; private static final String[] CASTMEDIA_PROJECTION = new String[] { CastMedia._ID, CastMedia._DESCRIPTION, CastMedia._TITLE, CastMedia._LOCAL_URI, CastMedia._MEDIA_URL, CastMedia._MIME_TYPE }; private static final int HIDE_TITLE = 0; private long mTitleShowStart; private final Handler mHandler = new Handler(){ @Override public void handleMessage(Message msg) { switch (msg.what){ case HIDE_TITLE: hideTitleNow(); break; } } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.videoplayer); mVideoView = (VideoView) findViewById(R.id.video); mMediaController = new MediaController(this); mMediaController.setMediaPlayer(mVideoView); mMediaController.setAnchorView(mVideoView); mVideoView.setOnPreparedListener(this); mVideoView.setOnErrorListener(this); mVideoView.setOnCompletionListener(this); mVideoView.setMediaController(mMediaController); mDescriptionView = (TextView) findViewById(R.id.description); mTitleView = (TextView) findViewById(R.id.title); final Intent intent = getIntent(); final String action = intent.getAction(); final String type = intent.resolveType(this); final LoaderManager lm = getSupportLoaderManager(); setProgressBar(true); if (MediaProvider.TYPE_CASTMEDIA_DIR.equals(type)) { lm.initLoader(LOADER_CASTMEDIA_DIR, null, this); } else if (MediaProvider.TYPE_CASTMEDIA_ITEM.equals(type)) { lm.initLoader(LOADER_CASTMEDIA_ITEM, null, this); } adjustForOrientation(getResources().getConfiguration()); } @Override protected void onResume() { super.onResume(); } @Override protected void onPause() { super.onPause(); mVideoView.pause(); } @Override public void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); adjustForOrientation(newConfig); getWindow().getDecorView().requestLayout(); } private void adjustForOrientation(Configuration newConfig){ if (Configuration.ORIENTATION_PORTRAIT == newConfig.orientation){ mDescriptionView.setVisibility(View.VISIBLE); mTitleView.setVisibility(View.VISIBLE); mHandler.removeMessages(HIDE_TITLE); }else{ mDescriptionView.setVisibility(View.INVISIBLE); if (mVideoView.isPlaying()){ hideTitleNow(); } } } @Override public Loader<Cursor> onCreateLoader(int id, Bundle extra) { switch (id) { case LOADER_CASTMEDIA_DIR: return new CursorLoader(this, getIntent().getData(), CASTMEDIA_PROJECTION, null, null, null); case LOADER_CASTMEDIA_ITEM: return new CursorLoader(this, getIntent().getData(), CASTMEDIA_PROJECTION, null, null, null); default: return null; } } /* * When the loader finishes, start playing. If it gets called again, but * it's already playing, that's probably due to a synchronization going on * in the background and it shouldn't be interrupted. If it's not * successfully playing, then it probably makes sense to try playing again. * * @see * android.support.v4.app.LoaderManager.LoaderCallbacks#onLoadFinished(android * .support.v4.content.Loader, java.lang.Object) */ @Override public void onLoadFinished(Loader<Cursor> loader, Cursor c) { if (!mVideoView.isPlaying()) { c.moveToFirst(); final String mimeType = c.getString(c .getColumnIndex(CastMedia._MIME_TYPE)); final Uri media = CastMedia.getMedia(c, c.getColumnIndex(CastMedia._MEDIA_URL), c.getColumnIndex(CastMedia._LOCAL_URI)); final String title = c.getString(c.getColumnIndex(CastMedia._TITLE)); if (title != null){ setTitle(title); showTitle(); } final String description = c.getString(c.getColumnIndex(CastMedia._DESCRIPTION)); if (description != null){ mDescriptionView.setText(description); } // TODO figure out how to put this on a non-UI thread. Unfortunately, // it looks like that will require using a MediaPlayer directly as this // method looks like it needs to be called on the UI thread. mVideoView.setVideoURI(media); mVideoView.start(); } } @Override public void onLoaderReset(Loader<Cursor> loader) { } @Override public void setTitle(CharSequence title){ super.setTitle(title); mTitleView.setText(title); } private void hideTitle(){ mHandler.sendMessageDelayed(mHandler.obtainMessage(HIDE_TITLE), Math.max(0, OSD_TIMEOUT - (System.currentTimeMillis() - mTitleShowStart))); } private void hideTitleNow(){ if (mTitleView.getVisibility() != View.INVISIBLE){ mTitleView.startAnimation(AnimationUtils.loadAnimation(VideoPlayer.this, R.anim.fade_out)); mTitleView.setVisibility(View.INVISIBLE); } } private void showTitle(){ if (mTitleView.getVisibility() != View.VISIBLE){ mTitleView.startAnimation(AnimationUtils.loadAnimation(VideoPlayer.this, R.anim.fade_in)); mTitleView.setVisibility(View.VISIBLE); mTitleShowStart = System.currentTimeMillis(); } } @Override public void onPrepared(MediaPlayer arg0) { setProgressBar(false); //getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); hideTitle(); } public void setProgressBar(boolean visible) { final View progress = findViewById(R.id.progress); final int newVisibility = visible ? View.VISIBLE : View.GONE; if (progress.getVisibility() != newVisibility) { progress.setVisibility(newVisibility); findViewById(R.id.progress_text).setVisibility(newVisibility); if (visible){ // keep the screen on and bright while the progress bar is going, so the user doesn't become annoyed while waiting getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); } } } public void setProgressText(int resid) { ((TextView) findViewById(R.id.progress_text)).setText(resid); } @Override public boolean onError(MediaPlayer arg0, int what, int extra) { setProgressBar(false); getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); return false; } @Override public void onCompletion(MediaPlayer arg0) { getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); } @Override public void onImageLoaded(long id, Uri imageUri, Drawable image) { ((ImageView)findViewById((int) id)).setImageDrawable(image); } }