From fa0984d6584bd0c82bbf70fd4d25315ad3479761 Mon Sep 17 00:00:00 2001 From: Likai Ding Date: Tue, 20 Aug 2013 16:21:57 +0800 Subject: Gallery2: add some video features including: previous/next video play mode, screen mode, fast forward/rewind button, step settings. Change-Id: I3f4890c4dd95956e0eca889a5fd8b8d83b8d542e --- AndroidManifest.xml | 6 +- res/drawable-hdpi/ic_media_bigscreen.png | Bin res/drawable-hdpi/ic_media_cropscreen.png | Bin res/drawable-hdpi/ic_media_fullscreen.png | Bin res/drawable-hdpi/ic_menu_disabled_forward.png | Bin res/drawable-hdpi/ic_menu_disabled_rewind.png | Bin res/drawable-hdpi/ic_menu_disabled_stop.png | Bin res/drawable-hdpi/ic_menu_forward.png | Bin res/drawable-hdpi/ic_menu_rewind.png | Bin res/drawable-hdpi/ic_menu_stop.png | Bin res/drawable-hdpi/ic_separator_line.png | Bin res/drawable-hdpi/ic_vidcontrol_disable_pause.png | Bin res/drawable-hdpi/ic_vidcontrol_disable_play.png | Bin res/drawable-hdpi/ic_vidcontrol_disable_reload.png | Bin res/drawable-hdpi/media_default_bkg.9.png | Bin res/drawable-mdpi/ic_media_bigscreen.png | Bin res/drawable-mdpi/ic_media_cropscreen.png | Bin res/drawable-mdpi/ic_media_fullscreen.png | Bin res/drawable-mdpi/ic_menu_disabled_forward.png | Bin res/drawable-mdpi/ic_menu_disabled_rewind.png | Bin res/drawable-mdpi/ic_menu_disabled_stop.png | Bin res/drawable-mdpi/ic_menu_forward.png | Bin res/drawable-mdpi/ic_menu_rewind.png | Bin res/drawable-mdpi/ic_menu_stop.png | Bin res/drawable-mdpi/ic_vidcontrol_disable_pause.png | Bin res/drawable-mdpi/ic_vidcontrol_disable_play.png | Bin res/drawable-mdpi/ic_vidcontrol_disable_reload.png | Bin res/drawable-mdpi/media_default_bkg.9.png | Bin .../ic_vidcontrol_disable_pause.png | Bin .../ic_vidcontrol_disable_play.png | Bin .../ic_vidcontrol_disable_reload.png | Bin res/drawable-xhdpi/ic_media_bigscreen.png | Bin res/drawable-xhdpi/ic_media_cropscreen.png | Bin res/drawable-xhdpi/ic_media_fullscreen.png | Bin res/drawable-xhdpi/ic_menu_disabled_forward.png | Bin res/drawable-xhdpi/ic_menu_disabled_rewind.png | Bin res/drawable-xhdpi/ic_menu_disabled_stop.png | Bin res/drawable-xhdpi/ic_menu_forward.png | Bin res/drawable-xhdpi/ic_menu_rewind.png | Bin res/drawable-xhdpi/ic_menu_stop.png | Bin res/drawable-xhdpi/ic_vidcontrol_disable_pause.png | Bin res/drawable-xhdpi/ic_vidcontrol_disable_play.png | Bin .../ic_vidcontrol_disable_reload.png | Bin res/drawable/icn_media_forward.xml | 0 res/drawable/icn_media_rewind.xml | 0 res/drawable/icn_media_stop.xml | 0 res/drawable/videoplayer_pause.xml | 0 res/drawable/videoplayer_play.xml | 0 res/drawable/videoplayer_reload.xml | 0 res/layout/setting_list.xml | 0 res/values-zh-rCN/codeaurora_strings.xml | 19 +- res/values-zh-rTW/codeaurora_strings.xml | 19 +- res/values/bool.xml | 2 + res/values/codeaurora_strings.xml | 19 +- res/xml/rtsp_settings_preferences.xml | 22 +- .../gallery3d/app/CommonControllerOverlay.java | 16 +- .../android/gallery3d/app/ControllerOverlay.java | 6 + src/com/android/gallery3d/app/MovieActivity.java | 93 ++- .../gallery3d/app/MovieControllerOverlay.java | 796 ++++++++++++++++++++- src/com/android/gallery3d/app/MoviePlayer.java | 323 ++++++++- src/com/android/gallery3d/app/TimeBar.java | 308 +++++++- .../gallery3d/app/TrimControllerOverlay.java | 10 + .../qcom/gallery3d/ext/IContrllerOverlayExt.java | 51 -- src/com/qcom/gallery3d/ext/IMovieList.java | 46 -- src/com/qcom/gallery3d/ext/IMovieListLoader.java | 50 -- src/com/qcom/gallery3d/ext/MovieList.java | 70 -- src/com/qcom/gallery3d/ext/MovieListLoader.java | 201 ------ .../video/IControllerRewindAndForward.java | 35 - src/com/qcom/gallery3d/video/MovieListHooker.java | 116 --- .../qcom/gallery3d/video/ScreenModeManager.java | 117 --- .../gallery3d/video/StepOptionDialogFragment.java | 83 --- .../gallery3d/video/StepOptionSettingsHooker.java | 41 -- .../gallery3d/video/VideoSettingsActivity.java | 182 ----- .../gallery3d/ext/IContrllerOverlayExt.java | 51 ++ src/org/codeaurora/gallery3d/ext/IMovieList.java | 46 ++ .../codeaurora/gallery3d/ext/IMovieListLoader.java | 50 ++ src/org/codeaurora/gallery3d/ext/IMoviePlayer.java | 7 + src/org/codeaurora/gallery3d/ext/MovieList.java | 72 ++ .../codeaurora/gallery3d/ext/MovieListLoader.java | 203 ++++++ .../gallery3d/video/CodeauroraVideoView.java | 254 +++---- .../gallery3d/video/ExtensionHelper.java | 5 + .../video/IControllerRewindAndForward.java | 35 + .../gallery3d/video/MovieListHooker.java | 116 +++ .../gallery3d/video/ScreenModeManager.java | 117 +++ .../gallery3d/video/SettingsActivity.java | 271 ++++--- .../gallery3d/video/StepOptionDialogFragment.java | 83 +++ .../gallery3d/video/StepOptionSettingsHooker.java | 41 ++ .../gallery3d/video/StereoAudioHooker.java | 21 +- .../gallery3d/video/StreamingHooker.java | 17 +- .../gallery3d/video/VideoSettingsActivity.java | 182 +++++ 90 files changed, 2813 insertions(+), 1389 deletions(-) mode change 100755 => 100644 res/drawable-hdpi/ic_media_bigscreen.png mode change 100755 => 100644 res/drawable-hdpi/ic_media_cropscreen.png mode change 100755 => 100644 res/drawable-hdpi/ic_media_fullscreen.png mode change 100755 => 100644 res/drawable-hdpi/ic_menu_disabled_forward.png mode change 100755 => 100644 res/drawable-hdpi/ic_menu_disabled_rewind.png mode change 100755 => 100644 res/drawable-hdpi/ic_menu_disabled_stop.png mode change 100755 => 100644 res/drawable-hdpi/ic_menu_forward.png mode change 100755 => 100644 res/drawable-hdpi/ic_menu_rewind.png mode change 100755 => 100644 res/drawable-hdpi/ic_menu_stop.png mode change 100755 => 100644 res/drawable-hdpi/ic_separator_line.png mode change 100755 => 100644 res/drawable-hdpi/ic_vidcontrol_disable_pause.png mode change 100755 => 100644 res/drawable-hdpi/ic_vidcontrol_disable_play.png mode change 100755 => 100644 res/drawable-hdpi/ic_vidcontrol_disable_reload.png mode change 100755 => 100644 res/drawable-hdpi/media_default_bkg.9.png mode change 100755 => 100644 res/drawable-mdpi/ic_media_bigscreen.png mode change 100755 => 100644 res/drawable-mdpi/ic_media_cropscreen.png mode change 100755 => 100644 res/drawable-mdpi/ic_media_fullscreen.png mode change 100755 => 100644 res/drawable-mdpi/ic_menu_disabled_forward.png mode change 100755 => 100644 res/drawable-mdpi/ic_menu_disabled_rewind.png mode change 100755 => 100644 res/drawable-mdpi/ic_menu_disabled_stop.png mode change 100755 => 100644 res/drawable-mdpi/ic_menu_forward.png mode change 100755 => 100644 res/drawable-mdpi/ic_menu_rewind.png mode change 100755 => 100644 res/drawable-mdpi/ic_menu_stop.png mode change 100755 => 100644 res/drawable-mdpi/ic_vidcontrol_disable_pause.png mode change 100755 => 100644 res/drawable-mdpi/ic_vidcontrol_disable_play.png mode change 100755 => 100644 res/drawable-mdpi/ic_vidcontrol_disable_reload.png mode change 100755 => 100644 res/drawable-mdpi/media_default_bkg.9.png mode change 100755 => 100644 res/drawable-sw600dp/ic_vidcontrol_disable_pause.png mode change 100755 => 100644 res/drawable-sw600dp/ic_vidcontrol_disable_play.png mode change 100755 => 100644 res/drawable-sw600dp/ic_vidcontrol_disable_reload.png mode change 100755 => 100644 res/drawable-xhdpi/ic_media_bigscreen.png mode change 100755 => 100644 res/drawable-xhdpi/ic_media_cropscreen.png mode change 100755 => 100644 res/drawable-xhdpi/ic_media_fullscreen.png mode change 100755 => 100644 res/drawable-xhdpi/ic_menu_disabled_forward.png mode change 100755 => 100644 res/drawable-xhdpi/ic_menu_disabled_rewind.png mode change 100755 => 100644 res/drawable-xhdpi/ic_menu_disabled_stop.png mode change 100755 => 100644 res/drawable-xhdpi/ic_menu_forward.png mode change 100755 => 100644 res/drawable-xhdpi/ic_menu_rewind.png mode change 100755 => 100644 res/drawable-xhdpi/ic_menu_stop.png mode change 100755 => 100644 res/drawable-xhdpi/ic_vidcontrol_disable_pause.png mode change 100755 => 100644 res/drawable-xhdpi/ic_vidcontrol_disable_play.png mode change 100755 => 100644 res/drawable-xhdpi/ic_vidcontrol_disable_reload.png mode change 100755 => 100644 res/drawable/icn_media_forward.xml mode change 100755 => 100644 res/drawable/icn_media_rewind.xml mode change 100755 => 100644 res/drawable/icn_media_stop.xml mode change 100755 => 100644 res/drawable/videoplayer_pause.xml mode change 100755 => 100644 res/drawable/videoplayer_play.xml mode change 100755 => 100644 res/drawable/videoplayer_reload.xml mode change 100755 => 100644 res/layout/setting_list.xml mode change 100644 => 100755 src/com/android/gallery3d/app/TimeBar.java delete mode 100755 src/com/qcom/gallery3d/ext/IContrllerOverlayExt.java delete mode 100755 src/com/qcom/gallery3d/ext/IMovieList.java delete mode 100755 src/com/qcom/gallery3d/ext/IMovieListLoader.java delete mode 100755 src/com/qcom/gallery3d/ext/MovieList.java delete mode 100755 src/com/qcom/gallery3d/ext/MovieListLoader.java delete mode 100755 src/com/qcom/gallery3d/video/IControllerRewindAndForward.java delete mode 100755 src/com/qcom/gallery3d/video/MovieListHooker.java delete mode 100755 src/com/qcom/gallery3d/video/ScreenModeManager.java delete mode 100755 src/com/qcom/gallery3d/video/StepOptionDialogFragment.java delete mode 100755 src/com/qcom/gallery3d/video/StepOptionSettingsHooker.java delete mode 100755 src/com/qcom/gallery3d/video/VideoSettingsActivity.java create mode 100644 src/org/codeaurora/gallery3d/ext/IContrllerOverlayExt.java create mode 100644 src/org/codeaurora/gallery3d/ext/IMovieList.java create mode 100644 src/org/codeaurora/gallery3d/ext/IMovieListLoader.java create mode 100644 src/org/codeaurora/gallery3d/ext/MovieList.java create mode 100644 src/org/codeaurora/gallery3d/ext/MovieListLoader.java create mode 100644 src/org/codeaurora/gallery3d/video/IControllerRewindAndForward.java create mode 100644 src/org/codeaurora/gallery3d/video/MovieListHooker.java create mode 100644 src/org/codeaurora/gallery3d/video/ScreenModeManager.java mode change 100644 => 100755 src/org/codeaurora/gallery3d/video/SettingsActivity.java create mode 100644 src/org/codeaurora/gallery3d/video/StepOptionDialogFragment.java create mode 100644 src/org/codeaurora/gallery3d/video/StepOptionSettingsHooker.java mode change 100644 => 100755 src/org/codeaurora/gallery3d/video/StereoAudioHooker.java mode change 100644 => 100755 src/org/codeaurora/gallery3d/video/StreamingHooker.java create mode 100644 src/org/codeaurora/gallery3d/video/VideoSettingsActivity.java diff --git a/AndroidManifest.xml b/AndroidManifest.xml index 5d44f902a..4e8a351c3 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -66,6 +66,7 @@ + @@ -412,6 +413,9 @@ - + + diff --git a/res/drawable-hdpi/ic_media_bigscreen.png b/res/drawable-hdpi/ic_media_bigscreen.png old mode 100755 new mode 100644 diff --git a/res/drawable-hdpi/ic_media_cropscreen.png b/res/drawable-hdpi/ic_media_cropscreen.png old mode 100755 new mode 100644 diff --git a/res/drawable-hdpi/ic_media_fullscreen.png b/res/drawable-hdpi/ic_media_fullscreen.png old mode 100755 new mode 100644 diff --git a/res/drawable-hdpi/ic_menu_disabled_forward.png b/res/drawable-hdpi/ic_menu_disabled_forward.png old mode 100755 new mode 100644 diff --git a/res/drawable-hdpi/ic_menu_disabled_rewind.png b/res/drawable-hdpi/ic_menu_disabled_rewind.png old mode 100755 new mode 100644 diff --git a/res/drawable-hdpi/ic_menu_disabled_stop.png b/res/drawable-hdpi/ic_menu_disabled_stop.png old mode 100755 new mode 100644 diff --git a/res/drawable-hdpi/ic_menu_forward.png b/res/drawable-hdpi/ic_menu_forward.png old mode 100755 new mode 100644 diff --git a/res/drawable-hdpi/ic_menu_rewind.png b/res/drawable-hdpi/ic_menu_rewind.png old mode 100755 new mode 100644 diff --git a/res/drawable-hdpi/ic_menu_stop.png b/res/drawable-hdpi/ic_menu_stop.png old mode 100755 new mode 100644 diff --git a/res/drawable-hdpi/ic_separator_line.png b/res/drawable-hdpi/ic_separator_line.png old mode 100755 new mode 100644 diff --git a/res/drawable-hdpi/ic_vidcontrol_disable_pause.png b/res/drawable-hdpi/ic_vidcontrol_disable_pause.png old mode 100755 new mode 100644 diff --git a/res/drawable-hdpi/ic_vidcontrol_disable_play.png b/res/drawable-hdpi/ic_vidcontrol_disable_play.png old mode 100755 new mode 100644 diff --git a/res/drawable-hdpi/ic_vidcontrol_disable_reload.png b/res/drawable-hdpi/ic_vidcontrol_disable_reload.png old mode 100755 new mode 100644 diff --git a/res/drawable-hdpi/media_default_bkg.9.png b/res/drawable-hdpi/media_default_bkg.9.png old mode 100755 new mode 100644 diff --git a/res/drawable-mdpi/ic_media_bigscreen.png b/res/drawable-mdpi/ic_media_bigscreen.png old mode 100755 new mode 100644 diff --git a/res/drawable-mdpi/ic_media_cropscreen.png b/res/drawable-mdpi/ic_media_cropscreen.png old mode 100755 new mode 100644 diff --git a/res/drawable-mdpi/ic_media_fullscreen.png b/res/drawable-mdpi/ic_media_fullscreen.png old mode 100755 new mode 100644 diff --git a/res/drawable-mdpi/ic_menu_disabled_forward.png b/res/drawable-mdpi/ic_menu_disabled_forward.png old mode 100755 new mode 100644 diff --git a/res/drawable-mdpi/ic_menu_disabled_rewind.png b/res/drawable-mdpi/ic_menu_disabled_rewind.png old mode 100755 new mode 100644 diff --git a/res/drawable-mdpi/ic_menu_disabled_stop.png b/res/drawable-mdpi/ic_menu_disabled_stop.png old mode 100755 new mode 100644 diff --git a/res/drawable-mdpi/ic_menu_forward.png b/res/drawable-mdpi/ic_menu_forward.png old mode 100755 new mode 100644 diff --git a/res/drawable-mdpi/ic_menu_rewind.png b/res/drawable-mdpi/ic_menu_rewind.png old mode 100755 new mode 100644 diff --git a/res/drawable-mdpi/ic_menu_stop.png b/res/drawable-mdpi/ic_menu_stop.png old mode 100755 new mode 100644 diff --git a/res/drawable-mdpi/ic_vidcontrol_disable_pause.png b/res/drawable-mdpi/ic_vidcontrol_disable_pause.png old mode 100755 new mode 100644 diff --git a/res/drawable-mdpi/ic_vidcontrol_disable_play.png b/res/drawable-mdpi/ic_vidcontrol_disable_play.png old mode 100755 new mode 100644 diff --git a/res/drawable-mdpi/ic_vidcontrol_disable_reload.png b/res/drawable-mdpi/ic_vidcontrol_disable_reload.png old mode 100755 new mode 100644 diff --git a/res/drawable-mdpi/media_default_bkg.9.png b/res/drawable-mdpi/media_default_bkg.9.png old mode 100755 new mode 100644 diff --git a/res/drawable-sw600dp/ic_vidcontrol_disable_pause.png b/res/drawable-sw600dp/ic_vidcontrol_disable_pause.png old mode 100755 new mode 100644 diff --git a/res/drawable-sw600dp/ic_vidcontrol_disable_play.png b/res/drawable-sw600dp/ic_vidcontrol_disable_play.png old mode 100755 new mode 100644 diff --git a/res/drawable-sw600dp/ic_vidcontrol_disable_reload.png b/res/drawable-sw600dp/ic_vidcontrol_disable_reload.png old mode 100755 new mode 100644 diff --git a/res/drawable-xhdpi/ic_media_bigscreen.png b/res/drawable-xhdpi/ic_media_bigscreen.png old mode 100755 new mode 100644 diff --git a/res/drawable-xhdpi/ic_media_cropscreen.png b/res/drawable-xhdpi/ic_media_cropscreen.png old mode 100755 new mode 100644 diff --git a/res/drawable-xhdpi/ic_media_fullscreen.png b/res/drawable-xhdpi/ic_media_fullscreen.png old mode 100755 new mode 100644 diff --git a/res/drawable-xhdpi/ic_menu_disabled_forward.png b/res/drawable-xhdpi/ic_menu_disabled_forward.png old mode 100755 new mode 100644 diff --git a/res/drawable-xhdpi/ic_menu_disabled_rewind.png b/res/drawable-xhdpi/ic_menu_disabled_rewind.png old mode 100755 new mode 100644 diff --git a/res/drawable-xhdpi/ic_menu_disabled_stop.png b/res/drawable-xhdpi/ic_menu_disabled_stop.png old mode 100755 new mode 100644 diff --git a/res/drawable-xhdpi/ic_menu_forward.png b/res/drawable-xhdpi/ic_menu_forward.png old mode 100755 new mode 100644 diff --git a/res/drawable-xhdpi/ic_menu_rewind.png b/res/drawable-xhdpi/ic_menu_rewind.png old mode 100755 new mode 100644 diff --git a/res/drawable-xhdpi/ic_menu_stop.png b/res/drawable-xhdpi/ic_menu_stop.png old mode 100755 new mode 100644 diff --git a/res/drawable-xhdpi/ic_vidcontrol_disable_pause.png b/res/drawable-xhdpi/ic_vidcontrol_disable_pause.png old mode 100755 new mode 100644 diff --git a/res/drawable-xhdpi/ic_vidcontrol_disable_play.png b/res/drawable-xhdpi/ic_vidcontrol_disable_play.png old mode 100755 new mode 100644 diff --git a/res/drawable-xhdpi/ic_vidcontrol_disable_reload.png b/res/drawable-xhdpi/ic_vidcontrol_disable_reload.png old mode 100755 new mode 100644 diff --git a/res/drawable/icn_media_forward.xml b/res/drawable/icn_media_forward.xml old mode 100755 new mode 100644 diff --git a/res/drawable/icn_media_rewind.xml b/res/drawable/icn_media_rewind.xml old mode 100755 new mode 100644 diff --git a/res/drawable/icn_media_stop.xml b/res/drawable/icn_media_stop.xml old mode 100755 new mode 100644 diff --git a/res/drawable/videoplayer_pause.xml b/res/drawable/videoplayer_pause.xml old mode 100755 new mode 100644 diff --git a/res/drawable/videoplayer_play.xml b/res/drawable/videoplayer_play.xml old mode 100755 new mode 100644 diff --git a/res/drawable/videoplayer_reload.xml b/res/drawable/videoplayer_reload.xml old mode 100755 new mode 100644 diff --git a/res/layout/setting_list.xml b/res/layout/setting_list.xml old mode 100755 new mode 100644 diff --git a/res/values-zh-rCN/codeaurora_strings.xml b/res/values-zh-rCN/codeaurora_strings.xml index ad4aefc6a..b1b2dbeb4 100644 --- a/res/values-zh-rCN/codeaurora_strings.xml +++ b/res/values-zh-rCN/codeaurora_strings.xml @@ -29,6 +29,12 @@ IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. --> + + 步长 + 定制快进/快退步长 + 3秒 + 6秒 + "循环" "单次" "立体声" @@ -36,27 +42,28 @@ IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. "媒体详情" "输入 URL" "流媒体设置" + "下一个" + "上一个" - RTP - RTCP + RTP/RTCP 最小端口: 最大端口: 缓存大小 优先接入点 RTP最小端口 RTP最大端口 - RTCP最小端口 - RTCP最大端口 设置RTP最小端口 设置RTP最大端口 - 设置RTCP最小端口 - 设置RTCP最大端口 设置缓冲大小 选择接入优先点 设置 "服务器超时" "是否重新连接服务器以播放该视频?" + "连接失败,正在尝试第%1$d次重连..." + 直播 + 正在播放 + 正在连接... "添加书签" "显示书签" diff --git a/res/values-zh-rTW/codeaurora_strings.xml b/res/values-zh-rTW/codeaurora_strings.xml index d72a86ecb..45317df19 100644 --- a/res/values-zh-rTW/codeaurora_strings.xml +++ b/res/values-zh-rTW/codeaurora_strings.xml @@ -29,6 +29,12 @@ IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. --> + + 步長 + 定制快進/快退步長 + 3秒 + >6秒 + "循環" "單次" "立體聲" @@ -36,27 +42,28 @@ IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. "媒體詳情" "輸入 URL" "串流設定" + "下一個" + "上一個" - RTP - RTCP + RTP/RTCP 最小端口: 最大端口: 緩存大小 優先接入點 RTP最小端口 RTP最大端口 - RTCP最小端口 - RTCP最大端口 設置RTP最小端口 設置RTP最大端口 - 設置RTCP最小端口 - 設置RTCP最大端口 設置緩衝大小 選擇接入優先點 設置 "伺服器逾時" "是否重新連線伺服器並播放視訊?" + "連線失敗,正在嘗試重新連線 %1$d..." + 直播 + 正在播放 + 正在連線... "添加書簽" "顯示書簽" diff --git a/res/values/bool.xml b/res/values/bool.xml index 8d2a9f9bc..70ee89ddd 100755 --- a/res/values/bool.xml +++ b/res/values/bool.xml @@ -15,7 +15,9 @@ --> false + false false false false + false \ No newline at end of file diff --git a/res/values/codeaurora_strings.xml b/res/values/codeaurora_strings.xml index 09de79cae..386d2b11a 100644 --- a/res/values/codeaurora_strings.xml +++ b/res/values/codeaurora_strings.xml @@ -29,6 +29,12 @@ IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. --> + + Step + Customize fast forward/backward step + 3 seconds + 6 seconds + "Loop" "Single" "Stereo" @@ -36,27 +42,28 @@ IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. "Media details" "Input URL" "Streaming Settings" + "Next" + "Previous" - RTP - RTCP + RTP/RTCP min port: max port: Buffer Size Prefered APN Min port Max port - Min port - Max port Set min port Set max port - Set min port - Set max port Set buffer size Select prefered apn Settings "Server Timeout" "Reconnect the server to play the video or not?" + "Connection failed, try to reconnect %1$d..." + Live + Playing + Connecting... "Add bookmark" "Show bookmarks" diff --git a/res/xml/rtsp_settings_preferences.xml b/res/xml/rtsp_settings_preferences.xml index a5853808b..8e26c4d8c 100644 --- a/res/xml/rtsp_settings_preferences.xml +++ b/res/xml/rtsp_settings_preferences.xml @@ -1,7 +1,7 @@ - + - - - - diff --git a/src/com/android/gallery3d/app/CommonControllerOverlay.java b/src/com/android/gallery3d/app/CommonControllerOverlay.java index 9adb4e7a8..7a553e906 100644 --- a/src/com/android/gallery3d/app/CommonControllerOverlay.java +++ b/src/com/android/gallery3d/app/CommonControllerOverlay.java @@ -47,10 +47,13 @@ public abstract class CommonControllerOverlay extends FrameLayout implements PAUSED, ENDED, ERROR, - LOADING + LOADING, + BUFFERING, + RETRY_CONNECTING, + RETRY_CONNECTING_ERROR } - private static final float ERROR_MESSAGE_RELATIVE_PADDING = 1.0f / 6; + protected static final float ERROR_MESSAGE_RELATIVE_PADDING = 1.0f / 6; protected Listener mListener; @@ -96,13 +99,9 @@ public abstract class CommonControllerOverlay extends FrameLayout implements ProgressBar spinner = new ProgressBar(context); spinner.setIndeterminate(true); mLoadingView.addView(spinner, wrapContent); - TextView loadingText = createOverlayTextView(context); - loadingText.setText(R.string.loading_video); - mLoadingView.addView(loadingText, wrapContent); addView(mLoadingView, wrapContent); mPlayPauseReplayView = new ImageView(context); - mPlayPauseReplayView.setImageResource(R.drawable.ic_vidcontrol_play); mPlayPauseReplayView.setContentDescription( context.getResources().getString(R.string.accessibility_play_video)); mPlayPauseReplayView.setBackgroundResource(R.drawable.bg_vidcontrol); @@ -119,7 +118,6 @@ public abstract class CommonControllerOverlay extends FrameLayout implements new RelativeLayout.LayoutParams( LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT); setLayoutParams(params); - hide(); } abstract protected void createTimeBar(Context context); @@ -252,7 +250,7 @@ public abstract class CommonControllerOverlay extends FrameLayout implements // | Navigation Bar | insets.bottom // +-----------------+/ // Please see View.fitSystemWindows() for more details. - private final Rect mWindowInsets = new Rect(); + protected final Rect mWindowInsets = new Rect(); @Override protected boolean fitSystemWindows(Rect insets) { @@ -290,7 +288,7 @@ public abstract class CommonControllerOverlay extends FrameLayout implements } } - private void layoutCenteredView(View view, int l, int t, int r, int b) { + protected void layoutCenteredView(View view, int l, int t, int r, int b) { int cw = view.getMeasuredWidth(); int ch = view.getMeasuredHeight(); int cl = (r - l - cw) / 2; diff --git a/src/com/android/gallery3d/app/ControllerOverlay.java b/src/com/android/gallery3d/app/ControllerOverlay.java index 36eda6257..6f049da2d 100644 --- a/src/com/android/gallery3d/app/ControllerOverlay.java +++ b/src/com/android/gallery3d/app/ControllerOverlay.java @@ -55,4 +55,10 @@ public interface ControllerOverlay { void setTimes(int currentTime, int totalTime, int trimStartTime, int trimEndTime); + + //set view enabled (play/pause asynchronous processing) + void setViewEnabled(boolean isEnabled); + + //view from disable to resume (play/pause asynchronous processing) + void setPlayPauseReplayResume(); } diff --git a/src/com/android/gallery3d/app/MovieActivity.java b/src/com/android/gallery3d/app/MovieActivity.java index 8f0a605e4..d22e56f82 100755 --- a/src/com/android/gallery3d/app/MovieActivity.java +++ b/src/com/android/gallery3d/app/MovieActivity.java @@ -30,6 +30,7 @@ import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.content.IntentFilter; +import android.content.res.Configuration; import android.content.SharedPreferences; import android.content.pm.ActivityInfo; import android.database.Cursor; @@ -65,8 +66,9 @@ import com.android.gallery3d.common.ApiHelper; import com.android.gallery3d.common.Utils; import com.android.gallery3d.ui.Knob; import org.codeaurora.gallery3d.ext.IActivityHooker; -import org.codeaurora.gallery3d.ext.MovieItem; import org.codeaurora.gallery3d.ext.IMovieItem; +import org.codeaurora.gallery3d.ext.MovieItem; +import org.codeaurora.gallery3d.ext.MovieUtils; import org.codeaurora.gallery3d.video.ExtensionHelper; import org.codeaurora.gallery3d.video.MovieTitleHelper; @@ -79,20 +81,21 @@ import org.codeaurora.gallery3d.video.MovieTitleHelper; */ public class MovieActivity extends Activity { @SuppressWarnings("unused") - private static final String TAG = "MovieActivity"; + private static final String TAG = "MovieActivity"; private static final boolean LOG = true; - public static final String KEY_LOGO_BITMAP = "logo-bitmap"; - public static final String KEY_TREAT_UP_AS_BACK = "treat-up-as-back"; - private static final String VIDEO_SDP_MIME_TYPE = "application/sdp"; - private static final String VIDEO_SDP_TITLE = "rtsp://"; - private static final String VIDEO_FILE_SCHEMA = "file"; - private static final String VIDEO_MIME_TYPE = "video/*"; + public static final String KEY_LOGO_BITMAP = "logo-bitmap"; + public static final String KEY_TREAT_UP_AS_BACK = "treat-up-as-back"; + private static final String VIDEO_SDP_MIME_TYPE = "application/sdp"; + private static final String VIDEO_SDP_TITLE = "rtsp://"; + private static final String VIDEO_FILE_SCHEMA = "file"; + private static final String VIDEO_MIME_TYPE = "video/*"; + private static final String SHARE_HISTORY_FILE = "video_share_history_file"; private MoviePlayer mPlayer; - private boolean mFinishOnCompletion; - private Uri mUri; + private boolean mFinishOnCompletion; + private Uri mUri; - private static final short BASSBOOST_MAX_STRENGTH = 1000; + private static final short BASSBOOST_MAX_STRENGTH = 1000; private static final short VIRTUALIZER_MAX_STRENGTH = 1000; private boolean mIsHeadsetOn = false; @@ -104,17 +107,19 @@ public class MovieActivity extends Activity { global_enabled, bb_strength, virt_strength }; - private BassBoost mBassBoostEffect; + private BassBoost mBassBoostEffect; private Virtualizer mVirtualizerEffect; private AlertDialog mEffectDialog; - private Switch mSwitch; - private Knob mBassBoostKnob; - private Knob mVirtualizerKnob; - - private IMovieItem mMovieItem; - private IActivityHooker mMovieHooker; - private KeyguardManager mKeyguardManager; - private boolean mResumed = false; + private Switch mSwitch; + private Knob mBassBoostKnob; + private Knob mVirtualizerKnob; + + private ShareActionProvider mShareProvider; + private IMovieItem mMovieItem; + private IActivityHooker mMovieHooker; + private KeyguardManager mKeyguardManager; + + private boolean mResumed = false; private boolean mControlResumed = false; private final BroadcastReceiver mReceiver = new BroadcastReceiver() { @@ -285,17 +290,14 @@ public class MovieActivity extends Activity { public boolean onCreateOptionsMenu(Menu menu) { super.onCreateOptionsMenu(menu); getMenuInflater().inflate(R.menu.movie, menu); - - // Document says EXTRA_STREAM should be a content: Uri - // So, we only share the video if it's "content:". - MenuItem shareItem = menu.findItem(R.id.action_share); - if (ContentResolver.SCHEME_CONTENT.equals(mUri.getScheme())) { - shareItem.setVisible(true); - ((ShareActionProvider) shareItem.getActionProvider()) - .setShareIntent(createShareIntent()); - } else { - shareItem.setVisible(false); + MenuItem shareMenu = menu.findItem(R.id.action_share); + ShareActionProvider provider = (ShareActionProvider) shareMenu.getActionProvider(); + mShareProvider = provider; + if (mShareProvider != null) { + // share provider is singleton, we should refresh our history file. + mShareProvider.setShareHistoryFileName(SHARE_HISTORY_FILE); } + refreshShareProvider(mMovieItem); final MenuItem mi = menu.add(R.string.audio_effects); mi.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() { @@ -564,6 +566,15 @@ public class MovieActivity extends Activity { mMovieHooker.onResume(); } + @Override + public void onConfigurationChanged(Configuration newConfig) { + super.onConfigurationChanged(newConfig); + if(this.getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE || + this.getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) { + mPlayer.setDefaultScreenMode(); + } + } + @Override public void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); @@ -673,6 +684,28 @@ public class MovieActivity extends Activity { return locked; } + public void refreshMovieInfo(IMovieItem info) { + mMovieItem = info; + setActionBarTitle(info.getTitle()); + refreshShareProvider(info); + mMovieHooker.setParameter(null, mMovieItem); + } + + private void refreshShareProvider(IMovieItem info) { + // we only share the video if it's "content:". + if (mShareProvider != null) { + Intent intent = new Intent(Intent.ACTION_SEND); + if (MovieUtils.isLocalFile(info.getUri(), info.getMimeType())) { + intent.setType("video/*"); + intent.putExtra(Intent.EXTRA_STREAM, info.getUri()); + } else { + intent.setType("text/plain"); + intent.putExtra(Intent.EXTRA_TEXT, String.valueOf(info.getUri())); + } + mShareProvider.setShareIntent(intent); + } + } + private void enhanceActionBar() { final IMovieItem movieItem = mMovieItem;// remember original item final Uri uri = mMovieItem.getUri(); diff --git a/src/com/android/gallery3d/app/MovieControllerOverlay.java b/src/com/android/gallery3d/app/MovieControllerOverlay.java index f01e619c6..8c69a3136 100644 --- a/src/com/android/gallery3d/app/MovieControllerOverlay.java +++ b/src/com/android/gallery3d/app/MovieControllerOverlay.java @@ -17,14 +17,39 @@ package com.android.gallery3d.app; import android.content.Context; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.graphics.Color; +import android.graphics.Rect; import android.os.Handler; +import android.util.DisplayMetrics; +import android.view.Gravity; import android.view.KeyEvent; import android.view.MotionEvent; import android.view.View; +import android.view.View.OnClickListener; +import android.view.ViewGroup; +import android.view.ViewGroup.LayoutParams; import android.view.animation.Animation; import android.view.animation.Animation.AnimationListener; import android.view.animation.AnimationUtils; +import android.widget.FrameLayout; +import android.widget.ImageView; +import android.widget.ImageView.ScaleType; +import android.widget.LinearLayout; +import android.widget.ProgressBar; +import android.widget.RelativeLayout; +import android.widget.TextView; + import com.android.gallery3d.R; +import com.android.gallery3d.app.CommonControllerOverlay.State; +import org.codeaurora.gallery3d.ext.IContrllerOverlayExt; +import org.codeaurora.gallery3d.video.IControllerRewindAndForward; +import org.codeaurora.gallery3d.video.IControllerRewindAndForward.IRewindAndForwardListener; +import org.codeaurora.gallery3d.video.ExtensionHelper; +import org.codeaurora.gallery3d.video.ScreenModeManager; +import org.codeaurora.gallery3d.video.ScreenModeManager.ScreenModeListener; + /** * The playback controller for the Movie Player. @@ -32,15 +57,25 @@ import com.android.gallery3d.R; public class MovieControllerOverlay extends CommonControllerOverlay implements AnimationListener { + private static final String TAG = "Gallery3D/MovieControllerOverlay"; + private static final boolean LOG = true; + + private ScreenModeManager mScreenModeManager; + private ScreenModeExt mScreenModeExt = new ScreenModeExt(); + private ControllerRewindAndForwardExt mControllerRewindAndForwardExt = new ControllerRewindAndForwardExt(); + private OverlayExtension mOverlayExt = new OverlayExtension(); private boolean hidden; private final Handler handler; private final Runnable startHidingRunnable; private final Animation hideAnimation; + private boolean enableRewindAndForward = false; + private Context mContext; + public MovieControllerOverlay(Context context) { super(context); - + mContext = context; handler = new Handler(); startHidingRunnable = new Runnable() { @Override @@ -52,9 +87,62 @@ public class MovieControllerOverlay extends CommonControllerOverlay implements hideAnimation = AnimationUtils.loadAnimation(context, R.anim.player_out); hideAnimation.setAnimationListener(this); + enableRewindAndForward = true; + Log.v(TAG, "enableRewindAndForward is " + enableRewindAndForward); + mControllerRewindAndForwardExt.init(context); + mScreenModeExt.init(context, mTimeBar); + mBackground.setClickable(true); hide(); } + public void showPlaying() { + if (!mOverlayExt.handleShowPlaying()) { + mState = State.PLAYING; + showMainView(mPlayPauseReplayView); + } + if (LOG) { + Log.v(TAG, "showPlaying() state=" + mState); + } + } + + public void showPaused() { + if (!mOverlayExt.handleShowPaused()) { + mState = State.PAUSED; + showMainView(mPlayPauseReplayView); + } + if (LOG) { + Log.v(TAG, "showPaused() state=" + mState); + } + } + + public void showEnded() { + mOverlayExt.onShowEnded(); + mState = State.ENDED; + showMainView(mPlayPauseReplayView); + if (LOG) { + Log.v(TAG, "showEnded() state=" + mState); + } + } + + public void showLoading() { + mOverlayExt.onShowLoading(); + mState = State.LOADING; + showMainView(mLoadingView); + if (LOG) { + Log.v(TAG, "showLoading() state=" + mState); + } + } + + public void showErrorMessage(String message) { + mOverlayExt.onShowErrorMessage(message); + mState = State.ERROR; + int padding = (int) (getMeasuredWidth() * ERROR_MESSAGE_RELATIVE_PADDING); + mErrorView.setPadding(padding, mErrorView.getPaddingTop(), padding, + mErrorView.getPaddingBottom()); + mErrorView.setText(message); + showMainView(mErrorView); + } + @Override protected void createTimeBar(Context context) { mTimeBar = new TimeBar(context, this); @@ -64,18 +152,44 @@ public class MovieControllerOverlay extends CommonControllerOverlay implements public void hide() { boolean wasHidden = hidden; hidden = true; - super.hide(); + mPlayPauseReplayView.setVisibility(View.INVISIBLE); + mLoadingView.setVisibility(View.INVISIBLE); + if (!mOverlayExt.handleHide()) { + setVisibility(View.INVISIBLE); + } + mBackground.setVisibility(View.INVISIBLE); + mTimeBar.setVisibility(View.INVISIBLE); + mScreenModeExt.onHide(); + if (enableRewindAndForward) { + mControllerRewindAndForwardExt.onHide(); + } + setFocusable(true); + requestFocus(); if (mListener != null && wasHidden != hidden) { mListener.onHidden(); } } + private void showMainView(View view) { + mMainView = view; + mErrorView.setVisibility(mMainView == mErrorView ? View.VISIBLE + : View.INVISIBLE); + mLoadingView.setVisibility(mMainView == mLoadingView ? View.VISIBLE + : View.INVISIBLE); + mPlayPauseReplayView + .setVisibility(mMainView == mPlayPauseReplayView ? View.VISIBLE + : View.INVISIBLE); + mOverlayExt.onShowMainView(view); + show(); + } @Override public void show() { boolean wasHidden = hidden; hidden = false; - super.show(); + updateViews(); + setVisibility(View.VISIBLE); + setFocusable(false); if (mListener != null && wasHidden != hidden) { mListener.onShown(); } @@ -90,8 +204,14 @@ public class MovieControllerOverlay extends CommonControllerOverlay implements } private void startHiding() { - startHideAnimation(mBackground); - startHideAnimation(mTimeBar); + if (mOverlayExt.canHidePanel()) { + startHideAnimation(mBackground); + startHideAnimation(mTimeBar); + mScreenModeExt.onStartHiding(); + if (enableRewindAndForward) { + mControllerRewindAndForwardExt.onStartHiding(); + } + } startHideAnimation(mPlayPauseReplayView); } @@ -103,8 +223,14 @@ public class MovieControllerOverlay extends CommonControllerOverlay implements private void cancelHiding() { handler.removeCallbacks(startHidingRunnable); - mBackground.setAnimation(null); - mTimeBar.setAnimation(null); + if (mOverlayExt.canHidePanel()) { + mBackground.setAnimation(null); + mTimeBar.setAnimation(null); + mScreenModeExt.onCancelHiding(); + if (enableRewindAndForward) { + mControllerRewindAndForwardExt.onCancelHiding(); + } + } mPlayPauseReplayView.setAnimation(null); } @@ -123,6 +249,61 @@ public class MovieControllerOverlay extends CommonControllerOverlay implements hide(); } + public void onClick(View view) { + if (LOG) { + Log.v(TAG, "onClick(" + view + ") listener=" + mListener + + ", state=" + mState + ", canReplay=" + mCanReplay); + } + if (mListener != null) { + if (view == mPlayPauseReplayView) { + if (mState == State.ENDED) { + if (mCanReplay) { + mListener.onReplay(); + } + } else if (mState == State.PAUSED || mState == State.PLAYING) { + mListener.onPlayPause(); + // set view disabled (play/pause asynchronous processing) + setViewEnabled(true); + } + } + } else { + mScreenModeExt.onClick(view); + if (enableRewindAndForward) { + mControllerRewindAndForwardExt.onClick(view); + } + } + } + + /* + * set view enable (non-Javadoc) + * @see com.android.gallery3d.app.ControllerOverlay#setViewEnabled(boolean) + */ + @Override + public void setViewEnabled(boolean isEnabled) { + if (mListener.onIsRTSP()) { + Log.v(TAG, "setViewEnabled is " + isEnabled); + mOverlayExt.setCanScrubbing(isEnabled); + mPlayPauseReplayView.setEnabled(isEnabled); + if (enableRewindAndForward) { + mControllerRewindAndForwardExt.setViewEnabled(isEnabled); + } + } + } + + /* + * set play pause button from disable to normal (non-Javadoc) + * @see + * com.android.gallery3d.app.ControllerOverlay#setPlayPauseReplayResume( + * void) + */ + @Override + public void setPlayPauseReplayResume() { + if (mListener.onIsRTSP()) { + Log.v(TAG, "setPlayPauseReplayResume is enabled is true"); + mPlayPauseReplayView.setEnabled(true); + } + } + @Override public boolean onKeyDown(int keyCode, KeyEvent event) { if (hidden) { @@ -144,7 +325,10 @@ public class MovieControllerOverlay extends CommonControllerOverlay implements switch (event.getAction()) { case MotionEvent.ACTION_DOWN: cancelHiding(); - if (mState == State.PLAYING || mState == State.PAUSED) { + // you can click play or pause when view is resumed + // play/pause asynchronous processing + if ((mState == State.PLAYING || mState == State.PAUSED) + && mOverlayExt.mEnableScrubbing) { mListener.onPlayPause(); } break; @@ -155,12 +339,72 @@ public class MovieControllerOverlay extends CommonControllerOverlay implements return true; } + @Override + protected void onLayout(boolean changed, int left, int top, int right, int bottom) { + int width = ((MovieActivity) mContext).getWindowManager().getDefaultDisplay().getWidth(); + Rect insets = mWindowInsets; + int pl = insets.left; // the left paddings + int pr = insets.right; + int pt = insets.top; + int pb = insets.bottom; + + int h = bottom - top; + int w = right - left; + boolean error = mErrorView.getVisibility() == View.VISIBLE; + + int y = h - pb; + // Put both TimeBar and Background just above the bottom system + // component. + // But extend the background to the width of the screen, since we don't + // care if it will be covered by a system component and it looks better. + + // Needed, otherwise the framework will not re-layout in case only the + // padding is changed + if (enableRewindAndForward) { + mBackground.layout(0, y - mTimeBar.getPreferredHeight() - 80, w, y); + mTimeBar.layout(pl, y - mTimeBar.getPreferredHeight() - 80, w - pr, + y - mTimeBar.getBarHeight()); + mControllerRewindAndForwardExt.onLayout(0, width, y); + } else { + mBackground.layout(0, y - mTimeBar.getBarHeight(), w, y); + mTimeBar.layout(pl, y - mTimeBar.getPreferredHeight(), + w - pr - mScreenModeExt.getAddedRightPadding(), y); + } + mScreenModeExt.onLayout(w, pr, y); + // Put the play/pause/next/ previous button in the center of the screen + layoutCenteredView(mPlayPauseReplayView, 0, 0, w, h); + + if (mMainView != null) { + layoutCenteredView(mMainView, 0, 0, w, h); + } + } + @Override protected void updateViews() { if (hidden) { return; } - super.updateViews(); + mBackground.setVisibility(View.VISIBLE); + mTimeBar.setVisibility(View.VISIBLE); + mPlayPauseReplayView.setImageResource( + mState == State.PAUSED ? R.drawable.videoplayer_play : + mState == State.PLAYING ? R.drawable.videoplayer_pause : + R.drawable.videoplayer_reload); + mScreenModeExt.onShow(); + if (enableRewindAndForward) { + mControllerRewindAndForwardExt.onShow(); + } + if (!mOverlayExt.handleUpdateViews()) { + mPlayPauseReplayView.setVisibility( + (mState != State.LOADING && mState != State.ERROR && + !(mState == State.ENDED && !mCanReplay)) + ? View.VISIBLE : View.GONE); + } + requestLayout(); + if (LOG) { + Log.v(TAG, "updateViews() state=" + mState + ", canReplay=" + + mCanReplay); + } } // TimeBar listener @@ -182,4 +426,538 @@ public class MovieControllerOverlay extends CommonControllerOverlay implements maybeStartHiding(); super.onScrubbingEnd(time, trimStartTime, trimEndTime); } + + public void setScreenModeManager(ScreenModeManager manager) { + mScreenModeManager = manager; + if (mScreenModeManager != null) { + mScreenModeManager.addListener(mScreenModeExt); + } + if (LOG) { + Log.v(TAG, "setScreenModeManager(" + manager + ")"); + } + } + + public void setDefaultScreenMode() { + mScreenModeManager.setScreenMode(ScreenModeManager.SCREENMODE_BIGSCREEN); + } + + public IContrllerOverlayExt getOverlayExt() { + return mOverlayExt; + } + + public IControllerRewindAndForward getControllerRewindAndForwardExt() { + if (enableRewindAndForward) { + return mControllerRewindAndForwardExt; + } + return null; + } + + private class OverlayExtension implements IContrllerOverlayExt { + private State mLastState; + private String mPlayingInfo; + // for pause feature + private boolean mCanPause = true; + private boolean mEnableScrubbing = false; + // for only audio feature + private boolean mAlwaysShowBottom; + + @Override + public void showBuffering(boolean fullBuffer, int percent) { + if (LOG) { + Log.v(TAG, "showBuffering(" + fullBuffer + ", " + percent + + ") " + "lastState=" + mLastState + ", state=" + mState); + } + if (fullBuffer) { + // do not show text and loading + mTimeBar.setSecondaryProgress(percent); + return; + } + if (mState == State.PAUSED || mState == State.PLAYING) { + mLastState = mState; + } + if (percent >= 0 && percent < 100) { // valid value + mState = State.BUFFERING; + String text = "media controller buffering"; + mTimeBar.setInfo(text); + showMainView(mLoadingView); + } else if (percent == 100) { + mState = mLastState; + mTimeBar.setInfo(null); + showMainView(mPlayPauseReplayView);// restore play pause state + } else { // here to restore old state + mState = mLastState; + mTimeBar.setInfo(null); + } + } + + // set buffer percent to unknown value + public void clearBuffering() { + if (LOG) { + Log.v(TAG, "clearBuffering()"); + } + mTimeBar.setSecondaryProgress(TimeBar.UNKNOWN); + showBuffering(false, TimeBar.UNKNOWN); + } + + public void showReconnecting(int times) { + clearBuffering(); + mState = State.RETRY_CONNECTING; + int msgId = R.string.videoview_error_text_cannot_connect_retry; + String text = getResources().getString(msgId, times); + mTimeBar.setInfo(text); + showMainView(mLoadingView); + if (LOG) { + Log.v(TAG, "showReconnecting(" + times + ")"); + } + } + + public void showReconnectingError() { + clearBuffering(); + mState = State.RETRY_CONNECTING_ERROR; + + String text = "can not connect to server"; + mTimeBar.setInfo(text); + showMainView(mPlayPauseReplayView); + if (LOG) { + Log.v(TAG, "showReconnectingError()"); + } + } + + public void setPlayingInfo(boolean liveStreaming) { + int msgId; + // TODO + if (liveStreaming) { + msgId = R.string.media_controller_live; + } else { + msgId = R.string.media_controller_playing; + } + mPlayingInfo = getResources().getString(msgId); + if (LOG) { + Log.v(TAG, "setPlayingInfo(" + liveStreaming + + ") playingInfo=" + mPlayingInfo); + } + } + + public void setCanPause(boolean canPause) { + this.mCanPause = canPause; + if (LOG) { + Log.v(TAG, "setCanPause(" + canPause + ")"); + } + } + + public void setCanScrubbing(boolean enable) { + mEnableScrubbing = enable; + mTimeBar.setScrubbing(enable); + if (LOG) { + Log.v(TAG, "setCanScrubbing(" + enable + ")"); + } + } + + public void setBottomPanel(boolean alwaysShow, boolean foreShow) { + mAlwaysShowBottom = alwaysShow; + if (!alwaysShow) { // clear background + setBackgroundDrawable(null); + setBackgroundColor(Color.TRANSPARENT); + } else { + setBackgroundResource(R.drawable.media_default_bkg); + if (foreShow) { + setVisibility(View.VISIBLE); + } + } + if (LOG) { + Log.v(TAG, "setBottomPanel(" + alwaysShow + ", " + foreShow + + ")"); + } + } + + public boolean isPlayingEnd() { + if (LOG) { + Log.v(TAG, "isPlayingEnd() state=" + mState); + } + boolean end = false; + if (State.ENDED == mState || State.ERROR == mState + || State.RETRY_CONNECTING_ERROR == mState) { + end = true; + } + return end; + } + + public boolean handleShowPlaying() { + if (mState == State.BUFFERING) { + mLastState = State.PLAYING; + return true; + } + return false; + } + + public boolean handleShowPaused() { + mTimeBar.setInfo(null); + if (mState == State.BUFFERING) { + mLastState = State.PAUSED; + return true; + } + return false; + } + + public void onShowLoading() { + // TODO + int msgId = R.string.media_controller_connecting; + String text = getResources().getString(msgId); + mTimeBar.setInfo(text); + } + + public void onShowEnded() { + clearBuffering(); + mTimeBar.setInfo(null); + } + + public void onShowErrorMessage(String message) { + clearBuffering(); + } + + public boolean handleUpdateViews() { + mPlayPauseReplayView + .setVisibility((mState != State.LOADING + && mState != State.ERROR + && mState != State.BUFFERING + && mState != State.RETRY_CONNECTING && !(mState != State.ENDED + && mState != State.RETRY_CONNECTING_ERROR && !mCanPause)) + // for live streaming + ? View.VISIBLE + : View.GONE); + + if (mPlayingInfo != null && mState == State.PLAYING) { + mTimeBar.setInfo(mPlayingInfo); + } + return true; + } + + public boolean handleHide() { + return mAlwaysShowBottom; + } + + public void onShowMainView(View view) { + if (LOG) { + Log.v(TAG, "showMainView(" + view + ") errorView=" + + mErrorView + ", loadingView=" + mLoadingView + + ", playPauseReplayView=" + mPlayPauseReplayView); + Log.v(TAG, "showMainView() enableScrubbing=" + + mEnableScrubbing + ", state=" + mState); + } + if (mEnableScrubbing + && (mState == State.PAUSED || mState == State.PLAYING)) { + mTimeBar.setScrubbing(true); + } else { + mTimeBar.setScrubbing(false); + } + } + + public boolean canHidePanel() { + return !mAlwaysShowBottom; + } + }; + + class ScreenModeExt implements View.OnClickListener, ScreenModeListener { + // for screen mode feature + private ImageView mScreenView; + private int mScreenPadding; + private int mScreenWidth; + + private static final int MARGIN = 10; // dip + private ViewGroup mParent; + private ImageView mSeprator; + + void init(Context context, View myTimeBar) { + DisplayMetrics metrics = context.getResources().getDisplayMetrics(); + int padding = (int) (metrics.density * MARGIN); + myTimeBar.setPadding(padding, 0, padding, 0); + + LayoutParams wrapContent = + new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); + // add screenView + mScreenView = new ImageView(context); + // default next screen mode + mScreenView.setImageResource(R.drawable.ic_media_fullscreen); + mScreenView.setScaleType(ScaleType.CENTER); + mScreenView.setFocusable(true); + mScreenView.setClickable(true); + mScreenView.setOnClickListener(this); + addView(mScreenView, wrapContent); + + if (enableRewindAndForward) { + Log.v(TAG, "ScreenModeExt enableRewindAndForward"); + mSeprator = new ImageView(context); + // default next screen mode + mSeprator.setImageResource(R.drawable.ic_separator_line); + mSeprator.setScaleType(ScaleType.CENTER); + mSeprator.setFocusable(true); + mSeprator.setClickable(true); + mSeprator.setOnClickListener(this); + addView(mSeprator, wrapContent); + + } else { + Log.v(TAG, "ScreenModeExt unenableRewindAndForward"); + } + + // for screen layout + Bitmap screenButton = BitmapFactory.decodeResource(context.getResources(), + R.drawable.ic_media_bigscreen); + mScreenWidth = screenButton.getWidth(); + mScreenPadding = (int) (metrics.density * MARGIN); + screenButton.recycle(); + } + + private void updateScreenModeDrawable() { + int screenMode = mScreenModeManager.getNextScreenMode(); + if (screenMode == ScreenModeManager.SCREENMODE_BIGSCREEN) { + mScreenView.setImageResource(R.drawable.ic_media_bigscreen); + } else if (screenMode == ScreenModeManager.SCREENMODE_FULLSCREEN) { + mScreenView.setImageResource(R.drawable.ic_media_fullscreen); + } else { + mScreenView.setImageResource(R.drawable.ic_media_cropscreen); + } + } + + @Override + public void onClick(View v) { + if (v == mScreenView && mScreenModeManager != null) { + mScreenModeManager.setScreenMode(mScreenModeManager + .getNextScreenMode()); + show(); + } + } + + public void onStartHiding() { + startHideAnimation(mScreenView); + } + + public void onCancelHiding() { + mScreenView.setAnimation(null); + } + + public void onHide() { + mScreenView.setVisibility(View.INVISIBLE); + if (enableRewindAndForward) { + mSeprator.setVisibility(View.INVISIBLE); + } + } + + public void onShow() { + mScreenView.setVisibility(View.VISIBLE); + if (enableRewindAndForward) { + mSeprator.setVisibility(View.VISIBLE); + } + } + + public void onLayout(int width, int paddingRight, int yPosition) { + // layout screen view position + int sw = getAddedRightPadding(); + mScreenView.layout(width - paddingRight - sw, yPosition + - mTimeBar.getPreferredHeight(), width - paddingRight, + yPosition); + if (enableRewindAndForward) { + mSeprator.layout(width - paddingRight - sw - 22, yPosition + - mTimeBar.getPreferredHeight(), width - paddingRight - sw - 20, + yPosition); + } + } + + public int getAddedRightPadding() { + return mScreenPadding * 2 + mScreenWidth; + } + + @Override + public void onScreenModeChanged(int newMode) { + updateScreenModeDrawable(); + } + } + + class ControllerRewindAndForwardExt implements View.OnClickListener, + IControllerRewindAndForward { + private LinearLayout mContollerButtons; + private ImageView mStop; + private ImageView mForward; + private ImageView mRewind; + private IRewindAndForwardListener mListenerForRewind; + private int mButtonWidth; + private static final int BUTTON_PADDING = 40; + private int mTimeBarHeight = 0; + + void init(Context context) { + Log.v(TAG, "ControllerRewindAndForwardExt init"); + mTimeBarHeight = mTimeBar.getPreferredHeight(); + Bitmap button = BitmapFactory.decodeResource(context.getResources(), + R.drawable.ic_menu_forward); + mButtonWidth = button.getWidth(); + button.recycle(); + + mContollerButtons = new LinearLayout(context); + LinearLayout.LayoutParams wrapContent = new LinearLayout.LayoutParams( + getAddedRightPadding(), mTimeBarHeight); + mContollerButtons.setHorizontalGravity(LinearLayout.HORIZONTAL); + mContollerButtons.setVisibility(View.VISIBLE); + mContollerButtons.setGravity(Gravity.CENTER); + + LinearLayout.LayoutParams buttonParam = new LinearLayout.LayoutParams( + mTimeBarHeight, mTimeBarHeight); + mRewind = new ImageView(context); + mRewind.setImageResource(R.drawable.icn_media_rewind); + mRewind.setScaleType(ScaleType.CENTER); + mRewind.setFocusable(true); + mRewind.setClickable(true); + mRewind.setOnClickListener(this); + mContollerButtons.addView(mRewind, buttonParam); + + mStop = new ImageView(context); + mStop.setImageResource(R.drawable.icn_media_stop); + mStop.setScaleType(ScaleType.CENTER); + mStop.setFocusable(true); + mStop.setClickable(true); + mStop.setOnClickListener(this); + LinearLayout.LayoutParams stopLayoutParam = new LinearLayout.LayoutParams( + mTimeBarHeight, mTimeBarHeight); + stopLayoutParam.setMargins(BUTTON_PADDING, 0, BUTTON_PADDING, 0); + mContollerButtons.addView(mStop, stopLayoutParam); + + mForward = new ImageView(context); + mForward.setImageResource(R.drawable.icn_media_forward); + mForward.setScaleType(ScaleType.CENTER); + mForward.setFocusable(true); + mForward.setClickable(true); + mForward.setOnClickListener(this); + mContollerButtons.addView(mForward, buttonParam); + + addView(mContollerButtons, wrapContent); + } + + @Override + public void onClick(View v) { + if (v == mStop) { + Log.v(TAG, "ControllerRewindAndForwardExt onClick mStop"); + mListenerForRewind.onStopVideo(); + } else if (v == mRewind) { + Log.v(TAG, "ControllerRewindAndForwardExt onClick mRewind"); + mListenerForRewind.onRewind(); + } else if (v == mForward) { + Log.v(TAG, "ControllerRewindAndForwardExt onClick mForward"); + mListenerForRewind.onForward(); + } + } + + public void onStartHiding() { + Log.v(TAG, "ControllerRewindAndForwardExt onStartHiding"); + startHideAnimation(mContollerButtons); + } + + public void onCancelHiding() { + Log.v(TAG, "ControllerRewindAndForwardExt onCancelHiding"); + mContollerButtons.setAnimation(null); + } + + public void onHide() { + Log.v(TAG, "ControllerRewindAndForwardExt onHide"); + mContollerButtons.setVisibility(View.INVISIBLE); + } + + public void onShow() { + Log.v(TAG, "ControllerRewindAndForwardExt onShow"); + mContollerButtons.setVisibility(View.VISIBLE); + } + + public void onLayout(int l, int r, int b) { + Log.v(TAG, "ControllerRewindAndForwardExt onLayout"); + int cl = (r - l - getAddedRightPadding()) / 2; + int cr = cl + getAddedRightPadding(); + mContollerButtons.layout(cl, b - mTimeBar.getPreferredHeight(), cr, b); + } + + public int getAddedRightPadding() { + return mTimeBarHeight * 3 + BUTTON_PADDING * 2; + } + + @Override + public void setIListener(IRewindAndForwardListener listener) { + Log.v(TAG, "ControllerRewindAndForwardExt setIListener " + listener); + mListenerForRewind = listener; + } + + @Override + public void showControllerButtonsView(boolean canStop, boolean canRewind, boolean canForward) { + Log.v(TAG, "ControllerRewindAndForwardExt showControllerButtonsView " + canStop + + canRewind + canForward); + // show ui + mStop.setEnabled(canStop); + mRewind.setEnabled(canRewind); + mForward.setEnabled(canForward); + } + + @Override + public void setListener(Listener listener) { + setListener(listener); + } + + @Override + public boolean getPlayPauseEanbled() { + return mPlayPauseReplayView.isEnabled(); + } + + @Override + public boolean getTimeBarEanbled() { + return mTimeBar.getScrubbing(); + } + + @Override + public void setCanReplay(boolean canReplay) { + setCanReplay(canReplay); + } + + @Override + public View getView() { + return mContollerButtons; + } + + @Override + public void show() { + show(); + } + + @Override + public void showPlaying() { + showPlaying(); + } + + @Override + public void showPaused() { + showPaused(); + } + + @Override + public void showEnded() { + showEnded(); + } + + @Override + public void showLoading() { + showLoading(); + } + + @Override + public void showErrorMessage(String message) { + showErrorMessage(message); + } + + public void setTimes(int currentTime, int totalTime, int trimStartTime, int trimEndTime) { + setTimes(currentTime, totalTime, 0, 0); + } + + public void setPlayPauseReplayResume() { + } + + public void setViewEnabled(boolean isEnabled) { + // TODO Auto-generated method stub + Log.v(TAG, "ControllerRewindAndForwardExt setViewEnabled is " + isEnabled); + mRewind.setEnabled(isEnabled); + mForward.setEnabled(isEnabled); + } + } } diff --git a/src/com/android/gallery3d/app/MoviePlayer.java b/src/com/android/gallery3d/app/MoviePlayer.java index 4ab7c14d1..af6eda5d4 100755 --- a/src/com/android/gallery3d/app/MoviePlayer.java +++ b/src/com/android/gallery3d/app/MoviePlayer.java @@ -28,6 +28,7 @@ import android.content.DialogInterface.OnDismissListener; import android.content.DialogInterface.OnShowListener; import android.content.Intent; import android.content.IntentFilter; +import android.content.SharedPreferences; import android.graphics.Color; import android.media.AudioManager; import android.media.MediaPlayer; @@ -51,11 +52,16 @@ import com.android.gallery3d.common.ApiHelper; import com.android.gallery3d.common.BlobCache; import com.android.gallery3d.util.CacheManager; import com.android.gallery3d.util.GalleryUtils; +import org.codeaurora.gallery3d.ext.IContrllerOverlayExt; import org.codeaurora.gallery3d.ext.IMoviePlayer; import org.codeaurora.gallery3d.ext.IMovieItem; import org.codeaurora.gallery3d.ext.MovieUtils; import org.codeaurora.gallery3d.video.BookmarkEnhance; import org.codeaurora.gallery3d.video.ExtensionHelper; +import org.codeaurora.gallery3d.video.IControllerRewindAndForward; +import org.codeaurora.gallery3d.video.IControllerRewindAndForward.IRewindAndForwardListener; +import org.codeaurora.gallery3d.video.ScreenModeManager; +import org.codeaurora.gallery3d.video.ScreenModeManager.ScreenModeListener; import org.codeaurora.gallery3d.video.CodeauroraVideoView; import java.io.ByteArrayInputStream; @@ -70,10 +76,12 @@ public class MoviePlayer implements ControllerOverlay.Listener, MediaPlayer.OnInfoListener, MediaPlayer.OnPreparedListener, - MediaPlayer.OnSeekCompleteListener { + MediaPlayer.OnSeekCompleteListener, + MediaPlayer.OnVideoSizeChangedListener, + MediaPlayer.OnBufferingUpdateListener { @SuppressWarnings("unused") private static final String TAG = "MoviePlayer"; - private static final boolean LOG = false; + private static final boolean LOG = true; private static final String KEY_VIDEO_POSITION = "video-position"; private static final String KEY_RESUMEABLE_TIME = "resumeable-timeout"; @@ -113,7 +121,6 @@ public class MoviePlayer implements private final CodeauroraVideoView mVideoView; private final View mRootView; private final Bookmarker mBookmarker; - private final Uri mUri; private final Handler mHandler = new Handler(); private final AudioBecomingNoisyReceiver mAudioBecomingNoisyReceiver; private final MovieControllerOverlay mController; @@ -125,6 +132,7 @@ public class MoviePlayer implements private boolean mCanResumed = false; private boolean mFirstBePlayed = false; private boolean mKeyguardLocked = false; + private boolean mIsOnlyAudio = false; private int mLastSystemUiVis = 0; // If the time bar is being dragged. @@ -139,6 +147,10 @@ public class MoviePlayer implements private MoviePlayerExtension mPlayerExt = new MoviePlayerExtension(); private RetryExtension mRetryExt = new RetryExtension(); private ServerTimeoutExtension mServerTimeoutExt = new ServerTimeoutExtension(); + private ScreenModeExt mScreenModeExt = new ScreenModeExt(); + private IContrllerOverlayExt mOverlayExt; + private IControllerRewindAndForward mControllerRewindAndForwardExt; + private IRewindAndForwardListener mRewindAndForwardListener = new ControllerRewindAndForwardExt(); private boolean mCanReplay; private boolean mVideoCanSeek = false; private boolean mVideoCanPause = false; @@ -201,6 +213,9 @@ public class MoviePlayer implements } mKeyguardLocked = false; mCanResumed = false; + } else if (Intent.ACTION_SHUTDOWN.equals(intent.getAction())) { + Log.v(TAG, "Intent.ACTION_SHUTDOWN received"); + mActivityContext.finish(); } } }; @@ -212,17 +227,20 @@ public class MoviePlayer implements mVideoView = (CodeauroraVideoView) rootView.findViewById(R.id.surface_view); mBookmarker = new Bookmarker(movieActivity); - mController = new MovieControllerOverlay(mContext); + mController = new MovieControllerOverlay(movieActivity); ((ViewGroup)rootView).addView(mController.getView()); mController.setListener(this); mController.setCanReplay(canReplay); init(movieActivity, info, canReplay); - mUri = mMovieItem.getUri(); mVideoView.setOnErrorListener(this); mVideoView.setOnCompletionListener(this); - mVideoView.setVideoURI(mUri); + + if (mVirtualizer != null) { + mVirtualizer.release(); + mVirtualizer = null; + } Intent ai = movieActivity.getIntent(); boolean virtualize = ai.getBooleanExtra(VIRTUALIZE_EXTRA, false); @@ -277,6 +295,7 @@ public class MoviePlayer implements final IntentFilter filter = new IntentFilter(); filter.addAction(Intent.ACTION_SCREEN_OFF); filter.addAction(Intent.ACTION_USER_PRESENT); + filter.addAction(Intent.ACTION_SHUTDOWN); mContext.registerReceiver(mReceiver, filter); Intent i = new Intent(SERVICECMD); @@ -286,8 +305,6 @@ public class MoviePlayer implements if (savedInstance != null) { // this is a resumed activity mVideoPosition = savedInstance.getInt(KEY_VIDEO_POSITION, 0); mResumeableTime = savedInstance.getLong(KEY_RESUMEABLE_TIME, Long.MAX_VALUE); - mVideoView.start(); - mVideoView.suspend(); onRestoreInstanceState(savedInstance); mHasPaused = true; } else { @@ -300,6 +317,7 @@ public class MoviePlayer implements doStartVideo(false, 0, 0); } } + mScreenModeExt.setScreenMode(); } @TargetApi(Build.VERSION_CODES.JELLY_BEAN) @@ -313,11 +331,17 @@ public class MoviePlayer implements new View.OnSystemUiVisibilityChangeListener() { @Override public void onSystemUiVisibilityChange(int visibility) { + boolean finish = (mActivityContext == null ? true : mActivityContext.isFinishing()); int diff = mLastSystemUiVis ^ visibility; mLastSystemUiVis = visibility; if ((diff & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) != 0 && (visibility & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) == 0) { mController.show(); + mRootView.setBackgroundColor(Color.BLACK); + } + + if (LOG) { + Log.v(TAG, "onSystemUiVisibilityChange(" + visibility + ") finishing()=" + finish); } } }); @@ -389,6 +413,12 @@ public class MoviePlayer implements dialog.show(); } + public void setDefaultScreenMode() { + addBackground(); + mController.setDefaultScreenMode(); + removeBackground(); + } + public boolean onPause() { if (LOG) { Log.v(TAG, "onPause() isLiveStreaming()=" + isLiveStreaming()); @@ -428,14 +458,14 @@ public class MoviePlayer implements mVideoLastDuration = duration > 0 ? duration : mVideoLastDuration; mBookmarker.setBookmark(mMovieItem.getUri(), mVideoPosition, mVideoLastDuration); long end1 = System.currentTimeMillis(); - // change suspend to release for sync paused and killed case - mVideoView.stopPlayback(); + mVideoView.suspend(); mResumeableTime = System.currentTimeMillis() + RESUMEABLE_TIMEOUT; mVideoView.setResumed(false);// avoid start after surface created // Workaround for last-seek frame difference mVideoView.setVisibility(View.INVISIBLE); long end2 = System.currentTimeMillis(); // TODO comments by sunlei + mOverlayExt.clearBuffering(); mServerTimeoutExt.recordDisconnectTime(); if (LOG) { Log.v(TAG, "doOnPause() save video info consume:" + (end1 - start)); @@ -478,7 +508,8 @@ public class MoviePlayer implements pauseVideo(); break; default: - doStartVideo(true, mVideoPosition, mVideoLastDuration); + mVideoView.seekTo(mVideoPosition); + mVideoView.resume(); pauseVideoMoreThanThreeMinutes(); break; } @@ -516,12 +547,16 @@ public class MoviePlayer implements // second by mProgressChecker and also from places where the time bar needs // to be updated immediately. private int setProgress() { - if (mDragging || !mShowing) { + if (mDragging || (!mShowing && !mIsOnlyAudio)) { return 0; } int position = mVideoView.getCurrentPosition(); int duration = mVideoView.getDuration(); mController.setTimes(position, duration, 0, 0); + if (mControllerRewindAndForwardExt != null + && mControllerRewindAndForwardExt.getPlayPauseEanbled()) { + updateRewindAndForwardUI(); + } return position; } @@ -533,6 +568,7 @@ public class MoviePlayer implements if ("http".equalsIgnoreCase(scheme) || "rtsp".equalsIgnoreCase(scheme) || "https".equalsIgnoreCase(scheme)) { mController.showLoading(); + mOverlayExt.setPlayingInfo(isLiveStreaming()); mHandler.removeCallbacks(mPlayingChecker); mHandler.postDelayed(mPlayingChecker, 250); } else { @@ -549,14 +585,15 @@ public class MoviePlayer implements } if (start) { mVideoView.start(); + mVideoView.setVisibility(View.VISIBLE); + mActivityContext.initEffects(mVideoView.getAudioSessionId()); } //we may start video from stopVideo, //this case, we should reset canReplay flag according canReplay and loop boolean loop = mPlayerExt.getLoop(); boolean canReplay = loop ? loop : mCanReplay; mController.setCanReplay(canReplay); - if (position > 0 && (mVideoCanSeek || mVideoView.canSeekBackward() - || mVideoView.canSeekForward())) { + if (position > 0 && (mVideoCanSeek || mVideoView.canSeek())) { mVideoView.seekTo(position); } if (enableFasten) { @@ -607,6 +644,8 @@ public class MoviePlayer implements mHandler.removeCallbacksAndMessages(null); // VideoView will show an error dialog if we return false, so no need // to show more message. + //M:resume controller + mController.setViewEnabled(true); mController.showErrorMessage(""); return false; } @@ -639,9 +678,23 @@ public class MoviePlayer implements @Override public void onPlayPause() { if (mVideoView.isPlaying()) { - pauseVideo(); + if (mVideoView.canPause()) { + pauseVideo(); + //set view disabled(play/pause asynchronous processing) + mController.setViewEnabled(true); + if (mControllerRewindAndForwardExt != null) { + mControllerRewindAndForwardExt.showControllerButtonsView(mPlayerExt + .canStop(), false, false); + } + } } else { playVideo(); + //set view disabled(play/pause asynchronous processing) + mController.setViewEnabled(true); + if (mControllerRewindAndForwardExt != null) { + mControllerRewindAndForwardExt.showControllerButtonsView(mPlayerExt + .canStop(), false, false); + } } } @@ -652,14 +705,17 @@ public class MoviePlayer implements @Override public void onSeekMove(int time) { - mVideoView.seekTo(time); + if (mVideoView.canSeek()) { + mVideoView.seekTo(time); + } } @Override public void onSeekEnd(int time, int start, int end) { mDragging = false; - mVideoView.seekTo(time); - setProgress(); + if (mVideoView.canSeek()) { + mVideoView.seekTo(time); + } } @Override @@ -669,6 +725,7 @@ public class MoviePlayer implements @Override public void onShown() { + addBackground(); mShowing = true; setProgress(); showSystemUi(true); @@ -678,6 +735,7 @@ public class MoviePlayer implements public void onHidden() { mShowing = false; showSystemUi(false); + removeBackground(); } @Override @@ -685,7 +743,11 @@ public class MoviePlayer implements if (LOG) { Log.v(TAG, "onInfo() what:" + what + " extra:" + extra); } - if (what == MediaPlayer.MEDIA_INFO_METADATA_UPDATE && mServerTimeoutExt != null) { + if (what == MediaPlayer.MEDIA_INFO_NOT_SEEKABLE && mOverlayExt != null) { + boolean flag = (extra == 1); + mOverlayExt.setCanPause(flag); + mOverlayExt.setCanScrubbing(flag); + } else if (what == MediaPlayer.MEDIA_INFO_METADATA_UPDATE && mServerTimeoutExt != null) { Log.e(TAG, "setServerTimeout " + extra); mServerTimeoutExt.setTimeout(extra * 1000); } @@ -695,17 +757,30 @@ public class MoviePlayer implements return false; } + @Override + public void onBufferingUpdate(MediaPlayer mp, int percent) { + boolean fullBuffer = isFullBuffer(); + mOverlayExt.showBuffering(fullBuffer, percent); + } + @Override public void onPrepared(MediaPlayer mp) { if (LOG) { Log.v(TAG, "onPrepared(" + mp + ")"); } + if (!isLocalFile()) { + mOverlayExt.setPlayingInfo(isLiveStreaming()); + } getVideoInfo(mp); boolean canPause = mVideoView.canPause(); - boolean canSeek = mVideoView.canSeekBackward() && mVideoView.canSeekForward(); + boolean canSeek = mVideoView.canSeek(); + mOverlayExt.setCanPause(canPause); + mOverlayExt.setCanScrubbing(canSeek); + mController.setPlayPauseReplayResume(); if (!canPause && !mVideoView.isTargetPlaying()) { mVideoView.start(); } + updateRewindAndForwardUI(); if (LOG) { Log.v(TAG, "onPrepared() canPause=" + canPause + ", canSeek=" + canSeek); } @@ -774,6 +849,19 @@ public class MoviePlayer implements return isMediaKey(keyCode); } + public void updateRewindAndForwardUI() { + Log.v(TAG, "updateRewindAndForwardUI"); + Log.v(TAG, "updateRewindAndForwardUI== getCurrentPosition = " + mVideoView.getCurrentPosition()); + Log.v(TAG, "updateRewindAndForwardUI==getDuration =" + mVideoView.getDuration()); + if (mControllerRewindAndForwardExt != null) { + mControllerRewindAndForwardExt.showControllerButtonsView(mPlayerExt + .canStop(), mVideoView.canSeekBackward() + && mControllerRewindAndForwardExt.getTimeBarEanbled(), mVideoView + .canSeekForward() + && mControllerRewindAndForwardExt.getTimeBarEanbled()); + } + } + private static boolean isMediaKey(int keyCode) { return keyCode == KeyEvent.KEYCODE_HEADSETHOOK || keyCode == KeyEvent.KEYCODE_MEDIA_PREVIOUS @@ -791,6 +879,20 @@ public class MoviePlayer implements mVideoView.setOnInfoListener(this); mVideoView.setOnPreparedListener(this); + mVideoView.setOnBufferingUpdateListener(this); + mVideoView.setOnVideoSizeChangedListener(this); + mRootView.setOnTouchListener(new View.OnTouchListener() { + @Override + public boolean onTouch(View v, MotionEvent event) { + mController.show(); + return true; + } + }); + mOverlayExt = mController.getOverlayExt(); + mControllerRewindAndForwardExt = mController.getControllerRewindAndForwardExt(); + if (mControllerRewindAndForwardExt != null) { + mControllerRewindAndForwardExt.setIListener(mRewindAndForwardListener); + } } // We want to pause when the headset is unplugged. @@ -807,7 +909,7 @@ public class MoviePlayer implements @Override public void onReceive(Context context, Intent intent) { - if (mVideoView.isPlaying()) pauseVideo(); + if (mVideoView.isPlaying() && mVideoView.canPause()) pauseVideo(); } } @@ -885,6 +987,20 @@ public class MoviePlayer implements return isLive; } + public void onVideoSizeChanged(MediaPlayer mp, int width, int height) { + // reget the audio type + if (width != 0 && height != 0) { + mIsOnlyAudio = false; + } else { + mIsOnlyAudio = true; + } + mOverlayExt.setBottomPanel(mIsOnlyAudio, true); + if (LOG) { + Log.v(TAG, "onVideoSizeChanged(" + width + ", " + height + ") mIsOnlyAudio=" + + mIsOnlyAudio); + } + } + public IMoviePlayer getMoviePlayerExt() { return mPlayerExt; } @@ -924,6 +1040,7 @@ public class MoviePlayer implements private void clearVideoInfo() { mVideoPosition = 0; mVideoLastDuration = 0; + mIsOnlyAudio = false; if (mServerTimeoutExt != null) { mServerTimeoutExt.clearServerInfo(); @@ -937,6 +1054,7 @@ public class MoviePlayer implements outState.putInt(KEY_VIDEO_STREAMING_TYPE, mStreamingType); outState.putString(KEY_VIDEO_STATE, String.valueOf(mTState)); mServerTimeoutExt.onSaveInstanceState(outState); + mScreenModeExt.onSaveInstanceState(outState); mRetryExt.onSaveInstanceState(outState); mPlayerExt.onSaveInstanceState(outState); } @@ -948,6 +1066,7 @@ public class MoviePlayer implements mStreamingType = icicle.getInt(KEY_VIDEO_STREAMING_TYPE); mTState = TState.valueOf(icicle.getString(KEY_VIDEO_STATE)); mServerTimeoutExt.onRestoreInstanceState(icicle); + mScreenModeExt.onRestoreInstanceState(icicle); mRetryExt.onRestoreInstanceState(icicle); mPlayerExt.onRestoreInstanceState(icicle); } @@ -974,6 +1093,26 @@ public class MoviePlayer implements } } + @Override + public void startNextVideo(IMovieItem item) { + IMovieItem next = item; + if (next != null && next != mMovieItem) { + int position = mVideoView.getCurrentPosition(); + int duration = mVideoView.getDuration(); + mBookmarker.setBookmark(mMovieItem.getUri(), position, duration); + mVideoView.stopPlayback(); + mVideoView.setVisibility(View.INVISIBLE); + clearVideoInfo(); + mMovieItem = next; + mActivityContext.refreshMovieInfo(mMovieItem); + doStartVideo(false, 0, 0); + mVideoView.setVisibility(View.VISIBLE); + } else { + Log.e(TAG, "Cannot play the next video! " + item); + } + mActivityContext.closeOptionsMenu(); + } + @Override public void onRestoreInstanceState(Bundle icicle) { mIsLoop = icicle.getBoolean(KEY_VIDEO_IS_LOOP, false); @@ -1003,6 +1142,7 @@ public class MoviePlayer implements mFirstBePlayed = false; mController.setCanReplay(true); mController.showEnded(); + mController.setViewEnabled(true); setProgress(); } @@ -1010,7 +1150,7 @@ public class MoviePlayer implements public boolean canStop() { boolean stopped = false; if (mController != null) { - //stopped = mOverlayExt.isPlayingEnd(); + stopped = mOverlayExt.isPlayingEnd(); } if (LOG) { Log.v(TAG, "canStop() stopped=" + stopped); @@ -1281,6 +1421,145 @@ public class MoviePlayer implements mServerTimeout = timeout; } } + + private class ScreenModeExt implements Restorable, ScreenModeListener { + private static final String KEY_VIDEO_SCREEN_MODE = "video_screen_mode"; + private int mScreenMode = ScreenModeManager.SCREENMODE_BIGSCREEN; + private ScreenModeManager mScreenModeManager = new ScreenModeManager(); + + public void setScreenMode() { + mVideoView.setScreenModeManager(mScreenModeManager); + mController.setScreenModeManager(mScreenModeManager); + mScreenModeManager.addListener(this); + //notify all listener to change screen mode + mScreenModeManager.setScreenMode(mScreenMode); + if (LOG) { + Log.v(TAG, "setScreenMode() mScreenMode=" + mScreenMode); + } + } + + @Override + public void onScreenModeChanged(int newMode) { + mScreenMode = newMode;// changed from controller + if (LOG) { + Log.v(TAG, "OnScreenModeClicked(" + newMode + ")"); + } + } + + @Override + public void onRestoreInstanceState(Bundle icicle) { + mScreenMode = icicle.getInt(KEY_VIDEO_SCREEN_MODE, + ScreenModeManager.SCREENMODE_BIGSCREEN); + } + + @Override + public void onSaveInstanceState(Bundle outState) { + outState.putInt(KEY_VIDEO_SCREEN_MODE, mScreenMode); + } + } + + private class ControllerRewindAndForwardExt implements IRewindAndForwardListener { + @Override + public void onPlayPause() { + onPlayPause(); + } + + @Override + public void onSeekStart() { + onSeekStart(); + } + + @Override + public void onSeekMove(int time) { + onSeekMove(time); + } + + @Override + public void onSeekEnd(int time, int trimStartTime, int trimEndTime) { + onSeekEnd(time, trimStartTime, trimEndTime); + } + + @Override + public void onShown() { + onShown(); + } + + @Override + public void onHidden() { + onHidden(); + } + + @Override + public void onReplay() { + onReplay(); + } + + @Override + public boolean onIsRTSP() { + return false; + } + + @Override + public void onStopVideo() { + Log.v(TAG, "ControllerRewindAndForwardExt onStopVideo()"); + if (mPlayerExt.canStop()) { + mPlayerExt.stopVideo(); + mControllerRewindAndForwardExt.showControllerButtonsView(false, + false, false); + } + } + + @Override + public void onRewind() { + Log.v(TAG, "ControllerRewindAndForwardExt onRewind()"); + if (mVideoView != null && mVideoView.canSeekBackward()) { + mControllerRewindAndForwardExt.showControllerButtonsView(mPlayerExt + .canStop(), + false, false); + int stepValue = getStepOptionValue(); + int targetDuration = mVideoView.getCurrentPosition() + - stepValue < 0 ? 0 : mVideoView.getCurrentPosition() + - stepValue; + Log.v(TAG, "onRewind targetDuration " + targetDuration); + mVideoView.seekTo(targetDuration); + } else { + mControllerRewindAndForwardExt.showControllerButtonsView(mPlayerExt + .canStop(), + false, false); + } + } + + @Override + public void onForward() { + Log.v(TAG, "ControllerRewindAndForwardExt onForward()"); + if (mVideoView != null && mVideoView.canSeekForward()) { + mControllerRewindAndForwardExt.showControllerButtonsView(mPlayerExt + .canStop(), + false, false); + int stepValue = getStepOptionValue(); + int targetDuration = mVideoView.getCurrentPosition() + + stepValue > mVideoView.getDuration() ? mVideoView + .getDuration() : mVideoView.getCurrentPosition() + + stepValue; + Log.v(TAG, "onForward targetDuration " + targetDuration); + mVideoView.seekTo(targetDuration); + } else { + mControllerRewindAndForwardExt.showControllerButtonsView(mPlayerExt + .canStop(), + false, false); + } + } + } + + public int getStepOptionValue() { + final String slectedStepOption = "selected_step_option"; + final String videoPlayerData = "video_player_data"; + final int stepBase = 3000; + final int stepOptionThreeSeconds = 0; + SharedPreferences mPrefs = mContext.getSharedPreferences( + videoPlayerData, 0); + return (mPrefs.getInt(slectedStepOption, stepOptionThreeSeconds) + 1) * stepBase; + } } class Bookmarker { diff --git a/src/com/android/gallery3d/app/TimeBar.java b/src/com/android/gallery3d/app/TimeBar.java old mode 100644 new mode 100755 index 246346a56..1b9ac24ed --- a/src/com/android/gallery3d/app/TimeBar.java +++ b/src/com/android/gallery3d/app/TimeBar.java @@ -23,6 +23,7 @@ import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.Rect; import android.util.DisplayMetrics; +import android.util.Log; import android.view.MotionEvent; import android.view.View; @@ -51,6 +52,10 @@ public class TimeBar extends View { private static final int TEXT_SIZE_IN_DP = 14; + private static final String TAG = "Gallery3D/TimeBar"; + private static final boolean LOG = true; + public static final int UNKNOWN = -1; + protected final Listener mListener; // the bars we use for displaying the progress @@ -71,6 +76,7 @@ public class TimeBar extends View { protected boolean mScrubbing; protected boolean mShowTimes; protected boolean mShowScrubber; + private boolean mEnableScrubbing; protected int mTotalTime; protected int mCurrentTime; @@ -78,6 +84,11 @@ public class TimeBar extends View { protected final Rect mTimeBounds; protected int mVPaddingInPx; + private int mLastShowTime = UNKNOWN; + + private ITimeBarSecondaryProgressExt mSecondaryProgressExt = new TimeBarSecondaryProgressExtImpl(); + private ITimeBarInfoExt mInfoExt = new TimeBarInfoExtImpl(); + private ITimeBarLayoutExt mLayoutExt = new TimeBarLayoutExtImpl(); public TimeBar(Context context, Listener listener) { super(context); @@ -102,12 +113,14 @@ public class TimeBar extends View { mTimeTextPaint.setTextAlign(Paint.Align.CENTER); mTimeBounds = new Rect(); - mTimeTextPaint.getTextBounds("0:00:00", 0, 7, mTimeBounds); mScrubber = BitmapFactory.decodeResource(getResources(), R.drawable.scrubber_knob); mScrubberPadding = (int) (metrics.density * SCRUBBER_PADDING_IN_DP); mVPaddingInPx = (int) (metrics.density * V_PADDING_IN_DP); + mLayoutExt.init(mScrubberPadding, mVPaddingInPx); + mInfoExt.init(textSizeInPx); + mSecondaryProgressExt.init(); } private void update() { @@ -115,7 +128,15 @@ public class TimeBar extends View { if (mTotalTime > 0) { mPlayedBar.right = - mPlayedBar.left + (int) ((mProgressBar.width() * (long) mCurrentTime) / mTotalTime); + mPlayedBar.left + + (int) ((mProgressBar.width() * (long) mCurrentTime) / mTotalTime); + /* + * M: if duration is not accurate, here just adjust playedBar we + * also show the accurate position text to final user. + */ + if (mPlayedBar.right > mProgressBar.right) { + mPlayedBar.right = mProgressBar.right; + } } else { mPlayedBar.right = mProgressBar.left; } @@ -123,6 +144,9 @@ public class TimeBar extends View { if (!mScrubbing) { mScrubberLeft = mPlayedBar.right - mScrubber.getWidth() / 2; } + // update text bounds when layout changed or time changed + updateBounds(); + mInfoExt.updateVisibleText(this, mProgressBar, mTimeBounds); invalidate(); } @@ -130,14 +154,16 @@ public class TimeBar extends View { * @return the preferred height of this view, including invisible padding */ public int getPreferredHeight() { - return mTimeBounds.height() + mVPaddingInPx + mScrubberPadding; + int preferredHeight = mTimeBounds.height() + mVPaddingInPx + mScrubberPadding; + return mLayoutExt.getPreferredHeight(preferredHeight, mTimeBounds); } /** * @return the height of the time bar, excluding invisible padding */ public int getBarHeight() { - return mTimeBounds.height() + mVPaddingInPx; + int barHeight = mTimeBounds.height() + mVPaddingInPx; + return mLayoutExt.getBarHeight(barHeight, mTimeBounds); } public void setTime(int currentTime, int totalTime, @@ -146,7 +172,10 @@ public class TimeBar extends View { return; } mCurrentTime = currentTime; - mTotalTime = totalTime; + mTotalTime = Math.abs(totalTime); + if (totalTime <= 0) { /// M: disable scrubbing before mediaplayer ready. + setScrubbing(false); + } update(); } @@ -180,7 +209,8 @@ public class TimeBar extends View { if (mShowTimes) { margin += mTimeBounds.width(); } - int progressY = (h + mScrubberPadding) / 2; + margin = mLayoutExt.getProgressMargin(margin); + int progressY = (h + mScrubberPadding) / 2 + mLayoutExt.getProgressOffset(mTimeBounds); mScrubberTop = progressY - mScrubber.getHeight() / 2 + 1; mProgressBar.set( getPaddingLeft() + margin, progressY, @@ -191,8 +221,10 @@ public class TimeBar extends View { @Override protected void onDraw(Canvas canvas) { + super.onDraw(canvas); // draw progress bars canvas.drawRect(mProgressBar, mProgressPaint); + mSecondaryProgressExt.draw(canvas, mProgressBar); canvas.drawRect(mPlayedBar, mPlayedPaint); // draw scrubber and timers @@ -202,20 +234,29 @@ public class TimeBar extends View { if (mShowTimes) { canvas.drawText( stringForTime(mCurrentTime), - mTimeBounds.width() / 2 + getPaddingLeft(), - mTimeBounds.height() + mVPaddingInPx / 2 + mScrubberPadding + 1, + mTimeBounds.width() / 2 + getPaddingLeft(), + mTimeBounds.height() + mVPaddingInPx / 2 + mScrubberPadding + 1 + + mLayoutExt.getTimeOffset(), mTimeTextPaint); canvas.drawText( stringForTime(mTotalTime), - getWidth() - getPaddingRight() - mTimeBounds.width() / 2, - mTimeBounds.height() + mVPaddingInPx / 2 + mScrubberPadding + 1, + getWidth() - getPaddingRight() - mTimeBounds.width() / 2, + mTimeBounds.height() + mVPaddingInPx / 2 + mScrubberPadding + 1 + + mLayoutExt.getTimeOffset(), mTimeTextPaint); } + mInfoExt.draw(canvas, mLayoutExt.getInfoBounds(this, mTimeBounds)); } @Override public boolean onTouchEvent(MotionEvent event) { - if (mShowScrubber) { + if (LOG) { + Log.v(TAG, "onTouchEvent() showScrubber=" + mShowScrubber + + ", enableScrubbing=" + mEnableScrubbing + ", totalTime=" + + mTotalTime + ", scrubbing=" + mScrubbing + ", event=" + + event); + } + if (mShowScrubber && mEnableScrubbing) { int x = (int) event.getX(); int y = (int) event.getY(); @@ -233,15 +274,19 @@ public class TimeBar extends View { clampScrubber(); mCurrentTime = getScrubberTime(); mListener.onScrubbingMove(mCurrentTime); + update(); invalidate(); return true; } case MotionEvent.ACTION_CANCEL: - case MotionEvent.ACTION_UP: { - mListener.onScrubbingEnd(getScrubberTime(), 0, 0); - mScrubbing = false; - return true; - } + case MotionEvent.ACTION_UP: + if (mScrubbing) { + mListener.onScrubbingEnd(getScrubberTime(), 0, 0); + mScrubbing = false; + update(); + return true; + } + break; } } return false; @@ -263,4 +308,235 @@ public class TimeBar extends View { mShowScrubber = canSeek; } + private void updateBounds() { + int showTime = mTotalTime > mCurrentTime ? mTotalTime : mCurrentTime; + if (mLastShowTime == showTime) { + // do not need to recompute the bounds. + return; + } + String durationText = stringForTime(showTime); + int length = durationText.length(); + mTimeTextPaint.getTextBounds(durationText, 0, length, mTimeBounds); + mLastShowTime = showTime; + if (LOG) { + Log.v(TAG, "updateBounds() durationText=" + durationText + ", timeBounds=" + + mTimeBounds); + } + } + + public void setScrubbing(boolean enable) { + if (LOG) { + Log.v(TAG, "setScrubbing(" + enable + ") scrubbing=" + mScrubbing); + } + mEnableScrubbing = enable; + if (mScrubbing) { // if it is scrubbing, change it to false + mListener.onScrubbingEnd(getScrubberTime(), 0, 0); + mScrubbing = false; + } + } + + public boolean getScrubbing() { + if (LOG) { + Log.v(TAG, "mEnableScrubbing=" + mEnableScrubbing); + } + return mEnableScrubbing; + } + + public void setInfo(String info) { + if (LOG) { + Log.v(TAG, "setInfo(" + info + ")"); + } + mInfoExt.setInfo(info); + mInfoExt.updateVisibleText(this, mProgressBar, mTimeBounds); + invalidate(); + } + + public void setSecondaryProgress(int percent) { + if (LOG) { + Log.v(TAG, "setSecondaryProgress(" + percent + ")"); + } + mSecondaryProgressExt.setSecondaryProgress(mProgressBar, percent); + invalidate(); + } +} + +interface ITimeBarInfoExt { + void init(float textSizeInPx); + + void setInfo(String info); + + void draw(Canvas canvas, Rect infoBounds); + + void updateVisibleText(View parent, Rect progressBar, Rect timeBounds); +} + +interface ITimeBarSecondaryProgressExt { + void init(); + + void setSecondaryProgress(Rect progressBar, int percent); + + void draw(Canvas canvas, Rect progressBounds); +} + +interface ITimeBarLayoutExt { + void init(int scrubberPadding, int vPaddingInPx); + + int getPreferredHeight(int originalPreferredHeight, Rect timeBounds); + + int getBarHeight(int originalBarHeight, Rect timeBounds); + + int getProgressMargin(int originalMargin); + + int getProgressOffset(Rect timeBounds); + + int getTimeOffset(); + + Rect getInfoBounds(View parent, Rect timeBounds); +} + +class TimeBarInfoExtImpl implements ITimeBarInfoExt { + private static final String TAG = "TimeBarInfoExtensionImpl"; + private static final boolean LOG = true; + private static final String ELLIPSE = "..."; + + private Paint mInfoPaint; + private Rect mInfoBounds; + private String mInfoText; + private String mVisibleText; + private int mEllipseLength; + + @Override + public void init(float textSizeInPx) { + mInfoPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + mInfoPaint.setColor(0xFFCECECE); + mInfoPaint.setTextSize(textSizeInPx); + mInfoPaint.setTextAlign(Paint.Align.CENTER); + + mEllipseLength = (int) Math.ceil(mInfoPaint.measureText(ELLIPSE)); + } + + @Override + public void draw(Canvas canvas, Rect infoBounds) { + if (mInfoText != null && mVisibleText != null) { + canvas.drawText(mVisibleText, infoBounds.centerX(), infoBounds.centerY(), mInfoPaint); + } + } + + @Override + public void setInfo(String info) { + mInfoText = info; + } + + public void updateVisibleText(View parent, Rect progressBar, Rect timeBounds) { + if (mInfoText == null) { + mVisibleText = null; + return; + } + float tw = mInfoPaint.measureText(mInfoText); + float space = progressBar.width() - timeBounds.width() * 2 - parent.getPaddingLeft() + - parent.getPaddingRight(); + if (tw > 0 && space > 0 && tw > space) { + // we need to cut the info text for visible + float originalNum = mInfoText.length(); + int realNum = (int) ((space - mEllipseLength) * originalNum / tw); + if (LOG) { + Log.v(TAG, "updateVisibleText() infoText=" + mInfoText + " text width=" + tw + + ", space=" + space + ", originalNum=" + originalNum + ", realNum=" + + realNum + + ", getPaddingLeft()=" + parent.getPaddingLeft() + ", getPaddingRight()=" + + parent.getPaddingRight() + + ", progressBar=" + progressBar + ", timeBounds=" + timeBounds); + } + mVisibleText = mInfoText.substring(0, realNum) + ELLIPSE; + } else { + mVisibleText = mInfoText; + } + if (LOG) { + Log.v(TAG, "updateVisibleText() infoText=" + mInfoText + ", visibleText=" + + mVisibleText + + ", text width=" + tw + ", space=" + space); + } + } +} + +class TimeBarSecondaryProgressExtImpl implements ITimeBarSecondaryProgressExt { + private static final String TAG = "TimeBarSecondaryProgressExtensionImpl"; + private static final boolean LOG = true; + + private int mBufferPercent; + private Rect mSecondaryBar; + private Paint mSecondaryPaint; + + @Override + public void init() { + mSecondaryBar = new Rect(); + mSecondaryPaint = new Paint(); + mSecondaryPaint.setColor(0xFF5CA0C5); + } + + @Override + public void draw(Canvas canvas, Rect progressBounds) { + if (mBufferPercent >= 0) { + mSecondaryBar.set(progressBounds); + mSecondaryBar.right = mSecondaryBar.left + + (int) (mBufferPercent * progressBounds.width() / 100); + canvas.drawRect(mSecondaryBar, mSecondaryPaint); + } + if (LOG) { + Log.v(TAG, "draw() bufferPercent=" + mBufferPercent + ", secondaryBar=" + + mSecondaryBar); + } + } + + @Override + public void setSecondaryProgress(Rect progressBar, int percent) { + mBufferPercent = percent; + } +} + +class TimeBarLayoutExtImpl implements ITimeBarLayoutExt { + private static final String TAG = "TimeBarLayoutExtensionImpl"; + private static final boolean LOG = true; + + private int mTextPadding; + private int mVPaddingInPx; + + @Override + public void init(int scrubberPadding, int vPaddingInPx) { + mTextPadding = scrubberPadding / 2; + mVPaddingInPx = vPaddingInPx; + } + + @Override + public int getPreferredHeight(int originalPreferredHeight, Rect timeBounds) { + return originalPreferredHeight + timeBounds.height() + mTextPadding; + } + + @Override + public int getBarHeight(int originalBarHeight, Rect timeBounds) { + return originalBarHeight + timeBounds.height() + mTextPadding; + } + + @Override + public int getProgressMargin(int originalMargin) { + return 0; + } + + @Override + public int getProgressOffset(Rect timeBounds) { + return (timeBounds.height() + mTextPadding) / 2; + } + + @Override + public int getTimeOffset() { + return mTextPadding - mVPaddingInPx / 2; + } + + @Override + public Rect getInfoBounds(View parent, Rect timeBounds) { + Rect bounds = new Rect(parent.getPaddingLeft(), 0, + parent.getWidth() - parent.getPaddingRight(), + (timeBounds.height() + mTextPadding * 3 + 1) * 2); + return bounds; + } } diff --git a/src/com/android/gallery3d/app/TrimControllerOverlay.java b/src/com/android/gallery3d/app/TrimControllerOverlay.java index cae016626..9d2e7aee1 100644 --- a/src/com/android/gallery3d/app/TrimControllerOverlay.java +++ b/src/com/android/gallery3d/app/TrimControllerOverlay.java @@ -108,4 +108,14 @@ public class TrimControllerOverlay extends CommonControllerOverlay { } return true; } + + @Override + public void setViewEnabled(boolean isEnabled) { + // TODO Auto-generated method stub + } + + @Override + public void setPlayPauseReplayResume() { + // TODO Auto-generated method stub + } } diff --git a/src/com/qcom/gallery3d/ext/IContrllerOverlayExt.java b/src/com/qcom/gallery3d/ext/IContrllerOverlayExt.java deleted file mode 100755 index 134d208df..000000000 --- a/src/com/qcom/gallery3d/ext/IContrllerOverlayExt.java +++ /dev/null @@ -1,51 +0,0 @@ -package com.qcom.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/com/qcom/gallery3d/ext/IMovieList.java b/src/com/qcom/gallery3d/ext/IMovieList.java deleted file mode 100755 index f58aab059..000000000 --- a/src/com/qcom/gallery3d/ext/IMovieList.java +++ /dev/null @@ -1,46 +0,0 @@ -package com.qcom.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/com/qcom/gallery3d/ext/IMovieListLoader.java b/src/com/qcom/gallery3d/ext/IMovieListLoader.java deleted file mode 100755 index 06b2f769e..000000000 --- a/src/com/qcom/gallery3d/ext/IMovieListLoader.java +++ /dev/null @@ -1,50 +0,0 @@ -package com.qcom.gallery3d.ext; - -import android.content.Context; -import android.content.Intent; - -public interface IMovieListLoader { - /** - * Load all video list or not.[boolean] - * "yes" means load all videos in all storages. - * "false" means load videos located in current video's folder. - */ - String EXTRA_ALL_VIDEO_FOLDER = "qcom.intent.extra.ALL_VIDEO_FOLDER"; - /** - * Video list order by column name.[String] - */ - String EXTRA_ORDERBY = "qcom.intent.extra.VIDEO_LIST_ORDERBY"; - /** - * Enable video list or not.[boolean] - */ - String EXTRA_ENABLE_VIDEO_LIST = "qcom.intent.extra.ENABLE_VIDEO_LIST"; - /** - * Loader listener interface - */ - public interface LoaderListener { - /** - * Will be called after movie list loaded. - * @param movieList - */ - void onListLoaded(IMovieList movieList); - } - /** - * Build the movie list from current item. - * @param context - * @param intent - * @param l - * @param item - */ - void fillVideoList(Context context, Intent intent, LoaderListener l, IMovieItem item); - /** - * enable video list or not. - * @param intent - * @return - */ - boolean isEnabledVideoList(Intent intent); - /** - * Cancel current loading process. - */ - void cancelList(); - -} diff --git a/src/com/qcom/gallery3d/ext/MovieList.java b/src/com/qcom/gallery3d/ext/MovieList.java deleted file mode 100755 index eeb7e8734..000000000 --- a/src/com/qcom/gallery3d/ext/MovieList.java +++ /dev/null @@ -1,70 +0,0 @@ -package com.qcom.gallery3d.ext; - -import java.util.ArrayList; - -public class MovieList implements IMovieList { - private static final String TAG = "MovieList"; - private static final boolean LOG = true; - - private final ArrayList mItems = new ArrayList(); - private static final int UNKNOWN = -1; - - @Override - public void add(IMovieItem item) { - if (LOG) { - QcomLog.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) { - QcomLog.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; - } -} \ No newline at end of file diff --git a/src/com/qcom/gallery3d/ext/MovieListLoader.java b/src/com/qcom/gallery3d/ext/MovieListLoader.java deleted file mode 100755 index 655beee83..000000000 --- a/src/com/qcom/gallery3d/ext/MovieListLoader.java +++ /dev/null @@ -1,201 +0,0 @@ -package com.qcom.gallery3d.ext; - -import android.content.ContentResolver; -import android.content.ContentUris; -import android.content.Context; -import android.content.Intent; -import android.database.Cursor; -import android.database.sqlite.SQLiteException; -import android.net.Uri; -import android.os.AsyncTask; -import android.provider.MediaStore; -import android.provider.OpenableColumns; -/** - * Movie list loader class. It will load videos from MediaProvider database. - * If MoviePlayer starting activity doesn't set any thing, default OrderBy will be used. - * Default OrderBy: MediaStore.Video.Media.DATE_TAKEN + " DESC, " + MediaStore.Video.Media._ID + " DESC "; - */ -public class MovieListLoader implements IMovieListLoader { - private static final String TAG = "MovieListLoader"; - private static final boolean LOG = true; - - private MovieListFetcherTask mListTask; - - @Override - public void fillVideoList(Context context, Intent intent, LoaderListener l, IMovieItem item) { - boolean fetechAll = false; - if (intent.hasExtra(EXTRA_ALL_VIDEO_FOLDER)) { - fetechAll = intent.getBooleanExtra(EXTRA_ALL_VIDEO_FOLDER, false); - } - //default order by - String orderBy = MediaStore.Video.Media.DATE_TAKEN + " DESC, " + MediaStore.Video.Media._ID + " DESC "; - if (intent.hasExtra(EXTRA_ORDERBY)) { - orderBy = intent.getStringExtra(EXTRA_ORDERBY); - } - cancelList(); - mListTask = new MovieListFetcherTask(context, fetechAll, l, orderBy); - mListTask.execute(item); - if (LOG) { - QcomLog.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) { - QcomLog.v(TAG, "isEnabledVideoList() return " + enable); - } - return enable; - } - - @Override - public void cancelList() { - if (mListTask != null) { - mListTask.cancel(true); - } - } - - private class MovieListFetcherTask extends AsyncTask { - private static final String TAG = "MovieListFetcherTask"; - private static final boolean LOG = true; - - // TODO comments by sunlei -// public static final String COLUMN_STEREO_TYPE = MediaStore.Video.Media.STEREO_TYPE; -// public static final String COLUMN_STEREO_TYPE = "STEREO_TYPE"; - - private final ContentResolver mCr; - private final LoaderListener mFetecherListener; - private final boolean mFetechAll; - private final String mOrderBy; - - public MovieListFetcherTask(Context context, boolean fetechAll, LoaderListener l, String orderBy) { - mCr = context.getContentResolver(); - mFetecherListener = l; - mFetechAll = fetechAll; - mOrderBy = orderBy; - if (LOG) { - QcomLog.v(TAG, "MovieListFetcherTask() fetechAll=" + fetechAll + ", orderBy=" + orderBy); - } - } - - @Override - protected void onPostExecute(IMovieList params) { - if (LOG) { - QcomLog.v(TAG, "onPostExecute() isCancelled()=" + isCancelled()); - } - if (isCancelled()) { - return; - } - if (mFetecherListener != null) { - mFetecherListener.onListLoaded(params); - } - } - - @Override - protected IMovieList doInBackground(IMovieItem... params) { - if (LOG) { - QcomLog.v(TAG, "doInBackground() begin"); - } - if (params[0] == null) { - return null; - } - IMovieList movieList = null; - Uri uri = params[0].getUri(); - String mime = params[0].getMimeType(); - if (mFetechAll) { //get all list - if (MovieUtils.isLocalFile(uri, mime)) { - String uristr = String.valueOf(uri); - if (uristr.toLowerCase().startsWith("content://media")) { - //from gallery, gallery3D, videoplayer - long curId = Long.parseLong(uri.getPathSegments().get(3)); - movieList = fillUriList(null, null, curId, params[0]); - } - } - } else { //get current list - if (MovieUtils.isLocalFile(uri, mime)) { - String uristr = String.valueOf(uri); - if (uristr.toLowerCase().startsWith("content://media")) { - Cursor cursor = mCr.query(uri, - new String[]{MediaStore.Video.Media.BUCKET_ID}, - null, null, null); - long bucketId = -1; - if (cursor != null) { - if (cursor.moveToFirst()) { - bucketId = cursor.getLong(0); - } - cursor.close(); - } - long curId = Long.parseLong(uri.getPathSegments().get(3)); - movieList = fillUriList(MediaStore.Video.Media.BUCKET_ID + "=? ", - new String[]{String.valueOf(bucketId)}, curId, params[0]); - } else if (uristr.toLowerCase().startsWith("file://")) { - String data = Uri.decode(uri.toString()); - data = data.replaceAll("'", "''"); - String where = "_data LIKE '%" + data.replaceFirst("file:///", "") + "'"; - Cursor cursor = mCr.query(MediaStore.Video.Media.EXTERNAL_CONTENT_URI, - new String[]{"_id", MediaStore.Video.Media.BUCKET_ID}, - where, null, null); - long bucketId = -1; - long curId = -1; - if (cursor != null) { - if (cursor.moveToFirst()) { - curId = cursor.getLong(0); - bucketId = cursor.getLong(1); - } - cursor.close(); - } - movieList = fillUriList(MediaStore.Video.Media.BUCKET_ID + "=? ", - new String[]{String.valueOf(bucketId)}, curId, params[0]); - } - } - } - if (LOG) { - QcomLog.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) { - QcomLog.v(TAG, "fillUriList() cursor=" + cursor + ", return " + movieList); - } - return movieList; - } - } -} \ No newline at end of file diff --git a/src/com/qcom/gallery3d/video/IControllerRewindAndForward.java b/src/com/qcom/gallery3d/video/IControllerRewindAndForward.java deleted file mode 100755 index 39316b165..000000000 --- a/src/com/qcom/gallery3d/video/IControllerRewindAndForward.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * 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 com.qcom.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/com/qcom/gallery3d/video/MovieListHooker.java b/src/com/qcom/gallery3d/video/MovieListHooker.java deleted file mode 100755 index 8a5c487af..000000000 --- a/src/com/qcom/gallery3d/video/MovieListHooker.java +++ /dev/null @@ -1,116 +0,0 @@ -package com.qcom.gallery3d.video; - -import android.os.Bundle; -import android.view.Menu; -import android.view.MenuItem; - -import com.android.gallery3d.R; -import com.qcom.gallery3d.ext.IMovieItem; -import com.qcom.gallery3d.ext.IMovieList; -import com.qcom.gallery3d.ext.IMovieListLoader; -import com.qcom.gallery3d.ext.IMovieListLoader.LoaderListener; -import com.qcom.gallery3d.ext.MovieListLoader; -import com.qcom.gallery3d.ext.QcomLog; - -public class MovieListHooker extends MovieHooker implements LoaderListener { - private static final String TAG = "MovieListHooker"; - private static final boolean LOG = true; - - private static final int MENU_NEXT = 1; - private static final int MENU_PREVIOUS = 2; - - private MenuItem mMenuNext; - private MenuItem mMenuPrevious; - - private IMovieListLoader mMovieLoader; - private IMovieList mMovieList; - - @Override - public void onCreate(final Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - mMovieLoader = new MovieListLoader(); - mMovieLoader.fillVideoList(getContext(), getIntent(), this, getMovieItem()); - } - @Override - public void onDestroy() { - super.onDestroy(); - mMovieLoader.cancelList(); - } - @Override - public boolean onCreateOptionsMenu(final Menu menu) { - super.onCreateOptionsMenu(menu); - if (mMovieList != null) { //list should be filled - if (mMovieLoader != null && mMovieLoader.isEnabledVideoList(getIntent())) { - mMenuPrevious = menu.add(0, getMenuActivityId(MENU_PREVIOUS), 0, R.string.previous); - mMenuNext = menu.add(0, getMenuActivityId(MENU_NEXT), 0, R.string.next); - } - } - return true; - } - @Override - public boolean onPrepareOptionsMenu(final Menu menu) { - super.onPrepareOptionsMenu(menu); - updatePrevNext(); - return true; - } - @Override - public boolean onOptionsItemSelected(final MenuItem item) { - super.onOptionsItemSelected(item); - switch(getMenuOriginalId(item.getItemId())) { - case MENU_PREVIOUS: - if (mMovieList == null) { - return false; - } - getPlayer().startNextVideo(mMovieList.getPrevious(getMovieItem())); - return true; - case MENU_NEXT: - if (mMovieList == null) { - return false; - } - getPlayer().startNextVideo(mMovieList.getNext(getMovieItem())); - return true; - default: - return false; - } - } - - @Override - public void onMovieItemChanged(final IMovieItem item) { - super.onMovieItemChanged(item); - updatePrevNext(); - } - - private void updatePrevNext() { - if (LOG) { - QcomLog.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) { - QcomLog.v(TAG, "onListLoaded() " + (mMovieList != null ? mMovieList.size() : "null")); - } - } -} \ No newline at end of file diff --git a/src/com/qcom/gallery3d/video/ScreenModeManager.java b/src/com/qcom/gallery3d/video/ScreenModeManager.java deleted file mode 100755 index 73f60520a..000000000 --- a/src/com/qcom/gallery3d/video/ScreenModeManager.java +++ /dev/null @@ -1,117 +0,0 @@ -package com.qcom.gallery3d.video; - -import com.qcom.gallery3d.ext.QcomLog; - -import java.util.ArrayList; - -public class ScreenModeManager { - private static final String TAG = "ScreenModeManager"; - private static final boolean LOG = true; - //support screen mode. - public static final int SCREENMODE_BIGSCREEN = 1; - public static final int SCREENMODE_FULLSCREEN = 2; - public static final int SCREENMODE_CROPSCREEN = 4; - public static final int SCREENMODE_ALL = 7; - - private int mScreenMode = SCREENMODE_BIGSCREEN; - private int mScreenModes = SCREENMODE_ALL; - - /** - * Enable specified screen mode list. - * The screen mode's value determines the order of being shown. - *
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}. - *
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; - QcomLog.w(TAG, "wrong screenModes=" + screenModes + ". use default value " + SCREENMODE_ALL); - } - if (LOG) { - QcomLog.v(TAG, "enableScreenMode(" + screenModes + ") mScreenModes=" + mScreenModes); - } - } - - /** - * Get the all screen modes of media controller. - *
Note: 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) { - QcomLog.v(TAG, "setScreenMode(" + curScreenMode + ")"); - } - mScreenMode = curScreenMode; - for (final ScreenModeListener listener : mListeners) { - listener.onScreenModeChanged(curScreenMode); - } - } - - public int getScreenMode() { - if (LOG) { - QcomLog.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) { - QcomLog.v(TAG, "getNextScreenMode() = " + mode); - } - return mode; - } - - private final ArrayList mListeners = new ArrayList(); - public void addListener(final ScreenModeListener l) { - if (!mListeners.contains(l)) { - mListeners.add(l); - } - if (LOG) { - QcomLog.v(TAG, "addListener(" + l + ")"); - } - } - - public void removeListener(final ScreenModeListener l) { - mListeners.remove(l); - if (LOG) { - QcomLog.v(TAG, "removeListener(" + l + ")"); - } - } - - public void clear() { - mListeners.clear(); - } - - public interface ScreenModeListener { - void onScreenModeChanged(int newMode); - } -} diff --git a/src/com/qcom/gallery3d/video/StepOptionDialogFragment.java b/src/com/qcom/gallery3d/video/StepOptionDialogFragment.java deleted file mode 100755 index 0daed55f6..000000000 --- a/src/com/qcom/gallery3d/video/StepOptionDialogFragment.java +++ /dev/null @@ -1,83 +0,0 @@ -package com.qcom.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/com/qcom/gallery3d/video/StepOptionSettingsHooker.java b/src/com/qcom/gallery3d/video/StepOptionSettingsHooker.java deleted file mode 100755 index ecc29670c..000000000 --- a/src/com/qcom/gallery3d/video/StepOptionSettingsHooker.java +++ /dev/null @@ -1,41 +0,0 @@ -package com.qcom.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 com.qcom.gallery3d.ext.ActivityHooker; -import com.qcom.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/com/qcom/gallery3d/video/VideoSettingsActivity.java b/src/com/qcom/gallery3d/video/VideoSettingsActivity.java deleted file mode 100755 index 98d5539fb..000000000 --- a/src/com/qcom/gallery3d/video/VideoSettingsActivity.java +++ /dev/null @@ -1,182 +0,0 @@ -package com.qcom.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> arrlist = new ArrayList>(1); - HashMap map = new HashMap(); - 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; - } -} diff --git a/src/org/codeaurora/gallery3d/ext/IContrllerOverlayExt.java b/src/org/codeaurora/gallery3d/ext/IContrllerOverlayExt.java new file mode 100644 index 000000000..da50cdffc --- /dev/null +++ b/src/org/codeaurora/gallery3d/ext/IContrllerOverlayExt.java @@ -0,0 +1,51 @@ +package org.codeaurora.gallery3d.ext; +/** + * Controller overlay extension interface. + */ +public interface IContrllerOverlayExt { + /** + * Show buffering state. + * @param fullBuffer + * @param percent + */ + void showBuffering(boolean fullBuffer, int percent); + /** + * Clear buffering state. + */ + void clearBuffering(); + /** + * Show re-connecting state. + * @param times + */ + void showReconnecting(int times); + /** + * Show re-connecting error for connecting fail error. + */ + void showReconnectingError(); + /** + * Show playing info or not. + * @param liveStreaming true means showing playing info, otherwise doesn't show playing info. + */ + void setPlayingInfo(boolean liveStreaming); + /** + * Indicates whether current video can be paused or not. + * @param canPause + */ + void setCanPause(boolean canPause); + /** + * Indicates whether thumb can be scrubbed or not. + * @param enable + */ + void setCanScrubbing(boolean enable); + /** + * Always show bottmon panel or not. + * @param alwaysShow + * @param foreShow + */ + void setBottomPanel(boolean alwaysShow, boolean foreShow); + /** + * Is playing end or not. + * @return + */ + boolean isPlayingEnd(); +} diff --git a/src/org/codeaurora/gallery3d/ext/IMovieList.java b/src/org/codeaurora/gallery3d/ext/IMovieList.java new file mode 100644 index 000000000..404d24c41 --- /dev/null +++ b/src/org/codeaurora/gallery3d/ext/IMovieList.java @@ -0,0 +1,46 @@ +package org.codeaurora.gallery3d.ext; +/** + * Movie list extension interface + */ +public interface IMovieList { + /** + * Add movie item to list. + * @param item + */ + void add(IMovieItem item); + /** + * Get the item index of list + * @param item + * @return + */ + int index(IMovieItem item); + /** + * + * @return list size + */ + int size(); + /** + * + * @param item + * @return next item of current item + */ + IMovieItem getNext(IMovieItem item); + /** + * + * @param item + * @return previous item of current item + */ + IMovieItem getPrevious(IMovieItem item); + /** + * Is first item in list + * @param item + * @return + */ + boolean isFirst(IMovieItem item); + /** + * Is last item in list. + * @param item + * @return + */ + boolean isLast(IMovieItem item); +} \ No newline at end of file diff --git a/src/org/codeaurora/gallery3d/ext/IMovieListLoader.java b/src/org/codeaurora/gallery3d/ext/IMovieListLoader.java new file mode 100644 index 000000000..db4c71347 --- /dev/null +++ b/src/org/codeaurora/gallery3d/ext/IMovieListLoader.java @@ -0,0 +1,50 @@ +package org.codeaurora.gallery3d.ext; + +import android.content.Context; +import android.content.Intent; + +public interface IMovieListLoader { + /** + * Load all video list or not.[boolean] + * "yes" means load all videos in all storages. + * "false" means load videos located in current video's folder. + */ + String EXTRA_ALL_VIDEO_FOLDER = "org.codeaurora.intent.extra.ALL_VIDEO_FOLDER"; + /** + * Video list order by column name.[String] + */ + String EXTRA_ORDERBY = "org.codeaurora.intent.extra.VIDEO_LIST_ORDERBY"; + /** + * Enable video list or not.[boolean] + */ + String EXTRA_ENABLE_VIDEO_LIST = "org.codeaurora.intent.extra.ENABLE_VIDEO_LIST"; + /** + * Loader listener interface + */ + public interface LoaderListener { + /** + * Will be called after movie list loaded. + * @param movieList + */ + void onListLoaded(IMovieList movieList); + } + /** + * Build the movie list from current item. + * @param context + * @param intent + * @param l + * @param item + */ + void fillVideoList(Context context, Intent intent, LoaderListener l, IMovieItem item); + /** + * enable video list or not. + * @param intent + * @return + */ + boolean isEnabledVideoList(Intent intent); + /** + * Cancel current loading process. + */ + void cancelList(); + +} diff --git a/src/org/codeaurora/gallery3d/ext/IMoviePlayer.java b/src/org/codeaurora/gallery3d/ext/IMoviePlayer.java index 3013cbcb1..32d400b0d 100644 --- a/src/org/codeaurora/gallery3d/ext/IMoviePlayer.java +++ b/src/org/codeaurora/gallery3d/ext/IMoviePlayer.java @@ -32,4 +32,11 @@ public interface IMoviePlayer { * Stop current video. */ void stopVideo(); + + /** + * start current item and stop playing video. + * + * @param item + */ + void startNextVideo(IMovieItem item); } diff --git a/src/org/codeaurora/gallery3d/ext/MovieList.java b/src/org/codeaurora/gallery3d/ext/MovieList.java new file mode 100644 index 000000000..585e288ef --- /dev/null +++ b/src/org/codeaurora/gallery3d/ext/MovieList.java @@ -0,0 +1,72 @@ +package org.codeaurora.gallery3d.ext; + +import android.util.Log; + +import java.util.ArrayList; + +public class MovieList implements IMovieList { + private static final String TAG = "MovieList"; + private static final boolean LOG = true; + + private final ArrayList mItems = new ArrayList(); + private static final int UNKNOWN = -1; + + @Override + public void add(IMovieItem item) { + if (LOG) { + Log.v(TAG, "add(" + item + ")"); + } + mItems.add(item); + } + + @Override + public int index(IMovieItem item) { + int find = UNKNOWN; + int size = mItems.size(); + for (int i = 0; i < size; i++) { + if (item == mItems.get(i)) { + find = i; + break; + } + } + if (LOG) { + Log.v(TAG, "index(" + item + ") return " + find); + } + return find; + } + + @Override + public int size() { + return mItems.size(); + } + + @Override + public IMovieItem getNext(IMovieItem item) { + IMovieItem next = null; + int find = index(item); + if (find >= 0 && find < size() - 1) { + next = mItems.get(++find); + } + return next; + } + + @Override + public IMovieItem getPrevious(IMovieItem item) { + IMovieItem prev = null; + int find = index(item); + if (find > 0 && find < size()) { + prev = mItems.get(--find); + } + return prev; + } + + @Override + public boolean isFirst(IMovieItem item) { + return getPrevious(item) == null; + } + + @Override + public boolean isLast(IMovieItem item) { + return getNext(item) == null; + } +} diff --git a/src/org/codeaurora/gallery3d/ext/MovieListLoader.java b/src/org/codeaurora/gallery3d/ext/MovieListLoader.java new file mode 100644 index 000000000..cb3505650 --- /dev/null +++ b/src/org/codeaurora/gallery3d/ext/MovieListLoader.java @@ -0,0 +1,203 @@ +package org.codeaurora.gallery3d.ext; + +import android.content.ContentResolver; +import android.content.ContentUris; +import android.content.Context; +import android.content.Intent; +import android.database.Cursor; +import android.database.sqlite.SQLiteException; +import android.net.Uri; +import android.os.AsyncTask; +import android.provider.MediaStore; +import android.provider.OpenableColumns; +import android.util.Log; + +/** + * Movie list loader class. It will load videos from MediaProvider database. + * If MoviePlayer starting activity doesn't set any thing, default OrderBy will be used. + * Default OrderBy: MediaStore.Video.Media.DATE_TAKEN + " DESC, " + MediaStore.Video.Media._ID + " DESC "; + */ +public class MovieListLoader implements IMovieListLoader { + private static final String TAG = "MovieListLoader"; + private static final boolean LOG = true; + + private MovieListFetcherTask mListTask; + + @Override + public void fillVideoList(Context context, Intent intent, LoaderListener l, IMovieItem item) { + boolean fetechAll = false; + if (intent.hasExtra(EXTRA_ALL_VIDEO_FOLDER)) { + fetechAll = intent.getBooleanExtra(EXTRA_ALL_VIDEO_FOLDER, false); + } + //default order by + String orderBy = MediaStore.Video.Media.DATE_TAKEN + " DESC, " + MediaStore.Video.Media._ID + " DESC "; + if (intent.hasExtra(EXTRA_ORDERBY)) { + orderBy = intent.getStringExtra(EXTRA_ORDERBY); + } + cancelList(); + mListTask = new MovieListFetcherTask(context, fetechAll, l, orderBy); + mListTask.execute(item); + if (LOG) { + Log.v(TAG, "fillVideoList() fetechAll=" + fetechAll + ", orderBy=" + orderBy); + } + } + + @Override + public boolean isEnabledVideoList(Intent intent) { + boolean enable = true; + if (intent != null && intent.hasExtra(EXTRA_ENABLE_VIDEO_LIST)) { + enable = intent.getBooleanExtra(EXTRA_ENABLE_VIDEO_LIST, true); + } + if (LOG) { + Log.v(TAG, "isEnabledVideoList() return " + enable); + } + return enable; + } + + @Override + public void cancelList() { + if (mListTask != null) { + mListTask.cancel(true); + } + } + + private class MovieListFetcherTask extends AsyncTask { + private static final String TAG = "MovieListFetcherTask"; + private static final boolean LOG = true; + + // TODO comments by sunlei +// public static final String COLUMN_STEREO_TYPE = MediaStore.Video.Media.STEREO_TYPE; +// public static final String COLUMN_STEREO_TYPE = "STEREO_TYPE"; + + private final ContentResolver mCr; + private final LoaderListener mFetecherListener; + private final boolean mFetechAll; + private final String mOrderBy; + + public MovieListFetcherTask(Context context, boolean fetechAll, LoaderListener l, String orderBy) { + mCr = context.getContentResolver(); + mFetecherListener = l; + mFetechAll = fetechAll; + mOrderBy = orderBy; + if (LOG) { + Log.v(TAG, "MovieListFetcherTask() fetechAll=" + fetechAll + ", orderBy=" + orderBy); + } + } + + @Override + protected void onPostExecute(IMovieList params) { + if (LOG) { + Log.v(TAG, "onPostExecute() isCancelled()=" + isCancelled()); + } + if (isCancelled()) { + return; + } + if (mFetecherListener != null) { + mFetecherListener.onListLoaded(params); + } + } + + @Override + protected IMovieList doInBackground(IMovieItem... params) { + if (LOG) { + Log.v(TAG, "doInBackground() begin"); + } + if (params[0] == null) { + return null; + } + IMovieList movieList = null; + Uri uri = params[0].getUri(); + String mime = params[0].getMimeType(); + if (mFetechAll) { //get all list + if (MovieUtils.isLocalFile(uri, mime)) { + String uristr = String.valueOf(uri); + if (uristr.toLowerCase().startsWith("content://media")) { + //from gallery, gallery3D, videoplayer + long curId = Long.parseLong(uri.getPathSegments().get(3)); + movieList = fillUriList(null, null, curId, params[0]); + } + } + } else { //get current list + if (MovieUtils.isLocalFile(uri, mime)) { + String uristr = String.valueOf(uri); + if (uristr.toLowerCase().startsWith("content://media")) { + Cursor cursor = mCr.query(uri, + new String[]{MediaStore.Video.Media.BUCKET_ID}, + null, null, null); + long bucketId = -1; + if (cursor != null) { + if (cursor.moveToFirst()) { + bucketId = cursor.getLong(0); + } + cursor.close(); + } + long curId = Long.parseLong(uri.getPathSegments().get(3)); + movieList = fillUriList(MediaStore.Video.Media.BUCKET_ID + "=? ", + new String[]{String.valueOf(bucketId)}, curId, params[0]); + } else if (uristr.toLowerCase().startsWith("file://")) { + String data = Uri.decode(uri.toString()); + data = data.replaceAll("'", "''"); + String where = "_data LIKE '%" + data.replaceFirst("file:///", "") + "'"; + Cursor cursor = mCr.query(MediaStore.Video.Media.EXTERNAL_CONTENT_URI, + new String[]{"_id", MediaStore.Video.Media.BUCKET_ID}, + where, null, null); + long bucketId = -1; + long curId = -1; + if (cursor != null) { + if (cursor.moveToFirst()) { + curId = cursor.getLong(0); + bucketId = cursor.getLong(1); + } + cursor.close(); + } + movieList = fillUriList(MediaStore.Video.Media.BUCKET_ID + "=? ", + new String[]{String.valueOf(bucketId)}, curId, params[0]); + } + } + } + if (LOG) { + Log.v(TAG, "doInBackground() done return " + movieList); + } + return movieList; + } + + private IMovieList fillUriList(String where, String[] whereArgs, long curId, IMovieItem current) { + IMovieList movieList = null; + Cursor cursor = null; + try { + cursor = mCr.query(MediaStore.Video.Media.EXTERNAL_CONTENT_URI, + new String[]{"_id", "mime_type", OpenableColumns.DISPLAY_NAME}, + where, + whereArgs, + mOrderBy); + boolean find = false; + if (cursor != null && cursor.getCount() > 0) { + movieList = new MovieList(); + while (cursor.moveToNext()) { + long id = cursor.getLong(0); + if (!find && id == curId) { + find = true; + movieList.add(current); + continue; + } + Uri uri = ContentUris.withAppendedId(MediaStore.Video.Media.EXTERNAL_CONTENT_URI, id); + String mimeType = cursor.getString(1); + String title = cursor.getString(2); + + movieList.add(new MovieItem(uri, mimeType, title)); + } + } + } catch (final SQLiteException e) { + e.printStackTrace(); + } finally { + if (cursor != null) { + cursor.close(); + } + } + if (LOG) { + Log.v(TAG, "fillUriList() cursor=" + cursor + ", return " + movieList); + } + return movieList; + } + } +} diff --git a/src/org/codeaurora/gallery3d/video/CodeauroraVideoView.java b/src/org/codeaurora/gallery3d/video/CodeauroraVideoView.java index 56fab2395..dc57b7058 100755 --- a/src/org/codeaurora/gallery3d/video/CodeauroraVideoView.java +++ b/src/org/codeaurora/gallery3d/video/CodeauroraVideoView.java @@ -7,6 +7,8 @@ import android.content.Intent; import android.content.res.Resources; import android.media.AudioManager; import android.media.MediaPlayer; +import android.media.MediaPlayer.OnBufferingUpdateListener; +import android.media.MediaPlayer.OnVideoSizeChangedListener; import android.media.Metadata; import android.media.MediaPlayer.OnCompletionListener; import android.media.MediaPlayer.OnErrorListener; @@ -26,6 +28,8 @@ import android.view.accessibility.AccessibilityNodeInfo; import android.widget.MediaController; import android.widget.MediaController.MediaPlayerControl; +import org.codeaurora.gallery3d.video.ScreenModeManager.ScreenModeListener; + import java.io.IOException; import java.util.Map; @@ -36,7 +40,7 @@ import java.util.Map; * it can be used in any layout manager, and provides various display options * such as scaling and tinting. */ -public class CodeauroraVideoView extends SurfaceView implements MediaPlayerControl { +public class CodeauroraVideoView extends SurfaceView implements MediaPlayerControl, ScreenModeListener{ private static final boolean LOG = true; private String TAG = "CodeauroraVideoView"; // settable by the client @@ -77,6 +81,7 @@ public class CodeauroraVideoView extends SurfaceView implements MediaPlayerContr private MediaPlayer.OnBufferingUpdateListener mOnBufferingUpdateListener; private MediaPlayer.OnVideoSizeChangedListener mVideoSizeListener; private MediaPlayer.OnPreparedListener mPreparedListener; + private ScreenModeManager mScreenManager; private int mCurrentBufferPercentage; private OnErrorListener mOnErrorListener; private OnInfoListener mOnInfoListener; @@ -84,6 +89,7 @@ public class CodeauroraVideoView extends SurfaceView implements MediaPlayerContr private boolean mCanPause; private boolean mCanSeekBack; private boolean mCanSeekForward; + private boolean mCanSeek; private boolean mHasGotPreparedCallBack = false; private boolean mNeedWaitLayout = false; private boolean mHasGotMetaData = false; @@ -99,9 +105,9 @@ public class CodeauroraVideoView extends SurfaceView implements MediaPlayerContr if (mMediaPlayer == null || mUri == null) { Log.w(TAG, "Cannot prepare play! mMediaPlayer=" + mMediaPlayer + ", mUri=" + mUri); - } else { - doPreparedIfReady(mMediaPlayer); + return; } + doPreparedIfReady(mMediaPlayer); break; default: Log.w(TAG, "Unhandled message " + msg); @@ -130,57 +136,47 @@ public class CodeauroraVideoView extends SurfaceView implements MediaPlayerContr @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - int width = getDefaultSize(mVideoWidth, widthMeasureSpec); - int height = getDefaultSize(mVideoHeight, heightMeasureSpec); - if (mVideoWidth > 0 && mVideoHeight > 0) { - - int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec); - int widthSpecSize = MeasureSpec.getSize(widthMeasureSpec); - int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec); - int heightSpecSize = MeasureSpec.getSize(heightMeasureSpec); - - if (widthSpecMode == MeasureSpec.EXACTLY && heightSpecMode == MeasureSpec.EXACTLY) { - // the size is fixed - width = widthSpecSize; - height = heightSpecSize; - - // for compatibility, we adjust size based on aspect ratio - if ( mVideoWidth * height < width * mVideoHeight ) { - width = height * mVideoWidth / mVideoHeight; - } else if ( mVideoWidth * height > width * mVideoHeight ) { - height = width * mVideoHeight / mVideoWidth; - } - } else if (widthSpecMode == MeasureSpec.EXACTLY) { - // only the width is fixed, adjust the height to match aspect ratio if possible - width = widthSpecSize; - height = width * mVideoHeight / mVideoWidth; - if (heightSpecMode == MeasureSpec.AT_MOST && height > heightSpecSize) { - // couldn't match aspect ratio within the constraints - height = heightSpecSize; - } - } else if (heightSpecMode == MeasureSpec.EXACTLY) { - // only the height is fixed, adjust the width to match aspect ratio if possible - height = heightSpecSize; - width = height * mVideoWidth / mVideoHeight; - if (widthSpecMode == MeasureSpec.AT_MOST && width > widthSpecSize) { - // couldn't match aspect ratio within the constraints - width = widthSpecSize; - } - } else { - // neither the width nor the height are fixed, try to use actual video size - width = mVideoWidth; - height = mVideoHeight; - if (heightSpecMode == MeasureSpec.AT_MOST && height > heightSpecSize) { - height = heightSpecSize; - width = height * mVideoWidth / mVideoHeight; + int width = 0; + int height = 0; + int screenMode = ScreenModeManager.SCREENMODE_BIGSCREEN; + if (mScreenManager != null) { + screenMode = mScreenManager.getScreenMode(); + } + switch (screenMode) { + case ScreenModeManager.SCREENMODE_BIGSCREEN: + width = getDefaultSize(mVideoWidth, widthMeasureSpec); + height = getDefaultSize(mVideoHeight, heightMeasureSpec); + if (mVideoWidth > 0 && mVideoHeight > 0) { + if (mVideoWidth * height > width * mVideoHeight) { + height = width * mVideoHeight / mVideoWidth; + } else if (mVideoWidth * height < width * mVideoHeight) { + width = height * mVideoWidth / mVideoHeight; + } } - if (widthSpecMode == MeasureSpec.AT_MOST && width > widthSpecSize) { - width = widthSpecSize; - height = width * mVideoHeight / mVideoWidth; + break; + case ScreenModeManager.SCREENMODE_FULLSCREEN: + width = getDefaultSize(mVideoWidth, widthMeasureSpec); + height = getDefaultSize(mVideoHeight, heightMeasureSpec); + break; + case ScreenModeManager.SCREENMODE_CROPSCREEN: + width = getDefaultSize(mVideoWidth, widthMeasureSpec); + height = getDefaultSize(mVideoHeight, heightMeasureSpec); + if (mVideoWidth > 0 && mVideoHeight > 0) { + if (mVideoWidth * height > width * mVideoHeight) { + width = height * mVideoWidth / mVideoHeight; + } else if (mVideoWidth * height < width * mVideoHeight) { + height = width * mVideoHeight / mVideoWidth; + } } - } - } else { - // no size yet, just adopt the given spec sizes + break; + default: + Log.w(TAG, "wrong screen mode : " + screenMode); + break; + } + if (LOG) { + Log.v(TAG, "onMeasure() set size: " + width + 'x' + height); + Log.v(TAG, "onMeasure() video size: " + mVideoWidth + 'x' + mVideoHeight); + Log.v(TAG, "onMeasure() mNeedWaitLayout=" + mNeedWaitLayout); } setMeasuredDimension(width, height); if (mNeedWaitLayout) { // when OnMeasure ok, start video. @@ -234,10 +230,13 @@ public class CodeauroraVideoView extends SurfaceView implements MediaPlayerContr || data.getBoolean(Metadata.SEEK_BACKWARD_AVAILABLE); mCanSeekForward = !data.has(Metadata.SEEK_FORWARD_AVAILABLE) || data.getBoolean(Metadata.SEEK_FORWARD_AVAILABLE); + mCanSeek = !data.has(Metadata.SEEK_AVAILABLE) + || data.getBoolean(Metadata.SEEK_AVAILABLE); } else { mCanPause = true; mCanSeekBack = true; mCanSeekForward = true; + mCanSeek = true; Log.w(TAG, "Metadata is null!"); } if (LOG) { @@ -251,11 +250,6 @@ public class CodeauroraVideoView extends SurfaceView implements MediaPlayerContr mErrorListener = new MediaPlayer.OnErrorListener() { public boolean onError(final MediaPlayer mp, final int frameworkErr, final int implErr) { Log.d(TAG, "Error: " + frameworkErr + "," + implErr); - if (mCurrentState == STATE_ERROR) { - Log.w(TAG, "Duplicate error message. error message has been sent! " + - "error=(" + frameworkErr + "," + implErr + ")"); - return true; - } //record error position and duration //here disturb the original logic mSeekWhenPrepared = getCurrentPosition(); @@ -349,11 +343,15 @@ public class CodeauroraVideoView extends SurfaceView implements MediaPlayerContr getHolder().removeCallback(mSHCallback); mSHCallback = new SurfaceHolder.Callback() { - public void surfaceChanged(final SurfaceHolder holder, final int format, final int w, final int h) { + public void surfaceChanged(final SurfaceHolder holder, final int format, + final int w, final int h) { if (LOG) { - Log.v(TAG, "surfaceChanged(" + holder + ", " + format + ", " + w + ", " + h + ")"); - Log.v(TAG, "surfaceChanged() mMediaPlayer=" + mMediaPlayer + ", mTargetState=" + mTargetState - + ", mVideoWidth=" + mVideoWidth + ", mVideoHeight=" + mVideoHeight); + Log.v(TAG, "surfaceChanged(" + holder + ", " + format + + ", " + w + ", " + h + ")"); + Log.v(TAG, "surfaceChanged() mMediaPlayer=" + mMediaPlayer + + ", mTargetState=" + mTargetState + + ", mVideoWidth=" + mVideoWidth + + ", mVideoHeight=" + mVideoHeight); } mSurfaceWidth = w; mSurfaceHeight = h; @@ -372,6 +370,11 @@ public class CodeauroraVideoView extends SurfaceView implements MediaPlayerContr if (LOG) { Log.v(TAG, "surfaceCreated(" + holder + ")"); } + if (mCurrentState == STATE_SUSPENDED) { + mSurfaceHolder = holder; + mMediaPlayer.setDisplay(mSurfaceHolder); + release(false); + } mSurfaceHolder = holder; openVideo(); } @@ -385,6 +388,10 @@ public class CodeauroraVideoView extends SurfaceView implements MediaPlayerContr if (mMediaController != null) { mMediaController.hide(); } + if (isHTTPStreaming(mUri) && mCurrentState == STATE_SUSPENDED) { + // Don't call release() while run suspend operation + return; + } release(true); } }; @@ -541,57 +548,7 @@ public class CodeauroraVideoView extends SurfaceView implements MediaPlayerContr } }; - private MediaPlayer.OnErrorListener mErrorListener = - new MediaPlayer.OnErrorListener() { - public boolean onError(MediaPlayer mp, int framework_err, int impl_err) { - Log.d(TAG, "Error: " + framework_err + "," + impl_err); - mCurrentState = STATE_ERROR; - mTargetState = STATE_ERROR; - if (mMediaController != null) { - mMediaController.hide(); - } - - /* If an error handler has been supplied, use it and finish. */ - if (mOnErrorListener != null) { - if (mOnErrorListener.onError(mMediaPlayer, framework_err, impl_err)) { - return true; - } - } - - /* Otherwise, pop up an error dialog so the user knows that - * something bad has happened. Only try and pop up the dialog - * if we're attached to a window. When we're going away and no - * longer have a window, don't bother showing the user an error. - */ - if (getWindowToken() != null) { - Resources r = mContext.getResources(); - int messageId; - - if (framework_err == MediaPlayer.MEDIA_ERROR_NOT_VALID_FOR_PROGRESSIVE_PLAYBACK) { - messageId = com.android.internal.R.string.VideoView_error_text_invalid_progressive_playback; - } else { - messageId = com.android.internal.R.string.VideoView_error_text_unknown; - } - - new AlertDialog.Builder(mContext) - .setMessage(messageId) - .setPositiveButton(com.android.internal.R.string.VideoView_error_button, - new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int whichButton) { - /* If we get here, there is no onError listener, so - * at least inform them that the video is over. - */ - if (mOnCompletionListener != null) { - mOnCompletionListener.onCompletion(mMediaPlayer); - } - } - }) - .setCancelable(false) - .show(); - } - return true; - } - }; + private MediaPlayer.OnErrorListener mErrorListener; private MediaPlayer.OnBufferingUpdateListener mBufferingUpdateListener = new MediaPlayer.OnBufferingUpdateListener() { @@ -658,27 +615,6 @@ public class CodeauroraVideoView extends SurfaceView implements MediaPlayerContr } public void surfaceCreated(SurfaceHolder 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(); - */ - if (LOG) { Log.v(TAG, "surfaceCreated(" + holder + ")"); } @@ -813,20 +749,19 @@ public class CodeauroraVideoView extends SurfaceView implements MediaPlayerContr } public void suspend() { - // HTTP streaming will call mMediaPlayer->suspend(), others will call release() - /* - if (isHTTPStreaming(mUri) && mCurrentState != STATE_PREPARING) { - if (mMediaPlayer.suspend()) { - mTargetState = mCurrentState; - mCurrentState = STATE_SUSPENDED; - return; - } - }*/ release(false); } public void resume() { - setResumed(true); + // HTTP streaming (with suspended status) will call mMediaPlayer->resume(), others will call openVideo() + if (mCurrentState == STATE_SUSPENDED) { + if (mSurfaceHolder != null) { + release(false); + } else { + // The surface has been destroyed, resume operation will be done after surface created + return; + } + } openVideo(); } @@ -919,6 +854,10 @@ public class CodeauroraVideoView extends SurfaceView implements MediaPlayerContr return mCanSeekForward; } + public boolean canSeek() { + return mCanSeek; + } + @Override public int getAudioSessionId() { if (mAudioSession == 0) { @@ -1029,4 +968,33 @@ public class CodeauroraVideoView extends SurfaceView implements MediaPlayerContr } return mTargetState == STATE_PLAYING; } + + public void setScreenModeManager(final ScreenModeManager manager) { + mScreenManager = manager; + if (mScreenManager != null) { + mScreenManager.addListener(this); + } + if (LOG) { + Log.v(TAG, "setScreenModeManager(" + manager + ")"); + } + } + + @Override + public void onScreenModeChanged(final int newMode) { + this.requestLayout(); + } + + public void setOnVideoSizeChangedListener(final OnVideoSizeChangedListener l) { + mVideoSizeListener = l; + if (LOG) { + Log.i(TAG, "setOnVideoSizeChangedListener(" + l + ")"); + } + } + + public void setOnBufferingUpdateListener(final OnBufferingUpdateListener l) { + mOnBufferingUpdateListener = l; + if (LOG) { + Log.v(TAG, "setOnBufferingUpdateListener(" + l + ")"); + } + } } diff --git a/src/org/codeaurora/gallery3d/video/ExtensionHelper.java b/src/org/codeaurora/gallery3d/video/ExtensionHelper.java index f95e9c09f..2ff61a4e5 100755 --- a/src/org/codeaurora/gallery3d/video/ExtensionHelper.java +++ b/src/org/codeaurora/gallery3d/video/ExtensionHelper.java @@ -19,6 +19,7 @@ public class ExtensionHelper { boolean loop = context.getResources().getBoolean(R.bool.loop); boolean stereo = context.getResources().getBoolean(R.bool.stereo); boolean streaming = context.getResources().getBoolean(R.bool.streaming); + boolean playlist = context.getResources().getBoolean(R.bool.playlist); if (loop == true) { group.addHooker(new LoopVideoHooker()); // add it for common feature. @@ -30,6 +31,10 @@ public class ExtensionHelper { group.addHooker(new StreamingHooker()); group.addHooker(new BookmarkHooker()); } + if (playlist == true) { + group.addHooker(new MovieListHooker()); // add it for common feature. + group.addHooker(new StepOptionSettingsHooker()); + } return group; } } diff --git a/src/org/codeaurora/gallery3d/video/IControllerRewindAndForward.java b/src/org/codeaurora/gallery3d/video/IControllerRewindAndForward.java new file mode 100644 index 000000000..1fc7f704d --- /dev/null +++ b/src/org/codeaurora/gallery3d/video/IControllerRewindAndForward.java @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.codeaurora.gallery3d.video; + +import com.android.gallery3d.app.ControllerOverlay; +import com.android.gallery3d.app.ControllerOverlay.Listener; + +///M: for CU rewind and forward +public interface IControllerRewindAndForward extends ControllerOverlay { + + interface IRewindAndForwardListener extends Listener { + void onStopVideo(); + void onRewind(); + void onForward(); + } + + boolean getPlayPauseEanbled(); + boolean getTimeBarEanbled(); + void setIListener(IRewindAndForwardListener listener); + void showControllerButtonsView(boolean canStop, boolean canRewind, boolean canForward); +} diff --git a/src/org/codeaurora/gallery3d/video/MovieListHooker.java b/src/org/codeaurora/gallery3d/video/MovieListHooker.java new file mode 100644 index 000000000..3da15b1dd --- /dev/null +++ b/src/org/codeaurora/gallery3d/video/MovieListHooker.java @@ -0,0 +1,116 @@ +package org.codeaurora.gallery3d.video; + +import android.os.Bundle; +import android.util.Log; +import android.view.Menu; +import android.view.MenuItem; + +import com.android.gallery3d.R; +import org.codeaurora.gallery3d.ext.IMovieItem; +import org.codeaurora.gallery3d.ext.IMovieList; +import org.codeaurora.gallery3d.ext.IMovieListLoader; +import org.codeaurora.gallery3d.ext.IMovieListLoader.LoaderListener; +import org.codeaurora.gallery3d.ext.MovieListLoader; + +public class MovieListHooker extends MovieHooker implements LoaderListener { + private static final String TAG = "MovieListHooker"; + private static final boolean LOG = true; + + private static final int MENU_NEXT = 1; + private static final int MENU_PREVIOUS = 2; + + private MenuItem mMenuNext; + private MenuItem mMenuPrevious; + + private IMovieListLoader mMovieLoader; + private IMovieList mMovieList; + + @Override + public void onCreate(final Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + mMovieLoader = new MovieListLoader(); + mMovieLoader.fillVideoList(getContext(), getIntent(), this, getMovieItem()); + } + @Override + public void onDestroy() { + super.onDestroy(); + mMovieLoader.cancelList(); + } + @Override + public boolean onCreateOptionsMenu(final Menu menu) { + super.onCreateOptionsMenu(menu); + if (mMovieList != null) { //list should be filled + if (mMovieLoader != null && mMovieLoader.isEnabledVideoList(getIntent())) { + mMenuPrevious = menu.add(0, getMenuActivityId(MENU_PREVIOUS), 0, R.string.previous); + mMenuNext = menu.add(0, getMenuActivityId(MENU_NEXT), 0, R.string.next); + } + } + return true; + } + @Override + public boolean onPrepareOptionsMenu(final Menu menu) { + super.onPrepareOptionsMenu(menu); + updatePrevNext(); + return true; + } + @Override + public boolean onOptionsItemSelected(final MenuItem item) { + super.onOptionsItemSelected(item); + switch(getMenuOriginalId(item.getItemId())) { + case MENU_PREVIOUS: + if (mMovieList == null) { + return false; + } + getPlayer().startNextVideo(mMovieList.getPrevious(getMovieItem())); + return true; + case MENU_NEXT: + if (mMovieList == null) { + return false; + } + getPlayer().startNextVideo(mMovieList.getNext(getMovieItem())); + return true; + default: + return false; + } + } + + @Override + public void onMovieItemChanged(final IMovieItem item) { + super.onMovieItemChanged(item); + updatePrevNext(); + } + + private void updatePrevNext() { + if (LOG) { + Log.v(TAG, "updatePrevNext()"); + } + if (mMovieList != null && mMenuPrevious != null && mMenuNext != null) { + if (mMovieList.isFirst(getMovieItem()) && mMovieList.isLast(getMovieItem())) { //only one movie + mMenuNext.setVisible(false); + mMenuPrevious.setVisible(false); + } else { + mMenuNext.setVisible(true); + mMenuPrevious.setVisible(true); + } + if (mMovieList.isFirst(getMovieItem())) { + mMenuPrevious.setEnabled(false); + } else { + mMenuPrevious.setEnabled(true); + } + if (mMovieList.isLast(getMovieItem())) { + mMenuNext.setEnabled(false); + } else { + mMenuNext.setEnabled(true); + } + } + } + + @Override + public void onListLoaded(final IMovieList movieList) { + mMovieList = movieList; + getContext().invalidateOptionsMenu(); + if (LOG) { + Log.v(TAG, "onListLoaded() " + (mMovieList != null ? mMovieList.size() : "null")); + } + } +} diff --git a/src/org/codeaurora/gallery3d/video/ScreenModeManager.java b/src/org/codeaurora/gallery3d/video/ScreenModeManager.java new file mode 100644 index 000000000..3dbba68d8 --- /dev/null +++ b/src/org/codeaurora/gallery3d/video/ScreenModeManager.java @@ -0,0 +1,117 @@ +package org.codeaurora.gallery3d.video; + +import android.util.Log; + +import java.util.ArrayList; + +public class ScreenModeManager { + private static final String TAG = "ScreenModeManager"; + private static final boolean LOG = true; + //support screen mode. + public static final int SCREENMODE_BIGSCREEN = 1; + public static final int SCREENMODE_FULLSCREEN = 2; + public static final int SCREENMODE_CROPSCREEN = 4; + public static final int SCREENMODE_ALL = 7; + + private int mScreenMode = SCREENMODE_BIGSCREEN; + private int mScreenModes = SCREENMODE_ALL; + + /** + * Enable specified screen mode list. + * The screen mode's value determines the order of being shown. + *
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}. + *
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. + *
Note: 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 mListeners = new ArrayList(); + 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 old mode 100644 new mode 100755 index 58ff53b8a..1490f234c --- a/src/org/codeaurora/gallery3d/video/SettingsActivity.java +++ b/src/org/codeaurora/gallery3d/video/SettingsActivity.java @@ -3,6 +3,7 @@ package org.codeaurora.gallery3d.video; import android.app.ActionBar; import android.app.Activity; import android.content.ContentResolver; +import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; import android.database.Cursor; @@ -18,6 +19,7 @@ import android.preference.PreferenceCategory; import android.preference.RingtonePreference; import android.preference.PreferenceScreen; import android.provider.ContactsContract; +import android.provider.Settings.System; import android.provider.Telephony; import android.telephony.MSimTelephonyManager; import android.telephony.TelephonyManager; @@ -31,26 +33,38 @@ import java.util.ArrayList; public class SettingsActivity extends PreferenceActivity { - public static final String PREFERENCE_RTP_MINPORT = "rtp_min_port"; - public static final String PREFERENCE_RTP_MAXPORT = "rtp_max_port"; - public static final String PREFERENCE_RTCP_MINPORT = "rtcp_min_port"; - public static final String PREFERENCE_RTCP_MAXPORT = "rtcp_max_port"; - public static final String PREFERENCE_BUFFER_SIZE = "buffer_size"; - public static final String PREFERENCE_APN = "apn"; + private static final String LOG_TAG = "SettingsActivity"; + public static final String PREFERENCE_RTP_MINPORT = "rtp_min_port"; + public static final String PREFERENCE_RTP_MAXPORT = "rtp_max_port"; + private static final String PREFERENCE_KEEP_ALIVE_INTERVAL_SECOND = "keep_alive_interval_second"; + private static final String PREFERENCE_CACHE_MIN_SIZE = "cache_min_size"; + private static final String PREFERENCE_CACHE_MAX_SIZE = "cache_max_size"; + public static final String PREFERENCE_BUFFER_SIZE = "buffer_size"; + public static final String PREFERENCE_APN = "apn"; + private static final String PACKAGE_NAME = "com.android.settings"; + + private static final int DEFAULT_RTP_MINPORT = 8192; + private static final int DEFAULT_RTP_MAXPORT = 65535; + private static final int DEFAULT_CACHE_MIN_SIZE = 4 * 1024 * 1024; + private static final int DEFAULT_CACHE_MAX_SIZE = 20 * 1024 * 1024; + private static final int DEFAULT_KEEP_ALIVE_INTERVAL_SECOND = 15; + + private static final int RTP_MIN_PORT = 1; + private static final int RTP_MAX_PORT = 2; + private static final int BUFFER_SIZE = 3; + + private SharedPreferences mPref; private EditTextPreference mRtpMinPort; private EditTextPreference mRtpMaxPort; - private EditTextPreference mRtcpMinPort; - private EditTextPreference mRtcpMaxPort; private EditTextPreference mBufferSize; - private PreferenceScreen mApn; - private CheckBoxPreference mRepeat; - - private static final int SELECT_APN = 1; - public static final String PREFERRED_APN_URI = "content://telephony/carriers/preferapn"; - private static final Uri PREFERAPN_URI = Uri.parse(PREFERRED_APN_URI); - private static final int ID_INDEX = 0; - private static final int NAME_INDEX = 1; + private PreferenceScreen mApn; + + private static final int SELECT_APN = 1; + public static final String PREFERRED_APN_URI = "content://telephony/carriers/preferapn"; + private static final Uri PREFERAPN_URI = Uri.parse(PREFERRED_APN_URI); + private static final int COLUMN_ID_INDEX = 0; + private static final int NAME_INDEX = 1; private boolean mUseNvOperatorForEhrpd = SystemProperties.getBoolean( "persist.radio.use_nv_for_ehrpd", false); @@ -60,111 +74,43 @@ public class SettingsActivity extends PreferenceActivity { super.onCreate(savedInstanceState); addPreferencesFromResource(R.xml.rtsp_settings_preferences); - SharedPreferences mPref; mPref = getPreferenceScreen().getSharedPreferences(); - String rtpMinport = mPref.getString(PREFERENCE_RTP_MINPORT, "8192"); - String rtpMaxport = mPref.getString(PREFERENCE_RTP_MAXPORT, "65535"); - String rtcpMinport = mPref.getString(PREFERENCE_RTCP_MAXPORT, null); - String rtcpMaxport = mPref.getString(PREFERENCE_RTCP_MAXPORT, null); - String bufferSize = mPref.getString(PREFERENCE_BUFFER_SIZE, null); - mRtpMinPort = (EditTextPreference) findPreference(PREFERENCE_RTP_MINPORT); - mRtpMinPort.getEditText().setKeyListener(DigitsKeyListener.getInstance("0123456789")); - mRtpMinPort.setSummary(rtpMinport); - mRtpMinPort.setText(rtpMinport); - mRtpMinPort.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() { - public boolean onPreferenceChange(Preference preference, Object newValue) { - final String summary = newValue.toString(); - mRtpMinPort.setSummary(summary); - Log.d("rtsp", "z66 summary = " + summary); - android.provider.Settings.System.putString(getContentResolver(), - "streaming_min_udp_port", summary); - return true; - } - }); - mRtpMaxPort = (EditTextPreference) findPreference(PREFERENCE_RTP_MAXPORT); - mRtpMaxPort.getEditText().setKeyListener(DigitsKeyListener.getInstance("0123456789")); - mRtpMaxPort.setSummary(rtpMaxport); - mRtpMaxPort.setText(rtpMaxport); - mRtpMaxPort.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() { - public boolean onPreferenceChange(Preference preference, Object newValue) { - final String summary = newValue.toString(); - mRtpMaxPort.setSummary(summary); - Log.w("rtsp", "z82 summary = " + summary); - android.provider.Settings.System.putString(getContentResolver(), - "streaming_max_udp_port", summary); - return true; - } - }); - mRtcpMinPort = (EditTextPreference) findPreference(PREFERENCE_RTCP_MINPORT); - mRtcpMinPort.getEditText().setKeyListener(DigitsKeyListener.getInstance("0123456789")); - mRtcpMinPort.setSummary(rtcpMinport); - mRtcpMinPort.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() { - public boolean onPreferenceChange(Preference preference, Object newValue) { - final String summary = newValue.toString(); - mRtcpMinPort.setSummary(summary); - return true; - } - }); - mRtcpMaxPort = (EditTextPreference) findPreference(PREFERENCE_RTCP_MAXPORT); - mRtcpMaxPort.getEditText().setKeyListener(DigitsKeyListener.getInstance("0123456789")); - mRtcpMaxPort.setSummary(rtcpMaxport); - mRtcpMaxPort.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() { - public boolean onPreferenceChange(Preference preference, Object newValue) { - final String summary = newValue.toString(); - mRtcpMaxPort.setSummary(summary); - return true; - } - }); - mBufferSize = (EditTextPreference) findPreference(PREFERENCE_BUFFER_SIZE); - mBufferSize.getEditText().setKeyListener(DigitsKeyListener.getInstance("0123456789")); - mBufferSize.setSummary(bufferSize); - mBufferSize.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() { - public boolean onPreferenceChange(Preference preference, Object newValue) { - final String summary = newValue.toString(); - mBufferSize.setSummary(summary); - return true; - } - }); - mApn = (PreferenceScreen) findPreference(PREFERENCE_APN); - mApn.setSummary(getDefaultApnName()); - mApn.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() { - public boolean onPreferenceClick(Preference preference) { - Intent intent = new Intent(); - intent.setClassName("com.android.settings", "com.android.settings.ApnSettings"); - startActivityForResult(intent, SELECT_APN); - return true; - } - }); + + setPreferenceListener(RTP_MIN_PORT, mRtpMinPort); + setPreferenceListener(RTP_MAX_PORT, mRtpMaxPort); + setPreferenceListener(BUFFER_SIZE, mBufferSize); + setApnListener(); ActionBar ab = getActionBar(); ab.setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD); ab.setDisplayHomeAsUpEnabled(true); ab.setTitle(R.string.setting); } - - private String getDefaultApnName() { - + + private String getApnKey() { // to find default key String key = null; - String name = null; Cursor cursor = getContentResolver().query(PREFERAPN_URI, new String[] { "_id" }, null, null, Telephony.Carriers.DEFAULT_SORT_ORDER); - if (cursor.getCount() > 0) { - cursor.moveToFirst(); - key = cursor.getString(ID_INDEX); + if (cursor.getCount() > 0 && cursor.moveToFirst()) { + key = cursor.getString(COLUMN_ID_INDEX); Log.v("settingActivty", "default apn key = " + key); } cursor.close(); - + return key; + } + + private String getApnName(String key) { + String name = null; // to find default proxy String where = getOperatorNumericSelection(); - cursor = getContentResolver().query(Telephony.Carriers.CONTENT_URI, new String[] { + Cursor cursor = getContentResolver().query(Telephony.Carriers.CONTENT_URI, new String[] { "_id", "name", "apn", "type" }, where, null, Telephony.Carriers.DEFAULT_SORT_ORDER); @@ -182,7 +128,11 @@ public class SettingsActivity extends PreferenceActivity { cursor.close(); } return name; + + } + private String getDefaultApnName() { + return getApnName(getApnKey()); } private String getSelectedApnKey() { @@ -205,13 +155,12 @@ public class SettingsActivity extends PreferenceActivity { @Override public void onActivityResult(int requestCode, int resultCode, Intent data) { - switch (requestCode) { - case SELECT_APN: - setResult(resultCode); - finish(); - Log.w("rtsp", "onActivityResult requestCode = " + requestCode); - break; + if (requestCode == SELECT_APN) { + setResult(resultCode); + finish(); + Log.w(LOG_TAG, "onActivityResult requestCode = " + requestCode); } + } @Override @@ -228,7 +177,7 @@ public class SettingsActivity extends PreferenceActivity { String where; where = (mccmncs[0] != null) ? "numeric=\"" + mccmncs[0] + "\"" : ""; where += (mccmncs[1] != null) ? " or numeric=\"" + mccmncs[1] + "\"" : ""; - Log.d("SettingsActivity", "getOperatorNumericSelection: " + where); + Log.d(LOG_TAG, "getOperatorNumericSelection: " + where); return where; } @@ -249,4 +198,114 @@ public class SettingsActivity extends PreferenceActivity { } return result.toArray(new String[2]); } + + private void enableRtpPortSetting() { + final String rtpMinPortStr = mPref.getString(PREFERENCE_RTP_MINPORT, + Integer.toString(DEFAULT_RTP_MINPORT)); + final String rtpMaxPortStr = mPref.getString(PREFERENCE_RTP_MAXPORT, + Integer.toString(DEFAULT_RTP_MAXPORT)); + final String CLASS_NAME = "com.android.settings.StreamingSettingsEnablerActivity"; + final int rtpMinPort; + final int rtpMaxPort; + try { + rtpMinPort = Integer.valueOf(rtpMinPortStr); + rtpMaxPort = Integer.valueOf(rtpMaxPortStr); + } catch (NumberFormatException e) { + Log.e(LOG_TAG, "Failed to parse rtp ports"); + return; + } + Intent intent = new Intent(); + intent.setClassName(PACKAGE_NAME, CLASS_NAME); + intent.putExtra(PREFERENCE_RTP_MINPORT, rtpMinPort); + intent.putExtra(PREFERENCE_RTP_MAXPORT, rtpMaxPort); + startActivity(intent); + } + + private void enableBufferSetting() { + final String bufferSizeStr = mPref.getString(PREFERENCE_BUFFER_SIZE, + Integer.toString(DEFAULT_CACHE_MAX_SIZE)); + final String CLASS_NAME = "com.android.settings.StreamingSettingsEnablerActivity"; + final int cacheMaxSize; + try { + cacheMaxSize = Integer.valueOf(bufferSizeStr); + } catch (NumberFormatException e) { + Log.e(LOG_TAG, "Failed to parse cache max size"); + return; + } + Intent intent = new Intent(); + intent.setClassName(PACKAGE_NAME, CLASS_NAME); + intent.putExtra(PREFERENCE_CACHE_MIN_SIZE, DEFAULT_CACHE_MIN_SIZE); + intent.putExtra(PREFERENCE_CACHE_MAX_SIZE, cacheMaxSize); + intent.putExtra(PREFERENCE_KEEP_ALIVE_INTERVAL_SECOND, DEFAULT_KEEP_ALIVE_INTERVAL_SECOND); + startActivity(intent); + } + + private void setPreferenceListener(final int which, final EditTextPreference etp) { + + final String DIGITS_ACCEPTABLE = "0123456789"; + String summaryStr = ""; + String preferStr = ""; + + switch (which) { + case RTP_MIN_PORT: + preferStr = mPref.getString(PREFERENCE_RTP_MINPORT, + Integer.toString(DEFAULT_RTP_MINPORT)); + summaryStr = "streaming_min_udp_port"; + break; + case RTP_MAX_PORT: + preferStr = mPref.getString(PREFERENCE_RTP_MAXPORT, + Integer.toString(DEFAULT_RTP_MAXPORT)); + summaryStr = "streaming_max_udp_port"; + break; + case BUFFER_SIZE: + preferStr = mPref.getString(PREFERENCE_BUFFER_SIZE, + Integer.toString(DEFAULT_CACHE_MAX_SIZE)); + break; + default: + return; + + } + + final String summaryString = summaryStr; + etp.getEditText().setKeyListener(DigitsKeyListener.getInstance(DIGITS_ACCEPTABLE)); + etp.setSummary(preferStr); + etp.setText(preferStr); + etp.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() { + public boolean onPreferenceChange(Preference preference, Object newValue) { + final String summary = newValue.toString(); + final int value; + try { + value = Integer.valueOf(summary); + } catch (NumberFormatException e) { + Log.e(LOG_TAG, "NumberFormatException"); + return false; + } + etp.setSummary(summary); + etp.setText(summary); + Log.d(LOG_TAG, "z66/z82 summary = " + summary); + if(which == RTP_MIN_PORT || which == RTP_MAX_PORT) { + System.putString(getContentResolver(), summaryString, summary); + enableRtpPortSetting(); + } else { + enableBufferSetting(); + } + return true; + } + }); + + } + + private void setApnListener() { + final String CLASS_NAME = "com.android.settings.ApnSettings"; + mApn.setSummary(getDefaultApnName()); + mApn.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() { + public boolean onPreferenceClick(Preference preference) { + Intent intent = new Intent(); + intent.setClassName(PACKAGE_NAME, CLASS_NAME); + startActivityForResult(intent, SELECT_APN); + return true; + } + }); + } + } diff --git a/src/org/codeaurora/gallery3d/video/StepOptionDialogFragment.java b/src/org/codeaurora/gallery3d/video/StepOptionDialogFragment.java new file mode 100644 index 000000000..50bd8a669 --- /dev/null +++ b/src/org/codeaurora/gallery3d/video/StepOptionDialogFragment.java @@ -0,0 +1,83 @@ +package org.codeaurora.gallery3d.video; + +import android.app.AlertDialog; +import android.app.Dialog; +import android.app.DialogFragment; +import android.content.DialogInterface; +import android.os.Bundle; + +/** M: use DialogFragment to show Dialog */ +public class StepOptionDialogFragment extends DialogFragment implements + DialogInterface.OnClickListener{ + + private static final String KEY_ITEM_ARRAY = "itemArray"; + private static final String KEY_TITLE = "title"; + private static final String KEY_DEFAULT_SELECT = "nowSelect"; + private DialogInterface.OnClickListener mClickListener = null; + + /** + * M: create a instance of SelectDialogFragment + * + * @param itemArrayID + * the resource id array of strings that show in list + * @param sufffixArray + * the suffix array at the right of list item + * @param titleID + * the resource id of title string + * @param nowSelect + * the current select item index + * @return the instance of SelectDialogFragment + */ + public static StepOptionDialogFragment newInstance(int[] itemArrayID, + int titleID, int nowSelect) { + StepOptionDialogFragment frag = new StepOptionDialogFragment(); + Bundle args = new Bundle(); + args.putIntArray(KEY_ITEM_ARRAY, itemArrayID); + args.putInt(KEY_TITLE, titleID); + args.putInt(KEY_DEFAULT_SELECT, nowSelect); + frag.setArguments(args); + return frag; + } + + @Override + /** + * M: create a select dialog + */ + public Dialog onCreateDialog(Bundle savedInstanceState) { + Bundle args = getArguments(); + final String title = getString(args.getInt(KEY_TITLE)); + final int[] itemArrayID = args.getIntArray(KEY_ITEM_ARRAY); + int arraySize = itemArrayID.length; + CharSequence[] itemArray = new CharSequence[arraySize]; + for (int i = 0; i < arraySize; i++) { + itemArray[i] = getString(itemArrayID[i]); + } + + AlertDialog.Builder builder = null; + int nowSelect = args.getInt(KEY_DEFAULT_SELECT); + builder = new AlertDialog.Builder(getActivity()); + builder.setTitle(title).setSingleChoiceItems(itemArray, nowSelect, this) + .setNegativeButton(getString(android.R.string.cancel), null); + return builder.create(); + } + + @Override + /** + * M: the process of select an item + */ + public void onClick(DialogInterface arg0, int arg1) { + if (null != mClickListener) { + mClickListener.onClick(arg0, arg1); + } + } + + /** + * M: set listener of click items + * + * @param listener + * the listener to be set + */ + public void setOnClickListener(DialogInterface.OnClickListener listener) { + mClickListener = listener; + } +} \ No newline at end of file diff --git a/src/org/codeaurora/gallery3d/video/StepOptionSettingsHooker.java b/src/org/codeaurora/gallery3d/video/StepOptionSettingsHooker.java new file mode 100644 index 000000000..eff8057bd --- /dev/null +++ b/src/org/codeaurora/gallery3d/video/StepOptionSettingsHooker.java @@ -0,0 +1,41 @@ +package org.codeaurora.gallery3d.video; + +import android.content.Intent; +import android.view.Menu; +import android.view.MenuItem; + +import com.android.gallery3d.R; +import com.android.gallery3d.app.MovieActivity; +import org.codeaurora.gallery3d.ext.ActivityHooker; +import org.codeaurora.gallery3d.video.VideoSettingsActivity; + +public class StepOptionSettingsHooker extends ActivityHooker { + private static final int MENU_STEP_OPTION_SETTING = 1; + private MenuItem mMenuStepOption; + + @Override + public boolean onCreateOptionsMenu(final Menu menu) { + super.onCreateOptionsMenu(menu); + mMenuStepOption = menu.add(0, getMenuActivityId(MENU_STEP_OPTION_SETTING), 0, R.string.settings); + return true; + } + @Override + public boolean onPrepareOptionsMenu(final Menu menu) { + super.onPrepareOptionsMenu(menu); + return true; + } + @Override + public boolean onOptionsItemSelected(final MenuItem item) { + super.onOptionsItemSelected(item); + switch(getMenuOriginalId(item.getItemId())) { + case MENU_STEP_OPTION_SETTING: + //start activity + Intent mIntent = new Intent(); + mIntent.setClass(getContext(), VideoSettingsActivity.class); + getContext().startActivity(mIntent); + return true; + default: + return false; + } + } +} \ No newline at end of file diff --git a/src/org/codeaurora/gallery3d/video/StereoAudioHooker.java b/src/org/codeaurora/gallery3d/video/StereoAudioHooker.java old mode 100644 new mode 100755 index cb52f5972..88012fa7d --- a/src/org/codeaurora/gallery3d/video/StereoAudioHooker.java +++ b/src/org/codeaurora/gallery3d/video/StereoAudioHooker.java @@ -51,14 +51,12 @@ public class StereoAudioHooker extends MovieHooker { @Override public boolean onOptionsItemSelected(final MenuItem item) { super.onOptionsItemSelected(item); - switch (getMenuOriginalId(item.getItemId())) { - case MENU_STEREO_AUDIO: - mCurrentStereoAudio = !mCurrentStereoAudio; - setStereoAudio(mCurrentStereoAudio); - return true; - default: - return false; + if(getMenuOriginalId(item.getItemId()) == MENU_STEREO_AUDIO) { + mCurrentStereoAudio = !mCurrentStereoAudio; + setStereoAudio(mCurrentStereoAudio); + return true; } + return false; } private boolean getStereoAudio() { @@ -93,13 +91,8 @@ public class StereoAudioHooker extends MovieHooker { private void updateStereoAudioIcon() { if (mMenuStereoAudio != null) { - if (mCurrentStereoAudio) { - mMenuStereoAudio.setTitle(R.string.single_track); - mMenuStereoAudio.setIcon(R.drawable.ic_menu_single_track); - } else { - mMenuStereoAudio.setTitle(R.string.stereo); - mMenuStereoAudio.setIcon(R.drawable.ic_menu_stereo); - } + mMenuStereoAudio.setTitle(mCurrentStereoAudio?R.string.single_track:R.string.stereo); + mMenuStereoAudio.setIcon(mCurrentStereoAudio?R.drawable.ic_menu_single_track:R.drawable.ic_menu_stereo); } } diff --git a/src/org/codeaurora/gallery3d/video/StreamingHooker.java b/src/org/codeaurora/gallery3d/video/StreamingHooker.java old mode 100644 new mode 100755 index d4fa43fc5..fdcc14c50 --- a/src/org/codeaurora/gallery3d/video/StreamingHooker.java +++ b/src/org/codeaurora/gallery3d/video/StreamingHooker.java @@ -52,24 +52,23 @@ public class StreamingHooker extends MovieHooker { } private void gotoInputUrl() { - final String appName = getClass().getName(); + final String APN_NAME = getClass().getName(); + final String URI_STR = "about:blank"; + final String EXTRA_NAME = "inputUrl"; + final Intent intent = new Intent(); intent.setAction(Intent.ACTION_VIEW); - intent.setData(Uri.parse("about:blank")); - intent.putExtra("inputUrl", true); - intent.putExtra(Browser.EXTRA_APPLICATION_ID, appName); + intent.setData(Uri.parse(URI_STR)); + intent.putExtra(EXTRA_NAME, true); + intent.putExtra(Browser.EXTRA_APPLICATION_ID, APN_NAME); getContext().startActivity(intent); if (LOG) { - Log.v(TAG, "gotoInputUrl() appName=" + appName); + Log.v(TAG, "gotoInputUrl() appName=" + APN_NAME); } } private void gotoSettings() { final Intent intent = new Intent(ACTION_STREAMING); - // intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP - // | Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY); - // intent.putExtra(KEY_LOGO_BITMAP, - // getIntent().getParcelableExtra(KEY_LOGO_BITMAP)); getContext().startActivity(intent); if (LOG) { Log.v(TAG, "gotoInputUrl()"); diff --git a/src/org/codeaurora/gallery3d/video/VideoSettingsActivity.java b/src/org/codeaurora/gallery3d/video/VideoSettingsActivity.java new file mode 100644 index 000000000..32ccfe70f --- /dev/null +++ b/src/org/codeaurora/gallery3d/video/VideoSettingsActivity.java @@ -0,0 +1,182 @@ +package org.codeaurora.gallery3d.video; + +import android.app.ListActivity; + +import android.app.ActionBar; +import android.app.Activity; +import android.app.DialogFragment; +import android.app.Fragment; +import android.app.FragmentManager; +import android.content.Context; +import android.content.DialogInterface; +import android.content.Intent; +import android.content.SharedPreferences; +import android.os.Bundle; +import android.preference.Preference; +import android.preference.PreferenceActivity; +import android.preference.PreferenceScreen; +import android.text.TextUtils; +import android.view.Menu; +import android.view.MenuItem; +import android.view.View; +import android.widget.AdapterView; +import android.widget.AdapterView.OnItemClickListener; +import android.widget.ArrayAdapter; +import android.widget.ListView; +import android.widget.SimpleAdapter; +import android.widget.TextView; +import android.widget.Toast; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import com.android.gallery3d.R; + +public class VideoSettingsActivity extends ListActivity { + private String OPTION_NAME = "option_name"; + private String OPTION_DESC = "option_desc"; + private String DIALOG_TAG_SELECT_STEP_OPTION = "step_option_dialog"; + private static int[] sStepOptionArray = null; + private static final int STEP_OPTION_THREE_SECOND = 0; + private static final int STEP_OPTION_SIX_SECOND = 1; + private static final String SELECTED_STEP_OPTION = "selected_step_option"; + private static final String VIDEO_PLAYER_DATA = "video_player_data"; + private int mSelectedStepOption = -1; + private SharedPreferences mPrefs = null; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + ActionBar actionBar = getActionBar(); + actionBar.setDisplayHomeAsUpEnabled(true); + actionBar.setTitle(getResources().getString(R.string.settings)); + setContentView(R.layout.setting_list); + ArrayList> arrlist = new ArrayList>(1); + HashMap map = new HashMap(); + 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; + } +} -- cgit v1.2.3