diff options
author | Likai Ding <likaid@codeaurora.org> | 2013-08-20 16:21:57 +0800 |
---|---|---|
committer | Xiaojing Zhang <zhangx@codeaurora.org> | 2014-11-04 20:38:08 -0800 |
commit | 253ebbd3baff765d034adcd960bdaf40e949a44f (patch) | |
tree | f0f5c2396db8f1990a1e999f6cff066eaf1d803e /src/org/codeaurora/gallery3d | |
parent | 5a4edcd17ea886d29c3d6bc97bba4e1f2b0d0e40 (diff) | |
download | android_packages_apps_Gallery2-253ebbd3baff765d034adcd960bdaf40e949a44f.tar.gz android_packages_apps_Gallery2-253ebbd3baff765d034adcd960bdaf40e949a44f.tar.bz2 android_packages_apps_Gallery2-253ebbd3baff765d034adcd960bdaf40e949a44f.zip |
Gallery2: add some video features
including: previous/next video play mode, screen mode,
fast forward/rewind button, step settings.
Change-Id: I3f4890c4dd95956e0eca889a5fd8b8d83b8d542e
Diffstat (limited to 'src/org/codeaurora/gallery3d')
17 files changed, 1347 insertions, 248 deletions
diff --git a/src/org/codeaurora/gallery3d/ext/IContrllerOverlayExt.java b/src/org/codeaurora/gallery3d/ext/IContrllerOverlayExt.java new file mode 100644 index 000000000..da50cdffc --- /dev/null +++ b/src/org/codeaurora/gallery3d/ext/IContrllerOverlayExt.java @@ -0,0 +1,51 @@ +package org.codeaurora.gallery3d.ext; +/** + * Controller overlay extension interface. + */ +public interface IContrllerOverlayExt { + /** + * Show buffering state. + * @param fullBuffer + * @param percent + */ + void showBuffering(boolean fullBuffer, int percent); + /** + * Clear buffering state. + */ + void clearBuffering(); + /** + * Show re-connecting state. + * @param times + */ + void showReconnecting(int times); + /** + * Show re-connecting error for connecting fail error. + */ + void showReconnectingError(); + /** + * Show playing info or not. + * @param liveStreaming true means showing playing info, otherwise doesn't show playing info. + */ + void setPlayingInfo(boolean liveStreaming); + /** + * Indicates whether current video can be paused or not. + * @param canPause + */ + void setCanPause(boolean canPause); + /** + * Indicates whether thumb can be scrubbed or not. + * @param enable + */ + void setCanScrubbing(boolean enable); + /** + * Always show bottmon panel or not. + * @param alwaysShow + * @param foreShow + */ + void setBottomPanel(boolean alwaysShow, boolean foreShow); + /** + * Is playing end or not. + * @return + */ + boolean isPlayingEnd(); +} diff --git a/src/org/codeaurora/gallery3d/ext/IMovieList.java b/src/org/codeaurora/gallery3d/ext/IMovieList.java new file mode 100644 index 000000000..404d24c41 --- /dev/null +++ b/src/org/codeaurora/gallery3d/ext/IMovieList.java @@ -0,0 +1,46 @@ +package org.codeaurora.gallery3d.ext; +/** + * Movie list extension interface + */ +public interface IMovieList { + /** + * Add movie item to list. + * @param item + */ + void add(IMovieItem item); + /** + * Get the item index of list + * @param item + * @return + */ + int index(IMovieItem item); + /** + * + * @return list size + */ + int size(); + /** + * + * @param item + * @return next item of current item + */ + IMovieItem getNext(IMovieItem item); + /** + * + * @param item + * @return previous item of current item + */ + IMovieItem getPrevious(IMovieItem item); + /** + * Is first item in list + * @param item + * @return + */ + boolean isFirst(IMovieItem item); + /** + * Is last item in list. + * @param item + * @return + */ + boolean isLast(IMovieItem item); +}
\ No newline at end of file diff --git a/src/org/codeaurora/gallery3d/ext/IMovieListLoader.java b/src/org/codeaurora/gallery3d/ext/IMovieListLoader.java new file mode 100644 index 000000000..db4c71347 --- /dev/null +++ b/src/org/codeaurora/gallery3d/ext/IMovieListLoader.java @@ -0,0 +1,50 @@ +package org.codeaurora.gallery3d.ext; + +import android.content.Context; +import android.content.Intent; + +public interface IMovieListLoader { + /** + * Load all video list or not.[boolean] + * "yes" means load all videos in all storages. + * "false" means load videos located in current video's folder. + */ + String EXTRA_ALL_VIDEO_FOLDER = "org.codeaurora.intent.extra.ALL_VIDEO_FOLDER"; + /** + * Video list order by column name.[String] + */ + String EXTRA_ORDERBY = "org.codeaurora.intent.extra.VIDEO_LIST_ORDERBY"; + /** + * Enable video list or not.[boolean] + */ + String EXTRA_ENABLE_VIDEO_LIST = "org.codeaurora.intent.extra.ENABLE_VIDEO_LIST"; + /** + * Loader listener interface + */ + public interface LoaderListener { + /** + * Will be called after movie list loaded. + * @param movieList + */ + void onListLoaded(IMovieList movieList); + } + /** + * Build the movie list from current item. + * @param context + * @param intent + * @param l + * @param item + */ + void fillVideoList(Context context, Intent intent, LoaderListener l, IMovieItem item); + /** + * enable video list or not. + * @param intent + * @return + */ + boolean isEnabledVideoList(Intent intent); + /** + * Cancel current loading process. + */ + void cancelList(); + +} diff --git a/src/org/codeaurora/gallery3d/ext/IMoviePlayer.java b/src/org/codeaurora/gallery3d/ext/IMoviePlayer.java index 3013cbcb1..32d400b0d 100644 --- a/src/org/codeaurora/gallery3d/ext/IMoviePlayer.java +++ b/src/org/codeaurora/gallery3d/ext/IMoviePlayer.java @@ -32,4 +32,11 @@ public interface IMoviePlayer { * Stop current video. */ void stopVideo(); + + /** + * start current item and stop playing video. + * + * @param item + */ + void startNextVideo(IMovieItem item); } diff --git a/src/org/codeaurora/gallery3d/ext/MovieList.java b/src/org/codeaurora/gallery3d/ext/MovieList.java new file mode 100644 index 000000000..585e288ef --- /dev/null +++ b/src/org/codeaurora/gallery3d/ext/MovieList.java @@ -0,0 +1,72 @@ +package org.codeaurora.gallery3d.ext; + +import android.util.Log; + +import java.util.ArrayList; + +public class MovieList implements IMovieList { + private static final String TAG = "MovieList"; + private static final boolean LOG = true; + + private final ArrayList<IMovieItem> mItems = new ArrayList<IMovieItem>(); + private static final int UNKNOWN = -1; + + @Override + public void add(IMovieItem item) { + if (LOG) { + Log.v(TAG, "add(" + item + ")"); + } + mItems.add(item); + } + + @Override + public int index(IMovieItem item) { + int find = UNKNOWN; + int size = mItems.size(); + for (int i = 0; i < size; i++) { + if (item == mItems.get(i)) { + find = i; + break; + } + } + if (LOG) { + Log.v(TAG, "index(" + item + ") return " + find); + } + return find; + } + + @Override + public int size() { + return mItems.size(); + } + + @Override + public IMovieItem getNext(IMovieItem item) { + IMovieItem next = null; + int find = index(item); + if (find >= 0 && find < size() - 1) { + next = mItems.get(++find); + } + return next; + } + + @Override + public IMovieItem getPrevious(IMovieItem item) { + IMovieItem prev = null; + int find = index(item); + if (find > 0 && find < size()) { + prev = mItems.get(--find); + } + return prev; + } + + @Override + public boolean isFirst(IMovieItem item) { + return getPrevious(item) == null; + } + + @Override + public boolean isLast(IMovieItem item) { + return getNext(item) == null; + } +} diff --git a/src/org/codeaurora/gallery3d/ext/MovieListLoader.java b/src/org/codeaurora/gallery3d/ext/MovieListLoader.java new file mode 100644 index 000000000..cb3505650 --- /dev/null +++ b/src/org/codeaurora/gallery3d/ext/MovieListLoader.java @@ -0,0 +1,203 @@ +package org.codeaurora.gallery3d.ext; + +import android.content.ContentResolver; +import android.content.ContentUris; +import android.content.Context; +import android.content.Intent; +import android.database.Cursor; +import android.database.sqlite.SQLiteException; +import android.net.Uri; +import android.os.AsyncTask; +import android.provider.MediaStore; +import android.provider.OpenableColumns; +import android.util.Log; + +/** + * Movie list loader class. It will load videos from MediaProvider database. + * If MoviePlayer starting activity doesn't set any thing, default OrderBy will be used. + * Default OrderBy: MediaStore.Video.Media.DATE_TAKEN + " DESC, " + MediaStore.Video.Media._ID + " DESC "; + */ +public class MovieListLoader implements IMovieListLoader { + private static final String TAG = "MovieListLoader"; + private static final boolean LOG = true; + + private MovieListFetcherTask mListTask; + + @Override + public void fillVideoList(Context context, Intent intent, LoaderListener l, IMovieItem item) { + boolean fetechAll = false; + if (intent.hasExtra(EXTRA_ALL_VIDEO_FOLDER)) { + fetechAll = intent.getBooleanExtra(EXTRA_ALL_VIDEO_FOLDER, false); + } + //default order by + String orderBy = MediaStore.Video.Media.DATE_TAKEN + " DESC, " + MediaStore.Video.Media._ID + " DESC "; + if (intent.hasExtra(EXTRA_ORDERBY)) { + orderBy = intent.getStringExtra(EXTRA_ORDERBY); + } + cancelList(); + mListTask = new MovieListFetcherTask(context, fetechAll, l, orderBy); + mListTask.execute(item); + if (LOG) { + Log.v(TAG, "fillVideoList() fetechAll=" + fetechAll + ", orderBy=" + orderBy); + } + } + + @Override + public boolean isEnabledVideoList(Intent intent) { + boolean enable = true; + if (intent != null && intent.hasExtra(EXTRA_ENABLE_VIDEO_LIST)) { + enable = intent.getBooleanExtra(EXTRA_ENABLE_VIDEO_LIST, true); + } + if (LOG) { + Log.v(TAG, "isEnabledVideoList() return " + enable); + } + return enable; + } + + @Override + public void cancelList() { + if (mListTask != null) { + mListTask.cancel(true); + } + } + + private class MovieListFetcherTask extends AsyncTask<IMovieItem, Void, IMovieList> { + private static final String TAG = "MovieListFetcherTask"; + private static final boolean LOG = true; + + // TODO comments by sunlei +// public static final String COLUMN_STEREO_TYPE = MediaStore.Video.Media.STEREO_TYPE; +// public static final String COLUMN_STEREO_TYPE = "STEREO_TYPE"; + + private final ContentResolver mCr; + private final LoaderListener mFetecherListener; + private final boolean mFetechAll; + private final String mOrderBy; + + public MovieListFetcherTask(Context context, boolean fetechAll, LoaderListener l, String orderBy) { + mCr = context.getContentResolver(); + mFetecherListener = l; + mFetechAll = fetechAll; + mOrderBy = orderBy; + if (LOG) { + Log.v(TAG, "MovieListFetcherTask() fetechAll=" + fetechAll + ", orderBy=" + orderBy); + } + } + + @Override + protected void onPostExecute(IMovieList params) { + if (LOG) { + Log.v(TAG, "onPostExecute() isCancelled()=" + isCancelled()); + } + if (isCancelled()) { + return; + } + if (mFetecherListener != null) { + mFetecherListener.onListLoaded(params); + } + } + + @Override + protected IMovieList doInBackground(IMovieItem... params) { + if (LOG) { + Log.v(TAG, "doInBackground() begin"); + } + if (params[0] == null) { + return null; + } + IMovieList movieList = null; + Uri uri = params[0].getUri(); + String mime = params[0].getMimeType(); + if (mFetechAll) { //get all list + if (MovieUtils.isLocalFile(uri, mime)) { + String uristr = String.valueOf(uri); + if (uristr.toLowerCase().startsWith("content://media")) { + //from gallery, gallery3D, videoplayer + long curId = Long.parseLong(uri.getPathSegments().get(3)); + movieList = fillUriList(null, null, curId, params[0]); + } + } + } else { //get current list + if (MovieUtils.isLocalFile(uri, mime)) { + String uristr = String.valueOf(uri); + if (uristr.toLowerCase().startsWith("content://media")) { + Cursor cursor = mCr.query(uri, + new String[]{MediaStore.Video.Media.BUCKET_ID}, + null, null, null); + long bucketId = -1; + if (cursor != null) { + if (cursor.moveToFirst()) { + bucketId = cursor.getLong(0); + } + cursor.close(); + } + long curId = Long.parseLong(uri.getPathSegments().get(3)); + movieList = fillUriList(MediaStore.Video.Media.BUCKET_ID + "=? ", + new String[]{String.valueOf(bucketId)}, curId, params[0]); + } else if (uristr.toLowerCase().startsWith("file://")) { + String data = Uri.decode(uri.toString()); + data = data.replaceAll("'", "''"); + String where = "_data LIKE '%" + data.replaceFirst("file:///", "") + "'"; + Cursor cursor = mCr.query(MediaStore.Video.Media.EXTERNAL_CONTENT_URI, + new String[]{"_id", MediaStore.Video.Media.BUCKET_ID}, + where, null, null); + long bucketId = -1; + long curId = -1; + if (cursor != null) { + if (cursor.moveToFirst()) { + curId = cursor.getLong(0); + bucketId = cursor.getLong(1); + } + cursor.close(); + } + movieList = fillUriList(MediaStore.Video.Media.BUCKET_ID + "=? ", + new String[]{String.valueOf(bucketId)}, curId, params[0]); + } + } + } + if (LOG) { + Log.v(TAG, "doInBackground() done return " + movieList); + } + return movieList; + } + + private IMovieList fillUriList(String where, String[] whereArgs, long curId, IMovieItem current) { + IMovieList movieList = null; + Cursor cursor = null; + try { + cursor = mCr.query(MediaStore.Video.Media.EXTERNAL_CONTENT_URI, + new String[]{"_id", "mime_type", OpenableColumns.DISPLAY_NAME}, + where, + whereArgs, + mOrderBy); + boolean find = false; + if (cursor != null && cursor.getCount() > 0) { + movieList = new MovieList(); + while (cursor.moveToNext()) { + long id = cursor.getLong(0); + if (!find && id == curId) { + find = true; + movieList.add(current); + continue; + } + Uri uri = ContentUris.withAppendedId(MediaStore.Video.Media.EXTERNAL_CONTENT_URI, id); + String mimeType = cursor.getString(1); + String title = cursor.getString(2); + + movieList.add(new MovieItem(uri, mimeType, title)); + } + } + } catch (final SQLiteException e) { + e.printStackTrace(); + } finally { + if (cursor != null) { + cursor.close(); + } + } + if (LOG) { + Log.v(TAG, "fillUriList() cursor=" + cursor + ", return " + movieList); + } + return movieList; + } + } +} diff --git a/src/org/codeaurora/gallery3d/video/CodeauroraVideoView.java b/src/org/codeaurora/gallery3d/video/CodeauroraVideoView.java index 39bf532e6..f6ed2c550 100755 --- a/src/org/codeaurora/gallery3d/video/CodeauroraVideoView.java +++ b/src/org/codeaurora/gallery3d/video/CodeauroraVideoView.java @@ -7,6 +7,8 @@ import android.content.Intent; import android.content.res.Resources; import android.media.AudioManager; import android.media.MediaPlayer; +import android.media.MediaPlayer.OnBufferingUpdateListener; +import android.media.MediaPlayer.OnVideoSizeChangedListener; import android.media.Metadata; import android.media.MediaPlayer.OnCompletionListener; import android.media.MediaPlayer.OnErrorListener; @@ -26,6 +28,8 @@ import android.view.accessibility.AccessibilityNodeInfo; import android.widget.MediaController; import android.widget.MediaController.MediaPlayerControl; +import org.codeaurora.gallery3d.video.ScreenModeManager.ScreenModeListener; + import java.io.IOException; import java.util.Map; @@ -36,7 +40,7 @@ import java.util.Map; * it can be used in any layout manager, and provides various display options * such as scaling and tinting. */ -public class CodeauroraVideoView extends SurfaceView implements MediaPlayerControl { +public class CodeauroraVideoView extends SurfaceView implements MediaPlayerControl, ScreenModeListener{ private static final boolean LOG = true; private String TAG = "CodeauroraVideoView"; // settable by the client @@ -77,6 +81,7 @@ public class CodeauroraVideoView extends SurfaceView implements MediaPlayerContr private MediaPlayer.OnBufferingUpdateListener mOnBufferingUpdateListener; private MediaPlayer.OnVideoSizeChangedListener mVideoSizeListener; private MediaPlayer.OnPreparedListener mPreparedListener; + private ScreenModeManager mScreenManager; private int mCurrentBufferPercentage; private OnErrorListener mOnErrorListener; private OnInfoListener mOnInfoListener; @@ -84,6 +89,7 @@ public class CodeauroraVideoView extends SurfaceView implements MediaPlayerContr private boolean mCanPause; private boolean mCanSeekBack; private boolean mCanSeekForward; + private boolean mCanSeek; private boolean mHasGotPreparedCallBack = false; private boolean mNeedWaitLayout = false; private boolean mHasGotMetaData = false; @@ -99,9 +105,9 @@ public class CodeauroraVideoView extends SurfaceView implements MediaPlayerContr if (mMediaPlayer == null || mUri == null) { Log.w(TAG, "Cannot prepare play! mMediaPlayer=" + mMediaPlayer + ", mUri=" + mUri); - } else { - doPreparedIfReady(mMediaPlayer); + return; } + doPreparedIfReady(mMediaPlayer); break; default: Log.w(TAG, "Unhandled message " + msg); @@ -130,57 +136,47 @@ public class CodeauroraVideoView extends SurfaceView implements MediaPlayerContr @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - int width = getDefaultSize(mVideoWidth, widthMeasureSpec); - int height = getDefaultSize(mVideoHeight, heightMeasureSpec); - if (mVideoWidth > 0 && mVideoHeight > 0) { - - int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec); - int widthSpecSize = MeasureSpec.getSize(widthMeasureSpec); - int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec); - int heightSpecSize = MeasureSpec.getSize(heightMeasureSpec); - - if (widthSpecMode == MeasureSpec.EXACTLY && heightSpecMode == MeasureSpec.EXACTLY) { - // the size is fixed - width = widthSpecSize; - height = heightSpecSize; - - // for compatibility, we adjust size based on aspect ratio - if ( mVideoWidth * height < width * mVideoHeight ) { - width = height * mVideoWidth / mVideoHeight; - } else if ( mVideoWidth * height > width * mVideoHeight ) { - height = width * mVideoHeight / mVideoWidth; - } - } else if (widthSpecMode == MeasureSpec.EXACTLY) { - // only the width is fixed, adjust the height to match aspect ratio if possible - width = widthSpecSize; - height = width * mVideoHeight / mVideoWidth; - if (heightSpecMode == MeasureSpec.AT_MOST && height > heightSpecSize) { - // couldn't match aspect ratio within the constraints - height = heightSpecSize; - } - } else if (heightSpecMode == MeasureSpec.EXACTLY) { - // only the height is fixed, adjust the width to match aspect ratio if possible - height = heightSpecSize; - width = height * mVideoWidth / mVideoHeight; - if (widthSpecMode == MeasureSpec.AT_MOST && width > widthSpecSize) { - // couldn't match aspect ratio within the constraints - width = widthSpecSize; - } - } else { - // neither the width nor the height are fixed, try to use actual video size - width = mVideoWidth; - height = mVideoHeight; - if (heightSpecMode == MeasureSpec.AT_MOST && height > heightSpecSize) { - height = heightSpecSize; - width = height * mVideoWidth / mVideoHeight; + int width = 0; + int height = 0; + int screenMode = ScreenModeManager.SCREENMODE_BIGSCREEN; + if (mScreenManager != null) { + screenMode = mScreenManager.getScreenMode(); + } + switch (screenMode) { + case ScreenModeManager.SCREENMODE_BIGSCREEN: + width = getDefaultSize(mVideoWidth, widthMeasureSpec); + height = getDefaultSize(mVideoHeight, heightMeasureSpec); + if (mVideoWidth > 0 && mVideoHeight > 0) { + if (mVideoWidth * height > width * mVideoHeight) { + height = width * mVideoHeight / mVideoWidth; + } else if (mVideoWidth * height < width * mVideoHeight) { + width = height * mVideoWidth / mVideoHeight; + } } - if (widthSpecMode == MeasureSpec.AT_MOST && width > widthSpecSize) { - width = widthSpecSize; - height = width * mVideoHeight / mVideoWidth; + break; + case ScreenModeManager.SCREENMODE_FULLSCREEN: + width = getDefaultSize(mVideoWidth, widthMeasureSpec); + height = getDefaultSize(mVideoHeight, heightMeasureSpec); + break; + case ScreenModeManager.SCREENMODE_CROPSCREEN: + width = getDefaultSize(mVideoWidth, widthMeasureSpec); + height = getDefaultSize(mVideoHeight, heightMeasureSpec); + if (mVideoWidth > 0 && mVideoHeight > 0) { + if (mVideoWidth * height > width * mVideoHeight) { + width = height * mVideoWidth / mVideoHeight; + } else if (mVideoWidth * height < width * mVideoHeight) { + height = width * mVideoHeight / mVideoWidth; + } } - } - } else { - // no size yet, just adopt the given spec sizes + break; + default: + Log.w(TAG, "wrong screen mode : " + screenMode); + break; + } + if (LOG) { + Log.v(TAG, "onMeasure() set size: " + width + 'x' + height); + Log.v(TAG, "onMeasure() video size: " + mVideoWidth + 'x' + mVideoHeight); + Log.v(TAG, "onMeasure() mNeedWaitLayout=" + mNeedWaitLayout); } setMeasuredDimension(width, height); if (mNeedWaitLayout) { // when OnMeasure ok, start video. @@ -234,10 +230,13 @@ public class CodeauroraVideoView extends SurfaceView implements MediaPlayerContr || data.getBoolean(Metadata.SEEK_BACKWARD_AVAILABLE); mCanSeekForward = !data.has(Metadata.SEEK_FORWARD_AVAILABLE) || data.getBoolean(Metadata.SEEK_FORWARD_AVAILABLE); + mCanSeek = !data.has(Metadata.SEEK_AVAILABLE) + || data.getBoolean(Metadata.SEEK_AVAILABLE); } else { mCanPause = true; mCanSeekBack = true; mCanSeekForward = true; + mCanSeek = true; Log.w(TAG, "Metadata is null!"); } if (LOG) { @@ -251,11 +250,6 @@ public class CodeauroraVideoView extends SurfaceView implements MediaPlayerContr mErrorListener = new MediaPlayer.OnErrorListener() { public boolean onError(final MediaPlayer mp, final int frameworkErr, final int implErr) { Log.d(TAG, "Error: " + frameworkErr + "," + implErr); - if (mCurrentState == STATE_ERROR) { - Log.w(TAG, "Duplicate error message. error message has been sent! " + - "error=(" + frameworkErr + "," + implErr + ")"); - return true; - } //record error position and duration //here disturb the original logic mSeekWhenPrepared = getCurrentPosition(); @@ -349,11 +343,15 @@ public class CodeauroraVideoView extends SurfaceView implements MediaPlayerContr getHolder().removeCallback(mSHCallback); mSHCallback = new SurfaceHolder.Callback() { - public void surfaceChanged(final SurfaceHolder holder, final int format, final int w, final int h) { + public void surfaceChanged(final SurfaceHolder holder, final int format, + final int w, final int h) { if (LOG) { - Log.v(TAG, "surfaceChanged(" + holder + ", " + format + ", " + w + ", " + h + ")"); - Log.v(TAG, "surfaceChanged() mMediaPlayer=" + mMediaPlayer + ", mTargetState=" + mTargetState - + ", mVideoWidth=" + mVideoWidth + ", mVideoHeight=" + mVideoHeight); + Log.v(TAG, "surfaceChanged(" + holder + ", " + format + + ", " + w + ", " + h + ")"); + Log.v(TAG, "surfaceChanged() mMediaPlayer=" + mMediaPlayer + + ", mTargetState=" + mTargetState + + ", mVideoWidth=" + mVideoWidth + + ", mVideoHeight=" + mVideoHeight); } mSurfaceWidth = w; mSurfaceHeight = h; @@ -372,6 +370,29 @@ public class CodeauroraVideoView extends SurfaceView implements MediaPlayerContr if (LOG) { Log.v(TAG, "surfaceCreated(" + holder + ")"); } + /* + if (mCurrentState == STATE_SUSPENDED) { + mSurfaceHolder = holder; + mMediaPlayer.setDisplay(mSurfaceHolder); + if (mMediaPlayer.resume()) { + mCurrentState = STATE_PREPARED; + if (mSeekWhenPrepared != 0) { + seekTo(mSeekWhenPrepared); + } + if (mTargetState == STATE_PLAYING) { + start(); + } + return; + } else { + release(false); + } + } + */ + if (mCurrentState == STATE_SUSPENDED) { + mSurfaceHolder = holder; + mMediaPlayer.setDisplay(mSurfaceHolder); + release(false); + } mSurfaceHolder = holder; openVideo(); } @@ -385,6 +406,10 @@ public class CodeauroraVideoView extends SurfaceView implements MediaPlayerContr if (mMediaController != null) { mMediaController.hide(); } + if (isHTTPStreaming(mUri) && mCurrentState == STATE_SUSPENDED) { + // Don't call release() while run suspend operation + return; + } release(true); } }; @@ -541,57 +566,7 @@ public class CodeauroraVideoView extends SurfaceView implements MediaPlayerContr } }; - private MediaPlayer.OnErrorListener mErrorListener = - new MediaPlayer.OnErrorListener() { - public boolean onError(MediaPlayer mp, int framework_err, int impl_err) { - Log.d(TAG, "Error: " + framework_err + "," + impl_err); - mCurrentState = STATE_ERROR; - mTargetState = STATE_ERROR; - if (mMediaController != null) { - mMediaController.hide(); - } - - /* If an error handler has been supplied, use it and finish. */ - if (mOnErrorListener != null) { - if (mOnErrorListener.onError(mMediaPlayer, framework_err, impl_err)) { - return true; - } - } - - /* Otherwise, pop up an error dialog so the user knows that - * something bad has happened. Only try and pop up the dialog - * if we're attached to a window. When we're going away and no - * longer have a window, don't bother showing the user an error. - */ - if (getWindowToken() != null) { - Resources r = mContext.getResources(); - int messageId; - - if (framework_err == MediaPlayer.MEDIA_ERROR_NOT_VALID_FOR_PROGRESSIVE_PLAYBACK) { - messageId = com.android.internal.R.string.VideoView_error_text_invalid_progressive_playback; - } else { - messageId = com.android.internal.R.string.VideoView_error_text_unknown; - } - - new AlertDialog.Builder(mContext) - .setMessage(messageId) - .setPositiveButton(com.android.internal.R.string.VideoView_error_button, - new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int whichButton) { - /* If we get here, there is no onError listener, so - * at least inform them that the video is over. - */ - if (mOnCompletionListener != null) { - mOnCompletionListener.onCompletion(mMediaPlayer); - } - } - }) - .setCancelable(false) - .show(); - } - return true; - } - }; + private MediaPlayer.OnErrorListener mErrorListener; private MediaPlayer.OnBufferingUpdateListener mBufferingUpdateListener = new MediaPlayer.OnBufferingUpdateListener() { @@ -678,7 +653,6 @@ public class CodeauroraVideoView extends SurfaceView implements MediaPlayerContr mSurfaceHolder = holder; openVideo(); */ - if (LOG) { Log.v(TAG, "surfaceCreated(" + holder + ")"); } @@ -813,20 +787,53 @@ public class CodeauroraVideoView extends SurfaceView implements MediaPlayerContr } public void suspend() { - // HTTP streaming will call mMediaPlayer->suspend(), others will call release() /* + // HTTP streaming will call mMediaPlayer->suspend(), others will call release() if (isHTTPStreaming(mUri) && mCurrentState != STATE_PREPARING) { - if (mMediaPlayer.suspend()) { - mTargetState = mCurrentState; - mCurrentState = STATE_SUSPENDED; - return; + if (mMediaPlayer != null) { + if (mMediaPlayer.suspend()) { + mTargetState = mCurrentState; + mCurrentState = STATE_SUSPENDED; + return; + } } }*/ release(false); } public void resume() { - setResumed(true); + /* + // HTTP streaming (with suspended status) will call mMediaPlayer->resume(), others will call openVideo() + if (mCurrentState == STATE_SUSPENDED) { + if (mSurfaceHolder != null) { + // The surface hasn't been destroyed + if (mMediaPlayer.resume()) { + mCurrentState = STATE_PREPARED; + if (mSeekWhenPrepared !=0) { + seekTo(mSeekWhenPrepared); + } + if (mTargetState == STATE_PLAYING) { + start(); + } + return; + } else { + // resume failed, so call release() before openVideo() + release(false); + } + } else { + // The surface has been destroyed, resume operation will be done after surface created + return; + } + }*/ + // HTTP streaming (with suspended status) will call mMediaPlayer->resume(), others will call openVideo() + if (mCurrentState == STATE_SUSPENDED) { + if (mSurfaceHolder != null) { + release(false); + } else { + // The surface has been destroyed, resume operation will be done after surface created + return; + } + } openVideo(); } @@ -919,6 +926,10 @@ public class CodeauroraVideoView extends SurfaceView implements MediaPlayerContr return mCanSeekForward; } + public boolean canSeek() { + return mCanSeek; + } + @Override public int getAudioSessionId() { if (mAudioSession == 0) { @@ -1029,4 +1040,33 @@ public class CodeauroraVideoView extends SurfaceView implements MediaPlayerContr } return mTargetState == STATE_PLAYING; } + + public void setScreenModeManager(final ScreenModeManager manager) { + mScreenManager = manager; + if (mScreenManager != null) { + mScreenManager.addListener(this); + } + if (LOG) { + Log.v(TAG, "setScreenModeManager(" + manager + ")"); + } + } + + @Override + public void onScreenModeChanged(final int newMode) { + this.requestLayout(); + } + + public void setOnVideoSizeChangedListener(final OnVideoSizeChangedListener l) { + mVideoSizeListener = l; + if (LOG) { + Log.i(TAG, "setOnVideoSizeChangedListener(" + l + ")"); + } + } + + public void setOnBufferingUpdateListener(final OnBufferingUpdateListener l) { + mOnBufferingUpdateListener = l; + if (LOG) { + Log.v(TAG, "setOnBufferingUpdateListener(" + l + ")"); + } + } } diff --git a/src/org/codeaurora/gallery3d/video/ExtensionHelper.java b/src/org/codeaurora/gallery3d/video/ExtensionHelper.java index f95e9c09f..2ff61a4e5 100755 --- a/src/org/codeaurora/gallery3d/video/ExtensionHelper.java +++ b/src/org/codeaurora/gallery3d/video/ExtensionHelper.java @@ -19,6 +19,7 @@ public class ExtensionHelper { boolean loop = context.getResources().getBoolean(R.bool.loop); boolean stereo = context.getResources().getBoolean(R.bool.stereo); boolean streaming = context.getResources().getBoolean(R.bool.streaming); + boolean playlist = context.getResources().getBoolean(R.bool.playlist); if (loop == true) { group.addHooker(new LoopVideoHooker()); // add it for common feature. @@ -30,6 +31,10 @@ public class ExtensionHelper { group.addHooker(new StreamingHooker()); group.addHooker(new BookmarkHooker()); } + if (playlist == true) { + group.addHooker(new MovieListHooker()); // add it for common feature. + group.addHooker(new StepOptionSettingsHooker()); + } return group; } } diff --git a/src/org/codeaurora/gallery3d/video/IControllerRewindAndForward.java b/src/org/codeaurora/gallery3d/video/IControllerRewindAndForward.java new file mode 100644 index 000000000..1fc7f704d --- /dev/null +++ b/src/org/codeaurora/gallery3d/video/IControllerRewindAndForward.java @@ -0,0 +1,35 @@ +/* + * Copyright (C) 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 org.codeaurora.gallery3d.video; + +import com.android.gallery3d.app.ControllerOverlay; +import com.android.gallery3d.app.ControllerOverlay.Listener; + +///M: for CU rewind and forward +public interface IControllerRewindAndForward extends ControllerOverlay { + + interface IRewindAndForwardListener extends Listener { + void onStopVideo(); + void onRewind(); + void onForward(); + } + + boolean getPlayPauseEanbled(); + boolean getTimeBarEanbled(); + void setIListener(IRewindAndForwardListener listener); + void showControllerButtonsView(boolean canStop, boolean canRewind, boolean canForward); +} diff --git a/src/org/codeaurora/gallery3d/video/MovieListHooker.java b/src/org/codeaurora/gallery3d/video/MovieListHooker.java new file mode 100644 index 000000000..3da15b1dd --- /dev/null +++ b/src/org/codeaurora/gallery3d/video/MovieListHooker.java @@ -0,0 +1,116 @@ +package org.codeaurora.gallery3d.video; + +import android.os.Bundle; +import android.util.Log; +import android.view.Menu; +import android.view.MenuItem; + +import com.android.gallery3d.R; +import org.codeaurora.gallery3d.ext.IMovieItem; +import org.codeaurora.gallery3d.ext.IMovieList; +import org.codeaurora.gallery3d.ext.IMovieListLoader; +import org.codeaurora.gallery3d.ext.IMovieListLoader.LoaderListener; +import org.codeaurora.gallery3d.ext.MovieListLoader; + +public class MovieListHooker extends MovieHooker implements LoaderListener { + private static final String TAG = "MovieListHooker"; + private static final boolean LOG = true; + + private static final int MENU_NEXT = 1; + private static final int MENU_PREVIOUS = 2; + + private MenuItem mMenuNext; + private MenuItem mMenuPrevious; + + private IMovieListLoader mMovieLoader; + private IMovieList mMovieList; + + @Override + public void onCreate(final Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + mMovieLoader = new MovieListLoader(); + mMovieLoader.fillVideoList(getContext(), getIntent(), this, getMovieItem()); + } + @Override + public void onDestroy() { + super.onDestroy(); + mMovieLoader.cancelList(); + } + @Override + public boolean onCreateOptionsMenu(final Menu menu) { + super.onCreateOptionsMenu(menu); + if (mMovieList != null) { //list should be filled + if (mMovieLoader != null && mMovieLoader.isEnabledVideoList(getIntent())) { + mMenuPrevious = menu.add(0, getMenuActivityId(MENU_PREVIOUS), 0, R.string.previous); + mMenuNext = menu.add(0, getMenuActivityId(MENU_NEXT), 0, R.string.next); + } + } + return true; + } + @Override + public boolean onPrepareOptionsMenu(final Menu menu) { + super.onPrepareOptionsMenu(menu); + updatePrevNext(); + return true; + } + @Override + public boolean onOptionsItemSelected(final MenuItem item) { + super.onOptionsItemSelected(item); + switch(getMenuOriginalId(item.getItemId())) { + case MENU_PREVIOUS: + if (mMovieList == null) { + return false; + } + getPlayer().startNextVideo(mMovieList.getPrevious(getMovieItem())); + return true; + case MENU_NEXT: + if (mMovieList == null) { + return false; + } + getPlayer().startNextVideo(mMovieList.getNext(getMovieItem())); + return true; + default: + return false; + } + } + + @Override + public void onMovieItemChanged(final IMovieItem item) { + super.onMovieItemChanged(item); + updatePrevNext(); + } + + private void updatePrevNext() { + if (LOG) { + Log.v(TAG, "updatePrevNext()"); + } + if (mMovieList != null && mMenuPrevious != null && mMenuNext != null) { + if (mMovieList.isFirst(getMovieItem()) && mMovieList.isLast(getMovieItem())) { //only one movie + mMenuNext.setVisible(false); + mMenuPrevious.setVisible(false); + } else { + mMenuNext.setVisible(true); + mMenuPrevious.setVisible(true); + } + if (mMovieList.isFirst(getMovieItem())) { + mMenuPrevious.setEnabled(false); + } else { + mMenuPrevious.setEnabled(true); + } + if (mMovieList.isLast(getMovieItem())) { + mMenuNext.setEnabled(false); + } else { + mMenuNext.setEnabled(true); + } + } + } + + @Override + public void onListLoaded(final IMovieList movieList) { + mMovieList = movieList; + getContext().invalidateOptionsMenu(); + if (LOG) { + Log.v(TAG, "onListLoaded() " + (mMovieList != null ? mMovieList.size() : "null")); + } + } +} diff --git a/src/org/codeaurora/gallery3d/video/ScreenModeManager.java b/src/org/codeaurora/gallery3d/video/ScreenModeManager.java new file mode 100644 index 000000000..3dbba68d8 --- /dev/null +++ b/src/org/codeaurora/gallery3d/video/ScreenModeManager.java @@ -0,0 +1,117 @@ +package org.codeaurora.gallery3d.video; + +import android.util.Log; + +import java.util.ArrayList; + +public class ScreenModeManager { + private static final String TAG = "ScreenModeManager"; + private static final boolean LOG = true; + //support screen mode. + public static final int SCREENMODE_BIGSCREEN = 1; + public static final int SCREENMODE_FULLSCREEN = 2; + public static final int SCREENMODE_CROPSCREEN = 4; + public static final int SCREENMODE_ALL = 7; + + private int mScreenMode = SCREENMODE_BIGSCREEN; + private int mScreenModes = SCREENMODE_ALL; + + /** + * Enable specified screen mode list. + * The screen mode's value determines the order of being shown. + * <br>you can enable three screen modes by setting screenModes = + * {@link #SCREENMODE_BIGSCREEN} | + * {@link #SCREENMODE_FULLSCREEN} | + * {@link #SCREENMODE_CROPSCREEN} or + * just enable two screen modes by setting screenModes = + * {@link #SCREENMODE_BIGSCREEN} | + * {@link #SCREENMODE_CROPSCREEN}. + * <br>If current screen mode is the last one of the ordered list, + * then the next screen mode will be the first one of the ordered list. + * @param screenModes enabled screen mode list. + */ + public void setScreenModes(final int screenModes) { + mScreenModes = (SCREENMODE_BIGSCREEN & screenModes) + | (SCREENMODE_FULLSCREEN & screenModes) + | (SCREENMODE_CROPSCREEN & screenModes); + if ((screenModes & SCREENMODE_ALL) == 0) { + mScreenModes = SCREENMODE_ALL; + Log.w(TAG, "wrong screenModes=" + screenModes + ". use default value " + SCREENMODE_ALL); + } + if (LOG) { + Log.v(TAG, "enableScreenMode(" + screenModes + ") mScreenModes=" + mScreenModes); + } + } + + /** + * Get the all screen modes of media controller. + * <br><b>Note:</b> it is not the video's current screen mode. + * @return the current screen modes. + */ + public int getScreenModes() { + return mScreenModes; + } + + public void setScreenMode(final int curScreenMode) { + if (LOG) { + Log.v(TAG, "setScreenMode(" + curScreenMode + ")"); + } + mScreenMode = curScreenMode; + for (final ScreenModeListener listener : mListeners) { + listener.onScreenModeChanged(curScreenMode); + } + } + + public int getScreenMode() { + if (LOG) { + Log.v(TAG, "getScreenMode() return " + mScreenMode); + } + return mScreenMode; + } + + public int getNextScreenMode() { + int mode = getScreenMode(); + mode <<= 1; + if ((mode & mScreenModes) == 0) { + //not exist, find the right one + if (mode > mScreenModes) { + mode = 1; + } + while ((mode & mScreenModes) == 0) { + mode <<= 1; + if (mode > mScreenModes) { + throw new RuntimeException("wrong screen mode = " + mScreenModes); + } + } + } + if (LOG) { + Log.v(TAG, "getNextScreenMode() = " + mode); + } + return mode; + } + + private final ArrayList<ScreenModeListener> mListeners = new ArrayList<ScreenModeListener>(); + public void addListener(final ScreenModeListener l) { + if (!mListeners.contains(l)) { + mListeners.add(l); + } + if (LOG) { + Log.v(TAG, "addListener(" + l + ")"); + } + } + + public void removeListener(final ScreenModeListener l) { + mListeners.remove(l); + if (LOG) { + Log.v(TAG, "removeListener(" + l + ")"); + } + } + + public void clear() { + mListeners.clear(); + } + + public interface ScreenModeListener { + void onScreenModeChanged(int newMode); + } +} diff --git a/src/org/codeaurora/gallery3d/video/SettingsActivity.java b/src/org/codeaurora/gallery3d/video/SettingsActivity.java index 450f10d7c..200c48813 100755 --- a/src/org/codeaurora/gallery3d/video/SettingsActivity.java +++ b/src/org/codeaurora/gallery3d/video/SettingsActivity.java @@ -3,6 +3,7 @@ package org.codeaurora.gallery3d.video; import android.app.ActionBar; import android.app.Activity; import android.content.ContentResolver; +import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; import android.database.Cursor; @@ -18,6 +19,7 @@ import android.preference.PreferenceCategory; import android.preference.RingtonePreference; import android.preference.PreferenceScreen; import android.provider.ContactsContract; +import android.provider.Settings.System; import android.provider.Telephony; import android.telephony.TelephonyManager; import android.text.method.DigitsKeyListener; @@ -30,26 +32,38 @@ import java.util.ArrayList; public class SettingsActivity extends PreferenceActivity { - public static final String PREFERENCE_RTP_MINPORT = "rtp_min_port"; - public static final String PREFERENCE_RTP_MAXPORT = "rtp_max_port"; - public static final String PREFERENCE_RTCP_MINPORT = "rtcp_min_port"; - public static final String PREFERENCE_RTCP_MAXPORT = "rtcp_max_port"; - public static final String PREFERENCE_BUFFER_SIZE = "buffer_size"; - public static final String PREFERENCE_APN = "apn"; + private static final String LOG_TAG = "SettingsActivity"; + public static final String PREFERENCE_RTP_MINPORT = "rtp_min_port"; + public static final String PREFERENCE_RTP_MAXPORT = "rtp_max_port"; + private static final String PREFERENCE_KEEP_ALIVE_INTERVAL_SECOND = "keep_alive_interval_second"; + private static final String PREFERENCE_CACHE_MIN_SIZE = "cache_min_size"; + private static final String PREFERENCE_CACHE_MAX_SIZE = "cache_max_size"; + public static final String PREFERENCE_BUFFER_SIZE = "buffer_size"; + public static final String PREFERENCE_APN = "apn"; + private static final String PACKAGE_NAME = "com.android.settings"; + + private static final int DEFAULT_RTP_MINPORT = 8192; + private static final int DEFAULT_RTP_MAXPORT = 65535; + private static final int DEFAULT_CACHE_MIN_SIZE = 4 * 1024 * 1024; + private static final int DEFAULT_CACHE_MAX_SIZE = 20 * 1024 * 1024; + private static final int DEFAULT_KEEP_ALIVE_INTERVAL_SECOND = 15; + + private static final int RTP_MIN_PORT = 1; + private static final int RTP_MAX_PORT = 2; + private static final int BUFFER_SIZE = 3; + + private SharedPreferences mPref; private EditTextPreference mRtpMinPort; private EditTextPreference mRtpMaxPort; - private EditTextPreference mRtcpMinPort; - private EditTextPreference mRtcpMaxPort; private EditTextPreference mBufferSize; - private PreferenceScreen mApn; - private CheckBoxPreference mRepeat; - - private static final int SELECT_APN = 1; - public static final String PREFERRED_APN_URI = "content://telephony/carriers/preferapn"; - private static final Uri PREFERAPN_URI = Uri.parse(PREFERRED_APN_URI); - private static final int ID_INDEX = 0; - private static final int NAME_INDEX = 1; + private PreferenceScreen mApn; + + private static final int SELECT_APN = 1; + public static final String PREFERRED_APN_URI = "content://telephony/carriers/preferapn"; + private static final Uri PREFERAPN_URI = Uri.parse(PREFERRED_APN_URI); + private static final int COLUMN_ID_INDEX = 0; + private static final int NAME_INDEX = 1; private boolean mUseNvOperatorForEhrpd = SystemProperties.getBoolean( "persist.radio.use_nv_for_ehrpd", false); @@ -59,111 +73,43 @@ public class SettingsActivity extends PreferenceActivity { super.onCreate(savedInstanceState); addPreferencesFromResource(R.xml.rtsp_settings_preferences); - SharedPreferences mPref; mPref = getPreferenceScreen().getSharedPreferences(); - String rtpMinport = mPref.getString(PREFERENCE_RTP_MINPORT, "8192"); - String rtpMaxport = mPref.getString(PREFERENCE_RTP_MAXPORT, "65535"); - String rtcpMinport = mPref.getString(PREFERENCE_RTCP_MAXPORT, null); - String rtcpMaxport = mPref.getString(PREFERENCE_RTCP_MAXPORT, null); - String bufferSize = mPref.getString(PREFERENCE_BUFFER_SIZE, null); - mRtpMinPort = (EditTextPreference) findPreference(PREFERENCE_RTP_MINPORT); - mRtpMinPort.getEditText().setKeyListener(DigitsKeyListener.getInstance("0123456789")); - mRtpMinPort.setSummary(rtpMinport); - mRtpMinPort.setText(rtpMinport); - mRtpMinPort.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() { - public boolean onPreferenceChange(Preference preference, Object newValue) { - final String summary = newValue.toString(); - mRtpMinPort.setSummary(summary); - Log.d("rtsp", "z66 summary = " + summary); - android.provider.Settings.System.putString(getContentResolver(), - "streaming_min_udp_port", summary); - return true; - } - }); - mRtpMaxPort = (EditTextPreference) findPreference(PREFERENCE_RTP_MAXPORT); - mRtpMaxPort.getEditText().setKeyListener(DigitsKeyListener.getInstance("0123456789")); - mRtpMaxPort.setSummary(rtpMaxport); - mRtpMaxPort.setText(rtpMaxport); - mRtpMaxPort.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() { - public boolean onPreferenceChange(Preference preference, Object newValue) { - final String summary = newValue.toString(); - mRtpMaxPort.setSummary(summary); - Log.w("rtsp", "z82 summary = " + summary); - android.provider.Settings.System.putString(getContentResolver(), - "streaming_max_udp_port", summary); - return true; - } - }); - mRtcpMinPort = (EditTextPreference) findPreference(PREFERENCE_RTCP_MINPORT); - mRtcpMinPort.getEditText().setKeyListener(DigitsKeyListener.getInstance("0123456789")); - mRtcpMinPort.setSummary(rtcpMinport); - mRtcpMinPort.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() { - public boolean onPreferenceChange(Preference preference, Object newValue) { - final String summary = newValue.toString(); - mRtcpMinPort.setSummary(summary); - return true; - } - }); - mRtcpMaxPort = (EditTextPreference) findPreference(PREFERENCE_RTCP_MAXPORT); - mRtcpMaxPort.getEditText().setKeyListener(DigitsKeyListener.getInstance("0123456789")); - mRtcpMaxPort.setSummary(rtcpMaxport); - mRtcpMaxPort.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() { - public boolean onPreferenceChange(Preference preference, Object newValue) { - final String summary = newValue.toString(); - mRtcpMaxPort.setSummary(summary); - return true; - } - }); - mBufferSize = (EditTextPreference) findPreference(PREFERENCE_BUFFER_SIZE); - mBufferSize.getEditText().setKeyListener(DigitsKeyListener.getInstance("0123456789")); - mBufferSize.setSummary(bufferSize); - mBufferSize.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() { - public boolean onPreferenceChange(Preference preference, Object newValue) { - final String summary = newValue.toString(); - mBufferSize.setSummary(summary); - return true; - } - }); - mApn = (PreferenceScreen) findPreference(PREFERENCE_APN); - mApn.setSummary(getDefaultApnName()); - mApn.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() { - public boolean onPreferenceClick(Preference preference) { - Intent intent = new Intent(); - intent.setClassName("com.android.settings", "com.android.settings.ApnSettings"); - startActivityForResult(intent, SELECT_APN); - return true; - } - }); + + setPreferenceListener(RTP_MIN_PORT, mRtpMinPort); + setPreferenceListener(RTP_MAX_PORT, mRtpMaxPort); + setPreferenceListener(BUFFER_SIZE, mBufferSize); + setApnListener(); ActionBar ab = getActionBar(); ab.setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD); ab.setDisplayHomeAsUpEnabled(true); ab.setTitle(R.string.setting); } - - private String getDefaultApnName() { - + + private String getApnKey() { // to find default key String key = null; - String name = null; Cursor cursor = getContentResolver().query(PREFERAPN_URI, new String[] { "_id" }, null, null, Telephony.Carriers.DEFAULT_SORT_ORDER); - if (cursor.getCount() > 0) { - cursor.moveToFirst(); - key = cursor.getString(ID_INDEX); + if (cursor.getCount() > 0 && cursor.moveToFirst()) { + key = cursor.getString(COLUMN_ID_INDEX); Log.v("settingActivty", "default apn key = " + key); } cursor.close(); - + return key; + } + + private String getApnName(String key) { + String name = null; // to find default proxy String where = getOperatorNumericSelection(); - cursor = getContentResolver().query(Telephony.Carriers.CONTENT_URI, new String[] { + Cursor cursor = getContentResolver().query(Telephony.Carriers.CONTENT_URI, new String[] { "_id", "name", "apn", "type" }, where, null, Telephony.Carriers.DEFAULT_SORT_ORDER); @@ -181,7 +127,11 @@ public class SettingsActivity extends PreferenceActivity { cursor.close(); } return name; + + } + private String getDefaultApnName() { + return getApnName(getApnKey()); } private String getSelectedApnKey() { @@ -204,13 +154,12 @@ public class SettingsActivity extends PreferenceActivity { @Override public void onActivityResult(int requestCode, int resultCode, Intent data) { - switch (requestCode) { - case SELECT_APN: - setResult(resultCode); - finish(); - Log.w("rtsp", "onActivityResult requestCode = " + requestCode); - break; + if (requestCode == SELECT_APN) { + setResult(resultCode); + finish(); + Log.w(LOG_TAG, "onActivityResult requestCode = " + requestCode); } + } @Override @@ -227,7 +176,7 @@ public class SettingsActivity extends PreferenceActivity { String where; where = (mccmncs[0] != null) ? "numeric=\"" + mccmncs[0] + "\"" : ""; where += (mccmncs[1] != null) ? " or numeric=\"" + mccmncs[1] + "\"" : ""; - Log.d("SettingsActivity", "getOperatorNumericSelection: " + where); + Log.d(LOG_TAG, "getOperatorNumericSelection: " + where); return where; } @@ -248,4 +197,114 @@ public class SettingsActivity extends PreferenceActivity { } return result.toArray(new String[2]); } + + private void enableRtpPortSetting() { + final String rtpMinPortStr = mPref.getString(PREFERENCE_RTP_MINPORT, + Integer.toString(DEFAULT_RTP_MINPORT)); + final String rtpMaxPortStr = mPref.getString(PREFERENCE_RTP_MAXPORT, + Integer.toString(DEFAULT_RTP_MAXPORT)); + final String CLASS_NAME = "com.android.settings.StreamingSettingsEnablerActivity"; + final int rtpMinPort; + final int rtpMaxPort; + try { + rtpMinPort = Integer.valueOf(rtpMinPortStr); + rtpMaxPort = Integer.valueOf(rtpMaxPortStr); + } catch (NumberFormatException e) { + Log.e(LOG_TAG, "Failed to parse rtp ports"); + return; + } + Intent intent = new Intent(); + intent.setClassName(PACKAGE_NAME, CLASS_NAME); + intent.putExtra(PREFERENCE_RTP_MINPORT, rtpMinPort); + intent.putExtra(PREFERENCE_RTP_MAXPORT, rtpMaxPort); + startActivity(intent); + } + + private void enableBufferSetting() { + final String bufferSizeStr = mPref.getString(PREFERENCE_BUFFER_SIZE, + Integer.toString(DEFAULT_CACHE_MAX_SIZE)); + final String CLASS_NAME = "com.android.settings.StreamingSettingsEnablerActivity"; + final int cacheMaxSize; + try { + cacheMaxSize = Integer.valueOf(bufferSizeStr); + } catch (NumberFormatException e) { + Log.e(LOG_TAG, "Failed to parse cache max size"); + return; + } + Intent intent = new Intent(); + intent.setClassName(PACKAGE_NAME, CLASS_NAME); + intent.putExtra(PREFERENCE_CACHE_MIN_SIZE, DEFAULT_CACHE_MIN_SIZE); + intent.putExtra(PREFERENCE_CACHE_MAX_SIZE, cacheMaxSize); + intent.putExtra(PREFERENCE_KEEP_ALIVE_INTERVAL_SECOND, DEFAULT_KEEP_ALIVE_INTERVAL_SECOND); + startActivity(intent); + } + + private void setPreferenceListener(final int which, final EditTextPreference etp) { + + final String DIGITS_ACCEPTABLE = "0123456789"; + String summaryStr = ""; + String preferStr = ""; + + switch (which) { + case RTP_MIN_PORT: + preferStr = mPref.getString(PREFERENCE_RTP_MINPORT, + Integer.toString(DEFAULT_RTP_MINPORT)); + summaryStr = "streaming_min_udp_port"; + break; + case RTP_MAX_PORT: + preferStr = mPref.getString(PREFERENCE_RTP_MAXPORT, + Integer.toString(DEFAULT_RTP_MAXPORT)); + summaryStr = "streaming_max_udp_port"; + break; + case BUFFER_SIZE: + preferStr = mPref.getString(PREFERENCE_BUFFER_SIZE, + Integer.toString(DEFAULT_CACHE_MAX_SIZE)); + break; + default: + return; + + } + + final String summaryString = summaryStr; + etp.getEditText().setKeyListener(DigitsKeyListener.getInstance(DIGITS_ACCEPTABLE)); + etp.setSummary(preferStr); + etp.setText(preferStr); + etp.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() { + public boolean onPreferenceChange(Preference preference, Object newValue) { + final String summary = newValue.toString(); + final int value; + try { + value = Integer.valueOf(summary); + } catch (NumberFormatException e) { + Log.e(LOG_TAG, "NumberFormatException"); + return false; + } + etp.setSummary(summary); + etp.setText(summary); + Log.d(LOG_TAG, "z66/z82 summary = " + summary); + if(which == RTP_MIN_PORT || which == RTP_MAX_PORT) { + System.putString(getContentResolver(), summaryString, summary); + enableRtpPortSetting(); + } else { + enableBufferSetting(); + } + return true; + } + }); + + } + + private void setApnListener() { + final String CLASS_NAME = "com.android.settings.ApnSettings"; + mApn.setSummary(getDefaultApnName()); + mApn.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() { + public boolean onPreferenceClick(Preference preference) { + Intent intent = new Intent(); + intent.setClassName(PACKAGE_NAME, CLASS_NAME); + startActivityForResult(intent, SELECT_APN); + return true; + } + }); + } + } diff --git a/src/org/codeaurora/gallery3d/video/StepOptionDialogFragment.java b/src/org/codeaurora/gallery3d/video/StepOptionDialogFragment.java new file mode 100644 index 000000000..50bd8a669 --- /dev/null +++ b/src/org/codeaurora/gallery3d/video/StepOptionDialogFragment.java @@ -0,0 +1,83 @@ +package org.codeaurora.gallery3d.video; + +import android.app.AlertDialog; +import android.app.Dialog; +import android.app.DialogFragment; +import android.content.DialogInterface; +import android.os.Bundle; + +/** M: use DialogFragment to show Dialog */ +public class StepOptionDialogFragment extends DialogFragment implements + DialogInterface.OnClickListener{ + + private static final String KEY_ITEM_ARRAY = "itemArray"; + private static final String KEY_TITLE = "title"; + private static final String KEY_DEFAULT_SELECT = "nowSelect"; + private DialogInterface.OnClickListener mClickListener = null; + + /** + * M: create a instance of SelectDialogFragment + * + * @param itemArrayID + * the resource id array of strings that show in list + * @param sufffixArray + * the suffix array at the right of list item + * @param titleID + * the resource id of title string + * @param nowSelect + * the current select item index + * @return the instance of SelectDialogFragment + */ + public static StepOptionDialogFragment newInstance(int[] itemArrayID, + int titleID, int nowSelect) { + StepOptionDialogFragment frag = new StepOptionDialogFragment(); + Bundle args = new Bundle(); + args.putIntArray(KEY_ITEM_ARRAY, itemArrayID); + args.putInt(KEY_TITLE, titleID); + args.putInt(KEY_DEFAULT_SELECT, nowSelect); + frag.setArguments(args); + return frag; + } + + @Override + /** + * M: create a select dialog + */ + public Dialog onCreateDialog(Bundle savedInstanceState) { + Bundle args = getArguments(); + final String title = getString(args.getInt(KEY_TITLE)); + final int[] itemArrayID = args.getIntArray(KEY_ITEM_ARRAY); + int arraySize = itemArrayID.length; + CharSequence[] itemArray = new CharSequence[arraySize]; + for (int i = 0; i < arraySize; i++) { + itemArray[i] = getString(itemArrayID[i]); + } + + AlertDialog.Builder builder = null; + int nowSelect = args.getInt(KEY_DEFAULT_SELECT); + builder = new AlertDialog.Builder(getActivity()); + builder.setTitle(title).setSingleChoiceItems(itemArray, nowSelect, this) + .setNegativeButton(getString(android.R.string.cancel), null); + return builder.create(); + } + + @Override + /** + * M: the process of select an item + */ + public void onClick(DialogInterface arg0, int arg1) { + if (null != mClickListener) { + mClickListener.onClick(arg0, arg1); + } + } + + /** + * M: set listener of click items + * + * @param listener + * the listener to be set + */ + public void setOnClickListener(DialogInterface.OnClickListener listener) { + mClickListener = listener; + } +}
\ No newline at end of file diff --git a/src/org/codeaurora/gallery3d/video/StepOptionSettingsHooker.java b/src/org/codeaurora/gallery3d/video/StepOptionSettingsHooker.java new file mode 100644 index 000000000..eff8057bd --- /dev/null +++ b/src/org/codeaurora/gallery3d/video/StepOptionSettingsHooker.java @@ -0,0 +1,41 @@ +package org.codeaurora.gallery3d.video; + +import android.content.Intent; +import android.view.Menu; +import android.view.MenuItem; + +import com.android.gallery3d.R; +import com.android.gallery3d.app.MovieActivity; +import org.codeaurora.gallery3d.ext.ActivityHooker; +import org.codeaurora.gallery3d.video.VideoSettingsActivity; + +public class StepOptionSettingsHooker extends ActivityHooker { + private static final int MENU_STEP_OPTION_SETTING = 1; + private MenuItem mMenuStepOption; + + @Override + public boolean onCreateOptionsMenu(final Menu menu) { + super.onCreateOptionsMenu(menu); + mMenuStepOption = menu.add(0, getMenuActivityId(MENU_STEP_OPTION_SETTING), 0, R.string.settings); + return true; + } + @Override + public boolean onPrepareOptionsMenu(final Menu menu) { + super.onPrepareOptionsMenu(menu); + return true; + } + @Override + public boolean onOptionsItemSelected(final MenuItem item) { + super.onOptionsItemSelected(item); + switch(getMenuOriginalId(item.getItemId())) { + case MENU_STEP_OPTION_SETTING: + //start activity + Intent mIntent = new Intent(); + mIntent.setClass(getContext(), VideoSettingsActivity.class); + getContext().startActivity(mIntent); + return true; + default: + return false; + } + } +}
\ No newline at end of file diff --git a/src/org/codeaurora/gallery3d/video/StereoAudioHooker.java b/src/org/codeaurora/gallery3d/video/StereoAudioHooker.java index cb52f5972..88012fa7d 100644..100755 --- a/src/org/codeaurora/gallery3d/video/StereoAudioHooker.java +++ b/src/org/codeaurora/gallery3d/video/StereoAudioHooker.java @@ -51,14 +51,12 @@ public class StereoAudioHooker extends MovieHooker { @Override public boolean onOptionsItemSelected(final MenuItem item) { super.onOptionsItemSelected(item); - switch (getMenuOriginalId(item.getItemId())) { - case MENU_STEREO_AUDIO: - mCurrentStereoAudio = !mCurrentStereoAudio; - setStereoAudio(mCurrentStereoAudio); - return true; - default: - return false; + if(getMenuOriginalId(item.getItemId()) == MENU_STEREO_AUDIO) { + mCurrentStereoAudio = !mCurrentStereoAudio; + setStereoAudio(mCurrentStereoAudio); + return true; } + return false; } private boolean getStereoAudio() { @@ -93,13 +91,8 @@ public class StereoAudioHooker extends MovieHooker { private void updateStereoAudioIcon() { if (mMenuStereoAudio != null) { - if (mCurrentStereoAudio) { - mMenuStereoAudio.setTitle(R.string.single_track); - mMenuStereoAudio.setIcon(R.drawable.ic_menu_single_track); - } else { - mMenuStereoAudio.setTitle(R.string.stereo); - mMenuStereoAudio.setIcon(R.drawable.ic_menu_stereo); - } + mMenuStereoAudio.setTitle(mCurrentStereoAudio?R.string.single_track:R.string.stereo); + mMenuStereoAudio.setIcon(mCurrentStereoAudio?R.drawable.ic_menu_single_track:R.drawable.ic_menu_stereo); } } diff --git a/src/org/codeaurora/gallery3d/video/StreamingHooker.java b/src/org/codeaurora/gallery3d/video/StreamingHooker.java index d4fa43fc5..fdcc14c50 100644..100755 --- a/src/org/codeaurora/gallery3d/video/StreamingHooker.java +++ b/src/org/codeaurora/gallery3d/video/StreamingHooker.java @@ -52,24 +52,23 @@ public class StreamingHooker extends MovieHooker { } private void gotoInputUrl() { - final String appName = getClass().getName(); + final String APN_NAME = getClass().getName(); + final String URI_STR = "about:blank"; + final String EXTRA_NAME = "inputUrl"; + final Intent intent = new Intent(); intent.setAction(Intent.ACTION_VIEW); - intent.setData(Uri.parse("about:blank")); - intent.putExtra("inputUrl", true); - intent.putExtra(Browser.EXTRA_APPLICATION_ID, appName); + intent.setData(Uri.parse(URI_STR)); + intent.putExtra(EXTRA_NAME, true); + intent.putExtra(Browser.EXTRA_APPLICATION_ID, APN_NAME); getContext().startActivity(intent); if (LOG) { - Log.v(TAG, "gotoInputUrl() appName=" + appName); + Log.v(TAG, "gotoInputUrl() appName=" + APN_NAME); } } private void gotoSettings() { final Intent intent = new Intent(ACTION_STREAMING); - // intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP - // | Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY); - // intent.putExtra(KEY_LOGO_BITMAP, - // getIntent().getParcelableExtra(KEY_LOGO_BITMAP)); getContext().startActivity(intent); if (LOG) { Log.v(TAG, "gotoInputUrl()"); diff --git a/src/org/codeaurora/gallery3d/video/VideoSettingsActivity.java b/src/org/codeaurora/gallery3d/video/VideoSettingsActivity.java new file mode 100644 index 000000000..32ccfe70f --- /dev/null +++ b/src/org/codeaurora/gallery3d/video/VideoSettingsActivity.java @@ -0,0 +1,182 @@ +package org.codeaurora.gallery3d.video; + +import android.app.ListActivity; + +import android.app.ActionBar; +import android.app.Activity; +import android.app.DialogFragment; +import android.app.Fragment; +import android.app.FragmentManager; +import android.content.Context; +import android.content.DialogInterface; +import android.content.Intent; +import android.content.SharedPreferences; +import android.os.Bundle; +import android.preference.Preference; +import android.preference.PreferenceActivity; +import android.preference.PreferenceScreen; +import android.text.TextUtils; +import android.view.Menu; +import android.view.MenuItem; +import android.view.View; +import android.widget.AdapterView; +import android.widget.AdapterView.OnItemClickListener; +import android.widget.ArrayAdapter; +import android.widget.ListView; +import android.widget.SimpleAdapter; +import android.widget.TextView; +import android.widget.Toast; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import com.android.gallery3d.R; + +public class VideoSettingsActivity extends ListActivity { + private String OPTION_NAME = "option_name"; + private String OPTION_DESC = "option_desc"; + private String DIALOG_TAG_SELECT_STEP_OPTION = "step_option_dialog"; + private static int[] sStepOptionArray = null; + private static final int STEP_OPTION_THREE_SECOND = 0; + private static final int STEP_OPTION_SIX_SECOND = 1; + private static final String SELECTED_STEP_OPTION = "selected_step_option"; + private static final String VIDEO_PLAYER_DATA = "video_player_data"; + private int mSelectedStepOption = -1; + private SharedPreferences mPrefs = null; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + ActionBar actionBar = getActionBar(); + actionBar.setDisplayHomeAsUpEnabled(true); + actionBar.setTitle(getResources().getString(R.string.settings)); + setContentView(R.layout.setting_list); + ArrayList<HashMap<String, Object>> arrlist = new ArrayList<HashMap<String, Object>>(1); + HashMap<String, Object> map = new HashMap<String, Object>(); + map.put(OPTION_NAME, getString(R.string.setp_option_name)); + map.put(OPTION_DESC, getString(R.string.step_option_desc)); + arrlist.add(map); + SimpleAdapter adapter = new SimpleAdapter(this, arrlist, android.R.layout.simple_expandable_list_item_2, + new String[] { OPTION_NAME, OPTION_DESC }, new int[] { + android.R.id.text1, android.R.id.text2}); + setListAdapter(adapter); + restoreStepOptionSettings(); + } + + @Override + protected void onSaveInstanceState(Bundle outState) { + storeStepOptionSettings(); + super.onSaveInstanceState(outState); + } + + @Override + protected void onRestoreInstanceState(Bundle savedInstanceState) { + super.onRestoreInstanceState(savedInstanceState); + restoreDialogFragment(); + restoreStepOptionSettings(); + } + + + + @Override + protected void onDestroy() { + // TODO Auto-generated method stub + storeStepOptionSettings(); + super.onDestroy(); + } + + @Override + protected void onListItemClick(ListView arg0, View arg1, int arg2, long arg3) { + switch (arg2) { + case 0: + DialogFragment newFragment = null; + FragmentManager fragmentManager = getFragmentManager(); + removeOldFragmentByTag(DIALOG_TAG_SELECT_STEP_OPTION); + newFragment = StepOptionDialogFragment.newInstance(getStepOptionIDArray(), + R.string.setp_option_name, mSelectedStepOption); + ((StepOptionDialogFragment) newFragment).setOnClickListener(mStepOptionSelectedListener); + newFragment.show(fragmentManager, DIALOG_TAG_SELECT_STEP_OPTION); + break; + default: + break; + } + } + + private int[] getStepOptionIDArray() { + int[] stepOptionIDArray = new int[2]; + stepOptionIDArray[STEP_OPTION_THREE_SECOND] = R.string.setp_option_three_second; + stepOptionIDArray[STEP_OPTION_SIX_SECOND] = R.string.setp_option_six_second; + sStepOptionArray = new int[2]; + sStepOptionArray[0] = STEP_OPTION_THREE_SECOND; + sStepOptionArray[1] = STEP_OPTION_SIX_SECOND; + return stepOptionIDArray; + } + + private DialogInterface.OnClickListener mStepOptionSelectedListener = new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int whichItemSelect) { + setSelectedStepOption(whichItemSelect); + dialog.dismiss(); + } + }; + + public void setSelectedStepOption(int which) { + mSelectedStepOption = getSelectedStepOption(which); + } + + static int getSelectedStepOption(int which) { + return sStepOptionArray[which]; + } + + /** + * remove old DialogFragment + * + * @param tag + * the tag of DialogFragment to be removed + */ + private void removeOldFragmentByTag(String tag) { + FragmentManager fragmentManager = getFragmentManager(); + DialogFragment oldFragment = (DialogFragment) fragmentManager.findFragmentByTag(tag); + if (null != oldFragment) { + oldFragment.dismissAllowingStateLoss(); + } + } + + private void restoreDialogFragment() { + FragmentManager fragmentManager = getFragmentManager(); + Fragment fragment = fragmentManager.findFragmentByTag(DIALOG_TAG_SELECT_STEP_OPTION); + if (null != fragment) { + ((StepOptionDialogFragment) fragment).setOnClickListener(mStepOptionSelectedListener); + } + } + + private void storeStepOptionSettings() { + if (null == mPrefs) { + mPrefs = getSharedPreferences(VIDEO_PLAYER_DATA, 0); + } + SharedPreferences.Editor ed = mPrefs.edit(); + ed.clear(); + ed.putInt(SELECTED_STEP_OPTION, mSelectedStepOption); + ed.commit(); + } + + private void restoreStepOptionSettings() { + if (null == mPrefs) { + mPrefs = getSharedPreferences(VIDEO_PLAYER_DATA, 0); + } + mSelectedStepOption = mPrefs.getInt(SELECTED_STEP_OPTION, STEP_OPTION_THREE_SECOND); + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + switch (item.getItemId()) { + case android.R.id.home: + // The user clicked on the Messaging icon in the action bar. Take them back from + // wherever they came from + finish(); + return true; + } + return false; + } +} |