summaryrefslogtreecommitdiffstats
path: root/src/org/codeaurora
diff options
context:
space:
mode:
Diffstat (limited to 'src/org/codeaurora')
-rw-r--r--src/org/codeaurora/gallery3d/ext/ActivityHooker.java96
-rw-r--r--src/org/codeaurora/gallery3d/ext/ActivityHookerGroup.java150
-rw-r--r--src/org/codeaurora/gallery3d/ext/IActivityHooker.java128
-rw-r--r--src/org/codeaurora/gallery3d/ext/IContrllerOverlayExt.java51
-rw-r--r--src/org/codeaurora/gallery3d/ext/IMovieItem.java66
-rw-r--r--src/org/codeaurora/gallery3d/ext/IMovieList.java46
-rw-r--r--src/org/codeaurora/gallery3d/ext/IMovieListLoader.java51
-rw-r--r--src/org/codeaurora/gallery3d/ext/IMoviePlayer.java42
-rw-r--r--src/org/codeaurora/gallery3d/ext/MovieItem.java115
-rw-r--r--src/org/codeaurora/gallery3d/ext/MovieList.java72
-rw-r--r--src/org/codeaurora/gallery3d/ext/MovieListLoader.java274
-rw-r--r--src/org/codeaurora/gallery3d/ext/MovieUtils.java98
-rw-r--r--src/org/codeaurora/gallery3d/video/BookmarkActivity.java244
-rw-r--r--src/org/codeaurora/gallery3d/video/BookmarkEnhance.java138
-rw-r--r--src/org/codeaurora/gallery3d/video/BookmarkHooker.java76
-rwxr-xr-xsrc/org/codeaurora/gallery3d/video/CodeauroraVideoView.java1049
-rw-r--r--src/org/codeaurora/gallery3d/video/DmReceiver.java65
-rwxr-xr-xsrc/org/codeaurora/gallery3d/video/ExtensionHelper.java72
-rw-r--r--src/org/codeaurora/gallery3d/video/IControllerRewindAndForward.java35
-rw-r--r--src/org/codeaurora/gallery3d/video/LoopVideoHooker.java60
-rw-r--r--src/org/codeaurora/gallery3d/video/MovieHooker.java44
-rw-r--r--src/org/codeaurora/gallery3d/video/MovieListHooker.java116
-rw-r--r--src/org/codeaurora/gallery3d/video/MovieTitleHelper.java108
-rw-r--r--src/org/codeaurora/gallery3d/video/ScreenModeManager.java117
-rwxr-xr-xsrc/org/codeaurora/gallery3d/video/SettingsActivity.java308
-rw-r--r--src/org/codeaurora/gallery3d/video/SpeakerHooker.java210
-rw-r--r--src/org/codeaurora/gallery3d/video/StepOptionDialogFragment.java83
-rw-r--r--src/org/codeaurora/gallery3d/video/StepOptionSettingsHooker.java41
-rwxr-xr-xsrc/org/codeaurora/gallery3d/video/StereoAudioHooker.java118
-rwxr-xr-xsrc/org/codeaurora/gallery3d/video/StreamingHooker.java86
-rw-r--r--src/org/codeaurora/gallery3d/video/VideoSettingsActivity.java182
31 files changed, 4341 insertions, 0 deletions
diff --git a/src/org/codeaurora/gallery3d/ext/ActivityHooker.java b/src/org/codeaurora/gallery3d/ext/ActivityHooker.java
new file mode 100644
index 000000000..65761ff23
--- /dev/null
+++ b/src/org/codeaurora/gallery3d/ext/ActivityHooker.java
@@ -0,0 +1,96 @@
+package org.codeaurora.gallery3d.ext;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.os.Bundle;
+import android.view.Menu;
+import android.view.MenuItem;
+
+/**
+ * Default implemention class of IActivityHooker.
+ */
+public class ActivityHooker implements IActivityHooker {
+
+ private static final int MENU_MAX_NUMBER = 100;
+ private static int sMenuId = 1;
+ private int mMenuId;
+ private static Object sMenuLock = new Object();
+ private Activity mContext;
+ private Intent mIntent;
+
+ public ActivityHooker() {
+ synchronized (sMenuLock) {
+ sMenuId++;
+ mMenuId = sMenuId * MENU_MAX_NUMBER;
+ }
+ }
+
+ @Override
+ public int getMenuActivityId(int id) {
+ return mMenuId + id;
+ };
+
+ @Override
+ public int getMenuOriginalId(int id) {
+ return id - mMenuId;
+ }
+
+ @Override
+ public void init(Activity context, Intent intent) {
+ mContext = context;
+ mIntent = intent;
+ }
+
+ @Override
+ public Activity getContext() {
+ return mContext;
+ }
+
+ @Override
+ public Intent getIntent() {
+ return mIntent;
+ }
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ }
+
+ @Override
+ public void onStart() {
+ }
+
+ @Override
+ public void onResume() {
+ }
+
+ @Override
+ public void onPause() {
+ }
+
+ @Override
+ public void onStop() {
+ }
+
+ @Override
+ public void onDestroy() {
+ }
+
+ @Override
+ public boolean onCreateOptionsMenu(Menu menu) {
+ return false;
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ return false;
+ }
+
+ @Override
+ public boolean onPrepareOptionsMenu(Menu menu) {
+ return false;
+ }
+
+ @Override
+ public void setParameter(String key, Object value) {
+ }
+}
diff --git a/src/org/codeaurora/gallery3d/ext/ActivityHookerGroup.java b/src/org/codeaurora/gallery3d/ext/ActivityHookerGroup.java
new file mode 100644
index 000000000..4bf8616e7
--- /dev/null
+++ b/src/org/codeaurora/gallery3d/ext/ActivityHookerGroup.java
@@ -0,0 +1,150 @@
+package org.codeaurora.gallery3d.ext;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.os.Bundle;
+import android.view.Menu;
+import android.view.MenuItem;
+
+import java.util.ArrayList;
+
+/**
+ * The composite pattern class. It will deliver every action to its leaf
+ * hookers.
+ */
+public class ActivityHookerGroup extends ActivityHooker {
+ private ArrayList<IActivityHooker> mHooks = new ArrayList<IActivityHooker>();
+
+ /**
+ * Add hooker to current group.
+ *
+ * @param hooker
+ * @return
+ */
+ public boolean addHooker(IActivityHooker hooker) {
+ return mHooks.add(hooker);
+ }
+
+ /**
+ * Remove hooker from current group.
+ *
+ * @param hooker
+ * @return
+ */
+ public boolean removeHooker(IActivityHooker hooker) {
+ return mHooks.remove(hooker);
+ }
+
+ /**
+ * Get hooker of requested location.
+ *
+ * @param index
+ * @return
+ */
+ public IActivityHooker getHooker(int index) {
+ return mHooks.get(index);
+ }
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ for (IActivityHooker hook : mHooks) {
+ hook.onCreate(savedInstanceState);
+ }
+ }
+
+ @Override
+ public void onStart() {
+ super.onStart();
+ for (IActivityHooker hook : mHooks) {
+ hook.onStart();
+ }
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ for (IActivityHooker hook : mHooks) {
+ hook.onResume();
+ }
+ }
+
+ @Override
+ public void onPause() {
+ super.onPause();
+ for (IActivityHooker hook : mHooks) {
+ hook.onPause();
+ }
+ }
+
+ @Override
+ public void onStop() {
+ super.onStop();
+ for (IActivityHooker hook : mHooks) {
+ hook.onStop();
+ }
+ }
+
+ @Override
+ public void onDestroy() {
+ super.onDestroy();
+ for (IActivityHooker hook : mHooks) {
+ hook.onDestroy();
+ }
+ }
+
+ @Override
+ public boolean onCreateOptionsMenu(Menu menu) {
+ super.onCreateOptionsMenu(menu);
+ boolean handle = false;
+ for (IActivityHooker hook : mHooks) {
+ boolean one = hook.onCreateOptionsMenu(menu);
+ if (!handle) {
+ handle = one;
+ }
+ }
+ return handle;
+ }
+
+ @Override
+ public boolean onPrepareOptionsMenu(Menu menu) {
+ super.onPrepareOptionsMenu(menu);
+ boolean handle = false;
+ for (IActivityHooker hook : mHooks) {
+ boolean one = hook.onPrepareOptionsMenu(menu);
+ if (!handle) {
+ handle = one;
+ }
+ }
+ return handle;
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ super.onOptionsItemSelected(item);
+ boolean handle = false;
+ for (IActivityHooker hook : mHooks) {
+ boolean one = hook.onOptionsItemSelected(item);
+ if (!handle) {
+ handle = one;
+ }
+ }
+ return handle;
+ }
+
+ @Override
+ public void setParameter(String key, Object value) {
+ super.setParameter(key, value);
+ for (IActivityHooker hook : mHooks) {
+ hook.setParameter(key, value);
+ }
+ }
+
+ @Override
+ public void init(Activity context, Intent intent) {
+ super.init(context, intent);
+ for (IActivityHooker hook : mHooks) {
+ hook.init(context, intent);
+ }
+ }
+}
diff --git a/src/org/codeaurora/gallery3d/ext/IActivityHooker.java b/src/org/codeaurora/gallery3d/ext/IActivityHooker.java
new file mode 100644
index 000000000..a83799626
--- /dev/null
+++ b/src/org/codeaurora/gallery3d/ext/IActivityHooker.java
@@ -0,0 +1,128 @@
+package org.codeaurora.gallery3d.ext;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.os.Bundle;
+import android.view.Menu;
+import android.view.MenuItem;
+
+/**
+ * Activity action hooker class. Host app's activity will call this hooker's
+ * functions in its lifecycle. For example:
+ * HostActivity.onCreate()-->hooker.onCreate(). But void init(Activity context,
+ * Intent intent) will be called before other functions. <br/>
+ * IActivityHooker objects may show menus, but we should give a unique menu id
+ * to every menus. Hooker can call getMenuActivityId(int) to get a global unique
+ * menu id to be used in menu.add(), and can call getMenuOriginalId(int) to get
+ * the original menu id. the example: class Hooker implements IActivityHooker {
+ * private static final int MENU_EXAMPLE = 1;
+ *
+ * @Override public boolean onCreateOptionsMenu(Menu menu) {
+ * super.onCreateOptionsMenu(menu); menu.add(0,
+ * getMenuActivityId(MENU_EXAMPLE), 0, android.R.string.ok); return
+ * true; }
+ * @Override public boolean onOptionsItemSelected(MenuItem item) {
+ * switch(getMenuOriginalId(item.getItemId())) { case MENU_EXAMPLE:
+ * //do something return true; default: return false; } } }
+ */
+public interface IActivityHooker {
+ /**
+ * Will be called in Host Activity.onCreate(Bundle savedInstanceState)
+ * @param savedInstanceState
+ */
+ void onCreate(Bundle savedInstanceState);
+ /**
+ * Will be called in Host Activity.onStart()
+ */
+ void onStart();
+ /**
+ * Will be called in Host Activity.onStop()
+ */
+ void onStop();
+ /**
+ * Will be called in Host Activity.onPause()
+ */
+ void onPause();
+ /**
+ * Will be called in Host Activity.onResume()
+ */
+ void onResume();
+ /**
+ * Will be called in Host Activity.onDestroy()
+ */
+ void onDestroy();
+ /**
+ * Will be called in Host Activity.onCreateOptionsMenu(Menu menu)
+ * @param menu
+ * @return
+ */
+ /**
+ * Will be called in Host Activity.onCreateOptionsMenu(Menu menu)
+ *
+ * @param menu
+ * @return
+ */
+ boolean onCreateOptionsMenu(Menu menu);
+
+ /**
+ * Will be called in Host Activity.onPrepareOptionsMenu(Menu menu)
+ *
+ * @param menu
+ * @return
+ */
+ boolean onPrepareOptionsMenu(Menu menu);
+
+ /**
+ * Will be called in Host Activity.onOptionsItemSelected(MenuItem item)
+ *
+ * @param item
+ * @return
+ */
+ boolean onOptionsItemSelected(MenuItem item);
+
+ /**
+ * Should be called before any other functions.
+ *
+ * @param context
+ * @param intent
+ */
+ void init(Activity context, Intent intent);
+
+ /**
+ * @return return activity set by init(Activity context, Intent intent)
+ */
+ Activity getContext();
+
+ /**
+ * @return return intent set by init(Activity context, Intent intent)
+ */
+ Intent getIntent();
+
+ /**
+ * IActivityHooker objects may show menus, but we should give a unique menu
+ * id to every menus. Hooker can call this function to get a global unique
+ * menu id to be used in menu.add()
+ *
+ * @param id
+ * @return
+ */
+ int getMenuActivityId(int id);
+
+ /**
+ * When onOptionsItemSelected is called, we can get menu's id from
+ * parameter. You can get the original menu id by calling this function.
+ *
+ * @param id
+ * @return
+ */
+ int getMenuOriginalId(int id);
+
+ /**
+ * Host activity will call this function to set parameter to hooker
+ * activity.
+ *
+ * @param key
+ * @param value
+ */
+ void setParameter(String key, Object value);
+}
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/IMovieItem.java b/src/org/codeaurora/gallery3d/ext/IMovieItem.java
new file mode 100644
index 000000000..dece4e803
--- /dev/null
+++ b/src/org/codeaurora/gallery3d/ext/IMovieItem.java
@@ -0,0 +1,66 @@
+package org.codeaurora.gallery3d.ext;
+
+import android.net.Uri;
+
+/**
+ * Movie info class
+ */
+public interface IMovieItem {
+ /**
+ * @return movie Uri, it's may be not the original Uri.
+ */
+ Uri getUri();
+
+ /**
+ * @return MIME type of video
+ */
+ String getMimeType();
+
+ /**
+ * @return title of video
+ */
+ String getTitle();
+
+ /**
+ * @return whether error occured or not.
+ */
+ boolean getError();
+
+ /**
+ * set title of video
+ *
+ * @param title
+ */
+ void setTitle(String title);
+
+ /**
+ * set video Uri
+ *
+ * @param uri
+ */
+ void setUri(Uri uri);
+
+ /**
+ * Set MIME type of video
+ *
+ * @param mimeType
+ */
+ void setMimeType(String mimeType);
+
+ /**
+ * Set error occured flag
+ */
+ void setError();
+
+ /**
+ * @return return original Uri of video.
+ */
+ Uri getOriginalUri();
+
+ /**
+ * Set video original Uri.
+ *
+ * @param uri
+ */
+ void setOriginalUri(Uri uri);
+}
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..fe5999858
--- /dev/null
+++ b/src/org/codeaurora/gallery3d/ext/IMovieListLoader.java
@@ -0,0 +1,51 @@
+package org.codeaurora.gallery3d.ext;
+
+import android.app.Activity;
+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(Activity 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
new file mode 100644
index 000000000..32d400b0d
--- /dev/null
+++ b/src/org/codeaurora/gallery3d/ext/IMoviePlayer.java
@@ -0,0 +1,42 @@
+package org.codeaurora.gallery3d.ext;
+
+public interface IMoviePlayer {
+
+ /**
+ * add new bookmark Uri.
+ */
+ void addBookmark();
+
+ /**
+ * Loop current video.
+ *
+ * @param loop
+ */
+ void setLoop(boolean loop);
+
+ /**
+ * Loop current video or not
+ *
+ * @return
+ */
+ boolean getLoop();
+
+ /**
+ * Can stop current video or not.
+ *
+ * @return
+ */
+ boolean canStop();
+
+ /**
+ * 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/MovieItem.java b/src/org/codeaurora/gallery3d/ext/MovieItem.java
new file mode 100644
index 000000000..56afdda4b
--- /dev/null
+++ b/src/org/codeaurora/gallery3d/ext/MovieItem.java
@@ -0,0 +1,115 @@
+package org.codeaurora.gallery3d.ext;
+
+import android.net.Uri;
+import android.provider.MediaStore;
+
+public class MovieItem implements IMovieItem {
+ private static final String TAG = "MovieItem";
+ private static final boolean LOG = false;
+
+ private Uri mUri;
+ private String mMimeType;
+ private String mTitle;
+ private boolean mError;
+ // private int mStereoType;
+ private Uri mOriginal;
+
+ private static final int STREO_TYPE_2D = 1;
+
+ public MovieItem(Uri uri, String mimeType, String title, int stereoType) {
+ mUri = uri;
+ mMimeType = mimeType;
+ mTitle = title;
+ // mStereoType = stereoType;
+ mOriginal = uri;
+ }
+
+ public MovieItem(String uri, String mimeType, String title, int stereoType) {
+ this(Uri.parse(uri), mimeType, title, stereoType);
+ }
+
+ public MovieItem(Uri uri, String mimeType, String title) {
+ this(uri, mimeType, title, STREO_TYPE_2D);
+ }
+
+ public MovieItem(String uri, String mimeType, String title) {
+ this(Uri.parse(uri), mimeType, title);
+ }
+
+ @Override
+ public Uri getUri() {
+ return mUri;
+ }
+
+ @Override
+ public String getMimeType() {
+ return mMimeType;
+ }
+
+ @Override
+ public String getTitle() {
+ return mTitle;
+ }
+
+ @Override
+ public boolean getError() {
+ return mError;
+ }
+
+ // @Override
+ // public int getStereoType() {
+ // return mStereoType;
+ // }
+
+ public void setTitle(String title) {
+ mTitle = title;
+ }
+
+ @Override
+ public void setUri(Uri uri) {
+ mUri = uri;
+ }
+
+ @Override
+ public void setMimeType(String mimeType) {
+ mMimeType = mimeType;
+ }
+
+ // @Override
+ // public void setStereoType(int stereoType) {
+ // mStereoType = stereoType;
+ // }
+
+ @Override
+ public void setError() {
+ mError = true;
+ }
+
+ @Override
+ public Uri getOriginalUri() {
+ return mOriginal;
+ }
+
+ @Override
+ public void setOriginalUri(Uri uri) {
+ mOriginal = uri;
+ }
+
+ @Override
+ public String toString() {
+ return new StringBuilder().append("MovieItem(uri=")
+ .append(mUri)
+ .append(", mime=")
+ .append(mMimeType)
+ .append(", title=")
+ .append(mTitle)
+ .append(", error=")
+ .append(mError)
+ // .append(", support3D=")
+ // .append(mStereoType)
+ .append(", mOriginal=")
+ .append(mOriginal)
+ .append(")")
+ .toString();
+ }
+}
diff --git a/src/org/codeaurora/gallery3d/ext/MovieList.java b/src/org/codeaurora/gallery3d/ext/MovieList.java
new file mode 100644
index 000000000..ecb7f0db3
--- /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 = false;
+
+ 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..237d7e138
--- /dev/null
+++ b/src/org/codeaurora/gallery3d/ext/MovieListLoader.java
@@ -0,0 +1,274 @@
+package org.codeaurora.gallery3d.ext;
+
+import android.app.Activity;
+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;
+
+import java.io.File;
+import java.util.ArrayList;
+
+/**
+ * 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 = false;
+
+ private MovieListFetcherTask mListTask;
+
+ @Override
+ public void fillVideoList(Activity activity, Intent intent, final LoaderListener l,
+ IMovieItem currentMovieItem) {
+
+ // determine if a video playlist has been passed in through the intent
+ // if a playlist does exist, use that
+ ArrayList<Uri> uris = intent.getParcelableArrayListExtra("EXTRA_FILE_LIST");
+ if (uris != null) {
+ final MovieList movieList = new MovieList();
+ ContentResolver cr = activity.getContentResolver();
+
+ for(Uri uri : uris) {
+ // add currentMovieItem in its proper place in the video playlist
+ // 'Next' and 'Previous' functionality in MovieListHooker is dependent on reference
+ // matching currentMovieItem
+ if (currentMovieItem.getOriginalUri().equals(uri)) {
+ movieList.add(currentMovieItem);
+ continue;
+ }
+
+ File videoFile = new File(uri.getPath());
+ movieList.add(new MovieItem(uri, cr.getType(uri), videoFile.getName()));
+ }
+
+ // notify callback on main thread
+ activity.runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ l.onListLoaded(movieList);
+ }
+ });
+
+ return;
+ }
+
+ // proceed with creating a playlist if one isn't found
+ 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(activity, fetechAll, l, orderBy);
+ mListTask.execute(currentMovieItem);
+ 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 = false;
+
+ // 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 if (uristr.toLowerCase().startsWith("file://")) {
+ long curId = getCursorId(uri);
+ 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();
+ }
+ try {
+ long curId = Long.parseLong(uri.getPathSegments().get(3));
+ movieList = fillUriList(MediaStore.Video.Media.BUCKET_ID + "=? ",
+ new String[]{String.valueOf(bucketId)}, curId, params[0]);
+ } catch (Exception e) {
+ Log.e(TAG, "Exception while creating movie list. " + e);
+ return null;
+ }
+ } 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;
+ }
+
+ private long getCursorId(Uri uri) {
+ long curId = -1;
+ Cursor cursor = null;
+ String data = Uri.decode(uri.toString());
+ data = data.replaceAll("'", "''");
+ String where = "_data LIKE '%" + data.replaceFirst("file:///", "") + "'";
+ try {
+ cursor = mCr.query(MediaStore.Video.Media.EXTERNAL_CONTENT_URI,
+ new String[] {
+ "_id"
+ }, where, null, null);
+
+ if (cursor != null && cursor.moveToFirst()) {
+ curId = cursor.getLong(0);
+ }
+ } catch (final SQLiteException e) {
+ e.printStackTrace();
+ } finally {
+ if (cursor != null) {
+ cursor.close();
+ }
+ }
+ return curId;
+ }
+ }
+}
diff --git a/src/org/codeaurora/gallery3d/ext/MovieUtils.java b/src/org/codeaurora/gallery3d/ext/MovieUtils.java
new file mode 100644
index 000000000..4bc70a39f
--- /dev/null
+++ b/src/org/codeaurora/gallery3d/ext/MovieUtils.java
@@ -0,0 +1,98 @@
+package org.codeaurora.gallery3d.ext;
+
+import android.net.Uri;
+import android.util.Log;
+
+import java.util.Locale;
+
+/**
+ * Util class for Movie functions. *
+ */
+public class MovieUtils {
+ private static final String TAG = "MovieUtils";
+ private static final boolean LOG = false;
+
+ private MovieUtils() {
+ }
+
+ /**
+ * Whether current video(Uri) is RTSP streaming or not.
+ *
+ * @param uri
+ * @param mimeType
+ * @return
+ */
+ public static boolean isRtspStreaming(Uri uri, String mimeType) {
+ boolean rtsp = false;
+ if (uri != null) {
+ if ("rtsp".equalsIgnoreCase(uri.getScheme())) {
+ rtsp = true;
+ }
+ }
+ if (LOG) {
+ Log.v(TAG, "isRtspStreaming(" + uri + ", " + mimeType + ") return " + rtsp);
+ }
+ return rtsp;
+ }
+
+ /**
+ * Whether current video(Uri) is HTTP streaming or not.
+ *
+ * @param uri
+ * @param mimeType
+ * @return
+ */
+ public static boolean isHttpStreaming(Uri uri, String mimeType) {
+ boolean http = false;
+ if (uri != null) {
+ if ("http".equalsIgnoreCase(uri.getScheme())) {
+ http = true;
+ } else if ("https".equalsIgnoreCase(uri.getScheme())) {
+ http = true;
+ }
+ }
+ if (LOG) {
+ Log.v(TAG, "isHttpStreaming(" + uri + ", " + mimeType + ") return " + http);
+ }
+ return http;
+ }
+
+ /**
+ * Whether current video(Uri) is live streaming or not.
+ *
+ * @param uri
+ * @param mimeType
+ * @return
+ */
+ public static boolean isSdpStreaming(Uri uri, String mimeType) {
+ boolean sdp = false;
+ if (uri != null) {
+ if ("application/sdp".equals(mimeType)) {
+ sdp = true;
+ } else if (uri.toString().toLowerCase(Locale.ENGLISH).endsWith(".sdp")) {
+ sdp = true;
+ }
+ }
+ if (LOG) {
+ Log.v(TAG, "isSdpStreaming(" + uri + ", " + mimeType + ") return " + sdp);
+ }
+ return sdp;
+ }
+
+ /**
+ * Whether current video(Uri) is local file or not.
+ *
+ * @param uri
+ * @param mimeType
+ * @return
+ */
+ public static boolean isLocalFile(Uri uri, String mimeType) {
+ boolean local = (!isSdpStreaming(uri, mimeType)
+ && !isRtspStreaming(uri, mimeType)
+ && !isHttpStreaming(uri, mimeType));
+ if (LOG) {
+ Log.v(TAG, "isLocalFile(" + uri + ", " + mimeType + ") return " + local);
+ }
+ return local;
+ }
+}
diff --git a/src/org/codeaurora/gallery3d/video/BookmarkActivity.java b/src/org/codeaurora/gallery3d/video/BookmarkActivity.java
new file mode 100644
index 000000000..e4662b4eb
--- /dev/null
+++ b/src/org/codeaurora/gallery3d/video/BookmarkActivity.java
@@ -0,0 +1,244 @@
+package org.codeaurora.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.util.Log;
+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;
+
+public class BookmarkActivity extends Activity implements OnItemClickListener {
+ private static final String TAG = "BookmarkActivity";
+ private static final boolean LOG = false;
+
+ 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) {
+ Log.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 {
+ Log.w(TAG, "wrong context item info " + info);
+ }
+ return true;
+ default:
+ return super.onContextItemSelected(item);
+ }
+ }
+
+ private void showEditDialog(final ViewHolder holder) {
+ if (LOG) {
+ Log.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/org/codeaurora/gallery3d/video/BookmarkEnhance.java b/src/org/codeaurora/gallery3d/video/BookmarkEnhance.java
new file mode 100644
index 000000000..cf607ecc4
--- /dev/null
+++ b/src/org/codeaurora/gallery3d/video/BookmarkEnhance.java
@@ -0,0 +1,138 @@
+package org.codeaurora.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 android.util.Log;
+
+import com.android.gallery3d.R;
+
+public class BookmarkEnhance {
+ private static final String TAG = "BookmarkEnhance";
+ private static final boolean LOG = false;
+
+ 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) {
+ Log.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) {
+ Log.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) {
+ Log.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) {
+ Log.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) {
+ Log.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) {
+ Log.v(TAG, "update(" + id + ", " + title + ", " + uri + ", " + position + ")" +
+ " return " + count);
+ }
+ return count;
+ }
+}
diff --git a/src/org/codeaurora/gallery3d/video/BookmarkHooker.java b/src/org/codeaurora/gallery3d/video/BookmarkHooker.java
new file mode 100644
index 000000000..015fc3c41
--- /dev/null
+++ b/src/org/codeaurora/gallery3d/video/BookmarkHooker.java
@@ -0,0 +1,76 @@
+package org.codeaurora.gallery3d.video;
+
+import android.content.Intent;
+import android.view.Menu;
+import android.view.MenuItem;
+
+import com.android.gallery3d.R;
+import org.codeaurora.gallery3d.ext.MovieUtils;
+
+public class BookmarkHooker extends MovieHooker {
+ private static final String TAG = "BookmarkHooker";
+ private static final boolean LOG = false;
+
+ private static final String ACTION_BOOKMARK = "org.codeaurora.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);
+ }
+}
diff --git a/src/org/codeaurora/gallery3d/video/CodeauroraVideoView.java b/src/org/codeaurora/gallery3d/video/CodeauroraVideoView.java
new file mode 100755
index 000000000..c637c295a
--- /dev/null
+++ b/src/org/codeaurora/gallery3d/video/CodeauroraVideoView.java
@@ -0,0 +1,1049 @@
+package org.codeaurora.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.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;
+import android.media.MediaPlayer.OnInfoListener;
+import android.net.Uri;
+import android.os.Handler;
+import android.os.Message;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.KeyEvent;
+import android.view.MotionEvent;
+import android.view.SurfaceHolder;
+import android.view.SurfaceView;
+import android.view.View;
+import android.view.accessibility.AccessibilityEvent;
+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;
+
+/**
+ * Displays a video file. The VideoView class
+ * can load images from various sources (such as resources or content
+ * providers), takes care of computing its measurement from the video so that
+ * 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, ScreenModeListener{
+ private static final boolean LOG = false;
+ private String TAG = "CodeauroraVideoView";
+ // settable by the client
+ private Uri mUri;
+ private Map<String, String> mHeaders;
+
+ // all possible internal states
+ private static final int STATE_ERROR = -1;
+ private static final int STATE_IDLE = 0;
+ private static final int STATE_PREPARING = 1;
+ private static final int STATE_PREPARED = 2;
+ private static final int STATE_PLAYING = 3;
+ private static final int STATE_PAUSED = 4;
+ private static final int STATE_PLAYBACK_COMPLETED = 5;
+ private static final int STATE_SUSPENDED = 6;
+ private static final int MSG_LAYOUT_READY = 1;
+
+ // mCurrentState is a VideoView object's current state.
+ // mTargetState is the state that a method caller intends to reach.
+ // For instance, regardless the VideoView object's current state,
+ // calling pause() intends to bring the object to a target state
+ // of STATE_PAUSED.
+ private int mCurrentState = STATE_IDLE;
+ private int mTargetState = STATE_IDLE;
+
+ // All the stuff we need for playing and showing a video
+ private SurfaceHolder mSurfaceHolder = null;
+ private MediaPlayer mMediaPlayer = null;
+ private int mAudioSession;
+ private int mVideoWidth;
+ private int mVideoHeight;
+ private int mSurfaceWidth;
+ private int mSurfaceHeight;
+ private int mDuration;
+ private MediaController mMediaController;
+ private OnCompletionListener mOnCompletionListener;
+ private MediaPlayer.OnPreparedListener mOnPreparedListener;
+ private MediaPlayer.OnBufferingUpdateListener mOnBufferingUpdateListener;
+ private MediaPlayer.OnVideoSizeChangedListener mVideoSizeListener;
+ private MediaPlayer.OnPreparedListener mPreparedListener;
+ private ScreenModeManager mScreenManager;
+ private int mCurrentBufferPercentage;
+ private OnErrorListener mOnErrorListener;
+ private OnInfoListener mOnInfoListener;
+ private int mSeekWhenPrepared; // recording the seek position while preparing
+ private boolean mCanPause;
+ private boolean mCanSeekBack;
+ private boolean mCanSeekForward;
+ private boolean mCanSeek;
+ private boolean mHasGotPreparedCallBack = false;
+ private boolean mNeedWaitLayout = false;
+ private boolean mHasGotMetaData = false;
+ private boolean mOnResumed;
+ private boolean mIsShowDialog = false;
+
+ private final Handler mHandler = new Handler() {
+ public void handleMessage(final Message msg) {
+ if (LOG) {
+ Log.v(TAG, "handleMessage() to do prepare. msg=" + msg);
+ }
+ switch (msg.what) {
+ case MSG_LAYOUT_READY:
+ if (mMediaPlayer == null || mUri == null) {
+ Log.w(TAG, "Cannot prepare play! mMediaPlayer=" + mMediaPlayer
+ + ", mUri=" + mUri);
+ return;
+ }
+ doPreparedIfReady(mMediaPlayer);
+ break;
+ default:
+ Log.w(TAG, "Unhandled message " + msg);
+ break;
+ }
+ }
+ };
+
+ public CodeauroraVideoView(Context context) {
+ super(context);
+ initVideoView();
+ initialize();
+ }
+
+ public CodeauroraVideoView(Context context, AttributeSet attrs) {
+ this(context, attrs, 0);
+ initVideoView();
+ initialize();
+ }
+
+ public CodeauroraVideoView(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+ initVideoView();
+ initialize();
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ 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;
+ }
+ }
+ 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;
+ }
+ }
+ 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.
+ mNeedWaitLayout = false;
+ mHandler.sendEmptyMessage(MSG_LAYOUT_READY);
+ }
+ }
+
+ @Override
+ public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
+ super.onInitializeAccessibilityEvent(event);
+ event.setClassName(CodeauroraVideoView.class.getName());
+ }
+
+ @Override
+ public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
+ super.onInitializeAccessibilityNodeInfo(info);
+ info.setClassName(CodeauroraVideoView.class.getName());
+ }
+
+ public int resolveAdjustedSize(int desiredSize, int measureSpec) {
+ return getDefaultSize(desiredSize, measureSpec);
+ }
+
+ private void initVideoView() {
+ mVideoWidth = 0;
+ mVideoHeight = 0;
+ getHolder().addCallback(mSHCallback);
+ getHolder().setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
+ setFocusable(true);
+ setFocusableInTouchMode(true);
+ requestFocus();
+ mCurrentState = STATE_IDLE;
+ mTargetState = STATE_IDLE;
+ }
+
+ private void initialize() {
+ mPreparedListener = new MediaPlayer.OnPreparedListener() {
+ public void onPrepared(final MediaPlayer mp) {
+ if (LOG) {
+ Log.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);
+ 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) {
+ Log.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);
+ //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;
+
+ 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;
+ }
+ 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;
+ }
+ };
+
+ mBufferingUpdateListener = new MediaPlayer.OnBufferingUpdateListener() {
+ public void onBufferingUpdate(final MediaPlayer mp, final int percent) {
+ mCurrentBufferPercentage = percent;
+ if (mOnBufferingUpdateListener != null) {
+ mOnBufferingUpdateListener.onBufferingUpdate(mp, percent);
+ }
+ if (LOG) {
+ Log.v(TAG, "onBufferingUpdate() Buffering percent: " + percent);
+ Log.v(TAG, "onBufferingUpdate() mTargetState=" + mTargetState);
+ Log.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) {
+ Log.v(TAG, "OnVideoSizeChagned(" + width + "," + height + ")");
+ Log.v(TAG, "OnVideoSizeChagned(" + mVideoWidth + "," + mVideoHeight + ")");
+ Log.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);
+ }
+ CodeauroraVideoView.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 + ")");
+ 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 + ")");
+ }
+ 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);
+ }
+ }
+ 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();
+ }
+ if (isHTTPStreaming(mUri) && mCurrentState == STATE_SUSPENDED) {
+ // Don't call release() while run suspend operation
+ return;
+ }
+ release(true);
+ }
+ };
+ getHolder().addCallback(mSHCallback);
+ }
+
+ public void setVideoPath(String path) {
+ setVideoURI(Uri.parse(path));
+ }
+
+ public void setVideoURI(Uri uri) {
+ setVideoURI(uri, null);
+ }
+
+ /**
+ * @hide
+ */
+ public void setVideoURI(Uri uri, Map<String, String> headers) {
+ Log.d(TAG,"setVideoURI uri = " + uri);
+ mDuration = -1;
+ setResumed(true);
+ mUri = uri;
+ mHeaders = headers;
+ mSeekWhenPrepared = 0;
+ openVideo();
+ requestLayout();
+ invalidate();
+ }
+
+ public void stopPlayback() {
+ if (mMediaPlayer != null) {
+ mMediaPlayer.stop();
+ mMediaPlayer.release();
+ mMediaPlayer = null;
+ mCurrentState = STATE_IDLE;
+ mTargetState = STATE_IDLE;
+ }
+ }
+
+ private void openVideo() {
+ clearVideoInfo();
+ if (mUri == null || mSurfaceHolder == null) {
+ // not ready for playback just yet, will try again later
+ return;
+ }
+
+ // 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();
+ if (mAudioSession != 0) {
+ mMediaPlayer.setAudioSessionId(mAudioSession);
+ } else {
+ mAudioSession = mMediaPlayer.getAudioSessionId();
+ }
+ mMediaPlayer.setOnPreparedListener(mPreparedListener);
+ mMediaPlayer.setOnVideoSizeChangedListener(mSizeChangedListener);
+ mMediaPlayer.setOnCompletionListener(mCompletionListener);
+ mMediaPlayer.setOnErrorListener(mErrorListener);
+ mMediaPlayer.setOnInfoListener(mOnInfoListener);
+ mMediaPlayer.setOnBufferingUpdateListener(mBufferingUpdateListener);
+ mCurrentBufferPercentage = 0;
+ mMediaPlayer.setDataSource(mContext, mUri, mHeaders);
+ mMediaPlayer.setDisplay(mSurfaceHolder);
+ mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
+ mMediaPlayer.setScreenOnWhilePlaying(true);
+ 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 (IOException ex) {
+ Log.w(TAG, "Unable to open content: " + mUri, ex);
+ mCurrentState = STATE_ERROR;
+ mTargetState = STATE_ERROR;
+ mErrorListener.onError(mMediaPlayer, MediaPlayer.MEDIA_ERROR_UNKNOWN, 0);
+ return;
+ } catch (IllegalArgumentException ex) {
+ Log.w(TAG, "Unable to open content: " + mUri, ex);
+ mCurrentState = STATE_ERROR;
+ mTargetState = STATE_ERROR;
+ mErrorListener.onError(mMediaPlayer, MediaPlayer.MEDIA_ERROR_UNKNOWN, 0);
+ return;
+ }
+ }
+
+ public void setMediaController(MediaController controller) {
+ if (mMediaController != null) {
+ mMediaController.hide();
+ }
+ mMediaController = controller;
+ attachMediaController();
+ }
+
+ private void attachMediaController() {
+ if (mMediaPlayer != null && mMediaController != null) {
+ mMediaController.setMediaPlayer(this);
+ View anchorView = this.getParent() instanceof View ?
+ (View)this.getParent() : this;
+ mMediaController.setAnchorView(anchorView);
+ mMediaController.setEnabled(isInPlaybackState());
+ }
+ }
+
+ private boolean isHTTPStreaming(Uri mUri) {
+ if (mUri != null){
+ String scheme = mUri.toString();
+ if (scheme.startsWith("http://") || scheme.startsWith("https://")) {
+ if (scheme.endsWith(".m3u8") || scheme.endsWith(".m3u")
+ || scheme.contains("m3u8") || scheme.endsWith(".mpd")) {
+ // HLS or DASH streaming source
+ return false;
+ }
+ // HTTP streaming
+ return true;
+ }
+ }
+ return false;
+ }
+
+ MediaPlayer.OnVideoSizeChangedListener mSizeChangedListener =
+ new MediaPlayer.OnVideoSizeChangedListener() {
+ public void onVideoSizeChanged(MediaPlayer mp, int width, int height) {
+ mVideoWidth = mp.getVideoWidth();
+ mVideoHeight = mp.getVideoHeight();
+ if (mVideoWidth != 0 && mVideoHeight != 0) {
+ getHolder().setFixedSize(mVideoWidth, mVideoHeight);
+ requestLayout();
+ }
+ }
+ };
+
+ private MediaPlayer.OnCompletionListener mCompletionListener =
+ new MediaPlayer.OnCompletionListener() {
+ public void onCompletion(MediaPlayer mp) {
+ mCurrentState = STATE_PLAYBACK_COMPLETED;
+ mTargetState = STATE_PLAYBACK_COMPLETED;
+ if (mMediaController != null) {
+ mMediaController.hide();
+ }
+ if (mOnCompletionListener != null) {
+ mOnCompletionListener.onCompletion(mMediaPlayer);
+ }
+ }
+ };
+
+ private MediaPlayer.OnErrorListener mErrorListener;
+
+ private MediaPlayer.OnBufferingUpdateListener mBufferingUpdateListener =
+ new MediaPlayer.OnBufferingUpdateListener() {
+ public void onBufferingUpdate(MediaPlayer mp, int percent) {
+ mCurrentBufferPercentage = percent;
+ }
+ };
+
+ /**
+ * Register a callback to be invoked when the media file
+ * is loaded and ready to go.
+ *
+ * @param l The callback that will be run
+ */
+ public void setOnPreparedListener(MediaPlayer.OnPreparedListener l) {
+ mOnPreparedListener = l;
+ }
+
+ /**
+ * Register a callback to be invoked when the end of a media file
+ * has been reached during playback.
+ *
+ * @param l The callback that will be run
+ */
+ public void setOnCompletionListener(OnCompletionListener l) {
+ mOnCompletionListener = l;
+ }
+
+ /**
+ * Register a callback to be invoked when an error occurs
+ * during playback or setup. If no listener is specified,
+ * or if the listener returned false, VideoView will inform
+ * the user of any errors.
+ *
+ * @param l The callback that will be run
+ */
+ public void setOnErrorListener(OnErrorListener l) {
+ mOnErrorListener = l;
+ }
+
+ /**
+ * Register a callback to be invoked when an informational event
+ * occurs during playback or setup.
+ *
+ * @param l The callback that will be run
+ */
+ public void setOnInfoListener(OnInfoListener l) {
+ mOnInfoListener = l;
+ }
+
+ SurfaceHolder.Callback mSHCallback = new SurfaceHolder.Callback() {
+ public void surfaceChanged(SurfaceHolder holder, int format,
+ int w, int h) {
+ mSurfaceWidth = w;
+ mSurfaceHeight = h;
+ boolean isValidState = (mTargetState == STATE_PLAYING);
+ boolean hasValidSize = (mVideoWidth == w && mVideoHeight == h);
+ if (mMediaPlayer != null && isValidState && hasValidSize) {
+ if (mSeekWhenPrepared != 0) {
+ seekTo(mSeekWhenPrepared);
+ }
+ start();
+ }
+ }
+
+ public void surfaceCreated(SurfaceHolder holder) {
+ 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);
+ }
+ }
+ mSurfaceHolder = holder;
+ openVideo();
+ }
+
+ public void surfaceDestroyed(SurfaceHolder holder) {
+ // after we return from this we can't use the surface any more
+ mSurfaceHolder = null;
+ if (mMediaController != null) mMediaController.hide();
+ if (isHTTPStreaming(mUri) && mCurrentState == STATE_SUSPENDED) {
+ // Don't call release() while run suspend operation
+ return;
+ }
+ release(true);
+ }
+ };
+
+ /*
+ * release the media player in any state
+ */
+ private void release(boolean cleartargetstate) {
+ if (mMediaPlayer != null) {
+ mMediaPlayer.reset();
+ mMediaPlayer.release();
+ mMediaPlayer = null;
+ mCurrentState = STATE_IDLE;
+ if (cleartargetstate) {
+ mTargetState = STATE_IDLE;
+ }
+ }
+ }
+
+ @Override
+ public boolean onTouchEvent(MotionEvent ev) {
+ if (isInPlaybackState() && mMediaController != null) {
+ toggleMediaControlsVisiblity();
+ }
+ return false;
+ }
+
+ @Override
+ public boolean onTrackballEvent(MotionEvent ev) {
+ if (isInPlaybackState() && mMediaController != null) {
+ toggleMediaControlsVisiblity();
+ }
+ return false;
+ }
+
+ @Override
+ public boolean onKeyDown(int keyCode, 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);
+ }
+
+ private void toggleMediaControlsVisiblity() {
+ if (mMediaController.isShowing()) {
+ mMediaController.hide();
+ } else {
+ mMediaController.show();
+ }
+ }
+
+ public void setDialogShowState(boolean isDialogShow) {
+ mIsShowDialog = isDialogShow;
+ }
+
+ @Override
+ public void start() {
+ if (mIsShowDialog) return;
+ if (isInPlaybackState()) {
+ mMediaPlayer.start();
+ mCurrentState = STATE_PLAYING;
+ }
+ mTargetState = STATE_PLAYING;
+ }
+
+ @Override
+ public void pause() {
+ if (isInPlaybackState()) {
+ if (mMediaPlayer.isPlaying()) {
+ mMediaPlayer.pause();
+ mCurrentState = STATE_PAUSED;
+ }
+ }
+ mTargetState = STATE_PAUSED;
+ }
+
+ public void suspend() {
+ // HTTP streaming will call mMediaPlayer->suspend(), others will call release()
+ if (isHTTPStreaming(mUri) && mCurrentState != STATE_PREPARING) {
+ if (mMediaPlayer != null) {
+ if (mMediaPlayer.suspend()) {
+ mTargetState = mCurrentState;
+ mCurrentState = STATE_SUSPENDED;
+ return;
+ }
+ }
+ }
+ release(false);
+ }
+
+ public void resume() {
+ // 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;
+ }
+ }
+ openVideo();
+ }
+
+ @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;
+ }
+ // in case the duration is zero or smaller than zero for streaming
+ // video
+ int tempDuration = mMediaPlayer.getDuration();
+ if (tempDuration <= 0) {
+ return mDuration;
+ } else {
+ mDuration = tempDuration;
+ }
+
+ return mDuration;
+ }
+ return mDuration;
+ }
+
+ @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()) {
+ position = mMediaPlayer.getCurrentPosition();
+ }
+ if (LOG) {
+ Log.v(TAG, "getCurrentPosition() return " + position
+ + ", mSeekWhenPrepared=" + mSeekWhenPrepared);
+ }
+ return position;
+ }
+
+ @Override
+ public void seekTo(int msec) {
+ if (isInPlaybackState()) {
+ mMediaPlayer.seekTo(msec);
+ mSeekWhenPrepared = 0;
+ } else {
+ mSeekWhenPrepared = msec;
+ }
+ }
+
+ @Override
+ public boolean isPlaying() {
+ return isInPlaybackState() && mMediaPlayer.isPlaying();
+ }
+
+ @Override
+ public int getBufferPercentage() {
+ if (mMediaPlayer != null) {
+ return mCurrentBufferPercentage;
+ }
+ return 0;
+ }
+
+ private boolean isInPlaybackState() {
+ return (mMediaPlayer != null &&
+ mCurrentState != STATE_ERROR &&
+ mCurrentState != STATE_IDLE &&
+ mCurrentState != STATE_PREPARING &&
+ mCurrentState != STATE_SUSPENDED);
+ }
+
+ @Override
+ public boolean canPause() {
+ return mCanPause;
+ }
+
+ @Override
+ public boolean canSeekBackward() {
+ return mCanSeekBack;
+ }
+
+ @Override
+ public boolean canSeekForward() {
+ return mCanSeekForward;
+ }
+
+ public boolean canSeek() {
+ return mCanSeek;
+ }
+
+ @Override
+ public int getAudioSessionId() {
+ if (mAudioSession == 0) {
+ MediaPlayer foo = new MediaPlayer();
+ mAudioSession = foo.getAudioSessionId();
+ foo.release();
+ }
+ return mAudioSession;
+ }
+
+ // for duration displayed
+ public void setDuration(final int duration) {
+ if (LOG) {
+ Log.v(TAG, "setDuration(" + duration + ")");
+ }
+ mDuration = (duration > 0 ? -duration : duration);
+ }
+
+ public void setVideoURI(final Uri uri, final Map<String, String> headers,
+ final boolean hasGotMetaData) {
+ if (LOG) {
+ Log.v(TAG, "setVideoURI(" + uri + ", " + headers + ")");
+ }
+ // clear the flags
+ mHasGotMetaData = hasGotMetaData;
+ setVideoURI(uri, headers);
+ }
+
+ private void doPreparedIfReady(final MediaPlayer mp) {
+ if (LOG) {
+ Log.v(TAG, "doPreparedIfReady() mHasGotPreparedCallBack=" + mHasGotPreparedCallBack
+ + ", mHasGotMetaData=" + mHasGotMetaData + ", mNeedWaitLayout="
+ + mNeedWaitLayout
+ + ", mCurrentState=" + mCurrentState);
+ }
+ if (mHasGotPreparedCallBack && mHasGotMetaData && !mNeedWaitLayout) {
+ doPrepared(mp);
+ }
+ }
+
+ private void doPrepared(final MediaPlayer mp) {
+ if (LOG) {
+ Log.v(TAG, "doPrepared(" + mp + ") start");
+ }
+ mCurrentState = STATE_PREPARED;
+ if (mOnPreparedListener != null) {
+ mOnPreparedListener.onPrepared(mMediaPlayer);
+ }
+ mVideoWidth = mp.getVideoWidth();
+ mVideoHeight = mp.getVideoHeight();
+
+ // mSeekWhenPrepared may be changed after seekTo()
+ final int seekToPosition = mSeekWhenPrepared;
+ if (seekToPosition != 0) {
+ seekTo(seekToPosition);
+ }
+ if (mVideoWidth != 0 && mVideoHeight != 0) {
+ getHolder().setFixedSize(mVideoWidth, mVideoHeight);
+ }
+
+ if (mTargetState == STATE_PLAYING) {
+ start();
+ }
+ if (LOG) {
+ Log.v(TAG, "doPrepared() end video size: " + mVideoWidth + "," + mVideoHeight
+ + ", mTargetState=" + mTargetState + ", mCurrentState=" + mCurrentState);
+ }
+ }
+
+ /**
+ * 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) {
+ Log.v(TAG, "setResumed(" + resume + ") mUri=" + mUri + ", mOnResumed=" + mOnResumed);
+ }
+ mOnResumed = resume;
+ }
+
+ private void clearVideoInfo() {
+ if (LOG) {
+ Log.v(TAG, "clearVideoInfo()");
+ }
+ mHasGotPreparedCallBack = false;
+ mNeedWaitLayout = false;
+ }
+
+ public void clearSeek() {
+ if (LOG) {
+ Log.v(TAG, "clearSeek() mSeekWhenPrepared=" + mSeekWhenPrepared);
+ }
+ mSeekWhenPrepared = 0;
+ }
+
+ public void clearDuration() {
+ if (LOG) {
+ Log.v(TAG, "clearDuration() mDuration=" + mDuration);
+ }
+ mDuration = -1;
+ }
+
+ public boolean isTargetPlaying() {
+ if (LOG) {
+ Log.v(TAG, "isTargetPlaying() mTargetState=" + mTargetState);
+ }
+ 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/DmReceiver.java b/src/org/codeaurora/gallery3d/video/DmReceiver.java
new file mode 100644
index 000000000..616ce33d6
--- /dev/null
+++ b/src/org/codeaurora/gallery3d/video/DmReceiver.java
@@ -0,0 +1,65 @@
+package org.codeaurora.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.provider.Settings.System;
+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) {
+ if (mPref == null) {
+ mPref = PreferenceManager.getDefaultSharedPreferences(context);
+ }
+ if (BOOT_COMPLETED.equals(intent.getAction())) {
+ 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");
+ System.putString(context.getContentResolver(),
+ "streaming_max_udp_port", rtpMaxport);
+ System.putString(context.getContentResolver(),
+ "streaming_min_udp_port", rtpMinport);
+ System.putString(context.getContentResolver(), "apn", apn);
+ } else if (WRITE_SETTING_ACTION.equals(intent.getAction())) {
+ 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();
+ 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();
+ System.putString(context.getContentResolver(),
+ "streaming_min_udp_port", value);
+ } else if (valueType == STREAMING_CONNPROFILE_IO_HANDLER_TYPE) {
+ mPref.edit().putString(SettingsActivity.PREFERENCE_APN,
+ value).commit();
+ System.putString(context.getContentResolver(),
+ "apn", value);
+ }
+ }
+ }
+}
diff --git a/src/org/codeaurora/gallery3d/video/ExtensionHelper.java b/src/org/codeaurora/gallery3d/video/ExtensionHelper.java
new file mode 100755
index 000000000..b5156100b
--- /dev/null
+++ b/src/org/codeaurora/gallery3d/video/ExtensionHelper.java
@@ -0,0 +1,72 @@
+/*
+Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of The Linux Foundation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+package org.codeaurora.gallery3d.video;
+
+import android.content.Context;
+
+import com.android.gallery3d.app.MovieActivity;
+import com.android.gallery3d.R;
+
+import org.codeaurora.gallery3d.ext.ActivityHookerGroup;
+import org.codeaurora.gallery3d.ext.IActivityHooker;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class ExtensionHelper {
+
+ public static IActivityHooker getHooker(final Context context) {
+
+ final ActivityHookerGroup group = new ActivityHookerGroup();
+ 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);
+ boolean speaker = context.getResources().getBoolean(R.bool.speaker);
+
+ if (loop == true) {
+ group.addHooker(new LoopVideoHooker()); // add it for common feature.
+ }
+ if (stereo == true) {
+ group.addHooker(new StereoAudioHooker()); // add it for common feature.
+ }
+ if (streaming == true) {
+ group.addHooker(new StreamingHooker());
+ group.addHooker(new BookmarkHooker());
+ }
+ if (playlist == true) {
+ group.addHooker(new MovieListHooker()); // add it for common feature.
+ group.addHooker(new StepOptionSettingsHooker());
+ }
+ if (speaker == true) {
+ group.addHooker(new SpeakerHooker());
+ }
+ 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/LoopVideoHooker.java b/src/org/codeaurora/gallery3d/video/LoopVideoHooker.java
new file mode 100644
index 000000000..004254856
--- /dev/null
+++ b/src/org/codeaurora/gallery3d/video/LoopVideoHooker.java
@@ -0,0 +1,60 @@
+package org.codeaurora.gallery3d.video;
+
+import android.view.Menu;
+import android.view.MenuItem;
+
+import com.android.gallery3d.R;
+import org.codeaurora.gallery3d.ext.MovieUtils;
+
+public class LoopVideoHooker extends MovieHooker {
+
+ private static final String TAG = "LoopVideoHooker";
+ private static final boolean LOG = false;
+ private static final int MENU_LOOP = 1;
+
+ private MenuItem mMenuLoopButton;
+
+ @Override
+ public boolean onCreateOptionsMenu(final Menu menu) {
+ super.onCreateOptionsMenu(menu);
+ mMenuLoopButton = menu.add(0, getMenuActivityId(MENU_LOOP), 0, R.string.loop);
+ return true;
+ }
+
+ @Override
+ public boolean onPrepareOptionsMenu(final Menu menu) {
+ super.onPrepareOptionsMenu(menu);
+ updateLoop();
+ return true;
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(final MenuItem item) {
+ super.onOptionsItemSelected(item);
+ switch (getMenuOriginalId(item.getItemId())) {
+ case MENU_LOOP:
+ getPlayer().setLoop(!getPlayer().getLoop());
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ private void updateLoop() {
+ if (mMenuLoopButton != null) {
+ if (MovieUtils.isLocalFile(getMovieItem().getUri(), getMovieItem().getMimeType())) {
+ mMenuLoopButton.setVisible(true);
+ } else {
+ mMenuLoopButton.setVisible(false);
+ }
+ final boolean newLoop = getPlayer().getLoop();
+ if (newLoop) {
+ mMenuLoopButton.setTitle(R.string.single);
+ mMenuLoopButton.setIcon(R.drawable.ic_menu_unloop);
+ } else {
+ mMenuLoopButton.setTitle(R.string.loop);
+ mMenuLoopButton.setIcon(R.drawable.ic_menu_loop);
+ }
+ }
+ }
+}
diff --git a/src/org/codeaurora/gallery3d/video/MovieHooker.java b/src/org/codeaurora/gallery3d/video/MovieHooker.java
new file mode 100644
index 000000000..a859d44a3
--- /dev/null
+++ b/src/org/codeaurora/gallery3d/video/MovieHooker.java
@@ -0,0 +1,44 @@
+package org.codeaurora.gallery3d.video;
+
+import android.util.Log;
+
+import org.codeaurora.gallery3d.ext.ActivityHooker;
+import org.codeaurora.gallery3d.ext.IMovieItem;
+import org.codeaurora.gallery3d.ext.IMoviePlayer;
+
+public class MovieHooker extends ActivityHooker {
+
+ private static final String TAG = "MovieHooker";
+ private static final boolean LOG = false;
+ private IMovieItem mMovieItem;
+ private IMoviePlayer mPlayer;
+
+ @Override
+ public void setParameter(final String key, final Object value) {
+ super.setParameter(key, value);
+ if (LOG) {
+ Log.v(TAG, "setParameter(" + key + ", " + value + ")");
+ }
+ if (value instanceof IMovieItem) {
+ mMovieItem = (IMovieItem) value;
+ onMovieItemChanged(mMovieItem);
+ } else if (value instanceof IMoviePlayer) {
+ mPlayer = (IMoviePlayer) value;
+ onMoviePlayerChanged(mPlayer);
+ }
+ }
+
+ public IMovieItem getMovieItem() {
+ return mMovieItem;
+ }
+
+ public IMoviePlayer getPlayer() {
+ return mPlayer;
+ }
+
+ public void onMovieItemChanged(final IMovieItem item) {
+ }
+
+ public void onMoviePlayerChanged(final IMoviePlayer player) {
+ }
+}
diff --git a/src/org/codeaurora/gallery3d/video/MovieListHooker.java b/src/org/codeaurora/gallery3d/video/MovieListHooker.java
new file mode 100644
index 000000000..ee360ac78
--- /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 = false;
+
+ 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/MovieTitleHelper.java b/src/org/codeaurora/gallery3d/video/MovieTitleHelper.java
new file mode 100644
index 000000000..4f23e81b8
--- /dev/null
+++ b/src/org/codeaurora/gallery3d/video/MovieTitleHelper.java
@@ -0,0 +1,108 @@
+package org.codeaurora.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 android.util.Log;
+
+
+import java.io.File;
+
+public class MovieTitleHelper {
+ private static final String TAG = "MovieTitleHelper";
+ private static final boolean LOG = false;
+
+ 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) {
+ Log.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) {
+ Log.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) {
+ Log.v(TAG, "getTitleFromDisplayName() return " + title);
+ }
+ return title;
+ }
+
+ public static String getTitleFromUri(final Uri uri) {
+ final String title = Uri.decode(uri.getLastPathSegment());
+ if (LOG) {
+ Log.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) {
+ Log.v(TAG, "getTitleFromData() return " + title);
+ }
+ return title;
+ }
+}
diff --git a/src/org/codeaurora/gallery3d/video/ScreenModeManager.java b/src/org/codeaurora/gallery3d/video/ScreenModeManager.java
new file mode 100644
index 000000000..a1c04c69f
--- /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 = false;
+ //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
new file mode 100755
index 000000000..3d7fac573
--- /dev/null
+++ b/src/org/codeaurora/gallery3d/video/SettingsActivity.java
@@ -0,0 +1,308 @@
+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;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.SystemProperties;
+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.ContactsContract;
+import android.provider.Settings;
+import android.provider.Settings.System;
+import android.provider.Telephony;
+import android.telephony.TelephonyManager;
+import android.text.method.DigitsKeyListener;
+import android.util.Log;
+import android.view.KeyEvent;
+import android.view.MenuItem;
+import com.android.gallery3d.R;
+
+import java.util.ArrayList;
+
+public class SettingsActivity extends PreferenceActivity {
+
+ 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 mBufferSize;
+ 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 static final String RTP_PORTS_PROPERTY_NAME = "persist.env.media.rtp-ports";
+ private static final String CACHE_PROPERTY_NAME = "persist.env.media.cache-params";
+
+ private boolean mUseNvOperatorForEhrpd = SystemProperties.getBoolean(
+ "persist.radio.use_nv_for_ehrpd", false);
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ addPreferencesFromResource(R.xml.rtsp_settings_preferences);
+
+ mPref = getPreferenceScreen().getSharedPreferences();
+ mRtpMinPort = (EditTextPreference) findPreference(PREFERENCE_RTP_MINPORT);
+ mRtpMaxPort = (EditTextPreference) findPreference(PREFERENCE_RTP_MAXPORT);
+ mBufferSize = (EditTextPreference) findPreference(PREFERENCE_BUFFER_SIZE);
+ mApn = (PreferenceScreen) findPreference(PREFERENCE_APN);
+
+ 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 getApnKey() {
+ // to find default key
+ String key = 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(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 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"));
+ if (curKey.equals(key)) {
+ Log.d("rtsp", "getDefaultApnName, find, key=" + curKey + ",curName=" + curName);
+ name = curName;
+ break;
+ }
+ }
+
+ if (cursor != null) {
+ cursor.close();
+ }
+ return name;
+
+ }
+
+ private String getDefaultApnName() {
+ return getApnName(getApnKey());
+ }
+
+ 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) {
+ if (requestCode == SELECT_APN) {
+ setResult(resultCode);
+ finish();
+ Log.w(LOG_TAG, "onActivityResult requestCode = " + requestCode);
+ }
+
+ }
+
+ @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(LOG_TAG, "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]);
+ }
+
+ 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));
+ // System property format: "rtpMinPort/rtpMaxPort"
+ final String propertyValue = rtpMinPortStr + "/" + rtpMaxPortStr;
+ Log.v(LOG_TAG, "set system property " + RTP_PORTS_PROPERTY_NAME + " : " + propertyValue);
+ SystemProperties.set(RTP_PORTS_PROPERTY_NAME, propertyValue);
+ }
+
+ private void enableBufferSetting() {
+ final String bufferSizeStr = mPref.getString(PREFERENCE_BUFFER_SIZE,
+ Integer.toString(DEFAULT_CACHE_MAX_SIZE));
+ final int cacheMaxSize;
+ final String ACTION_NAME = "org.codeaurora.gallery3d.video.STREAMING_SETTINGS_ENABLER";
+ try {
+ cacheMaxSize = Integer.valueOf(bufferSizeStr);
+ } catch (NumberFormatException e) {
+ Log.e(LOG_TAG, "Failed to parse cache max size");
+ return;
+ }
+ // System property format: "minCacheSizeKB/maxCacheSizeKB/keepAliveIntervalSeconds"
+ final String propertyValue = (DEFAULT_CACHE_MIN_SIZE / 1024) + "/" +
+ (cacheMaxSize / 1024) + "/" + DEFAULT_KEEP_ALIVE_INTERVAL_SECOND;
+ Log.v(LOG_TAG, "set system property " + CACHE_PROPERTY_NAME + " : " + propertyValue);
+ SystemProperties.set(CACHE_PROPERTY_NAME, propertyValue);
+ }
+
+ 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 SUBSCRIPTION_KEY = "subscription";
+ mApn.setSummary(getDefaultApnName());
+ mApn.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
+ public boolean onPreferenceClick(Preference preference) {
+ Intent intent = new Intent(Settings.ACTION_APN_SETTINGS);
+ int subscription = 0;
+ try {
+ subscription = Settings.Global.getInt(SettingsActivity.this.getContentResolver(),
+ Settings.Global.MULTI_SIM_DATA_CALL_SUBSCRIPTION);
+ } catch (Exception e) {
+ Log.d("SettingActivity", "Can't get subscription for Exception: " + e);
+ } finally {
+ intent.putExtra(SUBSCRIPTION_KEY, subscription);
+ }
+ startActivityForResult(intent, SELECT_APN);
+ return true;
+ }
+ });
+ }
+}
diff --git a/src/org/codeaurora/gallery3d/video/SpeakerHooker.java b/src/org/codeaurora/gallery3d/video/SpeakerHooker.java
new file mode 100644
index 000000000..9bf534872
--- /dev/null
+++ b/src/org/codeaurora/gallery3d/video/SpeakerHooker.java
@@ -0,0 +1,210 @@
+/*
+Copyright (c) 2014, The Linux Foundation. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of The Linux Foundation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+package org.codeaurora.gallery3d.video;
+
+import android.view.Menu;
+import android.view.MenuItem;
+import android.widget.Toast;
+
+import android.bluetooth.BluetoothClass;
+import android.bluetooth.BluetoothDevice;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.media.AudioManager;
+import android.media.AudioSystem;
+import android.os.Bundle;
+
+import com.android.gallery3d.R;
+
+public class SpeakerHooker extends MovieHooker {
+
+ private static final int MENU_SPEAKER = 1;
+
+ private AudioManager mAudioManager;
+
+ private MenuItem mMenuSpeakerButton;
+
+ private boolean mIsHeadsetOn = false;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ initAudioManager();
+ }
+
+ private void initAudioManager() {
+ if (mAudioManager == null) {
+ mAudioManager = (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE);
+ }
+ }
+
+ @Override
+ public void onDestroy() {
+ turnSpeakerOff();
+ super.onDestroy();
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ registerHeadSetReceiver();
+ }
+
+ private void registerHeadSetReceiver() {
+ final IntentFilter intentFilter = new IntentFilter(Intent.ACTION_HEADSET_PLUG);
+ intentFilter.addAction(BluetoothDevice.ACTION_ACL_CONNECTED);
+ intentFilter.addAction(BluetoothDevice.ACTION_ACL_DISCONNECTED);
+ intentFilter.addAction(AudioManager.ACTION_AUDIO_BECOMING_NOISY);
+ getContext().registerReceiver(mHeadSetReceiver, intentFilter);
+ }
+
+ @Override
+ public void onPause() {
+ unregisterHeadSetReceiver();
+ super.onPause();
+ }
+
+ private void unregisterHeadSetReceiver() {
+ try {
+ getContext().unregisterReceiver(mHeadSetReceiver);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ private final BroadcastReceiver mHeadSetReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ final String action = intent.getAction();
+ if (mAudioManager == null) {
+ initAudioManager();
+ }
+ if (action.equals(Intent.ACTION_HEADSET_PLUG)) {
+ mIsHeadsetOn = (intent.getIntExtra("state", 0) == 1)
+ || mAudioManager.isBluetoothA2dpOn();
+ } else if (action.equals(BluetoothDevice.ACTION_ACL_CONNECTED)
+ || action.equals(BluetoothDevice.ACTION_ACL_DISCONNECTED)) {
+ final int deviceClass = ((BluetoothDevice)
+ intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE))
+ .getBluetoothClass().getDeviceClass();
+ if ((deviceClass == BluetoothClass.Device.AUDIO_VIDEO_HEADPHONES)
+ || (deviceClass == BluetoothClass.Device.AUDIO_VIDEO_WEARABLE_HEADSET)) {
+ mIsHeadsetOn = action.equals(BluetoothDevice.ACTION_ACL_CONNECTED)
+ || mAudioManager.isWiredHeadsetOn();
+ }
+ } else if (action.equals(AudioManager.ACTION_AUDIO_BECOMING_NOISY)) {
+ mIsHeadsetOn = false;
+ }
+ updateSpeakerButton();
+ if (!mIsHeadsetOn) {
+ turnSpeakerOff();
+ }
+ }
+ };
+
+ @Override
+ public boolean onCreateOptionsMenu(Menu menu) {
+ super.onCreateOptionsMenu(menu);
+ mMenuSpeakerButton = menu.add(0, getMenuActivityId(MENU_SPEAKER), 0, R.string.speaker_on);
+ return true;
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ super.onOptionsItemSelected(item);
+ switch (getMenuOriginalId(item.getItemId())) {
+ case MENU_SPEAKER:
+ changeSpeakerState();
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ private void changeSpeakerState() {
+ if (isSpeakerOn()) {
+ turnSpeakerOff();
+ } else {
+ if (mIsHeadsetOn) {
+ turnSpeakerOn();
+ } else {
+ Toast.makeText(getContext(), getContext().getString(R.string.speaker_need_headset),
+ Toast.LENGTH_SHORT).show();
+ }
+ }
+ updateSpeakerButton();
+ }
+
+ private void turnSpeakerOn() {
+ if (mAudioManager == null) {
+ initAudioManager();
+ }
+ mAudioManager.setSpeakerphoneOn(true);
+ AudioSystem.setForceUse(AudioSystem.FOR_MEDIA,
+ AudioSystem.FORCE_SPEAKER);
+ }
+
+ private void turnSpeakerOff() {
+ if (mAudioManager == null) {
+ initAudioManager();
+ }
+ AudioSystem.setForceUse(AudioSystem.FOR_MEDIA,
+ AudioSystem.FORCE_NONE);
+ mAudioManager.setSpeakerphoneOn(false);
+ }
+
+ @Override
+ public boolean onPrepareOptionsMenu(Menu menu) {
+ super.onPrepareOptionsMenu(menu);
+ updateSpeakerButton();
+ return true;
+ }
+
+ private void updateSpeakerButton() {
+ if (mMenuSpeakerButton != null) {
+ if (isSpeakerOn()) {
+ mMenuSpeakerButton.setTitle(R.string.speaker_off);
+ } else {
+ mMenuSpeakerButton.setTitle(R.string.speaker_on);
+ }
+ }
+ }
+
+ private boolean isSpeakerOn() {
+ boolean isSpeakerOn = false;
+ if (mAudioManager == null) {
+ initAudioManager();
+ }
+ isSpeakerOn = mAudioManager.isSpeakerphoneOn();
+ return isSpeakerOn;
+ }
+
+}
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
new file mode 100755
index 000000000..cbf2f357a
--- /dev/null
+++ b/src/org/codeaurora/gallery3d/video/StereoAudioHooker.java
@@ -0,0 +1,118 @@
+package org.codeaurora.gallery3d.video;
+
+import android.content.Context;
+import android.media.AudioManager;
+import android.util.Log;
+import android.view.Menu;
+import android.view.MenuItem;
+
+import com.android.gallery3d.R;
+
+public class StereoAudioHooker extends MovieHooker {
+ private static final String TAG = "StereoAudioHooker";
+ private static final boolean LOG = false;
+
+ private static final int MENU_STEREO_AUDIO = 1;
+ private MenuItem mMenuStereoAudio;
+
+ private static final String KEY_STEREO = "EnableStereoOutput";
+ private boolean mSystemStereoAudio;
+ private boolean mCurrentStereoAudio;
+ private boolean mIsInitedStereoAudio;
+ private AudioManager mAudioManager;
+
+ @Override
+ public void onStart() {
+ super.onStart();
+ enableStereoAudio();
+ }
+
+ @Override
+ public void onStop() {
+ super.onStop();
+ restoreStereoAudio();
+ }
+
+ @Override
+ public boolean onCreateOptionsMenu(final Menu menu) {
+ super.onCreateOptionsMenu(menu);
+ mMenuStereoAudio = menu.add(0, getMenuActivityId(MENU_STEREO_AUDIO), 0,
+ R.string.single_track);
+ return true;
+ }
+
+ @Override
+ public boolean onPrepareOptionsMenu(final Menu menu) {
+ super.onPrepareOptionsMenu(menu);
+ updateStereoAudioIcon();
+ return true;
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(final MenuItem item) {
+ super.onOptionsItemSelected(item);
+ if(getMenuOriginalId(item.getItemId()) == MENU_STEREO_AUDIO) {
+ mCurrentStereoAudio = !mCurrentStereoAudio;
+ setStereoAudio(mCurrentStereoAudio);
+ return true;
+ }
+ return false;
+ }
+
+ private boolean getStereoAudio() {
+ boolean isstereo = false;
+ if (mAudioManager == null) {
+ mAudioManager = (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE);
+ }
+ final String stereo = mAudioManager.getParameters(KEY_STEREO);
+ final String key = KEY_STEREO + "=1";
+ if (stereo != null && stereo.indexOf(key) > -1) {
+ isstereo = true;
+ } else {
+ isstereo = false;
+ }
+ if (LOG) {
+ Log.v(TAG, "getStereoAudio() isstereo=" + isstereo + ", stereo=" + stereo
+ + ", key=" + key);
+ }
+ return isstereo;
+ }
+
+ private void setStereoAudio(final boolean flag) {
+ final String value = KEY_STEREO + "=" + (flag ? "1" : "0");
+ if (mAudioManager == null) {
+ mAudioManager = (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE);
+ }
+ mAudioManager.setParameters(value);
+ if (LOG) {
+ Log.v(TAG, "setStereoAudio(" + flag + ") value=" + value);
+ }
+ }
+
+ private void updateStereoAudioIcon() {
+ if (mMenuStereoAudio != null) {
+ mMenuStereoAudio.setTitle(mCurrentStereoAudio?R.string.single_track:R.string.stereo);
+ mMenuStereoAudio.setIcon(mCurrentStereoAudio?R.drawable.ic_menu_single_track:R.drawable.ic_menu_stereo);
+ }
+ }
+
+ private void enableStereoAudio() {
+ if (LOG) {
+ Log.v(TAG, "enableStereoAudio() mIsInitedStereoAudio=" + mIsInitedStereoAudio
+ + ", mCurrentStereoAudio=" + mCurrentStereoAudio);
+ }
+ mSystemStereoAudio = getStereoAudio();
+ if (!mIsInitedStereoAudio) {
+ mCurrentStereoAudio = mSystemStereoAudio;
+ mIsInitedStereoAudio = true;
+ } else {
+ // restore old stereo type
+ setStereoAudio(mCurrentStereoAudio);
+ }
+ updateStereoAudioIcon();
+ }
+
+ private void restoreStereoAudio() {
+ setStereoAudio(mSystemStereoAudio);
+ }
+}
diff --git a/src/org/codeaurora/gallery3d/video/StreamingHooker.java b/src/org/codeaurora/gallery3d/video/StreamingHooker.java
new file mode 100755
index 000000000..55735f44c
--- /dev/null
+++ b/src/org/codeaurora/gallery3d/video/StreamingHooker.java
@@ -0,0 +1,86 @@
+package org.codeaurora.gallery3d.video;
+
+import android.content.ActivityNotFoundException;
+import android.content.Intent;
+import android.net.Uri;
+import android.provider.Browser;
+import android.util.Log;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.widget.Toast;
+
+import com.android.gallery3d.R;
+import org.codeaurora.gallery3d.ext.MovieUtils;
+
+public class StreamingHooker extends MovieHooker {
+ private static final String TAG = "StreamingHooker";
+ private static final boolean LOG = false;
+
+ private static final String ACTION_STREAMING = "org.codeaurora.settings.streaming";
+ private static final int MENU_INPUT_URL = 1;
+ private static final int MENU_SETTINGS = 2;
+ private static final int MENU_DETAIL = 3;
+
+ 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.
+ 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);
+ 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;
+ default:
+ return false;
+ }
+ }
+
+ private void gotoInputUrl() {
+ 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(URI_STR));
+ intent.putExtra(EXTRA_NAME, true);
+ intent.putExtra(Browser.EXTRA_APPLICATION_ID, APN_NAME);
+
+ try {
+ getContext().startActivity(intent);
+ } catch (ActivityNotFoundException e) {
+ Toast.makeText(getContext(),
+ R.string.fail_to_load, Toast.LENGTH_LONG).show();
+ }
+
+ if (LOG) {
+ Log.v(TAG, "gotoInputUrl() appName=" + APN_NAME);
+ }
+ }
+
+ private void gotoSettings() {
+ final Intent intent = new Intent(ACTION_STREAMING);
+ 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;
+ }
+}