diff options
author | Likai Ding <likaid@codeaurora.org> | 2013-08-15 15:02:24 +0800 |
---|---|---|
committer | emancebo <emancebo@cyngn.com> | 2014-09-04 10:40:18 -0700 |
commit | 93a66b850bdb0a06ad7fda0549eb47b8123292bc (patch) | |
tree | e7a0d0ce434eff6e9757f728fc80d413fe34dce2 /src | |
parent | bce738c2b78bd4ec6dbdfc8f808059f882e59595 (diff) | |
download | android_packages_apps_Gallery2-93a66b850bdb0a06ad7fda0549eb47b8123292bc.tar.gz android_packages_apps_Gallery2-93a66b850bdb0a06ad7fda0549eb47b8123292bc.tar.bz2 android_packages_apps_Gallery2-93a66b850bdb0a06ad7fda0549eb47b8123292bc.zip |
Gallery2: support live streaming and bookmarks
(cherry picked new files from commit id
990c6d43ea7c184846e19d41bef0d93aee4e581b)
Change-Id: Idc254cf0f7e8a9b492203313fa63349d07d19d5c
Diffstat (limited to 'src')
-rwxr-xr-x | src/com/qcom/gallery3d/video/BookmarkActivity.java | 242 | ||||
-rwxr-xr-x | src/com/qcom/gallery3d/video/BookmarkEnhance.java | 132 | ||||
-rwxr-xr-x | src/com/qcom/gallery3d/video/BookmarkHooker.java | 72 | ||||
-rwxr-xr-x | src/com/qcom/gallery3d/video/DmReceiver.java | 82 | ||||
-rwxr-xr-x | src/com/qcom/gallery3d/video/MovieTitleHelper.java | 98 | ||||
-rwxr-xr-x | src/com/qcom/gallery3d/video/QcomVideoView.java | 721 | ||||
-rwxr-xr-x | src/com/qcom/gallery3d/video/SettingsActivity.java | 371 | ||||
-rwxr-xr-x | src/com/qcom/gallery3d/video/StreamingHooker.java | 89 |
8 files changed, 1807 insertions, 0 deletions
diff --git a/src/com/qcom/gallery3d/video/BookmarkActivity.java b/src/com/qcom/gallery3d/video/BookmarkActivity.java new file mode 100755 index 000000000..8e792815c --- /dev/null +++ b/src/com/qcom/gallery3d/video/BookmarkActivity.java @@ -0,0 +1,242 @@ +package com.qcom.gallery3d.video; + +import android.app.Activity; +import android.app.AlertDialog; +import android.content.Context; +import android.content.DialogInterface; +import android.content.DialogInterface.OnClickListener; +import android.content.Intent; +import android.database.Cursor; +import android.graphics.Bitmap; +import android.graphics.drawable.BitmapDrawable; +import android.net.Uri; +import android.os.Bundle; +import android.view.ContextMenu; +import android.view.ContextMenu.ContextMenuInfo; +import android.view.LayoutInflater; +import android.view.Menu; +import android.view.MenuItem; +import android.view.View; +import android.view.ViewGroup; +import android.view.WindowManager; +import android.widget.AdapterView; +import android.widget.AdapterView.AdapterContextMenuInfo; +import android.widget.AdapterView.OnItemClickListener; +import android.widget.EditText; +import android.widget.ListView; +import android.widget.SimpleCursorAdapter; +import android.widget.TextView; + +import com.android.gallery3d.R; +import com.android.gallery3d.app.MovieActivity; +import com.qcom.gallery3d.ext.QcomLog; + +public class BookmarkActivity extends Activity implements OnItemClickListener { + private static final String TAG = "BookmarkActivity"; + private static final boolean LOG = true; + + private BookmarkEnhance mBookmark; + private BookmarkAdapter mAdapter; + private Cursor mCursor; + private ListView mListView; + private TextView mEmptyView; + + private static final int MENU_DELETE_ALL = 1; + private static final int MENU_DELETE_ONE = 2; + private static final int MENU_EDIT = 3; + + public static final String KEY_LOGO_BITMAP = "logo-bitmap"; + + @Override + protected void onCreate(final Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.bookmark); + + Bitmap logo = getIntent().getParcelableExtra(KEY_LOGO_BITMAP); + if (logo != null) { + getActionBar().setLogo(new BitmapDrawable(getResources(), logo)); + } + + mListView = (ListView) findViewById(android.R.id.list); + mEmptyView = (TextView) findViewById(android.R.id.empty); + + mBookmark = new BookmarkEnhance(this); + mCursor = mBookmark.query(); + mAdapter = new BookmarkAdapter(this, R.layout.bookmark_item, null, new String[]{}, new int[]{}); + mListView.setEmptyView(mEmptyView); + mListView.setAdapter(mAdapter); + mAdapter.changeCursor(mCursor); + + mListView.setOnItemClickListener(this); + registerForContextMenu(mListView); + } + + @Override + protected void onStart() { + super.onStart(); + } + + @Override + protected void onResume() { + super.onResume(); + } + + @Override + protected void onPause() { + super.onPause(); + } + + @Override + protected void onDestroy() { + if (mAdapter != null) { + mAdapter.changeCursor(null); + } + super.onDestroy(); + } + + @Override + public boolean onCreateOptionsMenu(final Menu menu) { + super.onCreateOptionsMenu(menu); + menu.add(0, MENU_DELETE_ALL, 0, R.string.delete_all) + .setIcon(android.R.drawable.ic_menu_delete); + return true; + } + + @Override + public boolean onOptionsItemSelected(final MenuItem item) { + switch(item.getItemId()) { + case MENU_DELETE_ALL: + mBookmark.deleteAll(); + return true; + default: + break; + } + return super.onOptionsItemSelected(item); + } + + private class BookmarkAdapter extends SimpleCursorAdapter { + + public BookmarkAdapter(final Context context, final int layout, final Cursor c, + final String[] from, final int[] to) { + super(context, layout, c, from, to); + } + + @Override + public View newView(final Context context, final Cursor cursor, final ViewGroup parent) { + final View view = super.newView(context, cursor, parent); + final ViewHolder holder = new ViewHolder(); + holder.mTitleView = (TextView) view.findViewById(R.id.title); + holder.mDataView = (TextView) view.findViewById(R.id.data); + view.setTag(holder); + return view; + } + + @Override + public void bindView(final View view, final Context context, final Cursor cursor) { + final ViewHolder holder = (ViewHolder) view.getTag(); + holder.mId = cursor.getLong(BookmarkEnhance.INDEX_ID); + holder.mTitle = cursor.getString(BookmarkEnhance.INDEX_TITLE); + holder.mData = cursor.getString(BookmarkEnhance.INDEX_DATA); + holder.mMimetype = cursor.getString(BookmarkEnhance.INDEX_MIME_TYPE); + holder.mTitleView.setText(holder.mTitle); + holder.mDataView.setText(holder.mData); + } + + @Override + public void changeCursor(final Cursor c) { + super.changeCursor(c); + } + + } + + private class ViewHolder { + long mId; + String mTitle; + String mData; + String mMimetype; + TextView mTitleView; + TextView mDataView; + } + + @Override + public void onItemClick(final AdapterView<?> parent, final View view, final int position, final long id) { + final Object o = view.getTag(); + if (o instanceof ViewHolder) { + final ViewHolder holder = (ViewHolder) o; + finish(); + final Intent intent = new Intent(this, MovieActivity.class); + intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); + String mime = "video/*"; + if (!(holder.mMimetype == null || "".equals(holder.mMimetype.trim()))) { + mime = holder.mMimetype; + } + intent.setDataAndType(Uri.parse(holder.mData), mime); + startActivity(intent); + } + if (LOG) { + QcomLog.v(TAG, "onItemClick(" + position + ", " + id + ")"); + } + } + + @Override + public void onCreateContextMenu(final ContextMenu menu, final View v, + final ContextMenuInfo menuInfo) { + super.onCreateContextMenu(menu, v, menuInfo); + menu.add(0, MENU_DELETE_ONE, 0, R.string.delete); + menu.add(0, MENU_EDIT, 0, R.string.edit); + } + + @Override + public boolean onContextItemSelected(final MenuItem item) { + final AdapterContextMenuInfo info = (AdapterContextMenuInfo) item.getMenuInfo(); + switch (item.getItemId()) { + case MENU_DELETE_ONE: + mBookmark.delete(info.id); + return true; + case MENU_EDIT: + final Object obj = info.targetView.getTag(); + if (obj instanceof ViewHolder) { + showEditDialog((ViewHolder)obj); + } else { + QcomLog.w(TAG, "wrong context item info " + info); + } + return true; + default: + return super.onContextItemSelected(item); + } + } + + private void showEditDialog(final ViewHolder holder) { + if (LOG) { + QcomLog.v(TAG, "showEditDialog(" + holder + ")"); + } + if (holder == null) { + return; + } + final LayoutInflater inflater = LayoutInflater.from(this); + final View v = inflater.inflate(R.layout.bookmark_edit_dialog, null); + final EditText titleView = (EditText)v.findViewById(R.id.title); + final EditText dataView = (EditText)v.findViewById(R.id.data); + titleView.setText(holder.mTitle); + dataView.setText(holder.mData); + + final AlertDialog.Builder builder = new AlertDialog.Builder(this); + builder.setTitle(R.string.edit); + builder.setView(v); + builder.setIcon(R.drawable.ic_menu_display_bookmark); + builder.setPositiveButton(android.R.string.ok, new OnClickListener() { + + @Override + public void onClick(final DialogInterface dialog, final int which) { + mBookmark.update(holder.mId, titleView.getText().toString(), + dataView.getText().toString(), 0); + } + + }); + builder.setNegativeButton(android.R.string.cancel, null); + final AlertDialog dialog = builder.create(); + dialog.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE); + dialog.setInverseBackgroundForced(true); + dialog.show(); + } +} diff --git a/src/com/qcom/gallery3d/video/BookmarkEnhance.java b/src/com/qcom/gallery3d/video/BookmarkEnhance.java new file mode 100755 index 000000000..033b055b5 --- /dev/null +++ b/src/com/qcom/gallery3d/video/BookmarkEnhance.java @@ -0,0 +1,132 @@ +package com.qcom.gallery3d.video; + +import android.content.ContentResolver; +import android.content.ContentUris; +import android.content.ContentValues; +import android.content.Context; +import android.database.Cursor; +import android.net.Uri; + +import com.android.gallery3d.R; +import com.qcom.gallery3d.ext.QcomLog; + +public class BookmarkEnhance { + private static final String TAG = "BookmarkEnhance"; + private static final boolean LOG = true; + + private static final Uri BOOKMARK_URI = Uri.parse("content://media/internal/bookmark"); + + public static final String COLUMN_ID = "_id"; + public static final String COLUMN_DATA = "_data"; + public static final String COLUMN_TITLE = "_display_name"; + public static final String COLUMN_ADD_DATE = "date_added"; + public static final String COLUMN_MEDIA_TYPE = "mime_type"; + private static final String COLUMN_POSITION = "position"; + private static final String COLUMN_MIME_TYPE = "media_type"; + + private static final String NULL_HOCK = COLUMN_POSITION; + public static final String ORDER_COLUMN = COLUMN_ADD_DATE + " ASC "; + private static final String VIDEO_STREAMING_MEDIA_TYPE = "streaming"; + + public static final int INDEX_ID = 0; + public static final int INDEX_DATA = 1; + public static final int INDEX_TITLE = 2; + public static final int INDEX_ADD_DATE = 3; + public static final int INDEX_MIME_TYPE = 4; + private static final int INDEX_POSITION = 5; + private static final int INDEX_MEDIA_TYPE = 6; + + public static final String[] PROJECTION = new String[]{ + COLUMN_ID, + COLUMN_DATA, + COLUMN_TITLE, + COLUMN_ADD_DATE, + COLUMN_MIME_TYPE, + }; + + private final Context mContext; + private final ContentResolver mCr; + + public BookmarkEnhance(final Context context) { + mContext = context; + mCr = context.getContentResolver(); + } + + public Uri insert(final String title, final String uri, final String mimeType,final long position) { + final ContentValues values = new ContentValues(); + final String mytitle = (title == null ? mContext.getString(R.string.default_title) : title); + values.put(COLUMN_TITLE, mytitle); + values.put(COLUMN_DATA, uri); + values.put(COLUMN_POSITION, position); + values.put(COLUMN_ADD_DATE, System.currentTimeMillis()); + values.put(COLUMN_MEDIA_TYPE, VIDEO_STREAMING_MEDIA_TYPE); + values.put(COLUMN_MIME_TYPE, mimeType); + final Uri insertUri = mCr.insert(BOOKMARK_URI, values); + if (LOG) { + QcomLog.v(TAG, "insert(" + title + "," + uri + ", " + position + ") return " + insertUri); + } + return insertUri; + } + + public int delete(final long id) { + final Uri uri = ContentUris.withAppendedId(BOOKMARK_URI, id); + final int count = mCr.delete(uri, null, null); + if (LOG) { + QcomLog.v(TAG, "delete(" + id + ") return " + count); + } + return count; + } + + public int deleteAll() { + final int count = mCr.delete(BOOKMARK_URI, COLUMN_MEDIA_TYPE + "=? ", new String[]{VIDEO_STREAMING_MEDIA_TYPE}); + if (LOG) { + QcomLog.v(TAG, "deleteAll() return " + count); + } + return count; + } + + public boolean exists(final String uri) { + final Cursor cursor = mCr.query(BOOKMARK_URI, + PROJECTION, + COLUMN_DATA + "=? and " + COLUMN_MEDIA_TYPE + "=? ", + new String[]{uri, VIDEO_STREAMING_MEDIA_TYPE}, + null + ); + boolean exist = false; + if (cursor != null) { + exist = cursor.moveToFirst(); + cursor.close(); + } + if (LOG) { + QcomLog.v(TAG, "exists(" + uri + ") return " + exist); + } + return exist; + } + + public Cursor query() { + final Cursor cursor = mCr.query(BOOKMARK_URI, + PROJECTION, + COLUMN_MEDIA_TYPE + "='" + VIDEO_STREAMING_MEDIA_TYPE + "' ", + null, + ORDER_COLUMN + ); + if (LOG) { + QcomLog.v(TAG, "query() return cursor=" + (cursor == null ? -1 : cursor.getCount())); + } + return cursor; + } + + public int update(final long id, final String title, final String uri, final int position) { + final ContentValues values = new ContentValues(); + values.put(COLUMN_TITLE, title); + values.put(COLUMN_DATA, uri); + values.put(COLUMN_POSITION, position); + final Uri updateUri = ContentUris.withAppendedId(BOOKMARK_URI, id); + final int count = mCr.update(updateUri, values, null, null); + if (LOG) { + QcomLog.v(TAG, "update(" + id + ", " + title + ", " + uri + ", " + position + ")" + + " return " + count); + } + return count; + } +} diff --git a/src/com/qcom/gallery3d/video/BookmarkHooker.java b/src/com/qcom/gallery3d/video/BookmarkHooker.java new file mode 100755 index 000000000..fc8bcd885 --- /dev/null +++ b/src/com/qcom/gallery3d/video/BookmarkHooker.java @@ -0,0 +1,72 @@ +package com.qcom.gallery3d.video; + +import android.content.Intent; +import android.view.Menu; +import android.view.MenuItem; + +import com.android.gallery3d.R; +import com.qcom.gallery3d.ext.MovieUtils; + +public class BookmarkHooker extends MovieHooker { + private static final String TAG = "BookmarkHooker"; + private static final boolean LOG = true; + + private static final String ACTION_BOOKMARK = "com.qcom.bookmark.VIEW"; + private static final int MENU_BOOKMARK_ADD = 1; + private static final int MENU_BOOKMARK_DISPLAY = 2; + private MenuItem mMenuBookmarks; + private MenuItem mMenuBookmarkAdd; + + public static final String KEY_LOGO_BITMAP = "logo-bitmap"; + + @Override + public boolean onCreateOptionsMenu(final Menu menu) { + super.onCreateOptionsMenu(menu); + mMenuBookmarkAdd = menu.add(0, getMenuActivityId(MENU_BOOKMARK_ADD), 0, R.string.bookmark_add); + mMenuBookmarks = menu.add(0, getMenuActivityId(MENU_BOOKMARK_DISPLAY), 0, R.string.bookmark_display); + return true; + } + @Override + public boolean onPrepareOptionsMenu(final Menu menu) { + super.onPrepareOptionsMenu(menu); + if (MovieUtils.isLocalFile(getMovieItem().getUri(), getMovieItem().getMimeType())) { + if (mMenuBookmarkAdd != null) { + mMenuBookmarkAdd.setVisible(false); + } + if (mMenuBookmarks != null) { + mMenuBookmarks.setVisible(false); + } + } else { + if (mMenuBookmarkAdd != null) { + mMenuBookmarkAdd.setVisible(true); + } + if (mMenuBookmarks != null) { + mMenuBookmarks.setVisible(true); + } + } + return true; + } + @Override + public boolean onOptionsItemSelected(final MenuItem item) { + super.onOptionsItemSelected(item); + switch(getMenuOriginalId(item.getItemId())) { + case MENU_BOOKMARK_ADD: + getPlayer().addBookmark(); + return true; + case MENU_BOOKMARK_DISPLAY: + gotoBookmark(); + return true; + default: + return false; + } + } + + private void gotoBookmark() { + final Intent intent = new Intent(ACTION_BOOKMARK); + intent.addCategory(Intent.CATEGORY_DEFAULT); + 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); + } +}
\ No newline at end of file diff --git a/src/com/qcom/gallery3d/video/DmReceiver.java b/src/com/qcom/gallery3d/video/DmReceiver.java new file mode 100755 index 000000000..4b4b6aa20 --- /dev/null +++ b/src/com/qcom/gallery3d/video/DmReceiver.java @@ -0,0 +1,82 @@ +
+
+
+package com.qcom.gallery3d.video;
+
+import android.app.Notification;
+import android.app.NotificationManager; +import android.app.PendingIntent; +import android.app.Service; +import android.content.BroadcastReceiver; +import android.content.ContentResolver; +import android.content.ContentValues; +import android.content.Context; +import android.content.Intent; +import android.content.SharedPreferences; +import android.content.res.Resources;
+import android.net.Uri; +import android.os.PowerManager; +import android.preference.PreferenceManager; +import android.util.Log;
+
+public class DmReceiver extends BroadcastReceiver {
+ private static final String TAG = "DmReceiver";
+ public static final String WRITE_SETTING_ACTION = "streaming.action.WRITE_SETTINGS";
+ public static final String BOOT_COMPLETED = "android.intent.action.BOOT_COMPLETED";
+
+ private SharedPreferences mPref;
+ static final int STREAMING_CONNPROFILE_IO_HANDLER_TYPE = 1;
+ static final int STREAMING_MAX_UDP_PORT_IO_HANDLER_TYPE = 3;
+ static final int STREAMING_MIN_UDP_PORT_IO_HANDLER_TYPE = 4;
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ Log.d(TAG, "z32 ### onReceive ###");
+ if (mPref == null) {
+ mPref = PreferenceManager.getDefaultSharedPreferences(context);
+ }
+ if (BOOT_COMPLETED.equals(intent.getAction()) )
+ {
+ Log.d(TAG, "z46 onReceive BOOT_COMPLETED ###");
+ String rtpMaxport
+ = mPref.getString(SettingsActivity.PREFERENCE_RTP_MAXPORT, "65535");
+ String rtpMinport
+ = mPref.getString(SettingsActivity.PREFERENCE_RTP_MINPORT, "8192");
+ String apn
+ = mPref.getString(SettingsActivity.PREFERENCE_APN, "CMWAP");
+ Log.d(TAG, "z43 rtpMinport = " + rtpMinport + ";rtpMaxport = " + rtpMaxport);
+
+ android.provider.Settings.System.putString(context.getContentResolver(), "streaming_max_udp_port", rtpMaxport);
+ android.provider.Settings.System.putString(context.getContentResolver(), "streaming_min_udp_port", rtpMinport);
+ android.provider.Settings.System.putString(context.getContentResolver(), "apn", apn);
+ }
+ else if (WRITE_SETTING_ACTION.equals(intent.getAction()))
+ {
+ Log.d(TAG, "z52 onReceive WRITE_SETTING_ACTION ###");
+ int valueType = intent.getIntExtra("type", 0);
+ String value = intent.getStringExtra("value");
+ if (valueType == STREAMING_MAX_UDP_PORT_IO_HANDLER_TYPE)
+ {
+ mPref.edit().putString(SettingsActivity.PREFERENCE_RTP_MAXPORT,
+ value).commit();
+ android.provider.Settings.System.putString(context.getContentResolver(),
+ "streaming_max_udp_port", value);
+ }
+ else if (valueType == STREAMING_MIN_UDP_PORT_IO_HANDLER_TYPE)
+ {
+ mPref.edit().putString(SettingsActivity.PREFERENCE_RTP_MINPORT,
+ value).commit();
+ android.provider.Settings.System.putString(context.getContentResolver(),
+ "streaming_min_udp_port", value);
+ }
+ else if (valueType == STREAMING_CONNPROFILE_IO_HANDLER_TYPE)
+ {
+ mPref.edit().putString(SettingsActivity.PREFERENCE_APN,
+ // "CMWAP").commit();
+ value).commit();
+ android.provider.Settings.System.putString(context.getContentResolver(),
+ "apn", value);
+ }
+ }
+ }
+}
+
diff --git a/src/com/qcom/gallery3d/video/MovieTitleHelper.java b/src/com/qcom/gallery3d/video/MovieTitleHelper.java new file mode 100755 index 000000000..42ba3ec90 --- /dev/null +++ b/src/com/qcom/gallery3d/video/MovieTitleHelper.java @@ -0,0 +1,98 @@ +package com.qcom.gallery3d.video; + +import android.content.Context; +import android.database.Cursor; +import android.database.sqlite.SQLiteException; +import android.net.Uri; +import android.provider.MediaStore; +import android.provider.OpenableColumns; + +import com.qcom.gallery3d.ext.QcomLog; + +import java.io.File; + +public class MovieTitleHelper { + private static final String TAG = "MovieTitleHelper"; + private static final boolean LOG = true; + + public static String getTitleFromMediaData(final Context context, final Uri uri) { + String title = null; + Cursor cursor = null; + try { + String data = Uri.decode(uri.toString()); + data = data.replaceAll("'", "''"); + final String where = "_data LIKE '%" + data.replaceFirst("file:///", "") + "'"; + cursor = context.getContentResolver().query(MediaStore.Video.Media.EXTERNAL_CONTENT_URI, + new String[]{OpenableColumns.DISPLAY_NAME}, where, null, null); + if (LOG) { + QcomLog.v(TAG, "setInfoFromMediaData() cursor=" + (cursor == null ? "null" : cursor.getCount())); + } + if (cursor != null && cursor.moveToFirst()) { + title = cursor.getString(0); + } + } catch (final SQLiteException ex) { + ex.printStackTrace(); + } finally { + if (cursor != null) { + cursor.close(); + } + } + if (LOG) { + QcomLog.v(TAG, "setInfoFromMediaData() return " + title); + } + return title; + } + + public static String getTitleFromDisplayName(final Context context, final Uri uri) { + String title = null; + Cursor cursor = null; + try { + cursor = context.getContentResolver().query(uri, + new String[]{OpenableColumns.DISPLAY_NAME}, null, null, null); + if (cursor != null && cursor.moveToFirst()) { + title = cursor.getString(0); + } + } catch (final SQLiteException ex) { + ex.printStackTrace(); + } finally { + if (cursor != null) { + cursor.close(); + } + } + if (LOG) { + QcomLog.v(TAG, "getTitleFromDisplayName() return " + title); + } + return title; + } + + public static String getTitleFromUri(final Uri uri) { + final String title = Uri.decode(uri.getLastPathSegment()); + if (LOG) { + QcomLog.v(TAG, "getTitleFromUri() return " + title); + } + return title; + } + + public static String getTitleFromData(final Context context, final Uri uri) { + String title = null; + Cursor cursor = null; + try { + cursor = context.getContentResolver().query(uri, + new String[]{"_data"}, null, null, null); + if (cursor != null && cursor.moveToFirst()) { + final File file = new File(cursor.getString(0)); + title = file.getName(); + } + } catch (final SQLiteException ex) { + ex.printStackTrace(); + } finally { + if (cursor != null) { + cursor.close(); + } + } + if (LOG) { + QcomLog.v(TAG, "getTitleFromData() return " + title); + } + return title; + } +} diff --git a/src/com/qcom/gallery3d/video/QcomVideoView.java b/src/com/qcom/gallery3d/video/QcomVideoView.java new file mode 100755 index 000000000..ba5485544 --- /dev/null +++ b/src/com/qcom/gallery3d/video/QcomVideoView.java @@ -0,0 +1,721 @@ +package com.qcom.gallery3d.video; + +import android.app.AlertDialog; +import android.content.Context; +import android.content.DialogInterface; +import android.content.Intent; +import android.content.res.Resources; +import android.database.sqlite.SQLiteException; +import android.media.AudioManager; +import android.media.MediaPlayer; +import android.media.MediaPlayer.OnBufferingUpdateListener; +import android.media.MediaPlayer.OnInfoListener; +import android.media.MediaPlayer.OnVideoSizeChangedListener; +import android.media.Metadata; +import android.net.Uri; +import android.os.Handler; +import android.os.Message; +import android.util.AttributeSet; +import android.view.KeyEvent; +import android.view.SurfaceHolder; +import android.widget.VideoView; + +import com.android.gallery3d.ui.Log; +import com.qcom.gallery3d.ext.QcomLog; +import com.qcom.gallery3d.video.ScreenModeManager.ScreenModeListener; + +import android.app.Activity; +import android.app.AlertDialog; +import android.app.Dialog; +import android.app.DialogFragment; +import android.app.FragmentManager; + +import java.io.IOException; +import java.util.Map; + +/** + * QcomVideoView enhance the streaming videoplayer process and UI. + * It only supports QcomMediaController. + * If you set android's default MediaController, + * some state will not be shown well. + * Moved from the package android.widget + */ +public class QcomVideoView extends VideoView implements ScreenModeListener { + private static final String TAG = "QcomVideoView"; + private static final boolean LOG = true; + + //add info listener to get info whether can get meta data or not for rtsp. + private MediaPlayer.OnInfoListener mOnInfoListener; + private MediaPlayer.OnBufferingUpdateListener mOnBufferingUpdateListener; + private MediaPlayer.OnVideoSizeChangedListener mVideoSizeListener; + + //when the streaming type is live, metadata maybe not right when prepared. + private boolean mHasGotMetaData = false; + private boolean mHasGotPreparedCallBack = false; + + private final MediaPlayer.OnInfoListener mInfoListener = new MediaPlayer.OnInfoListener() { + + public boolean onInfo(final MediaPlayer mp, final int what, final int extra) { + if (LOG) { + QcomLog.v(TAG, "onInfo() what:" + what + " extra:" + extra); + } + if (mOnInfoListener != null && mOnInfoListener.onInfo(mp, what, extra)) { + return true; + } else { + // TODO comments by sunlei +// if (what == MediaPlayer.MEDIA_INFO_METADATA_CHECK_COMPLETE) { +// mHasGotMetaData = true; +// doPreparedIfReady(mMediaPlayer); +// return true; +// } + } + return false; + } + + }; + + private void doPreparedIfReady(final MediaPlayer mp) { + if (LOG) { + QcomLog.v(TAG, "doPreparedIfReady() mHasGotPreparedCallBack=" + mHasGotPreparedCallBack + + ", mHasGotMetaData=" + mHasGotMetaData + ", mNeedWaitLayout=" + mNeedWaitLayout + + ", mCurrentState=" + mCurrentState); + } + if (mHasGotPreparedCallBack && mHasGotMetaData && !mNeedWaitLayout) { + doPrepared(mp); + } + } + + public QcomVideoView(final Context context) { + super(context); + initialize(); + } + + public QcomVideoView(final Context context, final AttributeSet attrs) { + super(context, attrs); + initialize(); + } + + public QcomVideoView(final Context context, final AttributeSet attrs, final int defStyle) { + super(context, attrs, defStyle); + initialize(); + } + + private void initialize() { + mPreparedListener = new MediaPlayer.OnPreparedListener() { + public void onPrepared(final MediaPlayer mp) { + if (LOG) { + QcomLog.v(TAG, "mPreparedListener.onPrepared(" + mp + ")"); + } + //Here we can get meta data from mediaplayer. + // Get the capabilities of the player for this stream + final Metadata data = mp.getMetadata(MediaPlayer.METADATA_ALL, + MediaPlayer.BYPASS_METADATA_FILTER); + if (data != null) { + mCanPause = !data.has(Metadata.PAUSE_AVAILABLE) + || data.getBoolean(Metadata.PAUSE_AVAILABLE); + mCanSeekBack = !data.has(Metadata.SEEK_BACKWARD_AVAILABLE) + || data.getBoolean(Metadata.SEEK_BACKWARD_AVAILABLE); + mCanSeekForward = !data.has(Metadata.SEEK_FORWARD_AVAILABLE) + || data.getBoolean(Metadata.SEEK_FORWARD_AVAILABLE); + } else { + mCanPause = true; + mCanSeekBack = true; + mCanSeekForward = true; + QcomLog.w(TAG, "Metadata is null!"); + } + if (LOG) { + QcomLog.v(TAG, "mPreparedListener.onPrepared() mCanPause=" + mCanPause); + } + mHasGotPreparedCallBack = true; + doPreparedIfReady(mMediaPlayer); + } + }; + + 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(); + if (LOG) { + Log.v(TAG, "onError() mSeekWhenPrepared=" + mSeekWhenPrepared + ", mDuration=" + mDuration); + } + //for old version Streaming server, getduration is not valid. + mDuration = Math.abs(mDuration); + 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, frameworkErr, implErr)) { + 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) { + final Resources r = mContext.getResources(); + int messageId; + + // TODO comments by sunlei +// if (frameworkErr == MediaPlayer.MEDIA_ERROR_BAD_FILE) { +// messageId = com.mediatek.R.string.VideoView_error_text_bad_file; +// } else if (frameworkErr == MediaPlayer.MEDIA_ERROR_CANNOT_CONNECT_TO_SERVER) { +// messageId = com.mediatek.R.string.VideoView_error_text_cannot_connect_to_server; +// } else if (frameworkErr == MediaPlayer.MEDIA_ERROR_TYPE_NOT_SUPPORTED) { +// messageId = com.mediatek.R.string.VideoView_error_text_type_not_supported; +// } else if (frameworkErr == MediaPlayer.MEDIA_ERROR_DRM_NOT_SUPPORTED) { +// messageId = com.mediatek.R.string.VideoView_error_text_drm_not_supported; +// } else if (frameworkErr == MediaPlayer.MEDIA_ERROR_INVALID_CONNECTION) { +// messageId = com.mediatek.internal.R.string.VideoView_error_text_invalid_connection; +// } else if (frameworkErr == 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; +// } + + if (frameworkErr == 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; + } + + final String errorDialogTag = "ERROR_DIALOG_TAG"; + FragmentManager fragmentManager = ((Activity)mContext).getFragmentManager(); + DialogFragment oldFragment = (DialogFragment) fragmentManager + .findFragmentByTag(errorDialogTag); + if (null != oldFragment) { + oldFragment.dismissAllowingStateLoss(); + } + DialogFragment newFragment = ErrorDialogFragment.newInstance(messageId); + newFragment.show(fragmentManager, errorDialogTag); + fragmentManager.executePendingTransactions(); + } + return true; + } + }; + + mBufferingUpdateListener = new MediaPlayer.OnBufferingUpdateListener() { + public void onBufferingUpdate(final MediaPlayer mp, final int percent) { + mCurrentBufferPercentage = percent; + if (mOnBufferingUpdateListener != null) { + mOnBufferingUpdateListener.onBufferingUpdate(mp, percent); + } + if (LOG) { + QcomLog.v(TAG, "onBufferingUpdate() Buffering percent: " + percent); + } + if (LOG) { + QcomLog.v(TAG, "onBufferingUpdate() mTargetState=" + mTargetState); + } + if (LOG) { + QcomLog.v(TAG, "onBufferingUpdate() mCurrentState=" + mCurrentState); + } + } + }; + + mSizeChangedListener = new MediaPlayer.OnVideoSizeChangedListener() { + public void onVideoSizeChanged(final MediaPlayer mp, final int width, final int height) { + mVideoWidth = mp.getVideoWidth(); + mVideoHeight = mp.getVideoHeight(); + if (LOG) { + QcomLog.v(TAG, "OnVideoSizeChagned(" + width + "," + height + ")"); + } + if (LOG) { + QcomLog.v(TAG, "OnVideoSizeChagned(" + mVideoWidth + "," + mVideoHeight + ")"); + } + if (LOG) { + QcomLog.v(TAG, "OnVideoSizeChagned() mCurrentState=" + mCurrentState); + } + if (mVideoWidth != 0 && mVideoHeight != 0) { + getHolder().setFixedSize(mVideoWidth, mVideoHeight); + if (mCurrentState == STATE_PREPARING) { + mNeedWaitLayout = true; + } + } + if (mVideoSizeListener != null) { + mVideoSizeListener.onVideoSizeChanged(mp, width, height); + } + QcomVideoView.this.requestLayout(); + } + }; + + getHolder().removeCallback(mSHCallback); + mSHCallback = new SurfaceHolder.Callback() { + 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 + ")"); + } + if (LOG) { + Log.v(TAG, "surfaceChanged() mMediaPlayer=" + mMediaPlayer + ", mTargetState=" + mTargetState + + ", mVideoWidth=" + mVideoWidth + ", mVideoHeight=" + mVideoHeight); + } + mSurfaceWidth = w; + mSurfaceHeight = h; + final boolean isValidState = (mTargetState == STATE_PLAYING); + final boolean hasValidSize = (mVideoWidth == w && mVideoHeight == h); + if (mMediaPlayer != null && isValidState && hasValidSize) { + if (mSeekWhenPrepared != 0) { + seekTo(mSeekWhenPrepared); + } + Log.v(TAG, "surfaceChanged() start()"); + start(); + } + } + + public void surfaceCreated(final SurfaceHolder holder) { + if (LOG) { + Log.v(TAG, "surfaceCreated(" + holder + ")"); + } + mSurfaceHolder = holder; + openVideo(); + } + + public void surfaceDestroyed(final SurfaceHolder holder) { + // after we return from this we can't use the surface any more + if (LOG) { + Log.v(TAG, "surfaceDestroyed(" + holder + ")"); + } + mSurfaceHolder = null; + if (mMediaController != null) { + mMediaController.hide(); + } + release(true); + } + }; + getHolder().addCallback(mSHCallback); + } + + @Override + protected void onMeasure(final int widthMeasureSpec, final int heightMeasureSpec) { + //Log.i("@@@@", "onMeasure"); + 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) { + //Log.i("@@@", "image too tall, correcting"); + height = width * mVideoHeight / mVideoWidth; + } else if (mVideoWidth * height < width * mVideoHeight) { + //Log.i("@@@", "image too wide, correcting"); + width = height * mVideoWidth / mVideoHeight; + } /*else { + //Log.i("@@@", "aspect ratio is correct: " + + //width+"/"+height+"="+ + //mVideoWidth+"/"+mVideoHeight); + }*/ + } + 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) { + //extend width to be cropped + width = height * mVideoWidth / mVideoHeight; + } else if (mVideoWidth * height < width * mVideoHeight) { + //extend height to be cropped + height = width * mVideoHeight / mVideoWidth; + } + } + break; + default: + QcomLog.w(TAG, "wrong screen mode : " + screenMode); + break; + } + if (LOG) { + QcomLog.v(TAG, "onMeasure() set size: " + width + 'x' + height); + QcomLog.v(TAG, "onMeasure() video size: " + mVideoWidth + 'x' + mVideoHeight); + QcomLog.v(TAG, "onMeasure() mNeedWaitLayout=" + mNeedWaitLayout); + } + setMeasuredDimension(width, height); + if (mNeedWaitLayout) { //when OnMeasure ok, start video. + mNeedWaitLayout = false; + mHandler.sendEmptyMessage(MSG_LAYOUT_READY); + } + } + +// @Override +// public boolean onTouchEvent(MotionEvent ev) { +// if (LOG) Log.v(TAG, "onTouchEvent(" + ev + ")"); +// if (mMediaController != null) { +// toggleMediaControlsVisiblity(); +// } +// return false; +// } + + @Override + public boolean onKeyDown(final int keyCode, final KeyEvent event) { + final boolean isKeyCodeSupported = keyCode != KeyEvent.KEYCODE_BACK && + keyCode != KeyEvent.KEYCODE_VOLUME_UP && + keyCode != KeyEvent.KEYCODE_VOLUME_DOWN && + keyCode != KeyEvent.KEYCODE_VOLUME_MUTE && + keyCode != KeyEvent.KEYCODE_MENU && + keyCode != KeyEvent.KEYCODE_CALL && + keyCode != KeyEvent.KEYCODE_ENDCALL && + keyCode != KeyEvent.KEYCODE_CAMERA; + if (isInPlaybackState() && isKeyCodeSupported && mMediaController != null) { + if (event.getRepeatCount() == 0 && (keyCode == KeyEvent.KEYCODE_HEADSETHOOK || + keyCode == KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE)) { + if (mMediaPlayer.isPlaying()) { + pause(); + mMediaController.show(); + } else { + start(); + mMediaController.hide(); + } + return true; + } else if (keyCode == KeyEvent.KEYCODE_MEDIA_PLAY) { + if (!mMediaPlayer.isPlaying()) { + start(); + mMediaController.hide(); + } + return true; + } else if (keyCode == KeyEvent.KEYCODE_MEDIA_STOP + || keyCode == KeyEvent.KEYCODE_MEDIA_PAUSE) { + if (mMediaPlayer.isPlaying()) { + pause(); + mMediaController.show(); + } + return true; + } else if (keyCode == KeyEvent.KEYCODE_MEDIA_FAST_FORWARD || + keyCode == KeyEvent.KEYCODE_MEDIA_NEXT || + keyCode == KeyEvent.KEYCODE_MEDIA_PREVIOUS || + keyCode == KeyEvent.KEYCODE_MEDIA_REWIND || + keyCode == KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE || + keyCode == KeyEvent.KEYCODE_HEADSETHOOK) { + //consume media action, so if video view if front, + //other media player will not play any sounds. + return true; + } else { + toggleMediaControlsVisiblity(); + } + } + + return super.onKeyDown(keyCode, event); + } + + @Override + public void setVideoURI(final Uri uri, final Map<String, String> headers) { + mDuration = -1; + setResumed(true); + super.setVideoURI(uri, headers); + } + + public void setVideoURI(final Uri uri, final Map<String, String> headers, final boolean hasGotMetaData) { + if (LOG) { + QcomLog.v(TAG, "setVideoURI(" + uri + ", " + headers + ")"); + } + //clear the flags + mHasGotMetaData = hasGotMetaData; + setVideoURI(uri, headers); + } + + private void clearVideoInfo() { + if (LOG) { + Log.v(TAG, "clearVideoInfo()"); + } + mHasGotPreparedCallBack = false; + mNeedWaitLayout = false; + } + + @Override + protected void openVideo() { + if (LOG) { + Log.v(TAG, "openVideo() mUri=" + mUri + ", mSurfaceHolder=" + mSurfaceHolder + + ", mSeekWhenPrepared=" + mSeekWhenPrepared + ", mMediaPlayer=" + mMediaPlayer + + ", mOnResumed=" + mOnResumed); + } + clearVideoInfo(); + if (!mOnResumed || mUri == null || mSurfaceHolder == null) { + // not ready for playback just yet, will try again later + return; + } + + // Tell the music playback service to pause + // TODO: these constants need to be published somewhere in the framework. + final Intent i = new Intent("com.android.music.musicservicecommand"); + i.putExtra("command", "pause"); + mContext.sendBroadcast(i); + + // we shouldn't clear the target state, because somebody might have + // called start() previously + release(false); + if ("".equalsIgnoreCase(String.valueOf(mUri))) { + Log.w(TAG, "Unable to open content: " + mUri); + mErrorListener.onError(mMediaPlayer, MediaPlayer.MEDIA_ERROR_UNKNOWN, 0); + return; + } + try { + mMediaPlayer = new MediaPlayer(); + //end update status. + mMediaPlayer.setOnPreparedListener(mPreparedListener); + mMediaPlayer.setOnVideoSizeChangedListener(mSizeChangedListener); + //mDuration = -1; + mMediaPlayer.setOnCompletionListener(mCompletionListener); + mMediaPlayer.setOnErrorListener(mErrorListener); + mMediaPlayer.setOnBufferingUpdateListener(mBufferingUpdateListener); + mMediaPlayer.setOnInfoListener(mInfoListener); + mCurrentBufferPercentage = 0; + Log.w(TAG, "openVideo setDataSource()"); + mMediaPlayer.setDataSource(mContext, mUri, mHeaders); + mMediaPlayer.setDisplay(mSurfaceHolder); + mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC); + mMediaPlayer.setScreenOnWhilePlaying(true); + Log.w(TAG, "openVideo prepareAsync()"); + mMediaPlayer.prepareAsync(); + // we don't set the target state here either, but preserve the + // target state that was there before. + mCurrentState = STATE_PREPARING; + //attachMediaController(); + } catch (final IOException ex) { + Log.w(TAG, "Unable to open content: " + mUri, ex); + mErrorListener.onError(mMediaPlayer, MediaPlayer.MEDIA_ERROR_UNKNOWN, 0); + return; + } catch (final IllegalArgumentException ex) { + Log.w(TAG, "Unable to open content: " + mUri, ex); + mErrorListener.onError(mMediaPlayer, MediaPlayer.MEDIA_ERROR_UNKNOWN, 0); + return; + } catch (final SQLiteException ex) { + Log.w(TAG, "Unable to open content: " + mUri, ex); + mErrorListener.onError(mMediaPlayer, MediaPlayer.MEDIA_ERROR_UNKNOWN, 0); + return; + } + if (LOG) { + Log.v(TAG, "openVideo() mUri=" + mUri + ", mSurfaceHolder=" + mSurfaceHolder + + ", mSeekWhenPrepared=" + mSeekWhenPrepared + ", mMediaPlayer=" + mMediaPlayer); + } + } + + private void doPrepared(final MediaPlayer mp) { + if (LOG) { + QcomLog.v(TAG, "doPrepared(" + mp + ") start"); + } + mCurrentState = STATE_PREPARED; + if (mOnPreparedListener != null) { + mOnPreparedListener.onPrepared(mMediaPlayer); + } + mVideoWidth = mp.getVideoWidth(); + mVideoHeight = mp.getVideoHeight(); + + final int seekToPosition = mSeekWhenPrepared; // mSeekWhenPrepared may be changed after seekTo() call + if (seekToPosition != 0) { + seekTo(seekToPosition); + } + if (mVideoWidth != 0 && mVideoHeight != 0) { + getHolder().setFixedSize(mVideoWidth, mVideoHeight); + } + + if (mTargetState == STATE_PLAYING) { + start(); + } + if (LOG) { + QcomLog.v(TAG, "doPrepared() end video size: " + mVideoWidth + "," + mVideoHeight + + ", mTargetState=" + mTargetState + ", mCurrentState=" + mCurrentState); + } + } + + private boolean mOnResumed; + /** + * surfaceCreate will invoke openVideo after the activity stoped. + * Here set this flag to avoid openVideo after the activity stoped. + * @param resume + */ + public void setResumed(final boolean resume) { + if (LOG) { + QcomLog.v(TAG, "setResumed(" + resume + ") mUri=" + mUri + ", mOnResumed=" + mOnResumed); + } + mOnResumed = resume; + } + + @Override + public void resume() { + if (LOG) { + QcomLog.v(TAG, "resume() mTargetState=" + mTargetState + ", mCurrentState=" + mCurrentState); + } + setResumed(true); + openVideo(); + } + + @Override + public void suspend() { + if (LOG) { + QcomLog.v(TAG, "suspend() mTargetState=" + mTargetState + ", mCurrentState=" + mCurrentState); + } + super.suspend(); + } + + public void setOnInfoListener(final OnInfoListener l) { + mOnInfoListener = l; + if (LOG) { + QcomLog.v(TAG, "setInfoListener(" + l + ")"); + } + } + + public void setOnBufferingUpdateListener(final OnBufferingUpdateListener l) { + mOnBufferingUpdateListener = l; + if (LOG) { + QcomLog.v(TAG, "setOnBufferingUpdateListener(" + l + ")"); + } + } + + public void setOnVideoSizeChangedListener(final OnVideoSizeChangedListener l) { + mVideoSizeListener = l; + if (LOG) { + Log.i(TAG, "setOnVideoSizeChangedListener(" + l + ")"); + } + } + + @Override + public int getCurrentPosition() { + int position = 0; + if (mSeekWhenPrepared > 0) { + //if connecting error before seek, + //we should remember this position for retry + position = mSeekWhenPrepared; + ///M: if player not started, getCurrentPosition() will lead to NE. + } else if (isInPlaybackState() && mCurrentState != STATE_PREPARED) { + position = mMediaPlayer.getCurrentPosition(); + } + if (LOG) { + QcomLog.v(TAG, "getCurrentPosition() return " + position + + ", mSeekWhenPrepared=" + mSeekWhenPrepared); + } + return position; + } + + //clear the seek position any way. + //this will effect the case: stop video before it's seek completed. + public void clearSeek() { + if (LOG) { + QcomLog.v(TAG, "clearSeek() mSeekWhenPrepared=" + mSeekWhenPrepared); + } + mSeekWhenPrepared = 0; + } + + public boolean isTargetPlaying() { + if (LOG) { + Log.v(TAG, "isTargetPlaying() mTargetState=" + mTargetState); + } + return mTargetState == STATE_PLAYING; + } + + public void dump() { + if (LOG) { + Log.v(TAG, "dump() mUri=" + mUri + + ", mTargetState=" + mTargetState + ", mCurrentState=" + mCurrentState + + ", mSeekWhenPrepared=" + mSeekWhenPrepared + + ", mVideoWidth=" + mVideoWidth + ", mVideoHeight=" + mVideoHeight + + ", mMediaPlayer=" + mMediaPlayer + ", mSurfaceHolder=" + mSurfaceHolder); + } + } + + @Override + public void seekTo(final int msec) { + if (LOG) { + Log.v(TAG, "seekTo(" + msec + ") isInPlaybackState()=" + isInPlaybackState()); + } + super.seekTo(msec); + } + + @Override + protected void release(final boolean cleartargetstate) { + if (LOG) { + Log.v(TAG, "release(" + cleartargetstate + ") mMediaPlayer=" + mMediaPlayer); + } + super.release(cleartargetstate); + } + + //for duration displayed + public void setDuration(final int duration) { + if (LOG) { + Log.v(TAG, "setDuration(" + duration + ")"); + } + mDuration = (duration > 0 ? -duration : duration); + } + + @Override + public int getDuration() { + final boolean inPlaybackState = isInPlaybackState(); + if (LOG) { + Log.v(TAG, "getDuration() mDuration=" + mDuration + ", inPlaybackState=" + inPlaybackState); + } + if (inPlaybackState) { + if (mDuration > 0) { + return mDuration; + } + mDuration = mMediaPlayer.getDuration(); + return mDuration; + } + //mDuration = -1; + return mDuration; + } + + public void clearDuration() { + if (LOG) { + QcomLog.v(TAG, "clearDuration() mDuration=" + mDuration); + } + mDuration = -1; + } + + //for video size changed before started issue + private static final int MSG_LAYOUT_READY = 1; + private boolean mNeedWaitLayout = false; + private final Handler mHandler = new Handler() { + public void handleMessage(final Message msg) { + if (LOG) { + QcomLog.v(TAG, "handleMessage() to do prepare. msg=" + msg); + } + switch(msg.what) { + case MSG_LAYOUT_READY: + if (mMediaPlayer == null || mUri == null) { + QcomLog.w(TAG, "Cannot prepare play! mMediaPlayer=" + mMediaPlayer + ", mUri=" + mUri); + } else { + doPreparedIfReady(mMediaPlayer); + } + break; + default: + QcomLog.w(TAG, "Unhandled message " + msg); + break; + } + } + }; + + private ScreenModeManager mScreenManager; + public void setScreenModeManager(final ScreenModeManager manager) { + mScreenManager = manager; + if (mScreenManager != null) { + mScreenManager.addListener(this); + } + if (LOG) { + QcomLog.v(TAG, "setScreenModeManager(" + manager + ")"); + } + } + + @Override + public void onScreenModeChanged(final int newMode) { + this.requestLayout(); + } +} diff --git a/src/com/qcom/gallery3d/video/SettingsActivity.java b/src/com/qcom/gallery3d/video/SettingsActivity.java new file mode 100755 index 000000000..0d73c5428 --- /dev/null +++ b/src/com/qcom/gallery3d/video/SettingsActivity.java @@ -0,0 +1,371 @@ +
+package com.qcom.gallery3d.video;
+
+import android.app.ActionBar;
+import android.app.Activity;
+import android.content.ContentResolver;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.database.Cursor;
+import android.os.Bundle;
+import android.preference.CheckBoxPreference;
+import android.preference.EditTextPreference;
+import android.preference.ListPreference;
+import android.preference.Preference;
+import android.preference.PreferenceActivity;
+import android.preference.PreferenceCategory;
+import android.preference.RingtonePreference;
+import android.preference.PreferenceScreen;
+import android.provider.Telephony;
+import android.telephony.MSimTelephonyManager;
+import java.util.ArrayList;
+import android.os.SystemProperties;
+
+
+
+
+
+/* wangyong 2012.2.9 begin*/
+//import android.provider.Calendar;
+/* wangyong 2012.2.9 end*/
+import android.provider.ContactsContract;
+import android.util.Log;
+import android.view.KeyEvent;
+import android.view.MenuItem;
+import android.text.method.DigitsKeyListener;
+import android.net.Uri;
+
+import android.telephony.TelephonyManager;
+import com.android.gallery3d.R;
+
+import com.android.internal.telephony.Phone;
+import com.android.internal.telephony.TelephonyIntents;
+import com.android.internal.telephony.TelephonyProperties;
+
+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 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 boolean mUseNvOperatorForEhrpd = SystemProperties.getBoolean(
+ "persist.radio.use_nv_for_ehrpd", false);
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ Log.v("settingActivty", "onCreate");
+ addPreferencesFromResource(R.xml.rtsp_settings_preferences);
+
+ // SharedPreferences mPref =
+ // PreferenceManager.getDefaultSharedPreferences(ComposeMessageActivity.this);
+ 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);
+ // String apn = getSelectedApnKey();//mPref.getString(PREFERENCE_APN,
+ // "CMWAP");
+ 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);
+ /* Start of zhuzhongwei 2011.2.14 */
+ Log.w("rtsp", "z66 summary = " + summary);
+ android.provider.Settings.System.putString(getContentResolver(),
+ "streaming_min_udp_port", summary);
+ /* End of zhuzhongwei 2011.2.14 */
+ 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);
+ /* Start of zhuzhongwei 2011.2.14 */
+ Log.w("rtsp", "z82 summary = " + summary);
+ android.provider.Settings.System.putString(getContentResolver(),
+ "streaming_max_udp_port", summary);
+ /* End of zhuzhongwei 2011.2.14 */
+ 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;
+ }
+ });
+
+ /*
+ * 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; } }); <!----
+ * <PreferenceCategory android:title="@string/buffer_size">
+ * <EditTextPreference android:order="5" android:key="buffer_size"
+ * android:title="@string/buffer_size" android:summary=""
+ * android:inputType="number"
+ * android:dialogTitle="@string/set_buffer_size" />
+ * </PreferenceCategory> ---->
+ */
+ /*
+ * mApn = (ListPreference) findPreference(PREFERENCE_APN);
+ * mApn.setValue(apn); mApn.setSummary(mApn.getEntry());
+ * mApn.setOnPreferenceChangeListener(new
+ * Preference.OnPreferenceChangeListener() { public boolean
+ * onPreferenceChange(Preference preference, Object newValue) { final
+ * String summary = newValue.toString(); int index =
+ * mApn.findIndexOfValue(summary);
+ * mApn.setSummary(mApn.getEntries()[index]); mApn.setValue(summary);
+ * android.provider.Settings.System.putString(getContentResolver(),
+ * "apn", summary); return true; } });
+ */
+ /*
+ * mApn = (ListPreference) findPreference(PREFERENCE_APN);
+ * mApn.setValue(getSelectedApnKey()); mApn.setSummary(mApn.getEntry());
+ * mApn.setOnPreferenceChangeListener(new
+ * Preference.OnPreferenceChangeListener() { public boolean
+ * onPreferenceChange(Preference preference, Object newValue) { //final
+ * String summary = newValue.toString(); //int index =
+ * mApn.findIndexOfValue(summary);
+ * ////mApn.setSummary(mApn.getEntries()[index]);
+ * //mApn.setValue(summary);
+ * //android.provider.Settings.System.putString(getContentResolver(),
+ * "apn", summary); Intent intent = new Intent();
+ * intent.setClassName("com.android.settings"
+ * ,"com.android.settings.ApnSettings"); //startActivity(intent);
+ * startActivityForResult(intent, SELECT_APN); return true; } });
+ */
+
+ mApn = (PreferenceScreen) findPreference(PREFERENCE_APN);
+ // mApn.setValue(getSelectedApnKey());
+ mApn.setSummary(getDefaultApnName());
+ mApn.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
+ public boolean onPreferenceClick(Preference preference) {
+ // final String summary = newValue.toString();
+ // int index = mApn.findIndexOfValue(summary);
+ // //mApn.setSummary(mApn.getEntries()[index]);
+ // mApn.setValue(summary);
+ // android.provider.Settings.System.putString(getContentResolver(),
+ // "apn", summary);
+
+ Intent intent = new Intent();
+ intent.setClassName("com.android.settings", "com.android.settings.ApnSettings");
+ // startActivity(intent);
+ startActivityForResult(intent, SELECT_APN);
+ return true;
+ }
+ });
+
+
+ // lizhongchao add for 4.0 UI START
+ ActionBar ab = getActionBar();
+ ab.setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD);
+ ab.setDisplayHomeAsUpEnabled(true);
+ ab.setTitle(R.string.setting);
+ // lizhongchao add for 4.0 UI END
+ }
+
+ private String getDefaultApnName() {
+
+ // 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);
+ Log.v("settingActivty", "default apn key = " + key);
+ }
+ cursor.close();
+
+ // to find default proxy
+ /**
+ String where = "numeric=\""
+ + android.os.SystemProperties.get(
+ TelephonyProperties.PROPERTY_ICC_OPERATOR_NUMERIC, "") + "\"";
+ */
+
+ String where = getOperatorNumericSelection();
+
+ cursor = getContentResolver().query(Telephony.Carriers.CONTENT_URI, new String[] {
+ "_id", "name", "apn", "type"
+ }, where, null, Telephony.Carriers.DEFAULT_SORT_ORDER);
+
+ while (cursor != null && cursor.moveToNext()) {
+ String curKey = cursor.getString(cursor.getColumnIndex("_id"));
+ String curName = cursor.getString(cursor.getColumnIndex("name"));
+ Log.v("settingActivty", "default apn curkey = " + curKey);
+ Log.v("settingActivty", "default apn curName = " + curName);
+ // String user = cursor.getString(cursor.getColumnIndex("user"));
+ // String password =
+ // cursor.getString(cursor.getColumnIndex("password"));
+ // a.proxy = cursor.getString(cursor.getColumnIndex("proxy"));
+ // a.type = cursor.getString(cursor.getColumnIndex("type"));
+
+ // logv( "getDefaultApn, a.key=" + a.key + ",a.apn=" + a.apn +
+ // ",a.user=" + a.user + ",a.password=" + a.password + ", a.proxy="
+ // + a.proxy);
+ // Log.d("rtsp","getDefaultApnName, cur, key=" + curKey +
+ // ",curName=" + curName);
+ if (curKey.equals(key)) {
+ Log.d("rtsp", "getDefaultApnName, find, key=" + curKey + ",curName=" + curName);
+ name = curName;
+ break;
+ }
+ }
+
+ if (cursor != null)
+ cursor.close();
+ Log.v("settingActivty", "default apn name = " + name);
+
+ return name;
+
+ }
+
+ private String getSelectedApnKey() {
+ String key = null;
+
+ Cursor cursor = getContentResolver().query(PREFERAPN_URI, new String[] {
+ "_id", "name"
+ }, null, null, null);
+ if (cursor.getCount() > 0) {
+ cursor.moveToFirst();
+ key = cursor.getString(NAME_INDEX);
+ }
+ cursor.close();
+
+ Log.w("rtsp", "getSelectedApnKey key = " + key);
+ if (null == key)
+ return new String("null");
+ return key;
+ }
+
+ @Override
+ public void onActivityResult(int requestCode, int resultCode, Intent data) {
+ switch (requestCode) {
+ case SELECT_APN:
+ // if (resultCode == RESULT_CANCELED) {
+ setResult(resultCode);
+ finish();
+ Log.w("rtsp", "onActivityResult requestCode = " + requestCode);
+ // mApn.setSummary(getDefaultApnName());
+ // }
+ break;
+ }
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ // TODO Auto-generated method stub
+ if(item.getItemId() == android.R.id.home){
+ finish();
+ }
+ return true;
+ }
+
+
+ private String getOperatorNumericSelection() {
+ String[] mccmncs = getOperatorNumeric(); + String where; + where = (mccmncs[0] != null) ? "numeric=\"" + mccmncs[0] + "\"" : ""; + where += (mccmncs[1] != null) ? " or numeric=\"" + mccmncs[1] + "\"" : ""; + Log.d("SettingsActivity", "getOperatorNumericSelection: " + where);
+ return where; + } + + private String[] getOperatorNumeric() { + ArrayList<String> result = new ArrayList<String>(); + String mccMncFromSim = null; + if (mUseNvOperatorForEhrpd) { + String mccMncForEhrpd = SystemProperties.get("ro.cdma.home.operator.numeric", null); + if (mccMncForEhrpd != null && mccMncForEhrpd.length() > 0) { + result.add(mccMncForEhrpd); + } + } +
+ mccMncFromSim = TelephonyManager.getDefault().getSimOperator();
+
+ if (mccMncFromSim != null && mccMncFromSim.length() > 0) { + result.add(mccMncFromSim); + } + return result.toArray(new String[2]); + }
+}
diff --git a/src/com/qcom/gallery3d/video/StreamingHooker.java b/src/com/qcom/gallery3d/video/StreamingHooker.java new file mode 100755 index 000000000..84152fc9d --- /dev/null +++ b/src/com/qcom/gallery3d/video/StreamingHooker.java @@ -0,0 +1,89 @@ +package com.qcom.gallery3d.video; + +import android.content.Intent; +import android.net.Uri; +import android.provider.Browser; +import android.view.Menu; +import android.view.MenuItem; + +import com.android.gallery3d.R; +import com.qcom.gallery3d.ext.MovieUtils; +import com.qcom.gallery3d.ext.QcomLog; + +public class StreamingHooker extends MovieHooker { + private static final String TAG = "StreamingHooker"; + private static final boolean LOG = true; + + private static final String ACTION_STREAMING = "com.qcom.settings.streaming"; + private static final int MENU_INPUT_URL = 1; + private static final int MENU_SETTINGS = 2; + private static final int MENU_DETAIL = 3; + private MenuItem mMenuDetail; + + public static final String KEY_LOGO_BITMAP = "logo-bitmap"; + + @Override + public boolean onCreateOptionsMenu(final Menu menu) { + super.onCreateOptionsMenu(menu); + //when in rtsp streaming type, generally it only has one uri. + mMenuDetail = menu.add(0, getMenuActivityId(MENU_DETAIL), 0, R.string.media_detail); + menu.add(0, getMenuActivityId(MENU_INPUT_URL), 0, R.string.input_url); + menu.add(0, getMenuActivityId(MENU_SETTINGS), 0, R.string.streaming_settings); + return true; + } + @Override + public boolean onPrepareOptionsMenu(final Menu menu) { + super.onPrepareOptionsMenu(menu); + if (MovieUtils.isLocalFile(getMovieItem().getUri(), getMovieItem().getMimeType())) { + if (mMenuDetail != null) { + mMenuDetail.setVisible(false); + } + } else { + if (mMenuDetail != null) { + mMenuDetail.setVisible(false); + } + } + return true; + } + @Override + public boolean onOptionsItemSelected(final MenuItem item) { + super.onOptionsItemSelected(item); + switch(getMenuOriginalId(item.getItemId())) { + case MENU_INPUT_URL: + gotoInputUrl(); + return true; + case MENU_SETTINGS: + gotoSettings(); + return true; + case MENU_DETAIL: + getPlayer().showDetail(); + return true; + default: + return false; + } + } + + private void gotoInputUrl() { + final String appName = getClass().getName(); + 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); + getContext().startActivity(intent); + if (LOG) { + QcomLog.v(TAG, "gotoInputUrl() appName=" + appName); + } + } + + 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) { + QcomLog.v(TAG, "gotoInputUrl()"); + } + } +}
\ No newline at end of file |