diff options
author | Likai Ding <likaid@codeaurora.org> | 2013-08-19 16:33:24 +0800 |
---|---|---|
committer | emancebo <emancebo@cyngn.com> | 2014-09-04 10:40:18 -0700 |
commit | 3a90696f1ed0609449ca9adc02c931970cefd988 (patch) | |
tree | 553f245c2506b6c791a281dab865fb686be90759 | |
parent | 93a66b850bdb0a06ad7fda0549eb47b8123292bc (diff) | |
download | android_packages_apps_Gallery2-3a90696f1ed0609449ca9adc02c931970cefd988.tar.gz android_packages_apps_Gallery2-3a90696f1ed0609449ca9adc02c931970cefd988.tar.bz2 android_packages_apps_Gallery2-3a90696f1ed0609449ca9adc02c931970cefd988.zip |
Gallery2: support live streaming and bookmarks
Users can input a URL for streaming display.
URL bookmarking is supported.
Change-Id: Ia69497cdcfee963ba2209119a5b9dc82b64497da
31 files changed, 2764 insertions, 1483 deletions
diff --git a/Android.mk b/Android.mk index cf5b767bb..328b0d5d3 100644..100755 --- a/Android.mk +++ b/Android.mk @@ -4,6 +4,8 @@ include $(CLEAR_VARS) LOCAL_MODULE_TAGS := optional +LOCAL_JAVA_LIBRARIES := telephony-common + LOCAL_STATIC_JAVA_LIBRARIES := android-support-v13 LOCAL_STATIC_JAVA_LIBRARIES += com.android.gallery3d.common2 LOCAL_STATIC_JAVA_LIBRARIES += xmp_toolkit @@ -29,9 +31,11 @@ LOCAL_AAPT_FLAGS := --auto-add-overlay LOCAL_PACKAGE_NAME := Gallery2 +LOCAL_CERTIFICATE := platform + LOCAL_OVERRIDES_PACKAGES := Gallery Gallery3D GalleryNew3D -LOCAL_SDK_VERSION := current +#LOCAL_SDK_VERSION := current # If this is an unbundled build (to install seprately) then include # the libraries in the APK, otherwise just put them in /system/lib and diff --git a/AndroidManifest.xml b/AndroidManifest.xml index eedb7b893..5d44f902a 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -32,6 +32,7 @@ <uses-permission android:name="android.permission.WAKE_LOCK" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.WRITE_SETTINGS" /> + <uses-permission android:name="android.permission.WRITE_APN_SETTINGS"/> <uses-permission android:name="android.permission.WRITE_SYNC_SETTINGS" /> <uses-permission android:name="com.android.gallery3d.permission.GALLERY_PROVIDER" /> @@ -384,5 +385,33 @@ </receiver> <service android:name="com.android.camera.MediaSaveService" /> + + <activity android:name="org.codeaurora.gallery3d.video.SettingsActivity" + android:configChanges="keyboardHidden|orientation|screenSize" + android:label="@string/streaming_settings" > + <intent-filter> + <action android:name="org.codeaurora.settings.streaming" /> + <action android:name="android.intent.action.MAIN" /> + <category android:name="android.intent.category.DEFAULT" /> + </intent-filter> + </activity> + <receiver android:name="org.codeaurora.gallery3d.video.DmReceiver" > + <intent-filter> + <action android:name="android.intent.action.BOOT_COMPLETED" /> + <action android:name="streaming.action.WRITE_SETTINGS" /> + </intent-filter> + </receiver> + + <activity android:name="org.codeaurora.gallery3d.video.BookmarkActivity" + android:configChanges="keyboardHidden|orientation|screenSize" + android:icon="@drawable/ic_menu_display_bookmark" + android:label="@string/bookmark_list" + android:theme="@android:style/Theme.Holo" > + <intent-filter> + <action android:name="org.codeaurora.bookmark.VIEW" /> + <category android:name="android.intent.category.DEFAULT" /> + </intent-filter> + </activity> + </application> </manifest> diff --git a/proguard.flags b/proguard.flags index 65104ec1e..7b6195bd2 100644 --- a/proguard.flags +++ b/proguard.flags @@ -1,6 +1,9 @@ # Disable the warnings of using dynamic method call in common library. -dontnote com.android.gallery3d.common.* +#Avoid the library class dependency error +-dontwarn android.view.inputmethod.InputMethodManager + # Keep all classes extended from com.android.gallery3d.common.Entry # Since we annotate on the fields and use reflection to create SQL # according to those field. diff --git a/res/drawable-hdpi/ic_menu_display_bookmark.png b/res/drawable-hdpi/ic_menu_display_bookmark.png Binary files differindex a5118ea85..a5118ea85 100755..100644 --- a/res/drawable-hdpi/ic_menu_display_bookmark.png +++ b/res/drawable-hdpi/ic_menu_display_bookmark.png diff --git a/res/drawable-mdpi/ic_menu_display_bookmark.png b/res/drawable-mdpi/ic_menu_display_bookmark.png Binary files differindex a3acdd64b..a3acdd64b 100755..100644 --- a/res/drawable-mdpi/ic_menu_display_bookmark.png +++ b/res/drawable-mdpi/ic_menu_display_bookmark.png diff --git a/res/drawable-xhdpi/ic_menu_display_bookmark.png b/res/drawable-xhdpi/ic_menu_display_bookmark.png Binary files differindex 4ad8414be..4ad8414be 100755..100644 --- a/res/drawable-xhdpi/ic_menu_display_bookmark.png +++ b/res/drawable-xhdpi/ic_menu_display_bookmark.png diff --git a/res/layout/bookmark.xml b/res/layout/bookmark.xml index 9b765d4d9..ac4ac34a4 100755..100644 --- a/res/layout/bookmark.xml +++ b/res/layout/bookmark.xml @@ -1,22 +1,21 @@ <?xml version="1.0" encoding="utf-8"?> <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" - android:layout_height="match_parent" - > + android:layout_height="match_parent" > + <ListView android:id="@android:id/list" android:layout_width="match_parent" - android:layout_height="match_parent" - /> + android:layout_height="match_parent" /> + <TextView android:id="@android:id/empty" - android:layout_width="match_parent" + android:layout_width="match_parent" android:layout_height="match_parent" android:layout_centerInParent="true" + android:gravity="center" android:paddingBottom="30dip" - android:gravity ="center" - android:textAppearance="?android:attr/textAppearanceLarge" android:text="@string/bookmark_empty" - android:visibility="gone" - /> + android:textAppearance="?android:attr/textAppearanceLarge" + android:visibility="gone" /> </FrameLayout> diff --git a/res/layout/bookmark_edit_dialog.xml b/res/layout/bookmark_edit_dialog.xml index fa1439cdb..8282d39af 100755..100644 --- a/res/layout/bookmark_edit_dialog.xml +++ b/res/layout/bookmark_edit_dialog.xml @@ -1,37 +1,43 @@ <?xml version="1.0" encoding="utf-8"?> <ScrollView xmlns:android="http://schemas.android.com/apk/res/android" - android:layout_width="wrap_content" - android:layout_height="wrap_content"> + android:layout_width="wrap_content" + android:layout_height="wrap_content" > + <LinearLayout - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:padding="8dip" - android:orientation="vertical"> - <TextView + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="vertical" + android:padding="8dip" > + + <TextView + style="?android:attr/textAppearanceSmallInverse" android:layout_width="wrap_content" android:layout_height="wrap_content" - style="?android:attr/textAppearanceSmallInverse" android:text="@string/bookmark_title" /> - <EditText + + <EditText android:id="@+id/title" - android:layout_width="match_parent" + android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="2dip" - android:singleLine="true" android:inputType="text" - android:scrollHorizontally="true" /> - <TextView + android:scrollHorizontally="true" + android:singleLine="true" /> + + <TextView + style="?android:attr/textAppearanceSmallInverse" android:layout_width="wrap_content" android:layout_height="wrap_content" - style="?android:attr/textAppearanceSmallInverse" android:text="@string/bookmark_location" /> - <EditText + + <EditText android:id="@+id/data" - android:layout_width="match_parent" + android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="2dip" - android:singleLine="true" android:inputType="textUri" - android:scrollHorizontally="true" /> - </LinearLayout> -</ScrollView>
\ No newline at end of file + android:scrollHorizontally="true" + android:singleLine="true" /> + </LinearLayout> + +</ScrollView> diff --git a/res/layout/bookmark_item.xml b/res/layout/bookmark_item.xml index a743e9e17..3fb2fab89 100755..100644 --- a/res/layout/bookmark_item.xml +++ b/res/layout/bookmark_item.xml @@ -3,19 +3,19 @@ android:id="@+id/panel" android:layout_width="match_parent" android:layout_height="wrap_content" - android:padding="6dip" android:orientation="vertical" - > + android:padding="6dip" > + <TextView - android:id="@+id/title" - android:layout_width="wrap_content" + android:id="@+id/title" + android:layout_width="wrap_content" android:layout_height="match_parent" - android:textAppearance="?android:attr/textAppearanceMedium" android:singleLine="true" - /> - <TextView + android:textAppearance="?android:attr/textAppearanceMedium" /> + + <TextView android:id="@+id/data" - android:layout_width="wrap_content" - android:layout_height="match_parent" - /> + android:layout_width="wrap_content" + android:layout_height="match_parent" /> + </LinearLayout> diff --git a/res/layout/movie_view.xml b/res/layout/movie_view.xml index 75b8dfd4f..a08679280 100644 --- a/res/layout/movie_view.xml +++ b/res/layout/movie_view.xml @@ -19,7 +19,7 @@ android:background="@android:color/black" android:layout_width="match_parent" android:layout_height="match_parent"> - <VideoView android:id="@+id/surface_view" + <org.codeaurora.gallery3d.video.CodeauroraVideoView android:id="@+id/surface_view" android:visibility="invisible" android:layout_width="match_parent" android:layout_height="match_parent" diff --git a/res/values-zh-rCN/codeaurora_strings.xml b/res/values-zh-rCN/codeaurora_strings.xml index cdf3c7811..ad4aefc6a 100644 --- a/res/values-zh-rCN/codeaurora_strings.xml +++ b/res/values-zh-rCN/codeaurora_strings.xml @@ -1,7 +1,71 @@ <?xml version="1.0" encoding="utf-8"?> +<!-- +Copyright (c) 2013, The Linux Foundation. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of The Linux Foundation nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED +WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS +BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE +OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN +IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +--> + <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="loop">"循环"</string> <string name="single">"单次"</string> <string name="stereo">"立体声"</string> <string name="single_track">"单声道"</string> + <string name="media_detail">"媒体详情"</string> + <string name="input_url">"输入 URL"</string> + <string name="streaming_settings">"流媒体设置"</string> + + <string name="rtp">RTP</string> + <string name="rtcp">RTCP</string> + <string name="min_port">最小端口:</string> + <string name="max_port">最大端口:</string> + <string name="buffer_size">缓存大小</string> + <string name="apn">优先接入点</string> + <string name="rtp_min_port">RTP最小端口</string> + <string name="rtp_max_port">RTP最大端口</string> + <string name="rtcp_min_port">RTCP最小端口</string> + <string name="rtcp_max_port">RTCP最大端口</string> + <string name="set_rtp_min_port">设置RTP最小端口</string> + <string name="set_rtp_max_port">设置RTP最大端口</string> + <string name="set_rtcp_min_port">设置RTCP最小端口</string> + <string name="set_rtcp_max_port">设置RTCP最大端口</string> + <string name="set_buffer_size">设置缓冲大小</string> + <string name="set_apn">选择接入优先点</string> + <string name="setting">设置</string> + + <string name="server_timeout_title">"服务器超时"</string> + <string name="server_timeout_message">"是否重新连接服务器以播放该视频?"</string> + + <string name="bookmark_add">"添加书签"</string> + <string name="bookmark_display">"显示书签"</string> + <string name="bookmark_empty">"无书签"</string> + <string name="bookmark_exist">"已存在相同书签"</string> + <string name="bookmark_add_success">"添加书签成功"</string> + <string name="bookmark_list">"书签列表"</string> + <string name="bookmark_title">"标题"</string> + <string name="bookmark_location">"地址"</string> + <string name="delete_all">"删除所有"</string> + <string name="default_title">"默认标题"</string> </resources> diff --git a/res/values-zh-rTW/codeaurora_strings.xml b/res/values-zh-rTW/codeaurora_strings.xml index 8af6493d4..d72a86ecb 100644 --- a/res/values-zh-rTW/codeaurora_strings.xml +++ b/res/values-zh-rTW/codeaurora_strings.xml @@ -1,7 +1,71 @@ <?xml version="1.0" encoding="utf-8"?> +<!-- +Copyright (c) 2013, The Linux Foundation. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of The Linux Foundation nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED +WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS +BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE +OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN +IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +--> + <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="loop">"循環"</string> <string name="single">"單次"</string> <string name="stereo">"立體聲"</string> <string name="single_track">"單聲道"</string> + <string name="media_detail">"媒體詳情"</string> + <string name="input_url">"輸入 URL"</string> + <string name="streaming_settings">"串流設定"</string> + + <string name="rtp">RTP</string> + <string name="rtcp">RTCP</string> + <string name="min_port">最小端口:</string> + <string name="max_port">最大端口:</string> + <string name="buffer_size">緩存大小</string> + <string name="apn">優先接入點</string> + <string name="rtp_min_port">RTP最小端口</string> + <string name="rtp_max_port">RTP最大端口</string> + <string name="rtcp_min_port">RTCP最小端口</string> + <string name="rtcp_max_port">RTCP最大端口</string> + <string name="set_rtp_min_port">設置RTP最小端口</string> + <string name="set_rtp_max_port">設置RTP最大端口</string> + <string name="set_rtcp_min_port">設置RTCP最小端口</string> + <string name="set_rtcp_max_port">設置RTCP最大端口</string> + <string name="set_buffer_size">設置緩衝大小</string> + <string name="set_apn">選擇接入優先點</string> + <string name="setting">設置</string> + + <string name="server_timeout_title">"伺服器逾時"</string> + <string name="server_timeout_message">"是否重新連線伺服器並播放視訊?"</string> + + <string name="bookmark_add">"添加書簽"</string> + <string name="bookmark_display">"顯示書簽"</string> + <string name="bookmark_empty">"無書簽"</string> + <string name="bookmark_exist">"已存在相同書簽"</string> + <string name="bookmark_add_success">"添加書簽成功"</string> + <string name="bookmark_list">"書簽列表"</string> + <string name="bookmark_title">"標題"</string> + <string name="bookmark_location">"位置"</string> + <string name="delete_all">"刪除所有"</string> + <string name="default_title">"默認標題"</string> </resources> diff --git a/res/values/bool.xml b/res/values/bool.xml index 802388e94..8d2a9f9bc 100755 --- a/res/values/bool.xml +++ b/res/values/bool.xml @@ -17,4 +17,5 @@ <bool name="show_action_bar_title">false</bool> <bool name="loop">false</bool> <bool name="stereo">false</bool> + <bool name="streaming">false</bool> </resources>
\ No newline at end of file diff --git a/res/values/codeaurora_strings.xml b/res/values/codeaurora_strings.xml index 5d918b522..09de79cae 100644 --- a/res/values/codeaurora_strings.xml +++ b/res/values/codeaurora_strings.xml @@ -1,7 +1,71 @@ <?xml version="1.0" encoding="utf-8"?> +<!-- +Copyright (c) 2013, The Linux Foundation. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of The Linux Foundation nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED +WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS +BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE +OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN +IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +--> + <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="loop">"Loop"</string> <string name="single">"Single"</string> <string name="stereo">"Stereo"</string> <string name="single_track">"Single track"</string> + <string name="media_detail">"Media details"</string> + <string name="input_url">"Input URL"</string> + <string name="streaming_settings">"Streaming Settings"</string> + + <string name="rtp">RTP</string> + <string name="rtcp">RTCP</string> + <string name="min_port">min port:</string> + <string name="max_port">max port:</string> + <string name="buffer_size">Buffer Size</string> + <string name="apn">Prefered APN</string> + <string name="rtp_min_port">Min port</string> + <string name="rtp_max_port">Max port</string> + <string name="rtcp_min_port">Min port</string> + <string name="rtcp_max_port">Max port</string> + <string name="set_rtp_min_port">Set min port</string> + <string name="set_rtp_max_port">Set max port</string> + <string name="set_rtcp_min_port">Set min port</string> + <string name="set_rtcp_max_port">Set max port</string> + <string name="set_buffer_size">Set buffer size</string> + <string name="set_apn">Select prefered apn</string> + <string name="setting">Settings</string> + + <string name="server_timeout_title">"Server Timeout"</string> + <string name="server_timeout_message">"Reconnect the server to play the video or not?"</string> + + <string name="bookmark_add">"Add bookmark"</string> + <string name="bookmark_display">"Show bookmarks"</string> + <string name="bookmark_empty">"No bookmarks"</string> + <string name="bookmark_exist">"Same bookmark in history"</string> + <string name="bookmark_add_success">"Add bookmark success"</string> + <string name="bookmark_list">"Bookmarks"</string> + <string name="bookmark_title">"Title"</string> + <string name="bookmark_location">"Location"</string> + <string name="delete_all">"Delete all"</string> + <string name="default_title">"Default title"</string> </resources> diff --git a/res/xml/rtsp_settings_preferences.xml b/res/xml/rtsp_settings_preferences.xml index b15080dfa..a5853808b 100755..100644 --- a/res/xml/rtsp_settings_preferences.xml +++ b/res/xml/rtsp_settings_preferences.xml @@ -1,89 +1,57 @@ <?xml version="1.0" encoding="utf-8"?> -<!-- -write by lhy ---> - -<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"> - - <PreferenceCategory - android:title="@string/rtp"> +<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android" > + <PreferenceCategory android:title="@string/rtp" > <EditTextPreference - android:order="1" + android:dialogTitle="@string/set_rtp_min_port" + android:inputType="number" android:key="rtp_min_port" - android:title="@string/rtp_min_port" + android:maxLength="5" + android:order="1" android:summary="" - android:inputType="number" - android:maxLength="5" - android:dialogTitle="@string/set_rtp_min_port" /> - + android:title="@string/rtp_min_port" /> <EditTextPreference - android:order="2" + android:dialogTitle="@string/rtp_max_port" + android:inputType="number" android:key="rtp_max_port" - android:title="@string/rtp_max_port" + android:maxLength="5" + android:order="2" android:summary="" - android:inputType="number" - android:maxLength="5" - android:dialogTitle="@string/rtp_max_port" /> + android:title="@string/rtp_max_port" /> </PreferenceCategory> - - <PreferenceCategory - android:title="@string/rtcp"> - + <PreferenceCategory android:title="@string/rtcp" > <EditTextPreference - android:order="3" + android:dialogTitle="@string/set_rtcp_min_port" + android:inputType="number" android:key="rtcp_min_port" - android:title="@string/rtcp_min_port" + android:maxLength="5" + android:order="3" android:summary="" - android:inputType="number" - android:maxLength="5" - android:dialogTitle="@string/set_rtcp_min_port" /> - + android:title="@string/rtcp_min_port" /> <EditTextPreference - android:order="4" + android:dialogTitle="@string/rtcp_max_port" + android:inputType="number" android:key="rtcp_max_port" - android:title="@string/rtcp_max_port" + android:maxLength="5" + android:order="4" android:summary="" - android:inputType="number" - android:maxLength="5" - android:dialogTitle="@string/rtcp_max_port" /> + android:title="@string/rtcp_max_port" /> </PreferenceCategory> - - <PreferenceCategory - android:title="@string/buffer_size"> - + <PreferenceCategory android:title="@string/buffer_size" > <EditTextPreference - android:order="5" + android:dialogTitle="@string/set_buffer_size" + android:inputType="number" android:key="buffer_size" - android:title="@string/buffer_size" + android:maxLength="5" + android:order="5" android:summary="" - android:inputType="number" - android:maxLength="5" - android:dialogTitle="@string/set_buffer_size" /> - + android:title="@string/buffer_size" /> </PreferenceCategory> - - <PreferenceCategory android:title="@string/apn"> - <PreferenceScreen - android:key="apn" - android:title="@string/apn"> - <!-- - <intent - android:action="android.intent.action.MAIN" - android:targetPackage="com.android.settings" - android:targetClass="com.android.settings.ApnSettings" /> - --> - </PreferenceScreen> - <!-- - <ListPreference - android:order="6" + <PreferenceCategory android:title="@string/apn" > + <PreferenceScreen android:key="apn" - android:title="@string/apn" - android:entries="@array/apn_entries" - android:entryValues="@array/apn_values" - android:dialogTitle="@string/set_apn" /> - --> + android:title="@string/apn" > + </PreferenceScreen> </PreferenceCategory> - </PreferenceScreen> diff --git a/src/com/android/gallery3d/app/ControllerOverlay.java b/src/com/android/gallery3d/app/ControllerOverlay.java index 078f59e28..36eda6257 100644 --- a/src/com/android/gallery3d/app/ControllerOverlay.java +++ b/src/com/android/gallery3d/app/ControllerOverlay.java @@ -27,6 +27,8 @@ public interface ControllerOverlay { void onSeekEnd(int time, int trimStartTime, int trimEndTime); void onShown(); void onHidden(); + // get current video is from RTSP + boolean onIsRTSP(); void onReplay(); } diff --git a/src/com/android/gallery3d/app/MovieActivity.java b/src/com/android/gallery3d/app/MovieActivity.java index ec5f40b00..8f0a605e4 100755 --- a/src/com/android/gallery3d/app/MovieActivity.java +++ b/src/com/android/gallery3d/app/MovieActivity.java @@ -20,6 +20,7 @@ import android.annotation.TargetApi; import android.app.ActionBar; import android.app.Activity; import android.app.AlertDialog; +import android.app.KeyguardManager; import android.bluetooth.BluetoothClass; import android.bluetooth.BluetoothDevice; import android.content.AsyncQueryHandler; @@ -41,6 +42,7 @@ import android.media.audiofx.BassBoost; import android.media.audiofx.Virtualizer; import android.media.MediaPlayer; import android.net.Uri; +import android.os.AsyncTask; import android.os.Build; import android.os.Bundle; import android.provider.MediaStore; @@ -66,6 +68,7 @@ import org.codeaurora.gallery3d.ext.IActivityHooker; import org.codeaurora.gallery3d.ext.MovieItem; import org.codeaurora.gallery3d.ext.IMovieItem; import org.codeaurora.gallery3d.video.ExtensionHelper; +import org.codeaurora.gallery3d.video.MovieTitleHelper; /** * This activity plays a video from a specified URI. @@ -77,8 +80,13 @@ import org.codeaurora.gallery3d.video.ExtensionHelper; public class MovieActivity extends Activity { @SuppressWarnings("unused") 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/*"; private MoviePlayer mPlayer; private boolean mFinishOnCompletion; @@ -105,6 +113,9 @@ public class MovieActivity extends Activity { private IMovieItem mMovieItem; private IActivityHooker mMovieHooker; + private KeyguardManager mKeyguardManager; + private boolean mResumed = false; + private boolean mControlResumed = false; private final BroadcastReceiver mReceiver = new BroadcastReceiver() { @Override @@ -214,27 +225,8 @@ public class MovieActivity extends Activity { mPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() { @Override public void onPrepared(MediaPlayer mp) { - int sessionId = mp.getAudioSessionId(); - if (mBassBoostSupported) { - mBassBoostEffect = new BassBoost(0, sessionId); - } - if (mVirtualizerSupported) { - mVirtualizerEffect = new Virtualizer(0, sessionId); - } - if (mIsHeadsetOn) { - if (mPrefs.getBoolean(Key.global_enabled.toString(), false)) { - if (mBassBoostSupported) { - mBassBoostEffect.setStrength((short) - mPrefs.getInt(Key.bb_strength.toString(), 0)); - mBassBoostEffect.setEnabled(true); - } - if (mVirtualizerSupported) { - mVirtualizerEffect.setStrength((short) - mPrefs.getInt(Key.virt_strength.toString(), 0)); - mVirtualizerEffect.setEnabled(true); - } - } - } + mPlayer.onPrepared(mp); + initEffects(mp.getAudioSessionId()); } }); } @@ -429,10 +421,59 @@ public class MovieActivity extends Activity { } } + public void initEffects(int sessionId) { + // Singleton instance + if ((mBassBoostEffect == null) && mBassBoostSupported) { + mBassBoostEffect = new BassBoost(0, sessionId); + } + + if ((mVirtualizerEffect == null) && mVirtualizerSupported) { + mVirtualizerEffect = new Virtualizer(0, sessionId); + } + + if (mIsHeadsetOn) { + if (mPrefs.getBoolean(Key.global_enabled.toString(), false)) { + if (mBassBoostSupported) { + mBassBoostEffect.setStrength((short) + mPrefs.getInt(Key.bb_strength.toString(), 0)); + mBassBoostEffect.setEnabled(true); + } + if (mVirtualizerSupported) { + mVirtualizerEffect.setStrength((short) + mPrefs.getInt(Key.virt_strength.toString(), 0)); + mVirtualizerEffect.setEnabled(true); + } + } else { + if (mBassBoostSupported) { + mBassBoostEffect.setStrength((short) + mPrefs.getInt(Key.bb_strength.toString(), 0)); + } + if (mVirtualizerSupported) { + mVirtualizerEffect.setStrength((short) + mPrefs.getInt(Key.virt_strength.toString(), 0)); + } + } + } + + } + + public void releaseEffects() { + if (mBassBoostEffect != null) { + mBassBoostEffect.setEnabled(false); + mBassBoostEffect.release(); + mBassBoostEffect = null; + } + if (mVirtualizerEffect != null) { + mVirtualizerEffect.setEnabled(false); + mVirtualizerEffect.release(); + mVirtualizerEffect = null; + } + } + private Intent createShareIntent() { Intent intent = new Intent(Intent.ACTION_SEND); intent.setType("video/*"); - intent.putExtra(Intent.EXTRA_STREAM, mUri); + intent.putExtra(Intent.EXTRA_STREAM, mMovieItem.getUri()); return intent; } @@ -466,6 +507,7 @@ public class MovieActivity extends Activity { AudioManager.AUDIOFOCUS_GAIN_TRANSIENT); super.onStart(); mMovieHooker.onStart(); + registerScreenOff(); } @Override @@ -473,24 +515,36 @@ public class MovieActivity extends Activity { ((AudioManager) getSystemService(AUDIO_SERVICE)) .abandonAudioFocus(null); super.onStop(); + if (mControlResumed && mPlayer != null) { + mPlayer.onStop(); + mControlResumed = false; + } mMovieHooker.onStop(); + unregisterScreenOff(); } @Override public void onPause() { - mPlayer.onPause(); + // Audio track will be deallocated for local video playback, + // thus recycle effect here. + releaseEffects(); try { unregisterReceiver(mReceiver); } catch (IllegalArgumentException e) { // Do nothing } + mResumed = false; + if (mControlResumed && mPlayer != null) { + mControlResumed = !mPlayer.onPause(); + } super.onPause(); mMovieHooker.onPause(); } @Override public void onResume() { - mPlayer.onResume(); + invalidateOptionsMenu(); + if ((mVirtualizerSupported) || (mBassBoostSupported)) { final IntentFilter intentFilter = new IntentFilter(Intent.ACTION_HEADSET_PLUG); intentFilter.addAction(BluetoothDevice.ACTION_ACL_CONNECTED); @@ -498,6 +552,14 @@ public class MovieActivity extends Activity { intentFilter.addAction(AudioManager.ACTION_AUDIO_BECOMING_NOISY); registerReceiver(mReceiver, intentFilter); } + + initEffects(mPlayer.getAudioSessionId()); + mResumed = true; + if (!isKeyguardLocked() && !mControlResumed && mPlayer != null) { + mPlayer.onResume(); + mControlResumed = true; + } + enhanceActionBar(); super.onResume(); mMovieHooker.onResume(); } @@ -524,6 +586,20 @@ public class MovieActivity extends Activity { } @Override + public void onWindowFocusChanged(boolean hasFocus) { + super.onWindowFocusChanged(hasFocus); + if (LOG) { + Log.v(TAG, "onWindowFocusChanged(" + hasFocus + ") isKeyguardLocked=" + + isKeyguardLocked() + + ", mResumed=" + mResumed + ", mControlResumed=" + mControlResumed); + } + if (hasFocus && !isKeyguardLocked() && mResumed && !mControlResumed && mPlayer != null) { + mPlayer.onResume(); + mControlResumed = true; + } + } + + @Override public boolean onKeyDown(int keyCode, KeyEvent event) { return mPlayer.onKeyDown(keyCode, event) || super.onKeyDown(keyCode, event); @@ -544,7 +620,109 @@ public class MovieActivity extends Activity { private void initMovieInfo(Intent intent) { Uri original = intent.getData(); String mimeType = intent.getType(); - mMovieItem = new MovieItem(original, mimeType, null); + if (VIDEO_SDP_MIME_TYPE.equalsIgnoreCase(mimeType) + && VIDEO_FILE_SCHEMA.equalsIgnoreCase(original.getScheme())) { + mMovieItem = new MovieItem(VIDEO_SDP_TITLE + original, mimeType, null); + } else { + mMovieItem = new MovieItem(original, mimeType, null); + } mMovieItem.setOriginalUri(original); } + + // we do not stop live streaming when other dialog overlays it. + private BroadcastReceiver mScreenOffReceiver = new BroadcastReceiver() { + + @Override + public void onReceive(Context context, Intent intent) { + if (LOG) { + Log.v(TAG, "onReceive(" + intent.getAction() + ") mControlResumed=" + + mControlResumed); + } + if (Intent.ACTION_SCREEN_OFF.equals(intent.getAction())) { + // Only stop video. + if (mControlResumed) { + mPlayer.onStop(); + mControlResumed = false; + } + } + } + + }; + + private void registerScreenOff() { + IntentFilter filter = new IntentFilter(); + filter.addAction(Intent.ACTION_SCREEN_OFF); + registerReceiver(mScreenOffReceiver, filter); + } + + private void unregisterScreenOff() { + unregisterReceiver(mScreenOffReceiver); + } + + private boolean isKeyguardLocked() { + if (mKeyguardManager == null) { + mKeyguardManager = (KeyguardManager) getSystemService(Context.KEYGUARD_SERVICE); + } + // isKeyguardSecure excludes the slide lock case. + boolean locked = (mKeyguardManager != null) + && mKeyguardManager.inKeyguardRestrictedInputMode(); + if (LOG) { + Log.v(TAG, "isKeyguardLocked() locked=" + locked + ", mKeyguardManager=" + + mKeyguardManager); + } + return locked; + } + + private void enhanceActionBar() { + final IMovieItem movieItem = mMovieItem;// remember original item + final Uri uri = mMovieItem.getUri(); + final String scheme = mMovieItem.getUri().getScheme(); + final String authority = mMovieItem.getUri().getAuthority(); + new AsyncTask<Void, Void, String>() { + @Override + protected String doInBackground(Void... params) { + String title = null; + if (ContentResolver.SCHEME_FILE.equals(scheme)) { + title = MovieTitleHelper.getTitleFromMediaData(MovieActivity.this, uri); + } else if (ContentResolver.SCHEME_CONTENT.equals(scheme)) { + title = MovieTitleHelper.getTitleFromDisplayName(MovieActivity.this, uri); + if (title == null) { + title = MovieTitleHelper.getTitleFromData(MovieActivity.this, uri); + } + } + if (title == null) { + title = MovieTitleHelper.getTitleFromUri(uri); + } + if (LOG) { + Log.v(TAG, "enhanceActionBar() task return " + title); + } + return title; + } + + @Override + protected void onPostExecute(String result) { + if (LOG) { + Log.v(TAG, "onPostExecute(" + result + ") movieItem=" + movieItem + + ", mMovieItem=" + mMovieItem); + } + movieItem.setTitle(result); + if (movieItem == mMovieItem) { + setActionBarTitle(result); + } + }; + }.execute(); + if (LOG) { + Log.v(TAG, "enhanceActionBar() " + mMovieItem); + } + } + + public void setActionBarTitle(String title) { + if (LOG) { + Log.v(TAG, "setActionBarTitle(" + title + ")"); + } + ActionBar actionBar = getActionBar(); + if (title != null) { + actionBar.setTitle(title); + } + } } diff --git a/src/com/android/gallery3d/app/MoviePlayer.java b/src/com/android/gallery3d/app/MoviePlayer.java index fb12e249f..4ab7c14d1 100644..100755 --- a/src/com/android/gallery3d/app/MoviePlayer.java +++ b/src/com/android/gallery3d/app/MoviePlayer.java @@ -24,10 +24,14 @@ import android.content.Context; import android.content.DialogInterface; import android.content.DialogInterface.OnCancelListener; import android.content.DialogInterface.OnClickListener; +import android.content.DialogInterface.OnDismissListener; +import android.content.DialogInterface.OnShowListener; import android.content.Intent; import android.content.IntentFilter; +import android.graphics.Color; import android.media.AudioManager; import android.media.MediaPlayer; +import android.media.Metadata; import android.media.audiofx.AudioEffect; import android.media.audiofx.Virtualizer; import android.net.Uri; @@ -40,6 +44,7 @@ import android.view.SurfaceView; import android.view.View; import android.view.ViewGroup; import android.widget.VideoView; +import android.widget.Toast; import com.android.gallery3d.R; import com.android.gallery3d.common.ApiHelper; @@ -48,18 +53,27 @@ import com.android.gallery3d.util.CacheManager; import com.android.gallery3d.util.GalleryUtils; 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.CodeauroraVideoView; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.DataInputStream; import java.io.DataOutputStream; +import java.util.HashMap; +import java.util.Map; public class MoviePlayer implements MediaPlayer.OnErrorListener, MediaPlayer.OnCompletionListener, - ControllerOverlay.Listener { + ControllerOverlay.Listener, + MediaPlayer.OnInfoListener, + MediaPlayer.OnPreparedListener, + MediaPlayer.OnSeekCompleteListener { @SuppressWarnings("unused") private static final String TAG = "MoviePlayer"; + private static final boolean LOG = false; private static final String KEY_VIDEO_POSITION = "video-position"; private static final String KEY_RESUMEABLE_TIME = "resumeable-timeout"; @@ -73,18 +87,30 @@ public class MoviePlayer implements private static final String CMDNAME = "command"; private static final String CMDPAUSE = "pause"; + private static final String KEY_VIDEO_CAN_SEEK = "video_can_seek"; + private static final String KEY_VIDEO_CAN_PAUSE = "video_can_pause"; + private static final String KEY_VIDEO_LAST_DURATION = "video_last_duration"; + private static final String KEY_VIDEO_LAST_DISCONNECT_TIME = "last_disconnect_time"; + private static final String KEY_VIDEO_STREAMING_TYPE = "video_streaming_type"; + private static final String KEY_VIDEO_STATE = "video_state"; + private static final String VIRTUALIZE_EXTRA = "virtualize"; private static final long BLACK_TIMEOUT = 500; + private static final int DELAY_REMOVE_MS = 10000; + public static final int SERVER_TIMEOUT = 8801; // If we resume the acitivty with in RESUMEABLE_TIMEOUT, we will keep playing. // Otherwise, we pause the player. private static final long RESUMEABLE_TIMEOUT = 3 * 60 * 1000; // 3 mins public static final int STREAMING_LOCAL = 0; + public static final int STREAMING_HTTP = 1; + public static final int STREAMING_RTSP = 2; + public static final int STREAMING_SDP = 3; private int mStreamingType = STREAMING_LOCAL; private Context mContext; - private final VideoView mVideoView; + private final CodeauroraVideoView mVideoView; private final View mRootView; private final Bookmarker mBookmarker; private final Uri mUri; @@ -97,6 +123,7 @@ public class MoviePlayer implements private boolean mHasPaused = false; private boolean mVideoHasPaused = false; private boolean mCanResumed = false; + private boolean mFirstBePlayed = false; private boolean mKeyguardLocked = false; private int mLastSystemUiVis = 0; @@ -108,10 +135,18 @@ public class MoviePlayer implements private Virtualizer mVirtualizer; + private MovieActivity mActivityContext;//for dialog and toast context private MoviePlayerExtension mPlayerExt = new MoviePlayerExtension(); + private RetryExtension mRetryExt = new RetryExtension(); + private ServerTimeoutExtension mServerTimeoutExt = new ServerTimeoutExtension(); private boolean mCanReplay; + private boolean mVideoCanSeek = false; + private boolean mVideoCanPause = false; + private boolean mWaitMetaData; + private boolean mIsShowResumingDialog; private TState mTState = TState.PLAYING; private IMovieItem mMovieItem; + private int mVideoLastDuration;//for duration displayed in init state private enum TState { PLAYING, @@ -145,6 +180,16 @@ public class MoviePlayer implements } }; + private Runnable mDelayVideoRunnable = new Runnable() { + @Override + public void run() { + if (LOG) { + Log.v(TAG, "mDelayVideoRunnable.run()"); + } + mVideoView.setVisibility(View.VISIBLE); + } + }; + private final BroadcastReceiver mReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { @@ -164,7 +209,7 @@ public class MoviePlayer implements IMovieItem info, Bundle savedInstance, boolean canReplay) { mContext = movieActivity.getApplicationContext(); mRootView = rootView; - mVideoView = (VideoView) rootView.findViewById(R.id.surface_view); + mVideoView = (CodeauroraVideoView) rootView.findViewById(R.id.surface_view); mBookmarker = new Bookmarker(movieActivity); mController = new MovieControllerOverlay(mContext); @@ -172,7 +217,7 @@ public class MoviePlayer implements mController.setListener(this); mController.setCanReplay(canReplay); - init(info, canReplay); + init(movieActivity, info, canReplay); mUri = mMovieItem.getUri(); mVideoView.setOnErrorListener(this); @@ -246,11 +291,13 @@ public class MoviePlayer implements onRestoreInstanceState(savedInstance); mHasPaused = true; } else { - final Integer bookmark = mBookmarker.getBookmark(mUri); + mTState = TState.PLAYING; + mFirstBePlayed = true; + final BookmarkerInfo bookmark = mBookmarker.getBookmark(mMovieItem.getUri()); if (bookmark != null) { showResumeDialog(movieActivity, bookmark); } else { - startVideo(); + doStartVideo(false, 0, 0); } } } @@ -298,12 +345,12 @@ public class MoviePlayer implements onSaveInstanceStateMore(outState); } - private void showResumeDialog(Context context, final int bookmark) { + private void showResumeDialog(Context context, final BookmarkerInfo bookmark) { AlertDialog.Builder builder = new AlertDialog.Builder(context); builder.setTitle(R.string.resume_playing_title); builder.setMessage(String.format( context.getString(R.string.resume_playing_message), - GalleryUtils.formatDuration(context, bookmark / 1000))); + GalleryUtils.formatDuration(context, bookmark.mBookmark / 1000))); builder.setOnCancelListener(new OnCancelListener() { @Override public void onCancel(DialogInterface dialog) { @@ -314,46 +361,146 @@ public class MoviePlayer implements R.string.resume_playing_resume, new OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { - mVideoView.seekTo(bookmark); - startVideo(); + // here try to seek for bookmark + mVideoCanSeek = true; + doStartVideo(true, bookmark.mBookmark, bookmark.mDuration); } }); builder.setNegativeButton( R.string.resume_playing_restart, new OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { - startVideo(); + doStartVideo(true, 0, bookmark.mDuration); } }); - builder.show(); + AlertDialog dialog = builder.create(); + dialog.setOnShowListener(new OnShowListener() { + @Override + public void onShow(DialogInterface arg0) { + mIsShowResumingDialog = true; + } + }); + dialog.setOnDismissListener(new OnDismissListener() { + @Override + public void onDismiss(DialogInterface arg0) { + mIsShowResumingDialog = false; + } + }); + dialog.show(); } - public void onPause() { + public boolean onPause() { + if (LOG) { + Log.v(TAG, "onPause() isLiveStreaming()=" + isLiveStreaming()); + } + boolean pause = false; + if (isLiveStreaming()) { + pause = false; + } else { + doOnPause(); + pause = true; + } + if (LOG) { + Log.v(TAG, "onPause() , return " + pause); + } + return pause; + } + + // we should stop video anyway after this function called. + public void onStop() { + if (LOG) { + Log.v(TAG, "onStop() mHasPaused=" + mHasPaused); + } + if (!mHasPaused) { + doOnPause(); + } + } + + private void doOnPause() { + long start = System.currentTimeMillis(); + addBackground(); mHasPaused = true; mHandler.removeCallbacksAndMessages(null); - mVideoPosition = mVideoView.getCurrentPosition(); - mBookmarker.setBookmark(mUri, mVideoPosition, mVideoView.getDuration()); - mVideoView.suspend(); + int position = mVideoView.getCurrentPosition(); + mVideoPosition = position >= 0 ? position : mVideoPosition; + Log.v(TAG, "mVideoPosition is " + mVideoPosition); + int duration = mVideoView.getDuration(); + 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(); 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 + mServerTimeoutExt.recordDisconnectTime(); + if (LOG) { + Log.v(TAG, "doOnPause() save video info consume:" + (end1 - start)); + Log.v(TAG, "doOnPause() suspend video consume:" + (end2 - end1)); + Log.v(TAG, "doOnPause() mVideoPosition=" + mVideoPosition + ", mResumeableTime=" + + mResumeableTime + + ", mVideoLastDuration=" + mVideoLastDuration + ", mIsShowResumingDialog=" + + mIsShowResumingDialog); + } } public void onResume() { + mDragging = false;// clear drag info if (mHasPaused) { - mVideoView.seekTo(mVideoPosition); - mVideoView.resume(); + //M: same as launch case to delay transparent. + mVideoView.removeCallbacks(mDelayVideoRunnable); + mVideoView.postDelayed(mDelayVideoRunnable, BLACK_TIMEOUT); - // If we have slept for too long, pause the play - if (System.currentTimeMillis() > mResumeableTime) { - pauseVideo(); - } else if (mKeyguardLocked){ - // If Keyguard Locked , pause the play - mCanResumed = true; - mVideoView.pause(); + if (mServerTimeoutExt.handleOnResume() || mIsShowResumingDialog) { + mHasPaused = false; + return; } + switch (mTState) { + case RETRY_ERROR: + mRetryExt.showRetry(); + break; + case STOPED: + mPlayerExt.stopVideo(); + break; + case COMPELTED: + mController.showEnded(); + if (mVideoCanSeek || mVideoView.canSeekForward()) { + mVideoView.seekTo(mVideoPosition); + } + mVideoView.setDuration(mVideoLastDuration); + break; + case PAUSED: + // if video was paused, so it should be started. + doStartVideo(true, mVideoPosition, mVideoLastDuration, false); + pauseVideo(); + break; + default: + doStartVideo(true, mVideoPosition, mVideoLastDuration); + pauseVideoMoreThanThreeMinutes(); + break; + } + mHasPaused = false; } mHandler.post(mProgressChecker); } + private void pauseVideoMoreThanThreeMinutes() { + // If we have slept for too long, pause the play + // If is live streaming, do not pause it too + long now = System.currentTimeMillis(); + if (now > mResumeableTime && !isLiveStreaming()) { + if (mVideoCanPause || mVideoView.canPause()) { + pauseVideo(); + } + } + if (LOG) { + Log.v(TAG, "pauseVideoMoreThanThreeMinutes() now=" + now); + } + } + public void onDestroy() { if (mVirtualizer != null) { mVirtualizer.release(); @@ -362,6 +509,7 @@ public class MoviePlayer implements mVideoView.stopPlayback(); mAudioBecomingNoisyReceiver.unregister(); mContext.unregisterReceiver(mReceiver); + mServerTimeoutExt.clearTimeoutDialog(); } // This updates the time bar display (if necessary). It is called every @@ -377,11 +525,13 @@ public class MoviePlayer implements return position; } - private void startVideo() { + private void doStartVideo(final boolean enableFasten, final int position, final int duration, + boolean start) { // For streams that we expect to be slow to start up, show a // progress spinner until playback starts. - String scheme = mUri.getScheme(); - if ("http".equalsIgnoreCase(scheme) || "rtsp".equalsIgnoreCase(scheme)) { + String scheme = mMovieItem.getUri().getScheme(); + if ("http".equalsIgnoreCase(scheme) || "rtsp".equalsIgnoreCase(scheme) + || "https".equalsIgnoreCase(scheme)) { mController.showLoading(); mHandler.removeCallbacks(mPlayingChecker); mHandler.postDelayed(mPlayingChecker, 250); @@ -390,16 +540,43 @@ public class MoviePlayer implements mController.hide(); } - mVideoView.start(); + if (onIsRTSP()) { + Map<String, String> header = new HashMap<String, String>(1); + header.put("CODEAURORA-ASYNC-RTSP-PAUSE-PLAY", "true"); + mVideoView.setVideoURI(mMovieItem.getUri(), header, !mWaitMetaData); + } else { + mVideoView.setVideoURI(mMovieItem.getUri(), null, !mWaitMetaData); + } + if (start) { + mVideoView.start(); + } //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())) { + mVideoView.seekTo(position); + } + if (enableFasten) { + mVideoView.setDuration(duration); + } setProgress(); } + private void doStartVideo(boolean enableFasten, int position, int duration) { + ((AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE)).requestAudioFocus( + null, AudioManager.STREAM_MUSIC, + AudioManager.AUDIOFOCUS_GAIN_TRANSIENT); + doStartVideo(enableFasten, position, duration, true); + } + private void playVideo() { + if (LOG) { + Log.v(TAG, "playVideo()"); + } + mTState = TState.PLAYING; mVideoView.start(); mController.showPlaying(); setProgress(); @@ -407,6 +584,10 @@ public class MoviePlayer implements } private void pauseVideo() { + if (LOG) { + Log.v(TAG, "pauseVideo()"); + } + mTState = TState.PAUSED; mVideoView.pause(); setProgress(); mController.showPaused(); @@ -416,6 +597,13 @@ public class MoviePlayer implements // Below are notifications from VideoView @Override public boolean onError(MediaPlayer player, int arg1, int arg2) { + mMovieItem.setError(); + if (mServerTimeoutExt.onError(player, arg1, arg2)) { + return true; + } + if (mRetryExt.onError(player, arg1, arg2)) { + return true; + } mHandler.removeCallbacksAndMessages(null); // VideoView will show an error dialog if we return false, so no need // to show more message. @@ -425,6 +613,14 @@ public class MoviePlayer implements @Override public void onCompletion(MediaPlayer mp) { + if (LOG) { + Log.v(TAG, "onCompletion() mCanReplay=" + mCanReplay); + } + if (mMovieItem.getError()) { + Log.w(TAG, "error occured, exit the video player!"); + mActivityContext.finish(); + return; + } if (mPlayerExt.getLoop()) { onReplay(); } else { //original logic @@ -467,6 +663,11 @@ public class MoviePlayer implements } @Override + public void onSeekComplete(MediaPlayer mp) { + setProgress(); + } + + @Override public void onShown() { mShowing = true; setProgress(); @@ -480,8 +681,57 @@ public class MoviePlayer implements } @Override + public boolean onInfo(MediaPlayer mp, int what, int extra) { + if (LOG) { + Log.v(TAG, "onInfo() what:" + what + " extra:" + extra); + } + if (what == MediaPlayer.MEDIA_INFO_METADATA_UPDATE && mServerTimeoutExt != null) { + Log.e(TAG, "setServerTimeout " + extra); + mServerTimeoutExt.setTimeout(extra * 1000); + } + if (mRetryExt.onInfo(mp, what, extra)) { + return true; + } + return false; + } + + @Override + public void onPrepared(MediaPlayer mp) { + if (LOG) { + Log.v(TAG, "onPrepared(" + mp + ")"); + } + getVideoInfo(mp); + boolean canPause = mVideoView.canPause(); + boolean canSeek = mVideoView.canSeekBackward() && mVideoView.canSeekForward(); + if (!canPause && !mVideoView.isTargetPlaying()) { + mVideoView.start(); + } + if (LOG) { + Log.v(TAG, "onPrepared() canPause=" + canPause + ", canSeek=" + canSeek); + } + } + + public boolean onIsRTSP() { + if (MovieUtils.isRtspStreaming(mMovieItem.getUri(), mMovieItem + .getMimeType())) { + Log.v(TAG, "onIsRTSP() is RTSP"); + return true; + } + Log.v(TAG, "onIsRTSP() is not RTSP"); + return false; + } + + @Override public void onReplay() { - startVideo(); + if (LOG) { + Log.v(TAG, "onReplay()"); + } + mTState = TState.PLAYING; + mFirstBePlayed = true; + if (mRetryExt.handleOnReplay()) { + return; + } + doStartVideo(false, 0, 0); } // Below are key events passed from MovieActivity. @@ -495,14 +745,14 @@ public class MoviePlayer implements switch (keyCode) { case KeyEvent.KEYCODE_HEADSETHOOK: case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE: - if (mVideoView.isPlaying()) { + if (mVideoView.isPlaying() && mVideoView.canPause()) { pauseVideo(); } else { playVideo(); } return true; case KEYCODE_MEDIA_PAUSE: - if (mVideoView.isPlaying()) { + if (mVideoView.isPlaying() && mVideoView.canPause()) { pauseVideo(); } return true; @@ -533,9 +783,14 @@ public class MoviePlayer implements || keyCode == KeyEvent.KEYCODE_MEDIA_PAUSE; } - private void init(IMovieItem info, boolean canReplay) { + private void init(MovieActivity movieActivity, IMovieItem info, boolean canReplay) { + mActivityContext = movieActivity; mCanReplay = canReplay; mMovieItem = info; + judgeStreamingType(info.getUri(), info.getMimeType()); + + mVideoView.setOnInfoListener(this); + mVideoView.setOnPreparedListener(this); } // We want to pause when the headset is unplugged. @@ -564,6 +819,13 @@ public class MoviePlayer implements mVideoView.setOnPreparedListener(listener); } + public boolean isFullBuffer() { + if (mStreamingType == STREAMING_RTSP || mStreamingType == STREAMING_SDP) { + return false; + } + return true; + } + public boolean isLocalFile() { if (mStreamingType == STREAMING_LOCAL) { return true; @@ -571,6 +833,58 @@ public class MoviePlayer implements return false; } + private void getVideoInfo(MediaPlayer mp) { + if (!MovieUtils.isLocalFile(mMovieItem.getUri(), mMovieItem.getMimeType())) { + Metadata data = mp.getMetadata(MediaPlayer.METADATA_ALL, + MediaPlayer.BYPASS_METADATA_FILTER); + if (data != null) { + // TODO comments by sunlei + mServerTimeoutExt.setVideoInfo(data); + } else { + Log.w(TAG, "Metadata is null!"); + } + } + } + + private void judgeStreamingType(Uri uri, String mimeType) { + if (LOG) { + Log.v(TAG, "judgeStreamingType(" + uri + ")"); + } + if (uri == null) { + return; + } + String scheme = uri.getScheme(); + mWaitMetaData = true; + if (MovieUtils.isSdpStreaming(uri, mimeType)) { + mStreamingType = STREAMING_SDP; + mWaitMetaData = false; + } else if (MovieUtils.isRtspStreaming(uri, mimeType)) { + mStreamingType = STREAMING_RTSP; + mWaitMetaData = false; + } else if (MovieUtils.isHttpStreaming(uri, mimeType)) { + mStreamingType = STREAMING_HTTP; + mWaitMetaData = false; + } else { + mStreamingType = STREAMING_LOCAL; + mWaitMetaData = false; + } + if (LOG) { + Log.v(TAG, "mStreamingType=" + mStreamingType + + " mCanGetMetaData=" + mWaitMetaData); + } + } + + public boolean isLiveStreaming() { + boolean isLive = false; + if (mStreamingType == STREAMING_SDP) { + isLive = true; + } + if (LOG) { + Log.v(TAG, "isLiveStreaming() return " + isLive); + } + return isLive; + } + public IMoviePlayer getMoviePlayerExt() { return mPlayerExt; } @@ -579,13 +893,62 @@ public class MoviePlayer implements return mVideoView; } - private void onSaveInstanceStateMore(Bundle outState) { + // Wait for any animation, ten seconds should be enough + private final Runnable mRemoveBackground = new Runnable() { + @Override + public void run() { + if (LOG) { + Log.v(TAG, "mRemoveBackground.run()"); + } + mRootView.setBackground(null); + } + }; + + private void removeBackground() { + if (LOG) { + Log.v(TAG, "removeBackground()"); + } + mHandler.removeCallbacks(mRemoveBackground); + mHandler.postDelayed(mRemoveBackground, DELAY_REMOVE_MS); + } + // add background for removing ghost image. + private void addBackground() { + if (LOG) { + Log.v(TAG, "addBackground()"); + } + mHandler.removeCallbacks(mRemoveBackground); + mRootView.setBackgroundColor(Color.BLACK); + } + + private void clearVideoInfo() { + mVideoPosition = 0; + mVideoLastDuration = 0; + + if (mServerTimeoutExt != null) { + mServerTimeoutExt.clearServerInfo(); + } + } + + private void onSaveInstanceStateMore(Bundle outState) { + outState.putInt(KEY_VIDEO_LAST_DURATION, mVideoLastDuration); + outState.putBoolean(KEY_VIDEO_CAN_SEEK, mVideoView.canSeekForward()); + outState.putBoolean(KEY_VIDEO_CAN_PAUSE, mVideoView.canPause()); + outState.putInt(KEY_VIDEO_STREAMING_TYPE, mStreamingType); + outState.putString(KEY_VIDEO_STATE, String.valueOf(mTState)); + mServerTimeoutExt.onSaveInstanceState(outState); + mRetryExt.onSaveInstanceState(outState); mPlayerExt.onSaveInstanceState(outState); } private void onRestoreInstanceState(Bundle icicle) { - + mVideoLastDuration = icicle.getInt(KEY_VIDEO_LAST_DURATION); + mVideoCanSeek = icicle.getBoolean(KEY_VIDEO_CAN_SEEK); + mVideoCanPause = icicle.getBoolean(KEY_VIDEO_CAN_PAUSE); + mStreamingType = icicle.getInt(KEY_VIDEO_STREAMING_TYPE); + mTState = TState.valueOf(icicle.getString(KEY_VIDEO_STATE)); + mServerTimeoutExt.onRestoreInstanceState(icicle); + mRetryExt.onRestoreInstanceState(icicle); mPlayerExt.onRestoreInstanceState(icicle); } @@ -593,7 +956,10 @@ public class MoviePlayer implements private static final String KEY_VIDEO_IS_LOOP = "video_is_loop"; + private BookmarkEnhance mBookmark;//for bookmark private boolean mIsLoop; + private boolean mLastPlaying; + private boolean mLastCanPaused; @Override public boolean getLoop() { @@ -620,7 +986,301 @@ public class MoviePlayer implements public void onSaveInstanceState(Bundle outState) { outState.putBoolean(KEY_VIDEO_IS_LOOP, mIsLoop); } + + @Override + public void stopVideo() { + if (LOG) { + Log.v(TAG, "stopVideo()"); + } + mTState = TState.STOPED; + mVideoView.clearSeek(); + mVideoView.clearDuration(); + mVideoView.stopPlayback(); + mVideoView.setResumed(false); + mVideoView.setVisibility(View.INVISIBLE); + mVideoView.setVisibility(View.VISIBLE); + clearVideoInfo(); + mFirstBePlayed = false; + mController.setCanReplay(true); + mController.showEnded(); + setProgress(); + } + + @Override + public boolean canStop() { + boolean stopped = false; + if (mController != null) { + //stopped = mOverlayExt.isPlayingEnd(); + } + if (LOG) { + Log.v(TAG, "canStop() stopped=" + stopped); + } + return !stopped; + } + + @Override + public void addBookmark() { + if (mBookmark == null) { + mBookmark = new BookmarkEnhance(mActivityContext); + } + String uri = String.valueOf(mMovieItem.getUri()); + if (mBookmark.exists(uri)) { + Toast.makeText(mActivityContext, R.string.bookmark_exist, Toast.LENGTH_SHORT) + .show(); + } else { + mBookmark.insert(mMovieItem.getTitle(), uri, + mMovieItem.getMimeType(), 0); + Toast.makeText(mActivityContext, R.string.bookmark_add_success, Toast.LENGTH_SHORT) + .show(); + } + } }; + + private class RetryExtension implements Restorable, MediaPlayer.OnErrorListener, + MediaPlayer.OnInfoListener { + private static final String KEY_VIDEO_RETRY_COUNT = "video_retry_count"; + private int mRetryDuration; + private int mRetryPosition; + private int mRetryCount; + + public void retry() { + doStartVideo(true, mRetryPosition, mRetryDuration); + if (LOG) { + Log.v(TAG, "retry() mRetryCount=" + mRetryCount + ", mRetryPosition=" + + mRetryPosition); + } + } + + public void clearRetry() { + if (LOG) { + Log.v(TAG, "clearRetry() mRetryCount=" + mRetryCount); + } + mRetryCount = 0; + } + + public boolean reachRetryCount() { + if (LOG) { + Log.v(TAG, "reachRetryCount() mRetryCount=" + mRetryCount); + } + if (mRetryCount > 3) { + return true; + } + return false; + } + + public int getRetryCount() { + if (LOG) { + Log.v(TAG, "getRetryCount() return " + mRetryCount); + } + return mRetryCount; + } + + public boolean isRetrying() { + boolean retry = false; + if (mRetryCount > 0) { + retry = true; + } + if (LOG) { + Log.v(TAG, "isRetrying() mRetryCount=" + mRetryCount); + } + return retry; + } + + @Override + public void onRestoreInstanceState(Bundle icicle) { + mRetryCount = icicle.getInt(KEY_VIDEO_RETRY_COUNT); + } + + @Override + public void onSaveInstanceState(Bundle outState) { + outState.putInt(KEY_VIDEO_RETRY_COUNT, mRetryCount); + } + + @Override + public boolean onError(MediaPlayer mp, int what, int extra) { + return false; + } + + @Override + public boolean onInfo(MediaPlayer mp, int what, int extra) { + return false; + } + + public boolean handleOnReplay() { + if (isRetrying()) { // from connecting error + clearRetry(); + int errorPosition = mVideoView.getCurrentPosition(); + int errorDuration = mVideoView.getDuration(); + doStartVideo(errorPosition > 0, errorPosition, errorDuration); + if (LOG) { + Log.v(TAG, "onReplay() errorPosition=" + errorPosition + ", errorDuration=" + + errorDuration); + } + return true; + } + return false; + } + + public void showRetry() { + if (mVideoCanSeek || mVideoView.canSeekForward()) { + mVideoView.seekTo(mVideoPosition); + } + mVideoView.setDuration(mVideoLastDuration); + mRetryPosition = mVideoPosition; + mRetryDuration = mVideoLastDuration; + } + } + private class ServerTimeoutExtension implements Restorable, MediaPlayer.OnErrorListener { + // for cmcc server timeout case + // please remember to clear this value when changed video. + private int mServerTimeout = -1; + private long mLastDisconnectTime; + private boolean mIsShowDialog = false; + private AlertDialog mServerTimeoutDialog; + + // check whether disconnect from server timeout or not. + // if timeout, return false. otherwise, return true. + private boolean passDisconnectCheck() { + if (!isFullBuffer()) { + // record the time disconnect from server + long now = System.currentTimeMillis(); + if (LOG) { + Log.v(TAG, "passDisconnectCheck() now=" + now + ", mLastDisconnectTime=" + + mLastDisconnectTime + + ", mServerTimeout=" + mServerTimeout); + } + if (mServerTimeout > 0 && (now - mLastDisconnectTime) > mServerTimeout) { + // disconnect time more than server timeout, notify user + notifyServerTimeout(); + return false; + } + } + return true; + } + + private void recordDisconnectTime() { + if (!isFullBuffer()) { + // record the time disconnect from server + mLastDisconnectTime = System.currentTimeMillis(); + } + if (LOG) { + Log.v(TAG, "recordDisconnectTime() mLastDisconnectTime=" + mLastDisconnectTime); + } + } + + private void clearServerInfo() { + mServerTimeout = -1; + } + + private void notifyServerTimeout() { + if (mServerTimeoutDialog == null) { + // for updating last position and duration. + if (mVideoCanSeek || mVideoView.canSeekForward()) { + mVideoView.seekTo(mVideoPosition); + } + mVideoView.setDuration(mVideoLastDuration); + AlertDialog.Builder builder = new AlertDialog.Builder(mActivityContext); + mServerTimeoutDialog = builder.setTitle(R.string.server_timeout_title) + .setMessage(R.string.server_timeout_message) + .setNegativeButton(android.R.string.cancel, new OnClickListener() { + + public void onClick(DialogInterface dialog, int which) { + if (LOG) { + Log.v(TAG, "NegativeButton.onClick() mIsShowDialog=" + + mIsShowDialog); + } + mController.showEnded(); + onCompletion(); + } + + }) + .setPositiveButton(R.string.resume_playing_resume, new OnClickListener() { + + public void onClick(DialogInterface dialog, int which) { + if (LOG) { + Log.v(TAG, "PositiveButton.onClick() mIsShowDialog=" + + mIsShowDialog); + } + doStartVideo(true, mVideoPosition, mVideoLastDuration); + } + + }) + .create(); + mServerTimeoutDialog.setOnDismissListener(new OnDismissListener() { + + public void onDismiss(DialogInterface dialog) { + if (LOG) { + Log.v(TAG, "mServerTimeoutDialog.onDismiss()"); + } + mIsShowDialog = false; + } + + }); + mServerTimeoutDialog.setOnShowListener(new OnShowListener() { + + public void onShow(DialogInterface dialog) { + if (LOG) { + Log.v(TAG, "mServerTimeoutDialog.onShow()"); + } + mIsShowDialog = true; + } + + }); + } + mServerTimeoutDialog.show(); + } + + private void clearTimeoutDialog() { + if (mServerTimeoutDialog != null && mServerTimeoutDialog.isShowing()) { + mServerTimeoutDialog.dismiss(); + } + mServerTimeoutDialog = null; + } + + @Override + public void onRestoreInstanceState(Bundle icicle) { + mLastDisconnectTime = icicle.getLong(KEY_VIDEO_LAST_DISCONNECT_TIME); + } + + @Override + public void onSaveInstanceState(Bundle outState) { + outState.putLong(KEY_VIDEO_LAST_DISCONNECT_TIME, mLastDisconnectTime); + } + + public boolean handleOnResume() { + if (mIsShowDialog && !isLiveStreaming()) { + // wait for user's operation + return true; + } + if (!passDisconnectCheck()) { + return true; + } + return false; + } + + public void setVideoInfo(Metadata data) { + if (data.has(SERVER_TIMEOUT)) { + mServerTimeout = data.getInt(SERVER_TIMEOUT); + if (LOG) { + Log.v(TAG, "get server timeout from metadata. mServerTimeout=" + + mServerTimeout); + } + } + } + + @Override + public boolean onError(MediaPlayer mp, int what, int extra) { + // if we are showing a dialog, cancel the error dialog + if (mIsShowDialog) { + return true; + } + return false; + } + + public void setTimeout(int timeout) { + mServerTimeout = timeout; + } + } } class Bookmarker { @@ -642,6 +1302,10 @@ class Bookmarker { public void setBookmark(Uri uri, int bookmark, int duration) { try { + // do not record or override bookmark if duration is not valid. + if (duration <= 0) { + return; + } BlobCache cache = CacheManager.getCache(mContext, BOOKMARK_CACHE_FILE, BOOKMARK_CACHE_MAX_ENTRIES, BOOKMARK_CACHE_MAX_BYTES, BOOKMARK_CACHE_VERSION); @@ -650,7 +1314,7 @@ class Bookmarker { DataOutputStream dos = new DataOutputStream(bos); dos.writeUTF(uri.toString()); dos.writeInt(bookmark); - dos.writeInt(duration); + dos.writeInt(Math.abs(duration)); dos.flush(); cache.insert(uri.hashCode(), bos.toByteArray()); } catch (Throwable t) { @@ -658,7 +1322,7 @@ class Bookmarker { } } - public Integer getBookmark(Uri uri) { + public BookmarkerInfo getBookmark(Uri uri) { try { BlobCache cache = CacheManager.getCache(mContext, BOOKMARK_CACHE_FILE, BOOKMARK_CACHE_MAX_ENTRIES, @@ -682,10 +1346,31 @@ class Bookmarker { || (bookmark > (duration - HALF_MINUTE))) { return null; } - return Integer.valueOf(bookmark); + return new BookmarkerInfo(bookmark, duration); } catch (Throwable t) { Log.w(TAG, "getBookmark failed", t); } return null; } } + +class BookmarkerInfo { + public final int mBookmark; + public final int mDuration; + + public BookmarkerInfo(int bookmark, int duration) { + this.mBookmark = bookmark; + this.mDuration = duration; + } + + @Override + public String toString() { + return new StringBuilder() + .append("BookmarkInfo(bookmark=") + .append(mBookmark) + .append(", duration=") + .append(mDuration) + .append(")") + .toString(); + } +} diff --git a/src/com/android/gallery3d/app/TrimVideo.java b/src/com/android/gallery3d/app/TrimVideo.java index a1fd26c4a..c5d721274 100644 --- a/src/com/android/gallery3d/app/TrimVideo.java +++ b/src/com/android/gallery3d/app/TrimVideo.java @@ -342,6 +342,12 @@ public class TrimVideo extends Activity implements } @Override + public boolean onIsRTSP() { + // TODO Auto-generated method stub + return false; + } + + @Override public void onReplay() { mVideoView.seekTo(mTrimStartTime); playVideo(); diff --git a/src/com/qcom/gallery3d/video/DmReceiver.java b/src/com/qcom/gallery3d/video/DmReceiver.java deleted file mode 100755 index 4b4b6aa20..000000000 --- a/src/com/qcom/gallery3d/video/DmReceiver.java +++ /dev/null @@ -1,82 +0,0 @@ -
-
-
-package com.qcom.gallery3d.video;
-
-import android.app.Notification;
-import android.app.NotificationManager; -import android.app.PendingIntent; -import android.app.Service; -import android.content.BroadcastReceiver; -import android.content.ContentResolver; -import android.content.ContentValues; -import android.content.Context; -import android.content.Intent; -import android.content.SharedPreferences; -import android.content.res.Resources;
-import android.net.Uri; -import android.os.PowerManager; -import android.preference.PreferenceManager; -import android.util.Log;
-
-public class DmReceiver extends BroadcastReceiver {
- private static final String TAG = "DmReceiver";
- public static final String WRITE_SETTING_ACTION = "streaming.action.WRITE_SETTINGS";
- public static final String BOOT_COMPLETED = "android.intent.action.BOOT_COMPLETED";
-
- private SharedPreferences mPref;
- static final int STREAMING_CONNPROFILE_IO_HANDLER_TYPE = 1;
- static final int STREAMING_MAX_UDP_PORT_IO_HANDLER_TYPE = 3;
- static final int STREAMING_MIN_UDP_PORT_IO_HANDLER_TYPE = 4;
- @Override
- public void onReceive(Context context, Intent intent) {
- Log.d(TAG, "z32 ### onReceive ###");
- if (mPref == null) {
- mPref = PreferenceManager.getDefaultSharedPreferences(context);
- }
- if (BOOT_COMPLETED.equals(intent.getAction()) )
- {
- Log.d(TAG, "z46 onReceive BOOT_COMPLETED ###");
- String rtpMaxport
- = mPref.getString(SettingsActivity.PREFERENCE_RTP_MAXPORT, "65535");
- String rtpMinport
- = mPref.getString(SettingsActivity.PREFERENCE_RTP_MINPORT, "8192");
- String apn
- = mPref.getString(SettingsActivity.PREFERENCE_APN, "CMWAP");
- Log.d(TAG, "z43 rtpMinport = " + rtpMinport + ";rtpMaxport = " + rtpMaxport);
-
- android.provider.Settings.System.putString(context.getContentResolver(), "streaming_max_udp_port", rtpMaxport);
- android.provider.Settings.System.putString(context.getContentResolver(), "streaming_min_udp_port", rtpMinport);
- android.provider.Settings.System.putString(context.getContentResolver(), "apn", apn);
- }
- else if (WRITE_SETTING_ACTION.equals(intent.getAction()))
- {
- Log.d(TAG, "z52 onReceive WRITE_SETTING_ACTION ###");
- int valueType = intent.getIntExtra("type", 0);
- String value = intent.getStringExtra("value");
- if (valueType == STREAMING_MAX_UDP_PORT_IO_HANDLER_TYPE)
- {
- mPref.edit().putString(SettingsActivity.PREFERENCE_RTP_MAXPORT,
- value).commit();
- android.provider.Settings.System.putString(context.getContentResolver(),
- "streaming_max_udp_port", value);
- }
- else if (valueType == STREAMING_MIN_UDP_PORT_IO_HANDLER_TYPE)
- {
- mPref.edit().putString(SettingsActivity.PREFERENCE_RTP_MINPORT,
- value).commit();
- android.provider.Settings.System.putString(context.getContentResolver(),
- "streaming_min_udp_port", value);
- }
- else if (valueType == STREAMING_CONNPROFILE_IO_HANDLER_TYPE)
- {
- mPref.edit().putString(SettingsActivity.PREFERENCE_APN,
- // "CMWAP").commit();
- value).commit();
- android.provider.Settings.System.putString(context.getContentResolver(),
- "apn", value);
- }
- }
- }
-}
-
diff --git a/src/com/qcom/gallery3d/video/QcomVideoView.java b/src/com/qcom/gallery3d/video/QcomVideoView.java deleted file mode 100755 index ba5485544..000000000 --- a/src/com/qcom/gallery3d/video/QcomVideoView.java +++ /dev/null @@ -1,721 +0,0 @@ -package com.qcom.gallery3d.video; - -import android.app.AlertDialog; -import android.content.Context; -import android.content.DialogInterface; -import android.content.Intent; -import android.content.res.Resources; -import android.database.sqlite.SQLiteException; -import android.media.AudioManager; -import android.media.MediaPlayer; -import android.media.MediaPlayer.OnBufferingUpdateListener; -import android.media.MediaPlayer.OnInfoListener; -import android.media.MediaPlayer.OnVideoSizeChangedListener; -import android.media.Metadata; -import android.net.Uri; -import android.os.Handler; -import android.os.Message; -import android.util.AttributeSet; -import android.view.KeyEvent; -import android.view.SurfaceHolder; -import android.widget.VideoView; - -import com.android.gallery3d.ui.Log; -import com.qcom.gallery3d.ext.QcomLog; -import com.qcom.gallery3d.video.ScreenModeManager.ScreenModeListener; - -import android.app.Activity; -import android.app.AlertDialog; -import android.app.Dialog; -import android.app.DialogFragment; -import android.app.FragmentManager; - -import java.io.IOException; -import java.util.Map; - -/** - * QcomVideoView enhance the streaming videoplayer process and UI. - * It only supports QcomMediaController. - * If you set android's default MediaController, - * some state will not be shown well. - * Moved from the package android.widget - */ -public class QcomVideoView extends VideoView implements ScreenModeListener { - private static final String TAG = "QcomVideoView"; - private static final boolean LOG = true; - - //add info listener to get info whether can get meta data or not for rtsp. - private MediaPlayer.OnInfoListener mOnInfoListener; - private MediaPlayer.OnBufferingUpdateListener mOnBufferingUpdateListener; - private MediaPlayer.OnVideoSizeChangedListener mVideoSizeListener; - - //when the streaming type is live, metadata maybe not right when prepared. - private boolean mHasGotMetaData = false; - private boolean mHasGotPreparedCallBack = false; - - private final MediaPlayer.OnInfoListener mInfoListener = new MediaPlayer.OnInfoListener() { - - public boolean onInfo(final MediaPlayer mp, final int what, final int extra) { - if (LOG) { - QcomLog.v(TAG, "onInfo() what:" + what + " extra:" + extra); - } - if (mOnInfoListener != null && mOnInfoListener.onInfo(mp, what, extra)) { - return true; - } else { - // TODO comments by sunlei -// if (what == MediaPlayer.MEDIA_INFO_METADATA_CHECK_COMPLETE) { -// mHasGotMetaData = true; -// doPreparedIfReady(mMediaPlayer); -// return true; -// } - } - return false; - } - - }; - - private void doPreparedIfReady(final MediaPlayer mp) { - if (LOG) { - QcomLog.v(TAG, "doPreparedIfReady() mHasGotPreparedCallBack=" + mHasGotPreparedCallBack - + ", mHasGotMetaData=" + mHasGotMetaData + ", mNeedWaitLayout=" + mNeedWaitLayout - + ", mCurrentState=" + mCurrentState); - } - if (mHasGotPreparedCallBack && mHasGotMetaData && !mNeedWaitLayout) { - doPrepared(mp); - } - } - - public QcomVideoView(final Context context) { - super(context); - initialize(); - } - - public QcomVideoView(final Context context, final AttributeSet attrs) { - super(context, attrs); - initialize(); - } - - public QcomVideoView(final Context context, final AttributeSet attrs, final int defStyle) { - super(context, attrs, defStyle); - initialize(); - } - - private void initialize() { - mPreparedListener = new MediaPlayer.OnPreparedListener() { - public void onPrepared(final MediaPlayer mp) { - if (LOG) { - QcomLog.v(TAG, "mPreparedListener.onPrepared(" + mp + ")"); - } - //Here we can get meta data from mediaplayer. - // Get the capabilities of the player for this stream - final Metadata data = mp.getMetadata(MediaPlayer.METADATA_ALL, - MediaPlayer.BYPASS_METADATA_FILTER); - if (data != null) { - mCanPause = !data.has(Metadata.PAUSE_AVAILABLE) - || data.getBoolean(Metadata.PAUSE_AVAILABLE); - mCanSeekBack = !data.has(Metadata.SEEK_BACKWARD_AVAILABLE) - || data.getBoolean(Metadata.SEEK_BACKWARD_AVAILABLE); - mCanSeekForward = !data.has(Metadata.SEEK_FORWARD_AVAILABLE) - || data.getBoolean(Metadata.SEEK_FORWARD_AVAILABLE); - } else { - mCanPause = true; - mCanSeekBack = true; - mCanSeekForward = true; - QcomLog.w(TAG, "Metadata is null!"); - } - if (LOG) { - QcomLog.v(TAG, "mPreparedListener.onPrepared() mCanPause=" + mCanPause); - } - mHasGotPreparedCallBack = true; - doPreparedIfReady(mMediaPlayer); - } - }; - - mErrorListener = new MediaPlayer.OnErrorListener() { - public boolean onError(final MediaPlayer mp, final int frameworkErr, final int implErr) { - Log.d(TAG, "Error: " + frameworkErr + "," + implErr); - if (mCurrentState == STATE_ERROR) { - Log.w(TAG, "Duplicate error message. error message has been sent! " + - "error=(" + frameworkErr + "," + implErr + ")"); - return true; - } - //record error position and duration - //here disturb the original logic - mSeekWhenPrepared = getCurrentPosition(); - if (LOG) { - Log.v(TAG, "onError() mSeekWhenPrepared=" + mSeekWhenPrepared + ", mDuration=" + mDuration); - } - //for old version Streaming server, getduration is not valid. - mDuration = Math.abs(mDuration); - mCurrentState = STATE_ERROR; - mTargetState = STATE_ERROR; - if (mMediaController != null) { - mMediaController.hide(); - } - - /* If an error handler has been supplied, use it and finish. */ - if (mOnErrorListener != null) { - if (mOnErrorListener.onError(mMediaPlayer, frameworkErr, implErr)) { - return true; - } - } - - /* Otherwise, pop up an error dialog so the user knows that - * something bad has happened. Only try and pop up the dialog - * if we're attached to a window. When we're going away and no - * longer have a window, don't bother showing the user an error. - */ - if (getWindowToken() != null) { - final Resources r = mContext.getResources(); - int messageId; - - // TODO comments by sunlei -// if (frameworkErr == MediaPlayer.MEDIA_ERROR_BAD_FILE) { -// messageId = com.mediatek.R.string.VideoView_error_text_bad_file; -// } else if (frameworkErr == MediaPlayer.MEDIA_ERROR_CANNOT_CONNECT_TO_SERVER) { -// messageId = com.mediatek.R.string.VideoView_error_text_cannot_connect_to_server; -// } else if (frameworkErr == MediaPlayer.MEDIA_ERROR_TYPE_NOT_SUPPORTED) { -// messageId = com.mediatek.R.string.VideoView_error_text_type_not_supported; -// } else if (frameworkErr == MediaPlayer.MEDIA_ERROR_DRM_NOT_SUPPORTED) { -// messageId = com.mediatek.R.string.VideoView_error_text_drm_not_supported; -// } else if (frameworkErr == MediaPlayer.MEDIA_ERROR_INVALID_CONNECTION) { -// messageId = com.mediatek.internal.R.string.VideoView_error_text_invalid_connection; -// } else if (frameworkErr == MediaPlayer.MEDIA_ERROR_NOT_VALID_FOR_PROGRESSIVE_PLAYBACK) { -// messageId = com.android.internal.R.string.VideoView_error_text_invalid_progressive_playback; -// } else { -// messageId = com.android.internal.R.string.VideoView_error_text_unknown; -// } - - if (frameworkErr == MediaPlayer.MEDIA_ERROR_NOT_VALID_FOR_PROGRESSIVE_PLAYBACK) { - messageId = com.android.internal.R.string.VideoView_error_text_invalid_progressive_playback; - } else { - messageId = com.android.internal.R.string.VideoView_error_text_unknown; - } - - final String errorDialogTag = "ERROR_DIALOG_TAG"; - FragmentManager fragmentManager = ((Activity)mContext).getFragmentManager(); - DialogFragment oldFragment = (DialogFragment) fragmentManager - .findFragmentByTag(errorDialogTag); - if (null != oldFragment) { - oldFragment.dismissAllowingStateLoss(); - } - DialogFragment newFragment = ErrorDialogFragment.newInstance(messageId); - newFragment.show(fragmentManager, errorDialogTag); - fragmentManager.executePendingTransactions(); - } - return true; - } - }; - - mBufferingUpdateListener = new MediaPlayer.OnBufferingUpdateListener() { - public void onBufferingUpdate(final MediaPlayer mp, final int percent) { - mCurrentBufferPercentage = percent; - if (mOnBufferingUpdateListener != null) { - mOnBufferingUpdateListener.onBufferingUpdate(mp, percent); - } - if (LOG) { - QcomLog.v(TAG, "onBufferingUpdate() Buffering percent: " + percent); - } - if (LOG) { - QcomLog.v(TAG, "onBufferingUpdate() mTargetState=" + mTargetState); - } - if (LOG) { - QcomLog.v(TAG, "onBufferingUpdate() mCurrentState=" + mCurrentState); - } - } - }; - - mSizeChangedListener = new MediaPlayer.OnVideoSizeChangedListener() { - public void onVideoSizeChanged(final MediaPlayer mp, final int width, final int height) { - mVideoWidth = mp.getVideoWidth(); - mVideoHeight = mp.getVideoHeight(); - if (LOG) { - QcomLog.v(TAG, "OnVideoSizeChagned(" + width + "," + height + ")"); - } - if (LOG) { - QcomLog.v(TAG, "OnVideoSizeChagned(" + mVideoWidth + "," + mVideoHeight + ")"); - } - if (LOG) { - QcomLog.v(TAG, "OnVideoSizeChagned() mCurrentState=" + mCurrentState); - } - if (mVideoWidth != 0 && mVideoHeight != 0) { - getHolder().setFixedSize(mVideoWidth, mVideoHeight); - if (mCurrentState == STATE_PREPARING) { - mNeedWaitLayout = true; - } - } - if (mVideoSizeListener != null) { - mVideoSizeListener.onVideoSizeChanged(mp, width, height); - } - QcomVideoView.this.requestLayout(); - } - }; - - getHolder().removeCallback(mSHCallback); - mSHCallback = new SurfaceHolder.Callback() { - public void surfaceChanged(final SurfaceHolder holder, final int format, final int w, final int h) { - if (LOG) { - Log.v(TAG, "surfaceChanged(" + holder + ", " + format + ", " + w + ", " + h + ")"); - } - if (LOG) { - Log.v(TAG, "surfaceChanged() mMediaPlayer=" + mMediaPlayer + ", mTargetState=" + mTargetState - + ", mVideoWidth=" + mVideoWidth + ", mVideoHeight=" + mVideoHeight); - } - mSurfaceWidth = w; - mSurfaceHeight = h; - final boolean isValidState = (mTargetState == STATE_PLAYING); - final boolean hasValidSize = (mVideoWidth == w && mVideoHeight == h); - if (mMediaPlayer != null && isValidState && hasValidSize) { - if (mSeekWhenPrepared != 0) { - seekTo(mSeekWhenPrepared); - } - Log.v(TAG, "surfaceChanged() start()"); - start(); - } - } - - public void surfaceCreated(final SurfaceHolder holder) { - if (LOG) { - Log.v(TAG, "surfaceCreated(" + holder + ")"); - } - mSurfaceHolder = holder; - openVideo(); - } - - public void surfaceDestroyed(final SurfaceHolder holder) { - // after we return from this we can't use the surface any more - if (LOG) { - Log.v(TAG, "surfaceDestroyed(" + holder + ")"); - } - mSurfaceHolder = null; - if (mMediaController != null) { - mMediaController.hide(); - } - release(true); - } - }; - getHolder().addCallback(mSHCallback); - } - - @Override - protected void onMeasure(final int widthMeasureSpec, final int heightMeasureSpec) { - //Log.i("@@@@", "onMeasure"); - int width = 0; - int height = 0; - int screenMode = ScreenModeManager.SCREENMODE_BIGSCREEN; - if (mScreenManager != null) { - screenMode = mScreenManager.getScreenMode(); - } - switch (screenMode) { - case ScreenModeManager.SCREENMODE_BIGSCREEN: - width = getDefaultSize(mVideoWidth, widthMeasureSpec); - height = getDefaultSize(mVideoHeight, heightMeasureSpec); - if (mVideoWidth > 0 && mVideoHeight > 0) { - if (mVideoWidth * height > width * mVideoHeight) { - //Log.i("@@@", "image too tall, correcting"); - height = width * mVideoHeight / mVideoWidth; - } else if (mVideoWidth * height < width * mVideoHeight) { - //Log.i("@@@", "image too wide, correcting"); - width = height * mVideoWidth / mVideoHeight; - } /*else { - //Log.i("@@@", "aspect ratio is correct: " + - //width+"/"+height+"="+ - //mVideoWidth+"/"+mVideoHeight); - }*/ - } - break; - case ScreenModeManager.SCREENMODE_FULLSCREEN: - width = getDefaultSize(mVideoWidth, widthMeasureSpec); - height = getDefaultSize(mVideoHeight, heightMeasureSpec); - break; - case ScreenModeManager.SCREENMODE_CROPSCREEN: - width = getDefaultSize(mVideoWidth, widthMeasureSpec); - height = getDefaultSize(mVideoHeight, heightMeasureSpec); - if (mVideoWidth > 0 && mVideoHeight > 0) { - if (mVideoWidth * height > width * mVideoHeight) { - //extend width to be cropped - width = height * mVideoWidth / mVideoHeight; - } else if (mVideoWidth * height < width * mVideoHeight) { - //extend height to be cropped - height = width * mVideoHeight / mVideoWidth; - } - } - break; - default: - QcomLog.w(TAG, "wrong screen mode : " + screenMode); - break; - } - if (LOG) { - QcomLog.v(TAG, "onMeasure() set size: " + width + 'x' + height); - QcomLog.v(TAG, "onMeasure() video size: " + mVideoWidth + 'x' + mVideoHeight); - QcomLog.v(TAG, "onMeasure() mNeedWaitLayout=" + mNeedWaitLayout); - } - setMeasuredDimension(width, height); - if (mNeedWaitLayout) { //when OnMeasure ok, start video. - mNeedWaitLayout = false; - mHandler.sendEmptyMessage(MSG_LAYOUT_READY); - } - } - -// @Override -// public boolean onTouchEvent(MotionEvent ev) { -// if (LOG) Log.v(TAG, "onTouchEvent(" + ev + ")"); -// if (mMediaController != null) { -// toggleMediaControlsVisiblity(); -// } -// return false; -// } - - @Override - public boolean onKeyDown(final int keyCode, final KeyEvent event) { - final boolean isKeyCodeSupported = keyCode != KeyEvent.KEYCODE_BACK && - keyCode != KeyEvent.KEYCODE_VOLUME_UP && - keyCode != KeyEvent.KEYCODE_VOLUME_DOWN && - keyCode != KeyEvent.KEYCODE_VOLUME_MUTE && - keyCode != KeyEvent.KEYCODE_MENU && - keyCode != KeyEvent.KEYCODE_CALL && - keyCode != KeyEvent.KEYCODE_ENDCALL && - keyCode != KeyEvent.KEYCODE_CAMERA; - if (isInPlaybackState() && isKeyCodeSupported && mMediaController != null) { - if (event.getRepeatCount() == 0 && (keyCode == KeyEvent.KEYCODE_HEADSETHOOK || - keyCode == KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE)) { - if (mMediaPlayer.isPlaying()) { - pause(); - mMediaController.show(); - } else { - start(); - mMediaController.hide(); - } - return true; - } else if (keyCode == KeyEvent.KEYCODE_MEDIA_PLAY) { - if (!mMediaPlayer.isPlaying()) { - start(); - mMediaController.hide(); - } - return true; - } else if (keyCode == KeyEvent.KEYCODE_MEDIA_STOP - || keyCode == KeyEvent.KEYCODE_MEDIA_PAUSE) { - if (mMediaPlayer.isPlaying()) { - pause(); - mMediaController.show(); - } - return true; - } else if (keyCode == KeyEvent.KEYCODE_MEDIA_FAST_FORWARD || - keyCode == KeyEvent.KEYCODE_MEDIA_NEXT || - keyCode == KeyEvent.KEYCODE_MEDIA_PREVIOUS || - keyCode == KeyEvent.KEYCODE_MEDIA_REWIND || - keyCode == KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE || - keyCode == KeyEvent.KEYCODE_HEADSETHOOK) { - //consume media action, so if video view if front, - //other media player will not play any sounds. - return true; - } else { - toggleMediaControlsVisiblity(); - } - } - - return super.onKeyDown(keyCode, event); - } - - @Override - public void setVideoURI(final Uri uri, final Map<String, String> headers) { - mDuration = -1; - setResumed(true); - super.setVideoURI(uri, headers); - } - - public void setVideoURI(final Uri uri, final Map<String, String> headers, final boolean hasGotMetaData) { - if (LOG) { - QcomLog.v(TAG, "setVideoURI(" + uri + ", " + headers + ")"); - } - //clear the flags - mHasGotMetaData = hasGotMetaData; - setVideoURI(uri, headers); - } - - private void clearVideoInfo() { - if (LOG) { - Log.v(TAG, "clearVideoInfo()"); - } - mHasGotPreparedCallBack = false; - mNeedWaitLayout = false; - } - - @Override - protected void openVideo() { - if (LOG) { - Log.v(TAG, "openVideo() mUri=" + mUri + ", mSurfaceHolder=" + mSurfaceHolder - + ", mSeekWhenPrepared=" + mSeekWhenPrepared + ", mMediaPlayer=" + mMediaPlayer - + ", mOnResumed=" + mOnResumed); - } - clearVideoInfo(); - if (!mOnResumed || mUri == null || mSurfaceHolder == null) { - // not ready for playback just yet, will try again later - return; - } - - // Tell the music playback service to pause - // TODO: these constants need to be published somewhere in the framework. - final Intent i = new Intent("com.android.music.musicservicecommand"); - i.putExtra("command", "pause"); - mContext.sendBroadcast(i); - - // we shouldn't clear the target state, because somebody might have - // called start() previously - release(false); - if ("".equalsIgnoreCase(String.valueOf(mUri))) { - Log.w(TAG, "Unable to open content: " + mUri); - mErrorListener.onError(mMediaPlayer, MediaPlayer.MEDIA_ERROR_UNKNOWN, 0); - return; - } - try { - mMediaPlayer = new MediaPlayer(); - //end update status. - mMediaPlayer.setOnPreparedListener(mPreparedListener); - mMediaPlayer.setOnVideoSizeChangedListener(mSizeChangedListener); - //mDuration = -1; - mMediaPlayer.setOnCompletionListener(mCompletionListener); - mMediaPlayer.setOnErrorListener(mErrorListener); - mMediaPlayer.setOnBufferingUpdateListener(mBufferingUpdateListener); - mMediaPlayer.setOnInfoListener(mInfoListener); - mCurrentBufferPercentage = 0; - Log.w(TAG, "openVideo setDataSource()"); - mMediaPlayer.setDataSource(mContext, mUri, mHeaders); - mMediaPlayer.setDisplay(mSurfaceHolder); - mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC); - mMediaPlayer.setScreenOnWhilePlaying(true); - Log.w(TAG, "openVideo prepareAsync()"); - mMediaPlayer.prepareAsync(); - // we don't set the target state here either, but preserve the - // target state that was there before. - mCurrentState = STATE_PREPARING; - //attachMediaController(); - } catch (final IOException ex) { - Log.w(TAG, "Unable to open content: " + mUri, ex); - mErrorListener.onError(mMediaPlayer, MediaPlayer.MEDIA_ERROR_UNKNOWN, 0); - return; - } catch (final IllegalArgumentException ex) { - Log.w(TAG, "Unable to open content: " + mUri, ex); - mErrorListener.onError(mMediaPlayer, MediaPlayer.MEDIA_ERROR_UNKNOWN, 0); - return; - } catch (final SQLiteException ex) { - Log.w(TAG, "Unable to open content: " + mUri, ex); - mErrorListener.onError(mMediaPlayer, MediaPlayer.MEDIA_ERROR_UNKNOWN, 0); - return; - } - if (LOG) { - Log.v(TAG, "openVideo() mUri=" + mUri + ", mSurfaceHolder=" + mSurfaceHolder - + ", mSeekWhenPrepared=" + mSeekWhenPrepared + ", mMediaPlayer=" + mMediaPlayer); - } - } - - private void doPrepared(final MediaPlayer mp) { - if (LOG) { - QcomLog.v(TAG, "doPrepared(" + mp + ") start"); - } - mCurrentState = STATE_PREPARED; - if (mOnPreparedListener != null) { - mOnPreparedListener.onPrepared(mMediaPlayer); - } - mVideoWidth = mp.getVideoWidth(); - mVideoHeight = mp.getVideoHeight(); - - final int seekToPosition = mSeekWhenPrepared; // mSeekWhenPrepared may be changed after seekTo() call - if (seekToPosition != 0) { - seekTo(seekToPosition); - } - if (mVideoWidth != 0 && mVideoHeight != 0) { - getHolder().setFixedSize(mVideoWidth, mVideoHeight); - } - - if (mTargetState == STATE_PLAYING) { - start(); - } - if (LOG) { - QcomLog.v(TAG, "doPrepared() end video size: " + mVideoWidth + "," + mVideoHeight - + ", mTargetState=" + mTargetState + ", mCurrentState=" + mCurrentState); - } - } - - private boolean mOnResumed; - /** - * surfaceCreate will invoke openVideo after the activity stoped. - * Here set this flag to avoid openVideo after the activity stoped. - * @param resume - */ - public void setResumed(final boolean resume) { - if (LOG) { - QcomLog.v(TAG, "setResumed(" + resume + ") mUri=" + mUri + ", mOnResumed=" + mOnResumed); - } - mOnResumed = resume; - } - - @Override - public void resume() { - if (LOG) { - QcomLog.v(TAG, "resume() mTargetState=" + mTargetState + ", mCurrentState=" + mCurrentState); - } - setResumed(true); - openVideo(); - } - - @Override - public void suspend() { - if (LOG) { - QcomLog.v(TAG, "suspend() mTargetState=" + mTargetState + ", mCurrentState=" + mCurrentState); - } - super.suspend(); - } - - public void setOnInfoListener(final OnInfoListener l) { - mOnInfoListener = l; - if (LOG) { - QcomLog.v(TAG, "setInfoListener(" + l + ")"); - } - } - - public void setOnBufferingUpdateListener(final OnBufferingUpdateListener l) { - mOnBufferingUpdateListener = l; - if (LOG) { - QcomLog.v(TAG, "setOnBufferingUpdateListener(" + l + ")"); - } - } - - public void setOnVideoSizeChangedListener(final OnVideoSizeChangedListener l) { - mVideoSizeListener = l; - if (LOG) { - Log.i(TAG, "setOnVideoSizeChangedListener(" + l + ")"); - } - } - - @Override - public int getCurrentPosition() { - int position = 0; - if (mSeekWhenPrepared > 0) { - //if connecting error before seek, - //we should remember this position for retry - position = mSeekWhenPrepared; - ///M: if player not started, getCurrentPosition() will lead to NE. - } else if (isInPlaybackState() && mCurrentState != STATE_PREPARED) { - position = mMediaPlayer.getCurrentPosition(); - } - if (LOG) { - QcomLog.v(TAG, "getCurrentPosition() return " + position - + ", mSeekWhenPrepared=" + mSeekWhenPrepared); - } - return position; - } - - //clear the seek position any way. - //this will effect the case: stop video before it's seek completed. - public void clearSeek() { - if (LOG) { - QcomLog.v(TAG, "clearSeek() mSeekWhenPrepared=" + mSeekWhenPrepared); - } - mSeekWhenPrepared = 0; - } - - public boolean isTargetPlaying() { - if (LOG) { - Log.v(TAG, "isTargetPlaying() mTargetState=" + mTargetState); - } - return mTargetState == STATE_PLAYING; - } - - public void dump() { - if (LOG) { - Log.v(TAG, "dump() mUri=" + mUri - + ", mTargetState=" + mTargetState + ", mCurrentState=" + mCurrentState - + ", mSeekWhenPrepared=" + mSeekWhenPrepared - + ", mVideoWidth=" + mVideoWidth + ", mVideoHeight=" + mVideoHeight - + ", mMediaPlayer=" + mMediaPlayer + ", mSurfaceHolder=" + mSurfaceHolder); - } - } - - @Override - public void seekTo(final int msec) { - if (LOG) { - Log.v(TAG, "seekTo(" + msec + ") isInPlaybackState()=" + isInPlaybackState()); - } - super.seekTo(msec); - } - - @Override - protected void release(final boolean cleartargetstate) { - if (LOG) { - Log.v(TAG, "release(" + cleartargetstate + ") mMediaPlayer=" + mMediaPlayer); - } - super.release(cleartargetstate); - } - - //for duration displayed - public void setDuration(final int duration) { - if (LOG) { - Log.v(TAG, "setDuration(" + duration + ")"); - } - mDuration = (duration > 0 ? -duration : duration); - } - - @Override - public int getDuration() { - final boolean inPlaybackState = isInPlaybackState(); - if (LOG) { - Log.v(TAG, "getDuration() mDuration=" + mDuration + ", inPlaybackState=" + inPlaybackState); - } - if (inPlaybackState) { - if (mDuration > 0) { - return mDuration; - } - mDuration = mMediaPlayer.getDuration(); - return mDuration; - } - //mDuration = -1; - return mDuration; - } - - public void clearDuration() { - if (LOG) { - QcomLog.v(TAG, "clearDuration() mDuration=" + mDuration); - } - mDuration = -1; - } - - //for video size changed before started issue - private static final int MSG_LAYOUT_READY = 1; - private boolean mNeedWaitLayout = false; - private final Handler mHandler = new Handler() { - public void handleMessage(final Message msg) { - if (LOG) { - QcomLog.v(TAG, "handleMessage() to do prepare. msg=" + msg); - } - switch(msg.what) { - case MSG_LAYOUT_READY: - if (mMediaPlayer == null || mUri == null) { - QcomLog.w(TAG, "Cannot prepare play! mMediaPlayer=" + mMediaPlayer + ", mUri=" + mUri); - } else { - doPreparedIfReady(mMediaPlayer); - } - break; - default: - QcomLog.w(TAG, "Unhandled message " + msg); - break; - } - } - }; - - private ScreenModeManager mScreenManager; - public void setScreenModeManager(final ScreenModeManager manager) { - mScreenManager = manager; - if (mScreenManager != null) { - mScreenManager.addListener(this); - } - if (LOG) { - QcomLog.v(TAG, "setScreenModeManager(" + manager + ")"); - } - } - - @Override - public void onScreenModeChanged(final int newMode) { - this.requestLayout(); - } -} diff --git a/src/org/codeaurora/gallery3d/ext/IMoviePlayer.java b/src/org/codeaurora/gallery3d/ext/IMoviePlayer.java index 9248ebdf4..3013cbcb1 100644 --- a/src/org/codeaurora/gallery3d/ext/IMoviePlayer.java +++ b/src/org/codeaurora/gallery3d/ext/IMoviePlayer.java @@ -1,6 +1,12 @@ package org.codeaurora.gallery3d.ext; public interface IMoviePlayer { + + /** + * add new bookmark Uri. + */ + void addBookmark(); + /** * Loop current video. * @@ -14,4 +20,16 @@ public interface IMoviePlayer { * @return */ boolean getLoop(); + + /** + * Can stop current video or not. + * + * @return + */ + boolean canStop(); + + /** + * Stop current video. + */ + void stopVideo(); } diff --git a/src/com/qcom/gallery3d/video/BookmarkActivity.java b/src/org/codeaurora/gallery3d/video/BookmarkActivity.java index 8e792815c..ed653f63a 100755..100644 --- a/src/com/qcom/gallery3d/video/BookmarkActivity.java +++ b/src/org/codeaurora/gallery3d/video/BookmarkActivity.java @@ -1,4 +1,4 @@ -package com.qcom.gallery3d.video; +package org.codeaurora.gallery3d.video; import android.app.Activity; import android.app.AlertDialog; @@ -11,6 +11,7 @@ import android.graphics.Bitmap; import android.graphics.drawable.BitmapDrawable; import android.net.Uri; import android.os.Bundle; +import android.util.Log; import android.view.ContextMenu; import android.view.ContextMenu.ContextMenuInfo; import android.view.LayoutInflater; @@ -29,63 +30,63 @@ import android.widget.TextView; import com.android.gallery3d.R; import com.android.gallery3d.app.MovieActivity; -import com.qcom.gallery3d.ext.QcomLog; public class BookmarkActivity extends Activity implements OnItemClickListener { private static final String TAG = "BookmarkActivity"; private static final boolean LOG = true; - + private BookmarkEnhance mBookmark; private BookmarkAdapter mAdapter; private Cursor mCursor; private ListView mListView; private TextView mEmptyView; - + private static final int MENU_DELETE_ALL = 1; private static final int MENU_DELETE_ONE = 2; private static final int MENU_EDIT = 3; - + public static final String KEY_LOGO_BITMAP = "logo-bitmap"; - + @Override protected void onCreate(final Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.bookmark); - + Bitmap logo = getIntent().getParcelableExtra(KEY_LOGO_BITMAP); if (logo != null) { getActionBar().setLogo(new BitmapDrawable(getResources(), logo)); } - + mListView = (ListView) findViewById(android.R.id.list); mEmptyView = (TextView) findViewById(android.R.id.empty); - + mBookmark = new BookmarkEnhance(this); mCursor = mBookmark.query(); - mAdapter = new BookmarkAdapter(this, R.layout.bookmark_item, null, new String[]{}, new int[]{}); + mAdapter = new BookmarkAdapter(this, R.layout.bookmark_item, null, new String[] {}, + new int[] {}); mListView.setEmptyView(mEmptyView); mListView.setAdapter(mAdapter); mAdapter.changeCursor(mCursor); - + mListView.setOnItemClickListener(this); registerForContextMenu(mListView); } - + @Override protected void onStart() { super.onStart(); } - + @Override protected void onResume() { super.onResume(); } - + @Override protected void onPause() { super.onPause(); } - + @Override protected void onDestroy() { if (mAdapter != null) { @@ -93,34 +94,34 @@ public class BookmarkActivity extends Activity implements OnItemClickListener { } super.onDestroy(); } - + @Override public boolean onCreateOptionsMenu(final Menu menu) { super.onCreateOptionsMenu(menu); menu.add(0, MENU_DELETE_ALL, 0, R.string.delete_all) - .setIcon(android.R.drawable.ic_menu_delete); + .setIcon(android.R.drawable.ic_menu_delete); return true; } - + @Override public boolean onOptionsItemSelected(final MenuItem item) { - switch(item.getItemId()) { - case MENU_DELETE_ALL: - mBookmark.deleteAll(); - return true; - default: - break; + switch (item.getItemId()) { + case MENU_DELETE_ALL: + mBookmark.deleteAll(); + return true; + default: + break; } return super.onOptionsItemSelected(item); } - + private class BookmarkAdapter extends SimpleCursorAdapter { public BookmarkAdapter(final Context context, final int layout, final Cursor c, final String[] from, final int[] to) { super(context, layout, c, from, to); } - + @Override public View newView(final Context context, final Cursor cursor, final ViewGroup parent) { final View view = super.newView(context, cursor, parent); @@ -130,7 +131,7 @@ public class BookmarkActivity extends Activity implements OnItemClickListener { view.setTag(holder); return view; } - + @Override public void bindView(final View view, final Context context, final Cursor cursor) { final ViewHolder holder = (ViewHolder) view.getTag(); @@ -141,14 +142,14 @@ public class BookmarkActivity extends Activity implements OnItemClickListener { holder.mTitleView.setText(holder.mTitle); holder.mDataView.setText(holder.mData); } - + @Override public void changeCursor(final Cursor c) { super.changeCursor(c); } - + } - + private class ViewHolder { long mId; String mTitle; @@ -159,7 +160,8 @@ public class BookmarkActivity extends Activity implements OnItemClickListener { } @Override - public void onItemClick(final AdapterView<?> parent, final View view, final int position, final long id) { + public void onItemClick(final AdapterView<?> parent, final View view, final int position, + final long id) { final Object o = view.getTag(); if (o instanceof ViewHolder) { final ViewHolder holder = (ViewHolder) o; @@ -174,7 +176,7 @@ public class BookmarkActivity extends Activity implements OnItemClickListener { startActivity(intent); } if (LOG) { - QcomLog.v(TAG, "onItemClick(" + position + ", " + id + ")"); + Log.v(TAG, "onItemClick(" + position + ", " + id + ")"); } } @@ -185,41 +187,41 @@ public class BookmarkActivity extends Activity implements OnItemClickListener { menu.add(0, MENU_DELETE_ONE, 0, R.string.delete); menu.add(0, MENU_EDIT, 0, R.string.edit); } - + @Override public boolean onContextItemSelected(final MenuItem item) { final AdapterContextMenuInfo info = (AdapterContextMenuInfo) item.getMenuInfo(); switch (item.getItemId()) { - case MENU_DELETE_ONE: - mBookmark.delete(info.id); - return true; - case MENU_EDIT: - final Object obj = info.targetView.getTag(); - if (obj instanceof ViewHolder) { - showEditDialog((ViewHolder)obj); - } else { - QcomLog.w(TAG, "wrong context item info " + info); - } - return true; - default: - return super.onContextItemSelected(item); + case MENU_DELETE_ONE: + mBookmark.delete(info.id); + return true; + case MENU_EDIT: + final Object obj = info.targetView.getTag(); + if (obj instanceof ViewHolder) { + showEditDialog((ViewHolder) obj); + } else { + Log.w(TAG, "wrong context item info " + info); + } + return true; + default: + return super.onContextItemSelected(item); } } - + private void showEditDialog(final ViewHolder holder) { if (LOG) { - QcomLog.v(TAG, "showEditDialog(" + holder + ")"); + Log.v(TAG, "showEditDialog(" + holder + ")"); } if (holder == null) { return; } final LayoutInflater inflater = LayoutInflater.from(this); final View v = inflater.inflate(R.layout.bookmark_edit_dialog, null); - final EditText titleView = (EditText)v.findViewById(R.id.title); - final EditText dataView = (EditText)v.findViewById(R.id.data); + final EditText titleView = (EditText) v.findViewById(R.id.title); + final EditText dataView = (EditText) v.findViewById(R.id.data); titleView.setText(holder.mTitle); dataView.setText(holder.mData); - + final AlertDialog.Builder builder = new AlertDialog.Builder(this); builder.setTitle(R.string.edit); builder.setView(v); @@ -231,7 +233,7 @@ public class BookmarkActivity extends Activity implements OnItemClickListener { mBookmark.update(holder.mId, titleView.getText().toString(), dataView.getText().toString(), 0); } - + }); builder.setNegativeButton(android.R.string.cancel, null); final AlertDialog dialog = builder.create(); diff --git a/src/com/qcom/gallery3d/video/BookmarkEnhance.java b/src/org/codeaurora/gallery3d/video/BookmarkEnhance.java index 033b055b5..fc3ed9b0f 100755..100644 --- a/src/com/qcom/gallery3d/video/BookmarkEnhance.java +++ b/src/org/codeaurora/gallery3d/video/BookmarkEnhance.java @@ -1,4 +1,4 @@ -package com.qcom.gallery3d.video; +package org.codeaurora.gallery3d.video; import android.content.ContentResolver; import android.content.ContentUris; @@ -6,16 +6,16 @@ import android.content.ContentValues; import android.content.Context; import android.database.Cursor; import android.net.Uri; +import android.util.Log; import com.android.gallery3d.R; -import com.qcom.gallery3d.ext.QcomLog; public class BookmarkEnhance { private static final String TAG = "BookmarkEnhance"; private static final boolean LOG = true; - + private static final Uri BOOKMARK_URI = Uri.parse("content://media/internal/bookmark"); - + public static final String COLUMN_ID = "_id"; public static final String COLUMN_DATA = "_data"; public static final String COLUMN_TITLE = "_display_name"; @@ -23,11 +23,11 @@ public class BookmarkEnhance { public static final String COLUMN_MEDIA_TYPE = "mime_type"; private static final String COLUMN_POSITION = "position"; private static final String COLUMN_MIME_TYPE = "media_type"; - + private static final String NULL_HOCK = COLUMN_POSITION; public static final String ORDER_COLUMN = COLUMN_ADD_DATE + " ASC "; private static final String VIDEO_STREAMING_MEDIA_TYPE = "streaming"; - + public static final int INDEX_ID = 0; public static final int INDEX_DATA = 1; public static final int INDEX_TITLE = 2; @@ -35,24 +35,25 @@ public class BookmarkEnhance { public static final int INDEX_MIME_TYPE = 4; private static final int INDEX_POSITION = 5; private static final int INDEX_MEDIA_TYPE = 6; - - public static final String[] PROJECTION = new String[]{ - COLUMN_ID, - COLUMN_DATA, - COLUMN_TITLE, - COLUMN_ADD_DATE, - COLUMN_MIME_TYPE, + + public static final String[] PROJECTION = new String[] { + COLUMN_ID, + COLUMN_DATA, + COLUMN_TITLE, + COLUMN_ADD_DATE, + COLUMN_MIME_TYPE, }; - + private final Context mContext; private final ContentResolver mCr; - + public BookmarkEnhance(final Context context) { mContext = context; mCr = context.getContentResolver(); } - - public Uri insert(final String title, final String uri, final String mimeType,final long position) { + + public Uri insert(final String title, final String uri, final String mimeType, + final long position) { final ContentValues values = new ContentValues(); final String mytitle = (title == null ? mContext.getString(R.string.default_title) : title); values.put(COLUMN_TITLE, mytitle); @@ -63,33 +64,38 @@ public class BookmarkEnhance { values.put(COLUMN_MIME_TYPE, mimeType); final Uri insertUri = mCr.insert(BOOKMARK_URI, values); if (LOG) { - QcomLog.v(TAG, "insert(" + title + "," + uri + ", " + position + ") return " + insertUri); + Log.v(TAG, "insert(" + title + "," + uri + ", " + position + ") return " + + insertUri); } return insertUri; } - + public int delete(final long id) { final Uri uri = ContentUris.withAppendedId(BOOKMARK_URI, id); final int count = mCr.delete(uri, null, null); if (LOG) { - QcomLog.v(TAG, "delete(" + id + ") return " + count); + Log.v(TAG, "delete(" + id + ") return " + count); } return count; } - + public int deleteAll() { - final int count = mCr.delete(BOOKMARK_URI, COLUMN_MEDIA_TYPE + "=? ", new String[]{VIDEO_STREAMING_MEDIA_TYPE}); + final int count = mCr.delete(BOOKMARK_URI, COLUMN_MEDIA_TYPE + "=? ", new String[] { + VIDEO_STREAMING_MEDIA_TYPE + }); if (LOG) { - QcomLog.v(TAG, "deleteAll() return " + count); + Log.v(TAG, "deleteAll() return " + count); } return count; } - + public boolean exists(final String uri) { final Cursor cursor = mCr.query(BOOKMARK_URI, PROJECTION, COLUMN_DATA + "=? and " + COLUMN_MEDIA_TYPE + "=? ", - new String[]{uri, VIDEO_STREAMING_MEDIA_TYPE}, + new String[] { + uri, VIDEO_STREAMING_MEDIA_TYPE + }, null ); boolean exist = false; @@ -98,11 +104,11 @@ public class BookmarkEnhance { cursor.close(); } if (LOG) { - QcomLog.v(TAG, "exists(" + uri + ") return " + exist); + Log.v(TAG, "exists(" + uri + ") return " + exist); } return exist; } - + public Cursor query() { final Cursor cursor = mCr.query(BOOKMARK_URI, PROJECTION, @@ -111,11 +117,11 @@ public class BookmarkEnhance { ORDER_COLUMN ); if (LOG) { - QcomLog.v(TAG, "query() return cursor=" + (cursor == null ? -1 : cursor.getCount())); + Log.v(TAG, "query() return cursor=" + (cursor == null ? -1 : cursor.getCount())); } return cursor; } - + public int update(final long id, final String title, final String uri, final int position) { final ContentValues values = new ContentValues(); values.put(COLUMN_TITLE, title); @@ -124,7 +130,7 @@ public class BookmarkEnhance { final Uri updateUri = ContentUris.withAppendedId(BOOKMARK_URI, id); final int count = mCr.update(updateUri, values, null, null); if (LOG) { - QcomLog.v(TAG, "update(" + id + ", " + title + ", " + uri + ", " + position + ")" + + Log.v(TAG, "update(" + id + ", " + title + ", " + uri + ", " + position + ")" + " return " + count); } return count; diff --git a/src/com/qcom/gallery3d/video/BookmarkHooker.java b/src/org/codeaurora/gallery3d/video/BookmarkHooker.java index fc8bcd885..9d7697d7a 100755..100644 --- a/src/com/qcom/gallery3d/video/BookmarkHooker.java +++ b/src/org/codeaurora/gallery3d/video/BookmarkHooker.java @@ -1,31 +1,34 @@ -package com.qcom.gallery3d.video; +package org.codeaurora.gallery3d.video; import android.content.Intent; import android.view.Menu; import android.view.MenuItem; import com.android.gallery3d.R; -import com.qcom.gallery3d.ext.MovieUtils; +import org.codeaurora.gallery3d.ext.MovieUtils; public class BookmarkHooker extends MovieHooker { private static final String TAG = "BookmarkHooker"; private static final boolean LOG = true; - - private static final String ACTION_BOOKMARK = "com.qcom.bookmark.VIEW"; + + private static final String ACTION_BOOKMARK = "org.codeaurora.bookmark.VIEW"; private static final int MENU_BOOKMARK_ADD = 1; private static final int MENU_BOOKMARK_DISPLAY = 2; private MenuItem mMenuBookmarks; private MenuItem mMenuBookmarkAdd; - + public static final String KEY_LOGO_BITMAP = "logo-bitmap"; @Override public boolean onCreateOptionsMenu(final Menu menu) { super.onCreateOptionsMenu(menu); - mMenuBookmarkAdd = menu.add(0, getMenuActivityId(MENU_BOOKMARK_ADD), 0, R.string.bookmark_add); - mMenuBookmarks = menu.add(0, getMenuActivityId(MENU_BOOKMARK_DISPLAY), 0, R.string.bookmark_display); + mMenuBookmarkAdd = menu.add(0, getMenuActivityId(MENU_BOOKMARK_ADD), 0, + R.string.bookmark_add); + mMenuBookmarks = menu.add(0, getMenuActivityId(MENU_BOOKMARK_DISPLAY), 0, + R.string.bookmark_display); return true; } + @Override public boolean onPrepareOptionsMenu(final Menu menu) { super.onPrepareOptionsMenu(menu); @@ -46,27 +49,28 @@ public class BookmarkHooker extends MovieHooker { } return true; } + @Override public boolean onOptionsItemSelected(final MenuItem item) { super.onOptionsItemSelected(item); - switch(getMenuOriginalId(item.getItemId())) { - case MENU_BOOKMARK_ADD: - getPlayer().addBookmark(); - return true; - case MENU_BOOKMARK_DISPLAY: - gotoBookmark(); - return true; - default: - return false; + switch (getMenuOriginalId(item.getItemId())) { + case MENU_BOOKMARK_ADD: + getPlayer().addBookmark(); + return true; + case MENU_BOOKMARK_DISPLAY: + gotoBookmark(); + return true; + default: + return false; } } - + private void gotoBookmark() { final Intent intent = new Intent(ACTION_BOOKMARK); intent.addCategory(Intent.CATEGORY_DEFAULT); - intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP + intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY); intent.putExtra(KEY_LOGO_BITMAP, getIntent().getParcelableExtra(KEY_LOGO_BITMAP)); getContext().startActivity(intent); } -}
\ No newline at end of file +} diff --git a/src/org/codeaurora/gallery3d/video/CodeauroraVideoView.java b/src/org/codeaurora/gallery3d/video/CodeauroraVideoView.java new file mode 100755 index 000000000..56fab2395 --- /dev/null +++ b/src/org/codeaurora/gallery3d/video/CodeauroraVideoView.java @@ -0,0 +1,1032 @@ +package org.codeaurora.gallery3d.video; + +import android.app.AlertDialog; +import android.content.Context; +import android.content.DialogInterface; +import android.content.Intent; +import android.content.res.Resources; +import android.media.AudioManager; +import android.media.MediaPlayer; +import android.media.Metadata; +import android.media.MediaPlayer.OnCompletionListener; +import android.media.MediaPlayer.OnErrorListener; +import android.media.MediaPlayer.OnInfoListener; +import android.net.Uri; +import android.os.Handler; +import android.os.Message; +import android.util.AttributeSet; +import android.util.Log; +import android.view.KeyEvent; +import android.view.MotionEvent; +import android.view.SurfaceHolder; +import android.view.SurfaceView; +import android.view.View; +import android.view.accessibility.AccessibilityEvent; +import android.view.accessibility.AccessibilityNodeInfo; +import android.widget.MediaController; +import android.widget.MediaController.MediaPlayerControl; + +import java.io.IOException; +import java.util.Map; + +/** + * Displays a video file. The VideoView class + * can load images from various sources (such as resources or content + * providers), takes care of computing its measurement from the video so that + * it can be used in any layout manager, and provides various display options + * such as scaling and tinting. + */ +public class CodeauroraVideoView extends SurfaceView implements MediaPlayerControl { + private static final boolean LOG = true; + private String TAG = "CodeauroraVideoView"; + // settable by the client + private Uri mUri; + private Map<String, String> mHeaders; + + // all possible internal states + private static final int STATE_ERROR = -1; + private static final int STATE_IDLE = 0; + private static final int STATE_PREPARING = 1; + private static final int STATE_PREPARED = 2; + private static final int STATE_PLAYING = 3; + private static final int STATE_PAUSED = 4; + private static final int STATE_PLAYBACK_COMPLETED = 5; + private static final int STATE_SUSPENDED = 6; + private static final int MSG_LAYOUT_READY = 1; + + // mCurrentState is a VideoView object's current state. + // mTargetState is the state that a method caller intends to reach. + // For instance, regardless the VideoView object's current state, + // calling pause() intends to bring the object to a target state + // of STATE_PAUSED. + private int mCurrentState = STATE_IDLE; + private int mTargetState = STATE_IDLE; + + // All the stuff we need for playing and showing a video + private SurfaceHolder mSurfaceHolder = null; + private MediaPlayer mMediaPlayer = null; + private int mAudioSession; + private int mVideoWidth; + private int mVideoHeight; + private int mSurfaceWidth; + private int mSurfaceHeight; + private int mDuration; + private MediaController mMediaController; + private OnCompletionListener mOnCompletionListener; + private MediaPlayer.OnPreparedListener mOnPreparedListener; + private MediaPlayer.OnBufferingUpdateListener mOnBufferingUpdateListener; + private MediaPlayer.OnVideoSizeChangedListener mVideoSizeListener; + private MediaPlayer.OnPreparedListener mPreparedListener; + private int mCurrentBufferPercentage; + private OnErrorListener mOnErrorListener; + private OnInfoListener mOnInfoListener; + private int mSeekWhenPrepared; // recording the seek position while preparing + private boolean mCanPause; + private boolean mCanSeekBack; + private boolean mCanSeekForward; + private boolean mHasGotPreparedCallBack = false; + private boolean mNeedWaitLayout = false; + private boolean mHasGotMetaData = false; + private boolean mOnResumed; + + private final Handler mHandler = new Handler() { + public void handleMessage(final Message msg) { + if (LOG) { + Log.v(TAG, "handleMessage() to do prepare. msg=" + msg); + } + switch (msg.what) { + case MSG_LAYOUT_READY: + if (mMediaPlayer == null || mUri == null) { + Log.w(TAG, "Cannot prepare play! mMediaPlayer=" + mMediaPlayer + + ", mUri=" + mUri); + } else { + doPreparedIfReady(mMediaPlayer); + } + break; + default: + Log.w(TAG, "Unhandled message " + msg); + break; + } + } + }; + + public CodeauroraVideoView(Context context) { + super(context); + initVideoView(); + initialize(); + } + + public CodeauroraVideoView(Context context, AttributeSet attrs) { + this(context, attrs, 0); + initVideoView(); + initialize(); + } + + public CodeauroraVideoView(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + initVideoView(); + initialize(); + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + int width = 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; + } + if (widthSpecMode == MeasureSpec.AT_MOST && width > widthSpecSize) { + width = widthSpecSize; + height = width * mVideoHeight / mVideoWidth; + } + } + } else { + // no size yet, just adopt the given spec sizes + } + setMeasuredDimension(width, height); + if (mNeedWaitLayout) { // when OnMeasure ok, start video. + mNeedWaitLayout = false; + mHandler.sendEmptyMessage(MSG_LAYOUT_READY); + } + } + + @Override + public void onInitializeAccessibilityEvent(AccessibilityEvent event) { + super.onInitializeAccessibilityEvent(event); + event.setClassName(CodeauroraVideoView.class.getName()); + } + + @Override + public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) { + super.onInitializeAccessibilityNodeInfo(info); + info.setClassName(CodeauroraVideoView.class.getName()); + } + + public int resolveAdjustedSize(int desiredSize, int measureSpec) { + return getDefaultSize(desiredSize, measureSpec); + } + + private void initVideoView() { + mVideoWidth = 0; + mVideoHeight = 0; + getHolder().addCallback(mSHCallback); + getHolder().setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); + setFocusable(true); + setFocusableInTouchMode(true); + requestFocus(); + mCurrentState = STATE_IDLE; + mTargetState = STATE_IDLE; + } + + private void initialize() { + mPreparedListener = new MediaPlayer.OnPreparedListener() { + public void onPrepared(final MediaPlayer mp) { + if (LOG) { + Log.v(TAG, "mPreparedListener.onPrepared(" + mp + ")"); + } + //Here we can get meta data from mediaplayer. + // Get the capabilities of the player for this stream + final Metadata data = mp.getMetadata(MediaPlayer.METADATA_ALL, + MediaPlayer.BYPASS_METADATA_FILTER); + if (data != null) { + mCanPause = !data.has(Metadata.PAUSE_AVAILABLE) + || data.getBoolean(Metadata.PAUSE_AVAILABLE); + mCanSeekBack = !data.has(Metadata.SEEK_BACKWARD_AVAILABLE) + || data.getBoolean(Metadata.SEEK_BACKWARD_AVAILABLE); + mCanSeekForward = !data.has(Metadata.SEEK_FORWARD_AVAILABLE) + || data.getBoolean(Metadata.SEEK_FORWARD_AVAILABLE); + } else { + mCanPause = true; + mCanSeekBack = true; + mCanSeekForward = true; + Log.w(TAG, "Metadata is null!"); + } + if (LOG) { + Log.v(TAG, "mPreparedListener.onPrepared() mCanPause=" + mCanPause); + } + mHasGotPreparedCallBack = true; + doPreparedIfReady(mMediaPlayer); + } + }; + + mErrorListener = new MediaPlayer.OnErrorListener() { + public boolean onError(final MediaPlayer mp, final int frameworkErr, final int implErr) { + Log.d(TAG, "Error: " + frameworkErr + "," + implErr); + if (mCurrentState == STATE_ERROR) { + Log.w(TAG, "Duplicate error message. error message has been sent! " + + "error=(" + frameworkErr + "," + implErr + ")"); + return true; + } + //record error position and duration + //here disturb the original logic + mSeekWhenPrepared = getCurrentPosition(); + if (LOG) { + Log.v(TAG, "onError() mSeekWhenPrepared=" + mSeekWhenPrepared + ", mDuration=" + mDuration); + } + //for old version Streaming server, getduration is not valid. + mDuration = Math.abs(mDuration); + mCurrentState = STATE_ERROR; + mTargetState = STATE_ERROR; + if (mMediaController != null) { + mMediaController.hide(); + } + + /* If an error handler has been supplied, use it and finish. */ + if (mOnErrorListener != null) { + if (mOnErrorListener.onError(mMediaPlayer, frameworkErr, implErr)) { + return true; + } + } + + /* Otherwise, pop up an error dialog so the user knows that + * something bad has happened. Only try and pop up the dialog + * if we're attached to a window. When we're going away and no + * longer have a window, don't bother showing the user an error. + */ + if (getWindowToken() != null) { + final Resources r = mContext.getResources(); + int messageId; + + if (frameworkErr == MediaPlayer.MEDIA_ERROR_NOT_VALID_FOR_PROGRESSIVE_PLAYBACK) { + messageId = com.android.internal.R.string.VideoView_error_text_invalid_progressive_playback; + } else { + messageId = com.android.internal.R.string.VideoView_error_text_unknown; + } + new AlertDialog.Builder(mContext) + .setMessage(messageId) + .setPositiveButton(com.android.internal.R.string.VideoView_error_button, + new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int whichButton) { + /* If we get here, there is no onError listener, so + * at least inform them that the video is over. + */ + if (mOnCompletionListener != null) { + mOnCompletionListener.onCompletion(mMediaPlayer); + } + } + }) + .setCancelable(false) + .show(); + } + return true; + } + }; + + mBufferingUpdateListener = new MediaPlayer.OnBufferingUpdateListener() { + public void onBufferingUpdate(final MediaPlayer mp, final int percent) { + mCurrentBufferPercentage = percent; + if (mOnBufferingUpdateListener != null) { + mOnBufferingUpdateListener.onBufferingUpdate(mp, percent); + } + if (LOG) { + Log.v(TAG, "onBufferingUpdate() Buffering percent: " + percent); + Log.v(TAG, "onBufferingUpdate() mTargetState=" + mTargetState); + Log.v(TAG, "onBufferingUpdate() mCurrentState=" + mCurrentState); + } + } + }; + + mSizeChangedListener = new MediaPlayer.OnVideoSizeChangedListener() { + public void onVideoSizeChanged(final MediaPlayer mp, final int width, final int height) { + mVideoWidth = mp.getVideoWidth(); + mVideoHeight = mp.getVideoHeight(); + if (LOG) { + Log.v(TAG, "OnVideoSizeChagned(" + width + "," + height + ")"); + Log.v(TAG, "OnVideoSizeChagned(" + mVideoWidth + "," + mVideoHeight + ")"); + Log.v(TAG, "OnVideoSizeChagned() mCurrentState=" + mCurrentState); + } + if (mVideoWidth != 0 && mVideoHeight != 0) { + getHolder().setFixedSize(mVideoWidth, mVideoHeight); + if (mCurrentState == STATE_PREPARING) { + mNeedWaitLayout = true; + } + } + if (mVideoSizeListener != null) { + mVideoSizeListener.onVideoSizeChanged(mp, width, height); + } + CodeauroraVideoView.this.requestLayout(); + } + }; + + getHolder().removeCallback(mSHCallback); + mSHCallback = new SurfaceHolder.Callback() { + public void surfaceChanged(final SurfaceHolder holder, final int format, final int w, final int h) { + if (LOG) { + Log.v(TAG, "surfaceChanged(" + holder + ", " + format + ", " + w + ", " + h + ")"); + Log.v(TAG, "surfaceChanged() mMediaPlayer=" + mMediaPlayer + ", mTargetState=" + mTargetState + + ", mVideoWidth=" + mVideoWidth + ", mVideoHeight=" + mVideoHeight); + } + mSurfaceWidth = w; + mSurfaceHeight = h; + final boolean isValidState = (mTargetState == STATE_PLAYING); + final boolean hasValidSize = (mVideoWidth == w && mVideoHeight == h); + if (mMediaPlayer != null && isValidState && hasValidSize) { + if (mSeekWhenPrepared != 0) { + seekTo(mSeekWhenPrepared); + } + Log.v(TAG, "surfaceChanged() start()"); + start(); + } + } + + public void surfaceCreated(final SurfaceHolder holder) { + if (LOG) { + Log.v(TAG, "surfaceCreated(" + holder + ")"); + } + mSurfaceHolder = holder; + openVideo(); + } + + public void surfaceDestroyed(final SurfaceHolder holder) { + // after we return from this we can't use the surface any more + if (LOG) { + Log.v(TAG, "surfaceDestroyed(" + holder + ")"); + } + mSurfaceHolder = null; + if (mMediaController != null) { + mMediaController.hide(); + } + release(true); + } + }; + getHolder().addCallback(mSHCallback); + } + + public void setVideoPath(String path) { + setVideoURI(Uri.parse(path)); + } + + public void setVideoURI(Uri uri) { + setVideoURI(uri, null); + } + + /** + * @hide + */ + public void setVideoURI(Uri uri, Map<String, String> headers) { + Log.d(TAG,"setVideoURI uri = " + uri); + mDuration = -1; + setResumed(true); + mUri = uri; + mHeaders = headers; + mSeekWhenPrepared = 0; + openVideo(); + requestLayout(); + invalidate(); + } + + public void stopPlayback() { + if (mMediaPlayer != null) { + mMediaPlayer.stop(); + mMediaPlayer.release(); + mMediaPlayer = null; + mCurrentState = STATE_IDLE; + mTargetState = STATE_IDLE; + } + } + + private void openVideo() { + clearVideoInfo(); + if (mUri == null || mSurfaceHolder == null) { + // not ready for playback just yet, will try again later + return; + } + // Tell the music playback service to pause + // TODO: these constants need to be published somewhere in the framework. + Intent i = new Intent("com.android.music.musicservicecommand"); + i.putExtra("command", "pause"); + mContext.sendBroadcast(i); + // we shouldn't clear the target state, because somebody might have + // called start() previously + release(false); + if ("".equalsIgnoreCase(String.valueOf(mUri))) { + Log.w(TAG, "Unable to open content: " + mUri); + mErrorListener.onError(mMediaPlayer, MediaPlayer.MEDIA_ERROR_UNKNOWN, 0); + return; + } + try { + mMediaPlayer = new MediaPlayer(); + if (mAudioSession != 0) { + mMediaPlayer.setAudioSessionId(mAudioSession); + } else { + mAudioSession = mMediaPlayer.getAudioSessionId(); + } + mMediaPlayer.setOnPreparedListener(mPreparedListener); + mMediaPlayer.setOnVideoSizeChangedListener(mSizeChangedListener); + mMediaPlayer.setOnCompletionListener(mCompletionListener); + mMediaPlayer.setOnErrorListener(mErrorListener); + mMediaPlayer.setOnInfoListener(mOnInfoListener); + mMediaPlayer.setOnBufferingUpdateListener(mBufferingUpdateListener); + mCurrentBufferPercentage = 0; + mMediaPlayer.setDataSource(mContext, mUri, mHeaders); + mMediaPlayer.setDisplay(mSurfaceHolder); + mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC); + mMediaPlayer.setScreenOnWhilePlaying(true); + mMediaPlayer.prepareAsync(); + // we don't set the target state here either, but preserve the + // target state that was there before. + mCurrentState = STATE_PREPARING; + attachMediaController(); + } catch (IOException ex) { + Log.w(TAG, "Unable to open content: " + mUri, ex); + mCurrentState = STATE_ERROR; + mTargetState = STATE_ERROR; + mErrorListener.onError(mMediaPlayer, MediaPlayer.MEDIA_ERROR_UNKNOWN, 0); + return; + } catch (IllegalArgumentException ex) { + Log.w(TAG, "Unable to open content: " + mUri, ex); + mCurrentState = STATE_ERROR; + mTargetState = STATE_ERROR; + mErrorListener.onError(mMediaPlayer, MediaPlayer.MEDIA_ERROR_UNKNOWN, 0); + return; + } + } + + public void setMediaController(MediaController controller) { + if (mMediaController != null) { + mMediaController.hide(); + } + mMediaController = controller; + attachMediaController(); + } + + private void attachMediaController() { + if (mMediaPlayer != null && mMediaController != null) { + mMediaController.setMediaPlayer(this); + View anchorView = this.getParent() instanceof View ? + (View)this.getParent() : this; + mMediaController.setAnchorView(anchorView); + mMediaController.setEnabled(isInPlaybackState()); + } + } + + private boolean isHTTPStreaming(Uri mUri) { + if (mUri != null){ + String scheme = mUri.toString(); + if (scheme.startsWith("http://") || scheme.startsWith("https://")) { + if (scheme.endsWith(".m3u8") || scheme.endsWith(".m3u") + || scheme.contains("m3u8") || scheme.endsWith(".mpd")) { + // HLS or DASH streaming source + return false; + } + // HTTP streaming + return true; + } + } + return false; + } + + MediaPlayer.OnVideoSizeChangedListener mSizeChangedListener = + new MediaPlayer.OnVideoSizeChangedListener() { + public void onVideoSizeChanged(MediaPlayer mp, int width, int height) { + mVideoWidth = mp.getVideoWidth(); + mVideoHeight = mp.getVideoHeight(); + if (mVideoWidth != 0 && mVideoHeight != 0) { + getHolder().setFixedSize(mVideoWidth, mVideoHeight); + requestLayout(); + } + } + }; + + private MediaPlayer.OnCompletionListener mCompletionListener = + new MediaPlayer.OnCompletionListener() { + public void onCompletion(MediaPlayer mp) { + mCurrentState = STATE_PLAYBACK_COMPLETED; + mTargetState = STATE_PLAYBACK_COMPLETED; + if (mMediaController != null) { + mMediaController.hide(); + } + if (mOnCompletionListener != null) { + mOnCompletionListener.onCompletion(mMediaPlayer); + } + } + }; + + private MediaPlayer.OnErrorListener mErrorListener = + 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.OnBufferingUpdateListener mBufferingUpdateListener = + new MediaPlayer.OnBufferingUpdateListener() { + public void onBufferingUpdate(MediaPlayer mp, int percent) { + mCurrentBufferPercentage = percent; + } + }; + + /** + * Register a callback to be invoked when the media file + * is loaded and ready to go. + * + * @param l The callback that will be run + */ + public void setOnPreparedListener(MediaPlayer.OnPreparedListener l) { + mOnPreparedListener = l; + } + + /** + * Register a callback to be invoked when the end of a media file + * has been reached during playback. + * + * @param l The callback that will be run + */ + public void setOnCompletionListener(OnCompletionListener l) { + mOnCompletionListener = l; + } + + /** + * Register a callback to be invoked when an error occurs + * during playback or setup. If no listener is specified, + * or if the listener returned false, VideoView will inform + * the user of any errors. + * + * @param l The callback that will be run + */ + public void setOnErrorListener(OnErrorListener l) { + mOnErrorListener = l; + } + + /** + * Register a callback to be invoked when an informational event + * occurs during playback or setup. + * + * @param l The callback that will be run + */ + public void setOnInfoListener(OnInfoListener l) { + mOnInfoListener = l; + } + + SurfaceHolder.Callback mSHCallback = new SurfaceHolder.Callback() { + public void surfaceChanged(SurfaceHolder holder, int format, + int w, int h) { + mSurfaceWidth = w; + mSurfaceHeight = h; + boolean isValidState = (mTargetState == STATE_PLAYING); + boolean hasValidSize = (mVideoWidth == w && mVideoHeight == h); + if (mMediaPlayer != null && isValidState && hasValidSize) { + if (mSeekWhenPrepared != 0) { + seekTo(mSeekWhenPrepared); + } + start(); + } + } + + public void surfaceCreated(SurfaceHolder holder) { + /* + if (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 + ")"); + } + if (mCurrentState == STATE_SUSPENDED) { + mSurfaceHolder = holder; + mMediaPlayer.setDisplay(mSurfaceHolder); + release(false); + } + mSurfaceHolder = holder; + openVideo(); + } + + public void surfaceDestroyed(SurfaceHolder holder) { + // after we return from this we can't use the surface any more + mSurfaceHolder = null; + if (mMediaController != null) mMediaController.hide(); + if (isHTTPStreaming(mUri) && mCurrentState == STATE_SUSPENDED) { + // Don't call release() while run suspend operation + return; + } + release(true); + } + }; + + /* + * release the media player in any state + */ + private void release(boolean cleartargetstate) { + if (mMediaPlayer != null) { + mMediaPlayer.reset(); + mMediaPlayer.release(); + mMediaPlayer = null; + mCurrentState = STATE_IDLE; + if (cleartargetstate) { + mTargetState = STATE_IDLE; + } + } + } + + @Override + public boolean onTouchEvent(MotionEvent ev) { + if (isInPlaybackState() && mMediaController != null) { + toggleMediaControlsVisiblity(); + } + return false; + } + + @Override + public boolean onTrackballEvent(MotionEvent ev) { + if (isInPlaybackState() && mMediaController != null) { + toggleMediaControlsVisiblity(); + } + return false; + } + + @Override + public boolean onKeyDown(int keyCode, KeyEvent event) { + final boolean isKeyCodeSupported = keyCode != KeyEvent.KEYCODE_BACK && + keyCode != KeyEvent.KEYCODE_VOLUME_UP && + keyCode != KeyEvent.KEYCODE_VOLUME_DOWN && + keyCode != KeyEvent.KEYCODE_VOLUME_MUTE && + keyCode != KeyEvent.KEYCODE_MENU && + keyCode != KeyEvent.KEYCODE_CALL && + keyCode != KeyEvent.KEYCODE_ENDCALL && + keyCode != KeyEvent.KEYCODE_CAMERA; + if (isInPlaybackState() && isKeyCodeSupported && mMediaController != null) { + if (event.getRepeatCount() == 0 && (keyCode == KeyEvent.KEYCODE_HEADSETHOOK || + keyCode == KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE)) { + if (mMediaPlayer.isPlaying()) { + pause(); + mMediaController.show(); + } else { + start(); + mMediaController.hide(); + } + return true; + } else if (keyCode == KeyEvent.KEYCODE_MEDIA_PLAY) { + if (!mMediaPlayer.isPlaying()) { + start(); + mMediaController.hide(); + } + return true; + } else if (keyCode == KeyEvent.KEYCODE_MEDIA_STOP + || keyCode == KeyEvent.KEYCODE_MEDIA_PAUSE) { + if (mMediaPlayer.isPlaying()) { + pause(); + mMediaController.show(); + } + return true; + } else if (keyCode == KeyEvent.KEYCODE_MEDIA_FAST_FORWARD || + keyCode == KeyEvent.KEYCODE_MEDIA_NEXT || + keyCode == KeyEvent.KEYCODE_MEDIA_PREVIOUS || + keyCode == KeyEvent.KEYCODE_MEDIA_REWIND || + keyCode == KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE || + keyCode == KeyEvent.KEYCODE_HEADSETHOOK) { + // consume media action, so if video view if front, + // other media player will not play any sounds. + return true; + } else { + toggleMediaControlsVisiblity(); + } + } + return super.onKeyDown(keyCode, event); + } + + private void toggleMediaControlsVisiblity() { + if (mMediaController.isShowing()) { + mMediaController.hide(); + } else { + mMediaController.show(); + } + } + + @Override + public void start() { + if (isInPlaybackState()) { + mMediaPlayer.start(); + mCurrentState = STATE_PLAYING; + } + mTargetState = STATE_PLAYING; + } + + @Override + public void pause() { + if (isInPlaybackState()) { + if (mMediaPlayer.isPlaying()) { + mMediaPlayer.pause(); + mCurrentState = STATE_PAUSED; + } + } + mTargetState = STATE_PAUSED; + } + + public void suspend() { + // HTTP streaming will call mMediaPlayer->suspend(), others will call release() + /* + if (isHTTPStreaming(mUri) && mCurrentState != STATE_PREPARING) { + if (mMediaPlayer.suspend()) { + mTargetState = mCurrentState; + mCurrentState = STATE_SUSPENDED; + return; + } + }*/ + release(false); + } + + public void resume() { + setResumed(true); + openVideo(); + } + + @Override + public int getDuration() { + final boolean inPlaybackState = isInPlaybackState(); + if (LOG) { + Log.v(TAG, "getDuration() mDuration=" + mDuration + ", inPlaybackState=" + + inPlaybackState); + } + if (inPlaybackState) { + if (mDuration > 0) { + return mDuration; + } + // in case the duration is zero or smaller than zero for streaming + // video + int tempDuration = mMediaPlayer.getDuration(); + if (tempDuration <= 0) { + return mDuration; + } else { + mDuration = tempDuration; + } + + return mDuration; + } + return mDuration; + } + + @Override + public int getCurrentPosition() { + int position = 0; + if (mSeekWhenPrepared > 0) { + // if connecting error before seek, + // we should remember this position for retry + position = mSeekWhenPrepared; + // /M: if player not started, getCurrentPosition() will lead to NE. + } else if (isInPlaybackState()) { + position = mMediaPlayer.getCurrentPosition(); + } + if (LOG) { + Log.v(TAG, "getCurrentPosition() return " + position + + ", mSeekWhenPrepared=" + mSeekWhenPrepared); + } + return position; + } + + @Override + public void seekTo(int msec) { + if (isInPlaybackState()) { + mMediaPlayer.seekTo(msec); + mSeekWhenPrepared = 0; + } else { + mSeekWhenPrepared = msec; + } + } + + @Override + public boolean isPlaying() { + return isInPlaybackState() && mMediaPlayer.isPlaying(); + } + + @Override + public int getBufferPercentage() { + if (mMediaPlayer != null) { + return mCurrentBufferPercentage; + } + return 0; + } + + private boolean isInPlaybackState() { + return (mMediaPlayer != null && + mCurrentState != STATE_ERROR && + mCurrentState != STATE_IDLE && + mCurrentState != STATE_PREPARING && + mCurrentState != STATE_SUSPENDED); + } + + @Override + public boolean canPause() { + return mCanPause; + } + + @Override + public boolean canSeekBackward() { + return mCanSeekBack; + } + + @Override + public boolean canSeekForward() { + return mCanSeekForward; + } + + @Override + public int getAudioSessionId() { + if (mAudioSession == 0) { + MediaPlayer foo = new MediaPlayer(); + mAudioSession = foo.getAudioSessionId(); + foo.release(); + } + return mAudioSession; + } + + // for duration displayed + public void setDuration(final int duration) { + if (LOG) { + Log.v(TAG, "setDuration(" + duration + ")"); + } + mDuration = (duration > 0 ? -duration : duration); + } + + public void setVideoURI(final Uri uri, final Map<String, String> headers, + final boolean hasGotMetaData) { + if (LOG) { + Log.v(TAG, "setVideoURI(" + uri + ", " + headers + ")"); + } + // clear the flags + mHasGotMetaData = hasGotMetaData; + setVideoURI(uri, headers); + } + + private void doPreparedIfReady(final MediaPlayer mp) { + if (LOG) { + Log.v(TAG, "doPreparedIfReady() mHasGotPreparedCallBack=" + mHasGotPreparedCallBack + + ", mHasGotMetaData=" + mHasGotMetaData + ", mNeedWaitLayout=" + + mNeedWaitLayout + + ", mCurrentState=" + mCurrentState); + } + if (mHasGotPreparedCallBack && mHasGotMetaData && !mNeedWaitLayout) { + doPrepared(mp); + } + } + + private void doPrepared(final MediaPlayer mp) { + if (LOG) { + Log.v(TAG, "doPrepared(" + mp + ") start"); + } + mCurrentState = STATE_PREPARED; + if (mOnPreparedListener != null) { + mOnPreparedListener.onPrepared(mMediaPlayer); + } + mVideoWidth = mp.getVideoWidth(); + mVideoHeight = mp.getVideoHeight(); + + // mSeekWhenPrepared may be changed after seekTo() + final int seekToPosition = mSeekWhenPrepared; + if (seekToPosition != 0) { + seekTo(seekToPosition); + } + if (mVideoWidth != 0 && mVideoHeight != 0) { + getHolder().setFixedSize(mVideoWidth, mVideoHeight); + } + + if (mTargetState == STATE_PLAYING) { + start(); + } + if (LOG) { + Log.v(TAG, "doPrepared() end video size: " + mVideoWidth + "," + mVideoHeight + + ", mTargetState=" + mTargetState + ", mCurrentState=" + mCurrentState); + } + } + + /** + * surfaceCreate will invoke openVideo after the activity stoped. Here set + * this flag to avoid openVideo after the activity stoped. + * + * @param resume + */ + public void setResumed(final boolean resume) { + if (LOG) { + Log.v(TAG, "setResumed(" + resume + ") mUri=" + mUri + ", mOnResumed=" + mOnResumed); + } + mOnResumed = resume; + } + + private void clearVideoInfo() { + if (LOG) { + Log.v(TAG, "clearVideoInfo()"); + } + mHasGotPreparedCallBack = false; + mNeedWaitLayout = false; + } + + public void clearSeek() { + if (LOG) { + Log.v(TAG, "clearSeek() mSeekWhenPrepared=" + mSeekWhenPrepared); + } + mSeekWhenPrepared = 0; + } + + public void clearDuration() { + if (LOG) { + Log.v(TAG, "clearDuration() mDuration=" + mDuration); + } + mDuration = -1; + } + + public boolean isTargetPlaying() { + if (LOG) { + Log.v(TAG, "isTargetPlaying() mTargetState=" + mTargetState); + } + return mTargetState == STATE_PLAYING; + } +} diff --git a/src/org/codeaurora/gallery3d/video/DmReceiver.java b/src/org/codeaurora/gallery3d/video/DmReceiver.java new file mode 100644 index 000000000..616ce33d6 --- /dev/null +++ b/src/org/codeaurora/gallery3d/video/DmReceiver.java @@ -0,0 +1,65 @@ +package org.codeaurora.gallery3d.video; + +import android.app.Notification; +import android.app.NotificationManager; +import android.app.PendingIntent; +import android.app.Service; +import android.content.BroadcastReceiver; +import android.content.ContentResolver; +import android.content.ContentValues; +import android.content.Context; +import android.content.Intent; +import android.content.SharedPreferences; +import android.content.res.Resources; +import android.net.Uri; +import android.os.PowerManager; +import android.preference.PreferenceManager; +import android.provider.Settings.System; +import android.util.Log; + +public class DmReceiver extends BroadcastReceiver { + private static final String TAG = "DmReceiver"; + public static final String WRITE_SETTING_ACTION = "streaming.action.WRITE_SETTINGS"; + public static final String BOOT_COMPLETED = "android.intent.action.BOOT_COMPLETED"; + + private SharedPreferences mPref; + static final int STREAMING_CONNPROFILE_IO_HANDLER_TYPE = 1; + static final int STREAMING_MAX_UDP_PORT_IO_HANDLER_TYPE = 3; + static final int STREAMING_MIN_UDP_PORT_IO_HANDLER_TYPE = 4; + + @Override + public void onReceive(Context context, Intent intent) { + if (mPref == null) { + mPref = PreferenceManager.getDefaultSharedPreferences(context); + } + if (BOOT_COMPLETED.equals(intent.getAction())) { + String rtpMaxport = mPref.getString(SettingsActivity.PREFERENCE_RTP_MAXPORT, "65535"); + String rtpMinport = mPref.getString(SettingsActivity.PREFERENCE_RTP_MINPORT, "8192"); + String apn = mPref.getString(SettingsActivity.PREFERENCE_APN, "CMWAP"); + System.putString(context.getContentResolver(), + "streaming_max_udp_port", rtpMaxport); + System.putString(context.getContentResolver(), + "streaming_min_udp_port", rtpMinport); + System.putString(context.getContentResolver(), "apn", apn); + } else if (WRITE_SETTING_ACTION.equals(intent.getAction())) { + int valueType = intent.getIntExtra("type", 0); + String value = intent.getStringExtra("value"); + if (valueType == STREAMING_MAX_UDP_PORT_IO_HANDLER_TYPE) { + mPref.edit().putString(SettingsActivity.PREFERENCE_RTP_MAXPORT, + value).commit(); + System.putString(context.getContentResolver(), + "streaming_max_udp_port", value); + } else if (valueType == STREAMING_MIN_UDP_PORT_IO_HANDLER_TYPE) { + mPref.edit().putString(SettingsActivity.PREFERENCE_RTP_MINPORT, + value).commit(); + System.putString(context.getContentResolver(), + "streaming_min_udp_port", value); + } else if (valueType == STREAMING_CONNPROFILE_IO_HANDLER_TYPE) { + mPref.edit().putString(SettingsActivity.PREFERENCE_APN, + value).commit(); + System.putString(context.getContentResolver(), + "apn", value); + } + } + } +} diff --git a/src/org/codeaurora/gallery3d/video/ExtensionHelper.java b/src/org/codeaurora/gallery3d/video/ExtensionHelper.java index 7694cbfff..f95e9c09f 100755 --- a/src/org/codeaurora/gallery3d/video/ExtensionHelper.java +++ b/src/org/codeaurora/gallery3d/video/ExtensionHelper.java @@ -18,6 +18,7 @@ public class ExtensionHelper { final ActivityHookerGroup group = new ActivityHookerGroup(); boolean loop = context.getResources().getBoolean(R.bool.loop); boolean stereo = context.getResources().getBoolean(R.bool.stereo); + boolean streaming = context.getResources().getBoolean(R.bool.streaming); if (loop == true) { group.addHooker(new LoopVideoHooker()); // add it for common feature. @@ -25,7 +26,10 @@ public class ExtensionHelper { if (stereo == true) { group.addHooker(new StereoAudioHooker()); // add it for common feature. } - + if (streaming == true) { + group.addHooker(new StreamingHooker()); + group.addHooker(new BookmarkHooker()); + } return group; } } diff --git a/src/com/qcom/gallery3d/video/MovieTitleHelper.java b/src/org/codeaurora/gallery3d/video/MovieTitleHelper.java index 42ba3ec90..5f2229d5e 100755..100644 --- a/src/com/qcom/gallery3d/video/MovieTitleHelper.java +++ b/src/org/codeaurora/gallery3d/video/MovieTitleHelper.java @@ -1,4 +1,4 @@ -package com.qcom.gallery3d.video; +package org.codeaurora.gallery3d.video; import android.content.Context; import android.database.Cursor; @@ -6,15 +6,15 @@ import android.database.sqlite.SQLiteException; import android.net.Uri; import android.provider.MediaStore; import android.provider.OpenableColumns; +import android.util.Log; -import com.qcom.gallery3d.ext.QcomLog; import java.io.File; public class MovieTitleHelper { private static final String TAG = "MovieTitleHelper"; private static final boolean LOG = true; - + public static String getTitleFromMediaData(final Context context, final Uri uri) { String title = null; Cursor cursor = null; @@ -22,14 +22,20 @@ public class MovieTitleHelper { String data = Uri.decode(uri.toString()); data = data.replaceAll("'", "''"); final String where = "_data LIKE '%" + data.replaceFirst("file:///", "") + "'"; - cursor = context.getContentResolver().query(MediaStore.Video.Media.EXTERNAL_CONTENT_URI, - new String[]{OpenableColumns.DISPLAY_NAME}, where, null, null); - if (LOG) { - QcomLog.v(TAG, "setInfoFromMediaData() cursor=" + (cursor == null ? "null" : cursor.getCount())); + cursor = context.getContentResolver().query( + MediaStore.Video.Media.EXTERNAL_CONTENT_URI, + new String[] { + OpenableColumns.DISPLAY_NAME + }, where, null, null); + if (LOG) { + Log.v( + TAG, + "setInfoFromMediaData() cursor=" + + (cursor == null ? "null" : cursor.getCount())); } if (cursor != null && cursor.moveToFirst()) { title = cursor.getString(0); - } + } } catch (final SQLiteException ex) { ex.printStackTrace(); } finally { @@ -38,20 +44,22 @@ public class MovieTitleHelper { } } if (LOG) { - QcomLog.v(TAG, "setInfoFromMediaData() return " + title); + Log.v(TAG, "setInfoFromMediaData() return " + title); } return title; } - + public static String getTitleFromDisplayName(final Context context, final Uri uri) { String title = null; Cursor cursor = null; try { cursor = context.getContentResolver().query(uri, - new String[]{OpenableColumns.DISPLAY_NAME}, null, null, null); + new String[] { + OpenableColumns.DISPLAY_NAME + }, null, null, null); if (cursor != null && cursor.moveToFirst()) { title = cursor.getString(0); - } + } } catch (final SQLiteException ex) { ex.printStackTrace(); } finally { @@ -60,29 +68,31 @@ public class MovieTitleHelper { } } if (LOG) { - QcomLog.v(TAG, "getTitleFromDisplayName() return " + title); + Log.v(TAG, "getTitleFromDisplayName() return " + title); } return title; } - + public static String getTitleFromUri(final Uri uri) { final String title = Uri.decode(uri.getLastPathSegment()); if (LOG) { - QcomLog.v(TAG, "getTitleFromUri() return " + title); + Log.v(TAG, "getTitleFromUri() return " + title); } return title; } - + public static String getTitleFromData(final Context context, final Uri uri) { String title = null; Cursor cursor = null; try { cursor = context.getContentResolver().query(uri, - new String[]{"_data"}, null, null, null); + new String[] { + "_data" + }, null, null, null); if (cursor != null && cursor.moveToFirst()) { final File file = new File(cursor.getString(0)); title = file.getName(); - } + } } catch (final SQLiteException ex) { ex.printStackTrace(); } finally { @@ -91,7 +101,7 @@ public class MovieTitleHelper { } } if (LOG) { - QcomLog.v(TAG, "getTitleFromData() return " + title); + Log.v(TAG, "getTitleFromData() return " + title); } return title; } diff --git a/src/com/qcom/gallery3d/video/SettingsActivity.java b/src/org/codeaurora/gallery3d/video/SettingsActivity.java index 0d73c5428..58ff53b8a 100755..100644 --- a/src/com/qcom/gallery3d/video/SettingsActivity.java +++ b/src/org/codeaurora/gallery3d/video/SettingsActivity.java @@ -1,353 +1,234 @@ -
-package com.qcom.gallery3d.video;
-
-import android.app.ActionBar;
-import android.app.Activity;
-import android.content.ContentResolver;
-import android.content.Intent;
-import android.content.SharedPreferences;
-import android.database.Cursor;
-import android.os.Bundle;
-import android.preference.CheckBoxPreference;
-import android.preference.EditTextPreference;
-import android.preference.ListPreference;
-import android.preference.Preference;
-import android.preference.PreferenceActivity;
-import android.preference.PreferenceCategory;
-import android.preference.RingtonePreference;
-import android.preference.PreferenceScreen;
-import android.provider.Telephony;
-import android.telephony.MSimTelephonyManager;
-import java.util.ArrayList;
-import android.os.SystemProperties;
-
-
-
-
-
-/* wangyong 2012.2.9 begin*/
-//import android.provider.Calendar;
-/* wangyong 2012.2.9 end*/
-import android.provider.ContactsContract;
-import android.util.Log;
-import android.view.KeyEvent;
-import android.view.MenuItem;
-import android.text.method.DigitsKeyListener;
-import android.net.Uri;
-
-import android.telephony.TelephonyManager;
-import com.android.gallery3d.R;
-
-import com.android.internal.telephony.Phone;
-import com.android.internal.telephony.TelephonyIntents;
-import com.android.internal.telephony.TelephonyProperties;
-
-public class SettingsActivity extends PreferenceActivity {
- public static final String PREFERENCE_RTP_MINPORT = "rtp_min_port";
-
- public static final String PREFERENCE_RTP_MAXPORT = "rtp_max_port";
-
- public static final String PREFERENCE_RTCP_MINPORT = "rtcp_min_port";
-
- public static final String PREFERENCE_RTCP_MAXPORT = "rtcp_max_port";
-
- public static final String PREFERENCE_BUFFER_SIZE = "buffer_size";
-
- public static final String PREFERENCE_APN = "apn";
-
-
- private EditTextPreference mRtpMinPort;
-
- private EditTextPreference mRtpMaxPort;
-
- private EditTextPreference mRtcpMinPort;
-
- private EditTextPreference mRtcpMaxPort;
-
- private EditTextPreference mBufferSize;
-
- private PreferenceScreen mApn;
-
- private CheckBoxPreference mRepeat;
-
- private static final int SELECT_APN = 1;
-
- public static final String PREFERRED_APN_URI = "content://telephony/carriers/preferapn";
-
- private static final Uri PREFERAPN_URI = Uri.parse(PREFERRED_APN_URI);
-
- private static final int ID_INDEX = 0;
-
- private static final int NAME_INDEX = 1;
-
- private boolean mUseNvOperatorForEhrpd = SystemProperties.getBoolean(
- "persist.radio.use_nv_for_ehrpd", false);
-
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- Log.v("settingActivty", "onCreate");
- addPreferencesFromResource(R.xml.rtsp_settings_preferences);
-
- // SharedPreferences mPref =
- // PreferenceManager.getDefaultSharedPreferences(ComposeMessageActivity.this);
- SharedPreferences mPref;
- mPref = getPreferenceScreen().getSharedPreferences();
- String rtpMinport = mPref.getString(PREFERENCE_RTP_MINPORT, "8192");
- String rtpMaxport = mPref.getString(PREFERENCE_RTP_MAXPORT, "65535");
- String rtcpMinport = mPref.getString(PREFERENCE_RTCP_MAXPORT, null);
- String rtcpMaxport = mPref.getString(PREFERENCE_RTCP_MAXPORT, null);
- String bufferSize = mPref.getString(PREFERENCE_BUFFER_SIZE, null);
- // String apn = getSelectedApnKey();//mPref.getString(PREFERENCE_APN,
- // "CMWAP");
- mRtpMinPort = (EditTextPreference) findPreference(PREFERENCE_RTP_MINPORT);
- mRtpMinPort.getEditText().setKeyListener(DigitsKeyListener.getInstance("0123456789"));
- mRtpMinPort.setSummary(rtpMinport);
- mRtpMinPort.setText(rtpMinport);
- mRtpMinPort.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
- public boolean onPreferenceChange(Preference preference, Object newValue) {
- final String summary = newValue.toString();
- mRtpMinPort.setSummary(summary);
- /* Start of zhuzhongwei 2011.2.14 */
- Log.w("rtsp", "z66 summary = " + summary);
- android.provider.Settings.System.putString(getContentResolver(),
- "streaming_min_udp_port", summary);
- /* End of zhuzhongwei 2011.2.14 */
- return true;
- }
- });
-
- mRtpMaxPort = (EditTextPreference) findPreference(PREFERENCE_RTP_MAXPORT);
- mRtpMaxPort.getEditText().setKeyListener(DigitsKeyListener.getInstance("0123456789"));
- mRtpMaxPort.setSummary(rtpMaxport);
- mRtpMaxPort.setText(rtpMaxport);
- mRtpMaxPort.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
- public boolean onPreferenceChange(Preference preference, Object newValue) {
- final String summary = newValue.toString();
- mRtpMaxPort.setSummary(summary);
- /* Start of zhuzhongwei 2011.2.14 */
- Log.w("rtsp", "z82 summary = " + summary);
- android.provider.Settings.System.putString(getContentResolver(),
- "streaming_max_udp_port", summary);
- /* End of zhuzhongwei 2011.2.14 */
- return true;
- }
- });
- mRtcpMinPort = (EditTextPreference) findPreference(PREFERENCE_RTCP_MINPORT);
- mRtcpMinPort.getEditText().setKeyListener(DigitsKeyListener.getInstance("0123456789"));
- mRtcpMinPort.setSummary(rtcpMinport);
- mRtcpMinPort.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
- public boolean onPreferenceChange(Preference preference, Object newValue) {
- final String summary = newValue.toString();
- mRtcpMinPort.setSummary(summary);
- return true;
- }
- });
- mRtcpMaxPort = (EditTextPreference) findPreference(PREFERENCE_RTCP_MAXPORT);
- mRtcpMaxPort.getEditText().setKeyListener(DigitsKeyListener.getInstance("0123456789"));
- mRtcpMaxPort.setSummary(rtcpMaxport);
- mRtcpMaxPort.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
- public boolean onPreferenceChange(Preference preference, Object newValue) {
- final String summary = newValue.toString();
- mRtcpMaxPort.setSummary(summary);
- return true;
- }
- });
-
- mBufferSize = (EditTextPreference) findPreference(PREFERENCE_BUFFER_SIZE);
- mBufferSize.getEditText().setKeyListener(DigitsKeyListener.getInstance("0123456789"));
- mBufferSize.setSummary(bufferSize);
- mBufferSize.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
- public boolean onPreferenceChange(Preference preference, Object newValue) {
- final String summary = newValue.toString();
- mBufferSize.setSummary(summary);
- return true;
- }
- });
-
- /*
- * mBufferSize= (EditTextPreference)
- * findPreference(PREFERENCE_BUFFER_SIZE);
- * mBufferSize.getEditText().setKeyListener
- * (DigitsKeyListener.getInstance("0123456789"));
- * mBufferSize.setSummary(bufferSize);
- * mBufferSize.setOnPreferenceChangeListener(new
- * Preference.OnPreferenceChangeListener() { public boolean
- * onPreferenceChange(Preference preference, Object newValue) { final
- * String summary = newValue.toString();
- * mBufferSize.setSummary(summary); return true; } }); <!----
- * <PreferenceCategory android:title="@string/buffer_size">
- * <EditTextPreference android:order="5" android:key="buffer_size"
- * android:title="@string/buffer_size" android:summary=""
- * android:inputType="number"
- * android:dialogTitle="@string/set_buffer_size" />
- * </PreferenceCategory> ---->
- */
- /*
- * mApn = (ListPreference) findPreference(PREFERENCE_APN);
- * mApn.setValue(apn); mApn.setSummary(mApn.getEntry());
- * mApn.setOnPreferenceChangeListener(new
- * Preference.OnPreferenceChangeListener() { public boolean
- * onPreferenceChange(Preference preference, Object newValue) { final
- * String summary = newValue.toString(); int index =
- * mApn.findIndexOfValue(summary);
- * mApn.setSummary(mApn.getEntries()[index]); mApn.setValue(summary);
- * android.provider.Settings.System.putString(getContentResolver(),
- * "apn", summary); return true; } });
- */
- /*
- * mApn = (ListPreference) findPreference(PREFERENCE_APN);
- * mApn.setValue(getSelectedApnKey()); mApn.setSummary(mApn.getEntry());
- * mApn.setOnPreferenceChangeListener(new
- * Preference.OnPreferenceChangeListener() { public boolean
- * onPreferenceChange(Preference preference, Object newValue) { //final
- * String summary = newValue.toString(); //int index =
- * mApn.findIndexOfValue(summary);
- * ////mApn.setSummary(mApn.getEntries()[index]);
- * //mApn.setValue(summary);
- * //android.provider.Settings.System.putString(getContentResolver(),
- * "apn", summary); Intent intent = new Intent();
- * intent.setClassName("com.android.settings"
- * ,"com.android.settings.ApnSettings"); //startActivity(intent);
- * startActivityForResult(intent, SELECT_APN); return true; } });
- */
-
- mApn = (PreferenceScreen) findPreference(PREFERENCE_APN);
- // mApn.setValue(getSelectedApnKey());
- mApn.setSummary(getDefaultApnName());
- mApn.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
- public boolean onPreferenceClick(Preference preference) {
- // final String summary = newValue.toString();
- // int index = mApn.findIndexOfValue(summary);
- // //mApn.setSummary(mApn.getEntries()[index]);
- // mApn.setValue(summary);
- // android.provider.Settings.System.putString(getContentResolver(),
- // "apn", summary);
-
- Intent intent = new Intent();
- intent.setClassName("com.android.settings", "com.android.settings.ApnSettings");
- // startActivity(intent);
- startActivityForResult(intent, SELECT_APN);
- return true;
- }
- });
-
-
- // lizhongchao add for 4.0 UI START
- ActionBar ab = getActionBar();
- ab.setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD);
- ab.setDisplayHomeAsUpEnabled(true);
- ab.setTitle(R.string.setting);
- // lizhongchao add for 4.0 UI END
- }
-
- private String getDefaultApnName() {
-
- // to find default key
- String key = null;
- String name = null;
- Cursor cursor = getContentResolver().query(PREFERAPN_URI, new String[] {
- "_id"
- }, null, null, Telephony.Carriers.DEFAULT_SORT_ORDER);
- if (cursor.getCount() > 0) {
- cursor.moveToFirst();
- key = cursor.getString(ID_INDEX);
- Log.v("settingActivty", "default apn key = " + key);
- }
- cursor.close();
-
- // to find default proxy
- /**
- String where = "numeric=\""
- + android.os.SystemProperties.get(
- TelephonyProperties.PROPERTY_ICC_OPERATOR_NUMERIC, "") + "\"";
- */
-
- String where = getOperatorNumericSelection();
-
- cursor = getContentResolver().query(Telephony.Carriers.CONTENT_URI, new String[] {
- "_id", "name", "apn", "type"
- }, where, null, Telephony.Carriers.DEFAULT_SORT_ORDER);
-
- while (cursor != null && cursor.moveToNext()) {
- String curKey = cursor.getString(cursor.getColumnIndex("_id"));
- String curName = cursor.getString(cursor.getColumnIndex("name"));
- Log.v("settingActivty", "default apn curkey = " + curKey);
- Log.v("settingActivty", "default apn curName = " + curName);
- // String user = cursor.getString(cursor.getColumnIndex("user"));
- // String password =
- // cursor.getString(cursor.getColumnIndex("password"));
- // a.proxy = cursor.getString(cursor.getColumnIndex("proxy"));
- // a.type = cursor.getString(cursor.getColumnIndex("type"));
-
- // logv( "getDefaultApn, a.key=" + a.key + ",a.apn=" + a.apn +
- // ",a.user=" + a.user + ",a.password=" + a.password + ", a.proxy="
- // + a.proxy);
- // Log.d("rtsp","getDefaultApnName, cur, key=" + curKey +
- // ",curName=" + curName);
- if (curKey.equals(key)) {
- Log.d("rtsp", "getDefaultApnName, find, key=" + curKey + ",curName=" + curName);
- name = curName;
- break;
- }
- }
-
- if (cursor != null)
- cursor.close();
- Log.v("settingActivty", "default apn name = " + name);
-
- return name;
-
- }
-
- private String getSelectedApnKey() {
- String key = null;
-
- Cursor cursor = getContentResolver().query(PREFERAPN_URI, new String[] {
- "_id", "name"
- }, null, null, null);
- if (cursor.getCount() > 0) {
- cursor.moveToFirst();
- key = cursor.getString(NAME_INDEX);
- }
- cursor.close();
-
- Log.w("rtsp", "getSelectedApnKey key = " + key);
- if (null == key)
- return new String("null");
- return key;
- }
-
- @Override
- public void onActivityResult(int requestCode, int resultCode, Intent data) {
- switch (requestCode) {
- case SELECT_APN:
- // if (resultCode == RESULT_CANCELED) {
- setResult(resultCode);
- finish();
- Log.w("rtsp", "onActivityResult requestCode = " + requestCode);
- // mApn.setSummary(getDefaultApnName());
- // }
- break;
- }
- }
-
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- // TODO Auto-generated method stub
- if(item.getItemId() == android.R.id.home){
- finish();
- }
- return true;
- }
-
-
- private String getOperatorNumericSelection() {
+package org.codeaurora.gallery3d.video; + +import android.app.ActionBar; +import android.app.Activity; +import android.content.ContentResolver; +import android.content.Intent; +import android.content.SharedPreferences; +import android.database.Cursor; +import android.net.Uri; +import android.os.Bundle; +import android.os.SystemProperties; +import android.preference.CheckBoxPreference; +import android.preference.EditTextPreference; +import android.preference.ListPreference; +import android.preference.Preference; +import android.preference.PreferenceActivity; +import android.preference.PreferenceCategory; +import android.preference.RingtonePreference; +import android.preference.PreferenceScreen; +import android.provider.ContactsContract; +import android.provider.Telephony; +import android.telephony.MSimTelephonyManager; +import android.telephony.TelephonyManager; +import android.text.method.DigitsKeyListener; +import android.util.Log; +import android.view.KeyEvent; +import android.view.MenuItem; +import com.android.gallery3d.R; + +import java.util.ArrayList; + +public class SettingsActivity extends PreferenceActivity { + + public static final String PREFERENCE_RTP_MINPORT = "rtp_min_port"; + public static final String PREFERENCE_RTP_MAXPORT = "rtp_max_port"; + public static final String PREFERENCE_RTCP_MINPORT = "rtcp_min_port"; + public static final String PREFERENCE_RTCP_MAXPORT = "rtcp_max_port"; + public static final String PREFERENCE_BUFFER_SIZE = "buffer_size"; + public static final String PREFERENCE_APN = "apn"; + + private EditTextPreference mRtpMinPort; + private EditTextPreference mRtpMaxPort; + private EditTextPreference mRtcpMinPort; + private EditTextPreference mRtcpMaxPort; + private EditTextPreference mBufferSize; + private PreferenceScreen mApn; + private CheckBoxPreference mRepeat; + + private static final int SELECT_APN = 1; + public static final String PREFERRED_APN_URI = "content://telephony/carriers/preferapn"; + private static final Uri PREFERAPN_URI = Uri.parse(PREFERRED_APN_URI); + private static final int ID_INDEX = 0; + private static final int NAME_INDEX = 1; + + private boolean mUseNvOperatorForEhrpd = SystemProperties.getBoolean( + "persist.radio.use_nv_for_ehrpd", false); + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + 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; + } + }); + + ActionBar ab = getActionBar(); + ab.setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD); + ab.setDisplayHomeAsUpEnabled(true); + ab.setTitle(R.string.setting); + } + + private String getDefaultApnName() { + + // to find default key + String key = null; + String name = null; + Cursor cursor = getContentResolver().query(PREFERAPN_URI, new String[] { + "_id" + }, null, null, Telephony.Carriers.DEFAULT_SORT_ORDER); + if (cursor.getCount() > 0) { + cursor.moveToFirst(); + key = cursor.getString(ID_INDEX); + Log.v("settingActivty", "default apn key = " + key); + } + cursor.close(); + + // to find default proxy + String where = getOperatorNumericSelection(); + + cursor = getContentResolver().query(Telephony.Carriers.CONTENT_URI, new String[] { + "_id", "name", "apn", "type" + }, where, null, Telephony.Carriers.DEFAULT_SORT_ORDER); + + while (cursor != null && cursor.moveToNext()) { + String curKey = cursor.getString(cursor.getColumnIndex("_id")); + String curName = cursor.getString(cursor.getColumnIndex("name")); + if (curKey.equals(key)) { + Log.d("rtsp", "getDefaultApnName, find, key=" + curKey + ",curName=" + curName); + name = curName; + break; + } + } + + if (cursor != null) { + cursor.close(); + } + return name; + + } + + private String getSelectedApnKey() { + String key = null; + + Cursor cursor = getContentResolver().query(PREFERAPN_URI, new String[] { + "_id", "name" + }, null, null, null); + if (cursor.getCount() > 0) { + cursor.moveToFirst(); + key = cursor.getString(NAME_INDEX); + } + cursor.close(); + + Log.w("rtsp", "getSelectedApnKey key = " + key); + if (null == key) + return new String("null"); + return key; + } + + @Override + public void onActivityResult(int requestCode, int resultCode, Intent data) { + switch (requestCode) { + case SELECT_APN: + setResult(resultCode); + finish(); + Log.w("rtsp", "onActivityResult requestCode = " + requestCode); + break; + } + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + // TODO Auto-generated method stub + if (item.getItemId() == android.R.id.home) { + finish(); + } + return true; + } + + private String getOperatorNumericSelection() { String[] mccmncs = getOperatorNumeric(); String where; where = (mccmncs[0] != null) ? "numeric=\"" + mccmncs[0] + "\"" : ""; where += (mccmncs[1] != null) ? " or numeric=\"" + mccmncs[1] + "\"" : ""; - Log.d("SettingsActivity", "getOperatorNumericSelection: " + where);
+ Log.d("SettingsActivity", "getOperatorNumericSelection: " + where); return where; } @@ -360,12 +241,12 @@ public class SettingsActivity extends PreferenceActivity { result.add(mccMncForEhrpd); } } -
- mccMncFromSim = TelephonyManager.getDefault().getSimOperator();
-
+ + mccMncFromSim = TelephonyManager.getDefault().getSimOperator(); + if (mccMncFromSim != null && mccMncFromSim.length() > 0) { result.add(mccMncFromSim); } return result.toArray(new String[2]); - }
-}
+ } +} diff --git a/src/com/qcom/gallery3d/video/StreamingHooker.java b/src/org/codeaurora/gallery3d/video/StreamingHooker.java index 84152fc9d..d4fa43fc5 100755..100644 --- a/src/com/qcom/gallery3d/video/StreamingHooker.java +++ b/src/org/codeaurora/gallery3d/video/StreamingHooker.java @@ -1,68 +1,56 @@ -package com.qcom.gallery3d.video; +package org.codeaurora.gallery3d.video; import android.content.Intent; import android.net.Uri; import android.provider.Browser; +import android.util.Log; import android.view.Menu; import android.view.MenuItem; import com.android.gallery3d.R; -import com.qcom.gallery3d.ext.MovieUtils; -import com.qcom.gallery3d.ext.QcomLog; +import org.codeaurora.gallery3d.ext.MovieUtils; public class StreamingHooker extends MovieHooker { private static final String TAG = "StreamingHooker"; private static final boolean LOG = true; - - private static final String ACTION_STREAMING = "com.qcom.settings.streaming"; + + private static final String ACTION_STREAMING = "org.codeaurora.settings.streaming"; private static final int MENU_INPUT_URL = 1; private static final int MENU_SETTINGS = 2; private static final int MENU_DETAIL = 3; - private MenuItem mMenuDetail; - + public static final String KEY_LOGO_BITMAP = "logo-bitmap"; - + @Override public boolean onCreateOptionsMenu(final Menu menu) { super.onCreateOptionsMenu(menu); - //when in rtsp streaming type, generally it only has one uri. - mMenuDetail = menu.add(0, getMenuActivityId(MENU_DETAIL), 0, R.string.media_detail); + // when in rtsp streaming type, generally it only has one uri. menu.add(0, getMenuActivityId(MENU_INPUT_URL), 0, R.string.input_url); menu.add(0, getMenuActivityId(MENU_SETTINGS), 0, R.string.streaming_settings); return true; } + @Override public boolean onPrepareOptionsMenu(final Menu menu) { super.onPrepareOptionsMenu(menu); - if (MovieUtils.isLocalFile(getMovieItem().getUri(), getMovieItem().getMimeType())) { - if (mMenuDetail != null) { - mMenuDetail.setVisible(false); - } - } else { - if (mMenuDetail != null) { - mMenuDetail.setVisible(false); - } - } return true; } + @Override public boolean onOptionsItemSelected(final MenuItem item) { super.onOptionsItemSelected(item); - switch(getMenuOriginalId(item.getItemId())) { - case MENU_INPUT_URL: - gotoInputUrl(); - return true; - case MENU_SETTINGS: - gotoSettings(); - return true; - case MENU_DETAIL: - getPlayer().showDetail(); - return true; - default: - return false; + switch (getMenuOriginalId(item.getItemId())) { + case MENU_INPUT_URL: + gotoInputUrl(); + return true; + case MENU_SETTINGS: + gotoSettings(); + return true; + default: + return false; } } - + private void gotoInputUrl() { final String appName = getClass().getName(); final Intent intent = new Intent(); @@ -72,18 +60,19 @@ public class StreamingHooker extends MovieHooker { intent.putExtra(Browser.EXTRA_APPLICATION_ID, appName); getContext().startActivity(intent); if (LOG) { - QcomLog.v(TAG, "gotoInputUrl() appName=" + appName); + Log.v(TAG, "gotoInputUrl() appName=" + appName); } } - + private void gotoSettings() { final Intent intent = new Intent(ACTION_STREAMING); -// intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP -// | Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY); -// intent.putExtra(KEY_LOGO_BITMAP, getIntent().getParcelableExtra(KEY_LOGO_BITMAP)); + // intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP + // | Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY); + // intent.putExtra(KEY_LOGO_BITMAP, + // getIntent().getParcelableExtra(KEY_LOGO_BITMAP)); getContext().startActivity(intent); if (LOG) { - QcomLog.v(TAG, "gotoInputUrl()"); + Log.v(TAG, "gotoInputUrl()"); } } -}
\ No newline at end of file +} |