├── .classpath ├── .gitignore ├── .project ├── AndroidManifest.xml ├── README.md ├── assets └── online.xml ├── ic_launcher-web.png ├── libs ├── android-support-v4.jar ├── armeabi-v7a │ └── libvinit.so ├── ormlite-android-4.42-SNAPSHOT.jar ├── ormlite-core-4.42-SNAPSHOT.jar ├── pinyin4j-2.5.0.jar └── vitamio.jar ├── proguard-project.txt ├── proguard ├── dump.txt ├── mapping.txt ├── seeds.txt └── usage.txt ├── project.properties ├── res ├── anim │ └── animation.xml ├── drawable-hdpi │ ├── arrow_right.png │ ├── ic_launcher.png │ ├── mediacontroller_bg.png │ ├── mediacontroller_pause01.png │ ├── mediacontroller_pause02.png │ ├── mediacontroller_play01.png │ ├── mediacontroller_play02.png │ ├── mediacontroller_seekbar01.png │ ├── mediacontroller_seekbar02.png │ ├── video_brightness_bg.png │ ├── video_num_bg.png │ ├── video_num_front.png │ └── video_volumn_bg.png ├── drawable-ldpi │ └── ic_launcher.png ├── drawable-mdpi │ ├── ic_launcher.png │ ├── logo_56.png │ ├── logo_cntv.png │ ├── logo_iqiyi.png │ ├── logo_letv.png │ ├── logo_pptv.png │ ├── logo_qq.png │ ├── logo_sina.png │ ├── logo_sohu.png │ ├── logo_tudou.png │ └── logo_youku.png ├── drawable-xhdpi │ └── ic_launcher.png ├── drawable │ ├── content.png │ ├── logo_live.png │ ├── mediacontroller_pause_button.xml │ ├── mediacontroller_play_button.xml │ ├── mediacontroller_seekbar.xml │ ├── mediacontroller_seekbar_thumb.xml │ ├── menu.png │ └── vip.png ├── layout │ ├── activity_main.xml │ ├── content_griditem.xml │ ├── content_listitem.xml │ ├── gridview.xml │ ├── mediacontroller.xml │ ├── menu_item.xml │ └── videoview.xml ├── menu │ └── activity_main.xml ├── raw │ ├── libarm.so │ └── pub.key ├── values-v11 │ └── styles.xml ├── values-v14 │ └── styles.xml └── values │ ├── colors.xml │ ├── strings.xml │ └── styles.xml └── src ├── com └── mx │ └── vipmediaplayer │ ├── Logger.java │ ├── VIPMediaPlayerApplication.java │ ├── VIPPlayerActivity.java │ ├── VipPreference.java │ ├── database │ ├── DatabaseHelper.java │ └── SqliteHelperOrm.java │ ├── model │ ├── OnlineVideo.java │ ├── VIPMedia.java │ └── VIPMediaBitmap.java │ ├── services │ └── MediaScanService.java │ ├── ui │ ├── AddOnlineActivity.java │ ├── ContentGridView.java │ ├── ContentListView.java │ ├── MenuListView.java │ ├── VideoPlayerActivity.java │ └── helper │ │ └── XmlReaderHelper.java │ └── util │ ├── ConvertUtils.java │ ├── FileUtils.java │ ├── ImageBuffer.java │ ├── ImageLoadUtils.java │ ├── MethodHandler.java │ ├── PinyinUtils.java │ └── StringUtils.java └── io └── vov └── vitamio ├── .svn ├── all-wcprops ├── entries └── text-base │ └── R.java.svn-base ├── R.java ├── activity └── InitActivity.java └── widget ├── CenterLayout.java ├── MediaController.java ├── OutlineTextView.java └── VideoView.java /.classpath: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .classpath 2 | .project 3 | .settings 4 | gen 5 | bin 6 | -------------------------------------------------------------------------------- /.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | VipMediaPlayer 4 | 5 | 6 | 7 | 8 | 9 | com.android.ide.eclipse.adt.ResourceManagerBuilder 10 | 11 | 12 | 13 | 14 | com.android.ide.eclipse.adt.PreCompilerBuilder 15 | 16 | 17 | 18 | 19 | org.eclipse.jdt.core.javabuilder 20 | 21 | 22 | 23 | 24 | com.android.ide.eclipse.adt.ApkBuilder 25 | 26 | 27 | 28 | 29 | 30 | com.android.ide.eclipse.adt.AndroidNature 31 | org.eclipse.jdt.core.javanature 32 | 33 | 34 | -------------------------------------------------------------------------------- /AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 28 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 55 | 58 | 61 | 64 | 67 | 70 | 73 | 76 | 79 | 82 | 85 | 88 | 91 | 94 | 97 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 216 | 217 | 218 | 219 | 220 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | vipmediaplayer 2 | ============== 3 | 4 | A media player which support local video, music and internet video stream.(http, rtsp, rtmp, udp, tcp, file, content, mms) 5 | -------------------------------------------------------------------------------- /assets/online.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 1.1.0 5 | default stream 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 000 36 | 001 37 | 002 38 | 003 39 | 004 40 | 005 41 | 42 | 43 | 44 | 45 | 301 46 | 47 | 48 | -------------------------------------------------------------------------------- /ic_launcher-web.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaogegexiao/vipmediaplayer/9d0c4331231ada4610c4f1512a770926608a9bc4/ic_launcher-web.png -------------------------------------------------------------------------------- /libs/android-support-v4.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaogegexiao/vipmediaplayer/9d0c4331231ada4610c4f1512a770926608a9bc4/libs/android-support-v4.jar -------------------------------------------------------------------------------- /libs/armeabi-v7a/libvinit.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaogegexiao/vipmediaplayer/9d0c4331231ada4610c4f1512a770926608a9bc4/libs/armeabi-v7a/libvinit.so -------------------------------------------------------------------------------- /libs/ormlite-android-4.42-SNAPSHOT.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaogegexiao/vipmediaplayer/9d0c4331231ada4610c4f1512a770926608a9bc4/libs/ormlite-android-4.42-SNAPSHOT.jar -------------------------------------------------------------------------------- /libs/ormlite-core-4.42-SNAPSHOT.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaogegexiao/vipmediaplayer/9d0c4331231ada4610c4f1512a770926608a9bc4/libs/ormlite-core-4.42-SNAPSHOT.jar -------------------------------------------------------------------------------- /libs/pinyin4j-2.5.0.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaogegexiao/vipmediaplayer/9d0c4331231ada4610c4f1512a770926608a9bc4/libs/pinyin4j-2.5.0.jar -------------------------------------------------------------------------------- /libs/vitamio.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaogegexiao/vipmediaplayer/9d0c4331231ada4610c4f1512a770926608a9bc4/libs/vitamio.jar -------------------------------------------------------------------------------- /proguard-project.txt: -------------------------------------------------------------------------------- 1 | # To enable ProGuard in your project, edit project.properties 2 | # to define the proguard.config property as described in that file. 3 | # 4 | # Add project specific ProGuard rules here. 5 | # By default, the flags in this file are appended to flags specified 6 | # in ${sdk.dir}/tools/proguard/proguard-android.txt 7 | # You can edit the include path and order by changing the ProGuard 8 | # include property in project.properties. 9 | # 10 | # For more details, see 11 | # http://developer.android.com/guide/developing/tools/proguard.html 12 | 13 | # Add any project specific keep options here: 14 | 15 | # If your project uses WebView with JS, uncomment the following 16 | # and specify the fully qualified class name to the JavaScript interface 17 | # class: 18 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 19 | # public *; 20 | #} 21 | -------------------------------------------------------------------------------- /proguard/dump.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaogegexiao/vipmediaplayer/9d0c4331231ada4610c4f1512a770926608a9bc4/proguard/dump.txt -------------------------------------------------------------------------------- /proguard/seeds.txt: -------------------------------------------------------------------------------- 1 | com.mx.vipmediaplayer.VIPMediaPlayerApplication 2 | com.mx.vipmediaplayer.VIPMediaPlayerApplication: VIPMediaPlayerApplication() 3 | com.mx.vipmediaplayer.VIPPlayerActivity 4 | com.mx.vipmediaplayer.VIPPlayerActivity: VIPPlayerActivity() 5 | com.mx.vipmediaplayer.services.MediaScanService 6 | com.mx.vipmediaplayer.services.MediaScanService: MediaScanService() 7 | com.mx.vipmediaplayer.ui.ContentGridView 8 | com.mx.vipmediaplayer.ui.ContentGridView: ContentGridView(android.content.Context,android.util.AttributeSet,int) 9 | com.mx.vipmediaplayer.ui.ContentGridView: ContentGridView(android.content.Context,android.util.AttributeSet) 10 | com.mx.vipmediaplayer.ui.ContentGridView: ContentGridView(android.content.Context) 11 | com.mx.vipmediaplayer.ui.ContentListView 12 | com.mx.vipmediaplayer.ui.ContentListView: ContentListView(android.content.Context,android.util.AttributeSet,int) 13 | com.mx.vipmediaplayer.ui.ContentListView: ContentListView(android.content.Context,android.util.AttributeSet) 14 | com.mx.vipmediaplayer.ui.ContentListView: ContentListView(android.content.Context) 15 | com.mx.vipmediaplayer.ui.MenuListView 16 | com.mx.vipmediaplayer.ui.MenuListView: MenuListView(android.content.Context,android.util.AttributeSet,int) 17 | com.mx.vipmediaplayer.ui.MenuListView: MenuListView(android.content.Context,android.util.AttributeSet) 18 | com.mx.vipmediaplayer.ui.MenuListView: MenuListView(android.content.Context) 19 | com.mx.vipmediaplayer.ui.VideoPlayerActivity 20 | com.mx.vipmediaplayer.ui.VideoPlayerActivity: VideoPlayerActivity() 21 | io.vov.vitamio.activity.InitActivity 22 | io.vov.vitamio.activity.InitActivity: InitActivity() 23 | io.vov.vitamio.widget.VideoView 24 | io.vov.vitamio.widget.VideoView: VideoView(android.content.Context) 25 | io.vov.vitamio.widget.VideoView: VideoView(android.content.Context,android.util.AttributeSet) 26 | io.vov.vitamio.widget.VideoView: VideoView(android.content.Context,android.util.AttributeSet,int) 27 | -------------------------------------------------------------------------------- /project.properties: -------------------------------------------------------------------------------- 1 | # This file is automatically generated by Android Tools. 2 | # Do not modify this file -- YOUR CHANGES WILL BE ERASED! 3 | # 4 | # This file must be checked in Version Control Systems. 5 | # 6 | # To customize properties used by the Ant build system edit 7 | # "ant.properties", and override values to adapt the script to your 8 | # project structure. 9 | # 10 | # To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home): 11 | proguard.config=proguard-project.txt 12 | 13 | # Project target. 14 | target=android-15 15 | -------------------------------------------------------------------------------- /res/anim/animation.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 10 | 11 | 12 | 16 | -------------------------------------------------------------------------------- /res/drawable-hdpi/arrow_right.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaogegexiao/vipmediaplayer/9d0c4331231ada4610c4f1512a770926608a9bc4/res/drawable-hdpi/arrow_right.png -------------------------------------------------------------------------------- /res/drawable-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaogegexiao/vipmediaplayer/9d0c4331231ada4610c4f1512a770926608a9bc4/res/drawable-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /res/drawable-hdpi/mediacontroller_bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaogegexiao/vipmediaplayer/9d0c4331231ada4610c4f1512a770926608a9bc4/res/drawable-hdpi/mediacontroller_bg.png -------------------------------------------------------------------------------- /res/drawable-hdpi/mediacontroller_pause01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaogegexiao/vipmediaplayer/9d0c4331231ada4610c4f1512a770926608a9bc4/res/drawable-hdpi/mediacontroller_pause01.png -------------------------------------------------------------------------------- /res/drawable-hdpi/mediacontroller_pause02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaogegexiao/vipmediaplayer/9d0c4331231ada4610c4f1512a770926608a9bc4/res/drawable-hdpi/mediacontroller_pause02.png -------------------------------------------------------------------------------- /res/drawable-hdpi/mediacontroller_play01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaogegexiao/vipmediaplayer/9d0c4331231ada4610c4f1512a770926608a9bc4/res/drawable-hdpi/mediacontroller_play01.png -------------------------------------------------------------------------------- /res/drawable-hdpi/mediacontroller_play02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaogegexiao/vipmediaplayer/9d0c4331231ada4610c4f1512a770926608a9bc4/res/drawable-hdpi/mediacontroller_play02.png -------------------------------------------------------------------------------- /res/drawable-hdpi/mediacontroller_seekbar01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaogegexiao/vipmediaplayer/9d0c4331231ada4610c4f1512a770926608a9bc4/res/drawable-hdpi/mediacontroller_seekbar01.png -------------------------------------------------------------------------------- /res/drawable-hdpi/mediacontroller_seekbar02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaogegexiao/vipmediaplayer/9d0c4331231ada4610c4f1512a770926608a9bc4/res/drawable-hdpi/mediacontroller_seekbar02.png -------------------------------------------------------------------------------- /res/drawable-hdpi/video_brightness_bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaogegexiao/vipmediaplayer/9d0c4331231ada4610c4f1512a770926608a9bc4/res/drawable-hdpi/video_brightness_bg.png -------------------------------------------------------------------------------- /res/drawable-hdpi/video_num_bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaogegexiao/vipmediaplayer/9d0c4331231ada4610c4f1512a770926608a9bc4/res/drawable-hdpi/video_num_bg.png -------------------------------------------------------------------------------- /res/drawable-hdpi/video_num_front.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaogegexiao/vipmediaplayer/9d0c4331231ada4610c4f1512a770926608a9bc4/res/drawable-hdpi/video_num_front.png -------------------------------------------------------------------------------- /res/drawable-hdpi/video_volumn_bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaogegexiao/vipmediaplayer/9d0c4331231ada4610c4f1512a770926608a9bc4/res/drawable-hdpi/video_volumn_bg.png -------------------------------------------------------------------------------- /res/drawable-ldpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaogegexiao/vipmediaplayer/9d0c4331231ada4610c4f1512a770926608a9bc4/res/drawable-ldpi/ic_launcher.png -------------------------------------------------------------------------------- /res/drawable-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaogegexiao/vipmediaplayer/9d0c4331231ada4610c4f1512a770926608a9bc4/res/drawable-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /res/drawable-mdpi/logo_56.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaogegexiao/vipmediaplayer/9d0c4331231ada4610c4f1512a770926608a9bc4/res/drawable-mdpi/logo_56.png -------------------------------------------------------------------------------- /res/drawable-mdpi/logo_cntv.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaogegexiao/vipmediaplayer/9d0c4331231ada4610c4f1512a770926608a9bc4/res/drawable-mdpi/logo_cntv.png -------------------------------------------------------------------------------- /res/drawable-mdpi/logo_iqiyi.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaogegexiao/vipmediaplayer/9d0c4331231ada4610c4f1512a770926608a9bc4/res/drawable-mdpi/logo_iqiyi.png -------------------------------------------------------------------------------- /res/drawable-mdpi/logo_letv.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaogegexiao/vipmediaplayer/9d0c4331231ada4610c4f1512a770926608a9bc4/res/drawable-mdpi/logo_letv.png -------------------------------------------------------------------------------- /res/drawable-mdpi/logo_pptv.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaogegexiao/vipmediaplayer/9d0c4331231ada4610c4f1512a770926608a9bc4/res/drawable-mdpi/logo_pptv.png -------------------------------------------------------------------------------- /res/drawable-mdpi/logo_qq.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaogegexiao/vipmediaplayer/9d0c4331231ada4610c4f1512a770926608a9bc4/res/drawable-mdpi/logo_qq.png -------------------------------------------------------------------------------- /res/drawable-mdpi/logo_sina.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaogegexiao/vipmediaplayer/9d0c4331231ada4610c4f1512a770926608a9bc4/res/drawable-mdpi/logo_sina.png -------------------------------------------------------------------------------- /res/drawable-mdpi/logo_sohu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaogegexiao/vipmediaplayer/9d0c4331231ada4610c4f1512a770926608a9bc4/res/drawable-mdpi/logo_sohu.png -------------------------------------------------------------------------------- /res/drawable-mdpi/logo_tudou.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaogegexiao/vipmediaplayer/9d0c4331231ada4610c4f1512a770926608a9bc4/res/drawable-mdpi/logo_tudou.png -------------------------------------------------------------------------------- /res/drawable-mdpi/logo_youku.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaogegexiao/vipmediaplayer/9d0c4331231ada4610c4f1512a770926608a9bc4/res/drawable-mdpi/logo_youku.png -------------------------------------------------------------------------------- /res/drawable-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaogegexiao/vipmediaplayer/9d0c4331231ada4610c4f1512a770926608a9bc4/res/drawable-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /res/drawable/content.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaogegexiao/vipmediaplayer/9d0c4331231ada4610c4f1512a770926608a9bc4/res/drawable/content.png -------------------------------------------------------------------------------- /res/drawable/logo_live.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaogegexiao/vipmediaplayer/9d0c4331231ada4610c4f1512a770926608a9bc4/res/drawable/logo_live.png -------------------------------------------------------------------------------- /res/drawable/mediacontroller_pause_button.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /res/drawable/mediacontroller_play_button.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /res/drawable/mediacontroller_seekbar.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 22 | 26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /res/drawable/mediacontroller_seekbar_thumb.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /res/drawable/menu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaogegexiao/vipmediaplayer/9d0c4331231ada4610c4f1512a770926608a9bc4/res/drawable/menu.png -------------------------------------------------------------------------------- /res/drawable/vip.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaogegexiao/vipmediaplayer/9d0c4331231ada4610c4f1512a770926608a9bc4/res/drawable/vip.png -------------------------------------------------------------------------------- /res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 6 | 7 | 14 | 15 | 21 | 22 | 23 | 30 | 31 | 37 | 38 | 39 | 40 | 47 | 51 | 52 | 56 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /res/layout/content_griditem.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 12 | 13 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /res/layout/content_listitem.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 16 | 17 | 24 | 25 | 38 | -------------------------------------------------------------------------------- /res/layout/gridview.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | -------------------------------------------------------------------------------- /res/layout/mediacontroller.xml: -------------------------------------------------------------------------------- 1 | 2 | 11 | 12 | 24 | 25 | 33 | 34 | 37 | 38 | 45 | 46 | 53 | 54 | 55 | 63 | 64 | 72 | 73 | 74 | -------------------------------------------------------------------------------- /res/layout/menu_item.xml: -------------------------------------------------------------------------------- 1 | 7 | 14 | 23 | -------------------------------------------------------------------------------- /res/layout/videoview.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 13 | 14 | 20 | 21 | 24 | 25 | 32 | 33 | 34 | 43 | 44 | 50 | 51 | 56 | 57 | 63 | 64 | 71 | 72 | 73 | 74 | -------------------------------------------------------------------------------- /res/menu/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | -------------------------------------------------------------------------------- /res/raw/libarm.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaogegexiao/vipmediaplayer/9d0c4331231ada4610c4f1512a770926608a9bc4/res/raw/libarm.so -------------------------------------------------------------------------------- /res/raw/pub.key: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaogegexiao/vipmediaplayer/9d0c4331231ada4610c4f1512a770926608a9bc4/res/raw/pub.key -------------------------------------------------------------------------------- /res/values-v11/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /res/values-v14/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 11 | 12 | -------------------------------------------------------------------------------- /res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #333333 4 | #663333 5 | #ff000000 6 | #ffffffff 7 | #ff274462 8 | -------------------------------------------------------------------------------- /res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | VipPlayer 5 | Hello world! 6 | Settings 7 | 8 | Play List 9 | Local Video 10 | Local Music 11 | 12 | First time for uncompressing encode package... 13 | 14 | VitamioLibrary 15 | Initializing decoders… 16 | Vitamio tools 17 | Access Vitamio package and resources. 18 | Receive Vitamio messages 19 | Receive all broadcasts from Vitamio service. 20 | Write Vitamio providers 21 | Delete, update or create new items in Vitamio providers. 22 | 23 | Cannot play video 24 | Sorry, this video is not valid for streaming to 25 | this device. 26 | 27 | Sorry, this video cannot be played. 28 | OK 29 | Play/Pause 30 | 31 | Buffering... 32 | -------------------------------------------------------------------------------- /res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 14 | 15 | 16 | 19 | 20 | 26 | 27 | 32 | 33 | 36 | -------------------------------------------------------------------------------- /src/com/mx/vipmediaplayer/Logger.java: -------------------------------------------------------------------------------- 1 | package com.mx.vipmediaplayer; 2 | 3 | import android.util.Log; 4 | 5 | /** 6 | * Log class 7 | * 8 | * @author Xiao Mei 9 | * @weibo http://weibo.com/u/1675796095 10 | * @email tss_chs@126.com 11 | * 12 | */ 13 | public class Logger { 14 | 15 | private static boolean isLog = true; 16 | private static final String TAG = "VIPMediaPlayer"; 17 | 18 | public static void setLog(boolean isLog) { 19 | Logger.isLog = isLog; 20 | } 21 | 22 | public static boolean getIsLog() { 23 | return isLog; 24 | } 25 | 26 | public static void d(String tag, String msg) { 27 | if (isLog) { 28 | Log.d(tag, msg); 29 | } 30 | } 31 | 32 | public static void d(String msg) { 33 | Log.d(TAG, msg); 34 | } 35 | 36 | /** 37 | * Send a {@link #DEBUG} log message and log the exception. 38 | * 39 | * @param tag Used to identify the source of a log message. It usually 40 | * identifies the class or activity where the log call occurs. 41 | * @param msg The message you would like logged. 42 | * @param tr An exception to log 43 | */ 44 | public static void d(String tag, String msg, Throwable tr) { 45 | if (isLog) { 46 | Log.d(tag, msg, tr); 47 | } 48 | } 49 | 50 | public static void e(Throwable tr) { 51 | if (isLog) { 52 | Log.e(TAG, "", tr); 53 | } 54 | } 55 | 56 | public static void i(String msg) { 57 | if (isLog) { 58 | Log.i(TAG, msg); 59 | } 60 | } 61 | 62 | public static void i(String tag, String msg) { 63 | if (isLog) { 64 | Log.i(tag, msg); 65 | } 66 | } 67 | 68 | /** 69 | * Send a {@link #INFO} log message and log the exception. 70 | * 71 | * @param tag Used to identify the source of a log message. It usually 72 | * identifies the class or activity where the log call occurs. 73 | * @param msg The message you would like logged. 74 | * @param tr An exception to log 75 | */ 76 | public static void i(String tag, String msg, Throwable tr) { 77 | if (isLog) { 78 | Log.i(tag, msg, tr); 79 | } 80 | 81 | } 82 | 83 | /** 84 | * Send an {@link #ERROR} log message. 85 | * 86 | * @param tag Used to identify the source of a log message. It usually 87 | * identifies the class or activity where the log call occurs. 88 | * @param msg The message you would like logged. 89 | */ 90 | public static void e(String tag, String msg) { 91 | if (isLog) { 92 | Log.e(tag, msg); 93 | } 94 | } 95 | 96 | public static void e(String msg) { 97 | if (isLog) { 98 | Log.e(TAG, msg); 99 | } 100 | } 101 | 102 | /** 103 | * Send a {@link #ERROR} log message and log the exception. 104 | * 105 | * @param tag Used to identify the source of a log message. It usually 106 | * identifies the class or activity where the log call occurs. 107 | * @param msg The message you would like logged. 108 | * @param tr An exception to log 109 | */ 110 | public static void e(String tag, String msg, Throwable tr) { 111 | if (isLog) { 112 | Log.e(tag, msg, tr); 113 | } 114 | } 115 | 116 | public static void systemErr(String msg) { 117 | // if (true) { 118 | if (isLog) { 119 | if (msg != null) { 120 | Log.e(TAG, msg); 121 | } 122 | 123 | } 124 | } 125 | 126 | } 127 | -------------------------------------------------------------------------------- /src/com/mx/vipmediaplayer/VIPMediaPlayerApplication.java: -------------------------------------------------------------------------------- 1 | package com.mx.vipmediaplayer; 2 | 3 | 4 | import android.app.Application; 5 | import android.content.Context; 6 | import android.os.Environment; 7 | 8 | import com.mx.vipmediaplayer.util.FileUtils; 9 | 10 | /** 11 | * Application class 12 | * 13 | * @author Xiao Mei 14 | * @weibo http://weibo.com/u/1675796095 15 | * @email tss_chs@126.com 16 | * 17 | */ 18 | public class VIPMediaPlayerApplication extends Application { 19 | 20 | private static VIPMediaPlayerApplication mApplication; 21 | 22 | /** OPlayer SD卡缓存路径 */ 23 | public static final String VIPPLAYER_CACHE_BASE = Environment.getExternalStorageDirectory() + "/vipplayer"; 24 | /** 视频截图缓冲路径 */ 25 | public static final String VIPPLAYER_VIDEO_THUMB = VIPPLAYER_CACHE_BASE + "/thumb/"; 26 | /** 首次扫描 */ 27 | public static final String PREF_KEY_FIRST = "application_first"; 28 | 29 | @Override 30 | public void onCreate() { 31 | Logger.d("Application on Create ==================================================== "); 32 | super.onCreate(); 33 | mApplication = this; 34 | 35 | init(); 36 | } 37 | 38 | private void init() { 39 | //创建缓存目录 40 | FileUtils.createIfNoExists(VIPPLAYER_CACHE_BASE); 41 | FileUtils.createIfNoExists(VIPPLAYER_VIDEO_THUMB); 42 | } 43 | 44 | public static VIPMediaPlayerApplication getApplication() { 45 | return mApplication; 46 | } 47 | 48 | public static Context getContext() { 49 | return mApplication; 50 | } 51 | 52 | /** 销毁 */ 53 | public void destory() { 54 | mApplication = null; 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/com/mx/vipmediaplayer/VIPPlayerActivity.java: -------------------------------------------------------------------------------- 1 | package com.mx.vipmediaplayer; 2 | 3 | import io.vov.vitamio.LibsChecker; 4 | 5 | import java.util.ArrayList; 6 | import java.util.List; 7 | 8 | import android.app.Activity; 9 | import android.content.ComponentName; 10 | import android.content.Context; 11 | import android.content.Intent; 12 | import android.content.ServiceConnection; 13 | import android.os.AsyncTask; 14 | import android.os.Bundle; 15 | import android.os.Environment; 16 | import android.os.Handler; 17 | import android.os.IBinder; 18 | import android.view.MotionEvent; 19 | import android.view.VelocityTracker; 20 | import android.view.View; 21 | import android.view.View.OnTouchListener; 22 | import android.view.Window; 23 | import android.view.WindowManager; 24 | import android.widget.ImageView; 25 | import android.widget.RelativeLayout; 26 | 27 | import com.mx.vipmediaplayer.model.VIPMedia; 28 | import com.mx.vipmediaplayer.services.MediaScanService; 29 | import com.mx.vipmediaplayer.services.MediaScanService.IMediaScanObserver; 30 | import com.mx.vipmediaplayer.services.MediaScanService.MediaScanServiceBinder; 31 | import com.mx.vipmediaplayer.ui.ContentGridView; 32 | import com.mx.vipmediaplayer.ui.ContentListView; 33 | import com.mx.vipmediaplayer.ui.MenuListView; 34 | import com.mx.vipmediaplayer.ui.MenuListView.OnMenuClickListener; 35 | import com.mx.vipmediaplayer.util.FileUtils; 36 | 37 | /** 38 | * main activity class of this application 39 | * 40 | * @author Xiao Mei 41 | * @weibo http://weibo.com/u/1675796095 42 | * @email tss_chs@126.com 43 | * 44 | */ 45 | public class VIPPlayerActivity extends Activity implements OnTouchListener, 46 | View.OnClickListener, OnMenuClickListener, IMediaScanObserver, ContentListView.OnOnlineVideoClickListener{ 47 | 48 | private boolean videoscanfinished = false; 49 | private boolean audioscanfinished = false; 50 | 51 | private Object writelock = new Object(); 52 | private List videoList = new ArrayList(); 53 | private List audioList = new ArrayList(); 54 | 55 | private int currentContent = MenuListView.POSITION_PLAYLIST; 56 | 57 | public static final int MSG_SHOW_CONTENT = 1; 58 | 59 | public static final int SNAP_VELOCITY = 200; 60 | 61 | private int screenWidth; 62 | 63 | private int leftEdgeForContent = 0; 64 | private int rightEdgeForContent; 65 | 66 | private int menuPadding = 280; 67 | 68 | private ImageView mVIPSwitcher; 69 | /** 70 | * View of Content. 71 | */ 72 | private View content; 73 | 74 | /** 75 | * View of Menu 76 | */ 77 | private View menu; 78 | 79 | private MenuListView menuListView; 80 | 81 | private ContentGridView contentGridView; 82 | private ContentListView contentListView; 83 | 84 | /** 85 | * menu布局的参数,通过此参数来更改leftMargin的值。 86 | */ 87 | private RelativeLayout.LayoutParams contentParams; 88 | 89 | /** 90 | * menu layout parameters 91 | */ 92 | private RelativeLayout.LayoutParams menuParams; 93 | 94 | /** 95 | * 记录手指按下时的横坐标。 96 | */ 97 | private float xDown; 98 | 99 | /** 100 | * 记录手指移动时的横坐标。 101 | */ 102 | private float xOldMove = 0; 103 | private float xMove = 0; 104 | 105 | private boolean mDirection = false; 106 | 107 | /** 108 | * 记录手机抬起时的横坐标。 109 | */ 110 | private float xUp; 111 | 112 | /** 113 | * menu当前是显示还是隐藏。只有完全显示或隐藏menu时才会更改此值,滑动过程中此值无效。 114 | */ 115 | private boolean isMenuVisible; 116 | private boolean isContentMoving = false; 117 | 118 | /** 119 | * 用于计算手指滑动的速度。 120 | */ 121 | private VelocityTracker mVelocityTracker; 122 | 123 | private Handler mHandler = new Handler(){ 124 | 125 | }; 126 | 127 | private MediaScanService mMediaScanService; 128 | private ServiceConnection mMediaScanServiceConnection = new ServiceConnection() { 129 | 130 | @Override 131 | public void onServiceDisconnected(ComponentName name) { 132 | Logger.d("service unbinded ================================================ "); 133 | mMediaScanService.deleteObserver(VIPPlayerActivity.this); 134 | mMediaScanService = null; 135 | } 136 | 137 | @Override 138 | public void onServiceConnected(ComponentName name, IBinder service) { 139 | Logger.d("service binded ================================================ "); 140 | mMediaScanService = ((MediaScanServiceBinder) service).getService(); 141 | mMediaScanService.addObserver(VIPPlayerActivity.this); 142 | // Toast.makeText(ComponentServiceActivity.this, "Service绑定成功!", 143 | // Toast.LENGTH_SHORT).show(); 144 | } 145 | }; 146 | 147 | @Override 148 | protected void onCreate(Bundle savedInstanceState) { 149 | super.onCreate(savedInstanceState); 150 | requestWindowFeature(Window.FEATURE_NO_TITLE); 151 | 152 | if (!LibsChecker.checkVitamioLibs(this)) 153 | return; 154 | 155 | setContentView(R.layout.activity_main); 156 | 157 | initValues(); 158 | content.setOnTouchListener(this); 159 | new DataTask().execute(); 160 | 161 | bindService( 162 | new Intent(getApplicationContext(), MediaScanService.class), 163 | mMediaScanServiceConnection, Context.BIND_AUTO_CREATE); 164 | VipPreference pref = new VipPreference(VIPPlayerActivity.this); 165 | if (pref.getBoolean(VIPMediaPlayerApplication.PREF_KEY_FIRST, 166 | true)) { 167 | Logger.d("first time =================== "); 168 | getApplicationContext().startService( 169 | new Intent(getApplicationContext(), 170 | MediaScanService.class).putExtra( 171 | MediaScanService.EXTRA_DIRECTORY, 172 | Environment.getExternalStorageDirectory() 173 | .getAbsolutePath())); 174 | } 175 | onPlaylistClicked(); 176 | } 177 | 178 | /** 179 | * 初始化一些关键性数据。包括获取屏幕的宽度,给content布局重新设置宽度,给menu布局重新设置宽度和偏移距离等。 180 | */ 181 | private void initValues() { 182 | WindowManager window = (WindowManager) getSystemService(Context.WINDOW_SERVICE); 183 | screenWidth = window.getDefaultDisplay().getWidth(); 184 | 185 | mVIPSwitcher = (ImageView) findViewById(R.id.IVSwitcher); 186 | mVIPSwitcher.setOnClickListener(this); 187 | contentListView = (ContentListView) findViewById(R.id.contentlist); 188 | contentListView.setActivity(this); 189 | contentListView.setOnlineVideoClickListener(this); 190 | 191 | contentGridView = (ContentGridView) findViewById(R.id.contentgrid); 192 | contentGridView.setActivity(this); 193 | 194 | menuListView = (MenuListView) findViewById(R.id.menulist); 195 | menuListView.setOnMenuClickListener(this); 196 | content = findViewById(R.id.content); 197 | menu = findViewById(R.id.menu); 198 | menuParams = (RelativeLayout.LayoutParams) menu.getLayoutParams(); 199 | menuParams.width = screenWidth - menuPadding; 200 | menu.setLayoutParams(menuParams); 201 | 202 | leftEdgeForContent = 0; 203 | // 左边缘的值赋值为menu宽度的负数 204 | rightEdgeForContent = menuPadding - screenWidth; 205 | 206 | contentParams = (RelativeLayout.LayoutParams) content.getLayoutParams(); 207 | // 将menu的宽度设置为屏幕宽度减去menuPadding 208 | contentParams.width = screenWidth; 209 | // menu的leftMargin设置为左边缘的值,这样初始化时menu就变为不可见 210 | // 将content的宽度设置为屏幕宽度 211 | contentParams.rightMargin = leftEdgeForContent; 212 | content.setLayoutParams(contentParams); 213 | } 214 | 215 | @Override 216 | public boolean onTouch(View v, MotionEvent event) { 217 | if (isContentMoving) 218 | return true; 219 | createVelocityTracker(event); 220 | switch (event.getAction()) { 221 | case MotionEvent.ACTION_DOWN: 222 | // 手指按下时,记录按下时的横坐标 223 | xDown = event.getRawX(); 224 | break; 225 | case MotionEvent.ACTION_MOVE: 226 | // 手指移动时,对比按下时的横坐标,计算出移动的距离,来调整menu的leftMargin值,从而显示和隐藏menu 227 | xOldMove = xMove; 228 | xMove = event.getRawX(); 229 | mDirection = xMove - xOldMove > 0 230 | || (xMove - xOldMove == 0 && mDirection); 231 | int distanceX = (int) (xMove - xDown); 232 | if (isMenuVisible) { 233 | contentParams.rightMargin = rightEdgeForContent - distanceX; 234 | } else { 235 | contentParams.rightMargin = leftEdgeForContent - distanceX; 236 | } 237 | if (contentParams.rightMargin > leftEdgeForContent) { 238 | contentParams.rightMargin = leftEdgeForContent; 239 | } else if (contentParams.rightMargin < rightEdgeForContent) { 240 | contentParams.rightMargin = rightEdgeForContent; 241 | } 242 | content.setLayoutParams(contentParams); 243 | break; 244 | case MotionEvent.ACTION_UP: 245 | // 手指抬起时,进行判断当前手势的意图,从而决定是滚动到menu界面,还是滚动到content界面 246 | xUp = event.getRawX(); 247 | if (wantToShowMenu()) { 248 | if (shouldScrollToMenu()) { 249 | scrollToMenu(); 250 | } else { 251 | scrollToContent(); 252 | } 253 | } else if (wantToShowContent()) { 254 | if (shouldScrollToContent()) { 255 | scrollToContent(); 256 | } else { 257 | scrollToMenu(); 258 | } 259 | } 260 | recycleVelocityTracker(); 261 | break; 262 | } 263 | return true; 264 | } 265 | 266 | /** 267 | * 判断当前手势的意图是不是想显示content。如果手指移动的距离是负数,且当前menu是可见的,则认为当前手势是想要显示content。 268 | * 269 | * @return 当前手势想显示content返回true,否则返回false。 270 | */ 271 | private boolean wantToShowContent() { 272 | return xUp - xDown < 0 && isMenuVisible; 273 | } 274 | 275 | /** 276 | * 判断当前手势的意图是不是想显示menu。如果手指移动的距离是正数,且当前menu是不可见的,则认为当前手势是想要显示menu。 277 | * 278 | * @return 当前手势想显示menu返回true,否则返回false。 279 | */ 280 | private boolean wantToShowMenu() { 281 | return xUp - xDown > 0 && !isMenuVisible; 282 | } 283 | 284 | /** 285 | * 判断是否应该滚动将menu展示出来。如果手指移动距离大于屏幕的1/2,或者手指移动速度大于SNAP_VELOCITY, 286 | * 就认为应该滚动将menu展示出来。 287 | * 288 | * @return 如果应该滚动将menu展示出来返回true,否则返回false。 289 | */ 290 | private boolean shouldScrollToMenu() { 291 | return mDirection /* || xUp - xDown > screenWidth / 2 */ 292 | /* || getScrollVelocity() > SNAP_VELOCITY */; 293 | } 294 | 295 | /** 296 | * 判断是否应该滚动将content展示出来。如果手指移动距离加上menuPadding大于屏幕的1/2, 297 | * 或者手指移动速度大于SNAP_VELOCITY, 就认为应该滚动将content展示出来。 298 | * 299 | * @return 如果应该滚动将content展示出来返回true,否则返回false。 300 | */ 301 | private boolean shouldScrollToContent() { 302 | return !mDirection /* || xDown - xUp + menuPadding > screenWidth / 2 */ 303 | /* || getScrollVelocity() > SNAP_VELOCITY */; 304 | } 305 | 306 | /** 307 | * 将屏幕滚动到menu界面,滚动速度设定为30. 308 | */ 309 | private void scrollToMenu() { 310 | new ContentScrollTask().execute(30); 311 | // new ScrollTask().execute(30); 312 | } 313 | 314 | /** 315 | * 将屏幕滚动到content界面,滚动速度设定为-30. 316 | */ 317 | private void scrollToContent() { 318 | new ContentScrollTask().execute(-30); 319 | // new ScrollTask().execute(-30); 320 | } 321 | 322 | /** 323 | * 创建VelocityTracker对象,并将触摸content界面的滑动事件加入到VelocityTracker当中。 324 | * 325 | * @param event 326 | * content界面的滑动事件 327 | */ 328 | private void createVelocityTracker(MotionEvent event) { 329 | if (mVelocityTracker == null) { 330 | mVelocityTracker = VelocityTracker.obtain(); 331 | } 332 | mVelocityTracker.addMovement(event); 333 | } 334 | 335 | /** 336 | * 获取手指在content界面滑动的速度。 337 | * 338 | * @return 滑动速度,以每秒钟移动了多少像素值为单位。 339 | */ 340 | private int getScrollVelocity() { 341 | mVelocityTracker.computeCurrentVelocity(1000); 342 | int velocity = (int) mVelocityTracker.getXVelocity(); 343 | return Math.abs(velocity); 344 | } 345 | 346 | /** 347 | * 回收VelocityTracker对象。 348 | */ 349 | private void recycleVelocityTracker() { 350 | mVelocityTracker.recycle(); 351 | mVelocityTracker = null; 352 | } 353 | 354 | class ContentScrollTask extends AsyncTask { 355 | 356 | @Override 357 | protected Integer doInBackground(Integer... speed) { 358 | isContentMoving = true; 359 | int contentRightMargin = contentParams.rightMargin; 360 | while (true) { 361 | contentRightMargin -= speed[0]; 362 | if (contentRightMargin < rightEdgeForContent) { 363 | contentRightMargin = rightEdgeForContent; 364 | break; 365 | } else if (contentRightMargin > leftEdgeForContent) { 366 | contentRightMargin = leftEdgeForContent; 367 | break; 368 | } 369 | publishProgress(contentRightMargin); 370 | sleep(20); 371 | } 372 | if (speed[0] > 0) { 373 | isMenuVisible = true; 374 | } else { 375 | isMenuVisible = false; 376 | } 377 | return contentRightMargin; 378 | } 379 | 380 | @Override 381 | protected void onPostExecute(Integer result) { 382 | contentParams.rightMargin = result; 383 | content.setLayoutParams(contentParams); 384 | isContentMoving = false; 385 | } 386 | 387 | @Override 388 | protected void onProgressUpdate(Integer... values) { 389 | contentParams.rightMargin = values[0]; 390 | content.setLayoutParams(contentParams); 391 | } 392 | 393 | } 394 | 395 | // class ScrollTask extends AsyncTask { 396 | // 397 | // @Override 398 | // protected Integer doInBackground(Integer... speed) { 399 | // int leftMargin = menuParams.leftMargin; 400 | // // 根据传入的速度来滚动界面,当滚动到达左边界或右边界时,跳出循环。 401 | // while (true) { 402 | // leftMargin = leftMargin + speed[0]; 403 | // if (leftMargin > rightEdge) { 404 | // leftMargin = rightEdge; 405 | // break; 406 | // } 407 | // if (leftMargin < leftEdge) { 408 | // leftMargin = leftEdge; 409 | // break; 410 | // } 411 | // publishProgress(leftMargin); 412 | // // 为了要有滚动效果产生,每次循环使线程睡眠20毫秒,这样肉眼才能够看到滚动动画。 413 | // sleep(20); 414 | // } 415 | // if (speed[0] > 0) { 416 | // isMenuVisible = true; 417 | // } else { 418 | // isMenuVisible = false; 419 | // } 420 | // return leftMargin; 421 | // } 422 | // 423 | // @Override 424 | // protected void onProgressUpdate(Integer... leftMargin) { 425 | // menuParams.leftMargin = leftMargin[0]; 426 | // menu.setLayoutParams(menuParams); 427 | // } 428 | // 429 | // @Override 430 | // protected void onPostExecute(Integer leftMargin) { 431 | // menuParams.leftMargin = leftMargin; 432 | // menu.setLayoutParams(menuParams); 433 | // } 434 | // } 435 | 436 | /** 437 | * 使当前线程睡眠指定的毫秒数。 438 | * 439 | * @param millis 440 | * 指定当前线程睡眠多久,以毫秒为单位 441 | */ 442 | private void sleep(long millis) { 443 | try { 444 | Thread.sleep(millis); 445 | } catch (InterruptedException e) { 446 | e.printStackTrace(); 447 | } 448 | } 449 | 450 | @Override 451 | public void onClick(View v) { 452 | switch (v.getId()) { 453 | case R.id.IVSwitcher: 454 | if (isMenuVisible) { 455 | scrollToContent(); 456 | } else { 457 | scrollToMenu(); 458 | } 459 | break; 460 | } 461 | } 462 | 463 | @Override 464 | public void onPlaylistClicked() { 465 | if (contentParams.rightMargin < 0) 466 | scrollToContent(); 467 | contentGridView.setVisibility(View.GONE); 468 | contentListView.setVisibility(View.VISIBLE); 469 | } 470 | 471 | @Override 472 | public void onLocalVideoClicked() { 473 | if (contentParams.rightMargin < 0) 474 | scrollToContent(); 475 | contentGridView.setVisibility(View.VISIBLE); 476 | contentListView.setVisibility(View.GONE); 477 | contentGridView.setList(videoList); 478 | contentGridView.getHandler().sendEmptyMessage(0); 479 | } 480 | 481 | @Override 482 | public void onLocalAudioClicked() { 483 | if (contentParams.rightMargin < 0) 484 | scrollToContent(); 485 | contentGridView.setVisibility(View.VISIBLE); 486 | contentListView.setVisibility(View.GONE); 487 | contentGridView.setList(audioList); 488 | contentGridView.getHandler().sendEmptyMessage(0); 489 | } 490 | 491 | @Override 492 | public void update(int flag, VIPMedia media, int scanfiletype) { 493 | switch (flag) { 494 | case MediaScanService.SCAN_STATUS_START: 495 | synchronized (writelock) { 496 | if(scanfiletype == MediaScanService.SCAN_INVALID_FILE_TYPE) { 497 | videoList.clear(); 498 | audioList.clear(); 499 | } else if(scanfiletype == MediaScanService.SCAN_VIDEO_FILE_TYPE) { 500 | videoList.clear(); 501 | } else if (scanfiletype == MediaScanService.SCAN_AUDIO_FILE_TYPE) { 502 | audioList.clear(); 503 | } 504 | } 505 | contentGridView.getHandler().sendEmptyMessage(0); 506 | break; 507 | case MediaScanService.SCAN_STATUS_END:// 扫描完成 508 | contentGridView.getHandler().sendEmptyMessage(0); 509 | break; 510 | case MediaScanService.SCAN_STATUS_RUNNING:// 扫到一个文件 511 | synchronized (writelock) { 512 | if(media.filetype == MediaScanService.SCAN_VIDEO_FILE_TYPE) { 513 | videoList.add(media); 514 | } else if(media.filetype == MediaScanService.SCAN_AUDIO_FILE_TYPE) { 515 | audioList.add(media); 516 | } 517 | } 518 | contentGridView.getHandler().sendEmptyMessage(0); 519 | break; 520 | } 521 | } 522 | 523 | private class DataTask extends AsyncTask { 524 | 525 | @Override 526 | protected void onPreExecute() { 527 | super.onPreExecute(); 528 | } 529 | 530 | @Override 531 | protected Void doInBackground(Void... params) { 532 | synchronized (writelock) { 533 | videoList.clear(); 534 | videoList.addAll(FileUtils.getAllSortFiles(MediaScanService.SCAN_VIDEO_FILE_TYPE)); 535 | 536 | audioList.clear(); 537 | audioList.addAll(FileUtils.getAllSortFiles(MediaScanService.SCAN_AUDIO_FILE_TYPE)); 538 | } 539 | return null; 540 | } 541 | 542 | @Override 543 | protected void onPostExecute(Void arg) { 544 | super.onPostExecute(arg); 545 | contentGridView.getHandler().sendEmptyMessage(0); 546 | } 547 | } 548 | 549 | @Override 550 | protected void onDestroy() { 551 | super.onDestroy(); 552 | try { 553 | this.unbindService(mMediaScanServiceConnection); 554 | } catch (Exception e) { 555 | } 556 | } 557 | 558 | @Override 559 | public void clearAndLoad(String url) { 560 | 561 | } 562 | 563 | } 564 | -------------------------------------------------------------------------------- /src/com/mx/vipmediaplayer/VipPreference.java: -------------------------------------------------------------------------------- 1 | package com.mx.vipmediaplayer; 2 | 3 | 4 | import java.util.Map.Entry; 5 | 6 | import android.content.ContentValues; 7 | import android.content.Context; 8 | import android.content.SharedPreferences; 9 | 10 | 11 | /** 12 | * Preference Storage system class 13 | * 14 | * @author Xiao Mei 15 | * @weibo http://weibo.com/u/1675796095 16 | * @email tss_chs@126.com 17 | * 18 | */ 19 | public class VipPreference { 20 | 21 | private static final String PREFERENCE_NAME = "preference.db"; 22 | 23 | private SharedPreferences mPreference; 24 | 25 | public VipPreference(Context ctx) { 26 | mPreference = ctx.getApplicationContext().getSharedPreferences(PREFERENCE_NAME, Context.MODE_PRIVATE); 27 | } 28 | 29 | public boolean putStringAndCommit(String key, String value) { 30 | return mPreference.edit().putString(key, value).commit(); 31 | } 32 | 33 | public boolean putIntAndCommit(String key, int value) { 34 | return mPreference.edit().putInt(key, value).commit(); 35 | } 36 | 37 | public boolean putBooleanAndCommit(String key, boolean value) { 38 | return mPreference.edit().putBoolean(key, value).commit(); 39 | } 40 | 41 | public boolean putIntAndCommit(ContentValues values) { 42 | SharedPreferences.Editor editor = mPreference.edit(); 43 | for (Entry value : values.valueSet()) { 44 | editor.putString(value.getKey(), value.getValue().toString()); 45 | } 46 | return editor.commit(); 47 | } 48 | 49 | public String getString(String key) { 50 | return getString(key, ""); 51 | } 52 | 53 | public String getString(String key, String defValue) { 54 | return mPreference.getString(key, defValue); 55 | } 56 | 57 | public int getInt(String key) { 58 | return getInt(key, -1); 59 | } 60 | 61 | public int getInt(String key, int defValue) { 62 | return mPreference.getInt(key, defValue); 63 | } 64 | 65 | public boolean getBoolean(String key) { 66 | return getBoolean(key, false); 67 | } 68 | 69 | public boolean getBoolean(String key, boolean defValue) { 70 | return mPreference.getBoolean(key, defValue); 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /src/com/mx/vipmediaplayer/database/DatabaseHelper.java: -------------------------------------------------------------------------------- 1 | package com.mx.vipmediaplayer.database; 2 | 3 | import java.sql.SQLException; 4 | import java.util.ArrayList; 5 | import java.util.List; 6 | import java.util.Map; 7 | 8 | import android.content.ContentValues; 9 | 10 | import com.j256.ormlite.dao.Dao; 11 | import com.j256.ormlite.stmt.QueryBuilder; 12 | import com.j256.ormlite.stmt.UpdateBuilder; 13 | import com.mx.vipmediaplayer.Logger; 14 | 15 | /** 16 | * Database helper class 17 | * 18 | * @author Xiao Mei 19 | * @weibo http://weibo.com/u/1675796095 20 | * @email tss_chs@126.com 21 | * 22 | */ 23 | @SuppressWarnings({ "unchecked", "rawtypes" }) 24 | public class DatabaseHelper { 25 | 26 | /** 新增一条记录 */ 27 | public int create(T po) { 28 | SqliteHelperOrm db = new SqliteHelperOrm(); 29 | try { 30 | Dao dao = db.getDao(po.getClass()); 31 | return dao.create(po); 32 | } catch (SQLException e) { 33 | Logger.e(e); 34 | } finally { 35 | if (db != null) 36 | db.close(); 37 | } 38 | return -1; 39 | } 40 | 41 | public boolean exists(T po, Map where) { 42 | SqliteHelperOrm db = new SqliteHelperOrm(); 43 | try { 44 | Dao dao = db.getDao(po.getClass()); 45 | if (dao.queryForFieldValues(where).size() > 0) { 46 | return true; 47 | } 48 | } catch (SQLException e) { 49 | Logger.e(e); 50 | } finally { 51 | if (db != null) 52 | db.close(); 53 | } 54 | return false; 55 | } 56 | 57 | public int createIfNotExists(T po, Map where) { 58 | SqliteHelperOrm db = new SqliteHelperOrm(); 59 | try { 60 | Dao dao = db.getDao(po.getClass()); 61 | if (dao.queryForFieldValues(where).size() < 1) { 62 | return dao.create(po); 63 | } 64 | } catch (SQLException e) { 65 | Logger.e(e); 66 | } finally { 67 | if (db != null) 68 | db.close(); 69 | } 70 | return -1; 71 | } 72 | 73 | /** 查询一条记录 */ 74 | public List queryForEq(Class c, String fieldName, Object value) { 75 | SqliteHelperOrm db = new SqliteHelperOrm(); 76 | try { 77 | Dao dao = db.getDao(c); 78 | return dao.queryForEq(fieldName, value); 79 | } catch (SQLException e) { 80 | Logger.e(e); 81 | } finally { 82 | if (db != null) 83 | db.close(); 84 | } 85 | return new ArrayList(); 86 | } 87 | 88 | /** 删除一条记录 */ 89 | public int remove(T po) { 90 | SqliteHelperOrm db = new SqliteHelperOrm(); 91 | try { 92 | Dao dao = db.getDao(po.getClass()); 93 | return dao.delete(po); 94 | } catch (SQLException e) { 95 | Logger.e(e); 96 | } finally { 97 | if (db != null) 98 | db.close(); 99 | } 100 | return -1; 101 | } 102 | 103 | /** 104 | * 根据特定条件更新特定字段 105 | * 106 | * @param c 107 | * @param values 108 | * @param columnName where字段 109 | * @param value where值 110 | * @return 111 | */ 112 | public int update(Class c, ContentValues values, String columnName, Object value) { 113 | SqliteHelperOrm db = new SqliteHelperOrm(); 114 | try { 115 | Dao dao = db.getDao(c); 116 | UpdateBuilder updateBuilder = dao.updateBuilder(); 117 | updateBuilder.where().eq(columnName, value); 118 | for (String key : values.keySet()) { 119 | updateBuilder.updateColumnValue(key, values.get(key)); 120 | } 121 | return updateBuilder.update(); 122 | } catch (SQLException e) { 123 | Logger.e(e); 124 | } finally { 125 | if (db != null) 126 | db.close(); 127 | } 128 | return -1; 129 | } 130 | 131 | /** 更新一条记录 */ 132 | public int update(T po) { 133 | SqliteHelperOrm db = new SqliteHelperOrm(); 134 | try { 135 | 136 | Dao dao = db.getDao(po.getClass()); 137 | return dao.update(po); 138 | } catch (SQLException e) { 139 | Logger.e(e); 140 | } finally { 141 | if (db != null) 142 | db.close(); 143 | } 144 | return -1; 145 | } 146 | 147 | /** 查询所有记录 */ 148 | public List queryForAll(Class c) { 149 | SqliteHelperOrm db = new SqliteHelperOrm(); 150 | try { 151 | Dao dao = db.getDao(c); 152 | return dao.queryForAll(); 153 | } catch (SQLException e) { 154 | Logger.e(e); 155 | } finally { 156 | if (db != null) 157 | db.close(); 158 | } 159 | return new ArrayList(); 160 | } 161 | } 162 | -------------------------------------------------------------------------------- /src/com/mx/vipmediaplayer/database/SqliteHelperOrm.java: -------------------------------------------------------------------------------- 1 | package com.mx.vipmediaplayer.database; 2 | 3 | 4 | import java.sql.SQLException; 5 | 6 | import android.content.Context; 7 | import android.database.sqlite.SQLiteDatabase; 8 | 9 | import com.j256.ormlite.android.apptools.OrmLiteSqliteOpenHelper; 10 | import com.j256.ormlite.support.ConnectionSource; 11 | import com.j256.ormlite.table.TableUtils; 12 | import com.mx.vipmediaplayer.Logger; 13 | import com.mx.vipmediaplayer.VIPMediaPlayerApplication; 14 | import com.mx.vipmediaplayer.model.VIPMedia; 15 | 16 | /** 17 | * Sql Helper class 18 | * 19 | * @author Xiao Mei 20 | * @weibo http://weibo.com/u/1675796095 21 | * @email tss_chs@126.com 22 | * 23 | */ 24 | public class SqliteHelperOrm extends OrmLiteSqliteOpenHelper { 25 | private static final String DATABASE_NAME = "vipplayer.db"; 26 | private static final int DATABASE_VERSION = 1; 27 | 28 | public SqliteHelperOrm(Context context) { 29 | super(context, DATABASE_NAME, null, DATABASE_VERSION); 30 | } 31 | 32 | public SqliteHelperOrm() { 33 | super(VIPMediaPlayerApplication.getContext(), DATABASE_NAME, null, DATABASE_VERSION); 34 | } 35 | 36 | @Override 37 | public void onCreate(SQLiteDatabase db, ConnectionSource connectionSource) { 38 | try { 39 | Logger.d("database on create =================================================== "); 40 | TableUtils.createTable(connectionSource, VIPMedia.class); 41 | } catch (SQLException e) { 42 | Logger.e(e); 43 | } 44 | } 45 | 46 | @Override 47 | public void onUpgrade(SQLiteDatabase db, ConnectionSource connectionSource, int arg2, int arg3) { 48 | try { 49 | TableUtils.dropTable(connectionSource, VIPMedia.class, true); 50 | onCreate(db, connectionSource); 51 | } catch (SQLException e) { 52 | Logger.e(e); 53 | } 54 | } 55 | } -------------------------------------------------------------------------------- /src/com/mx/vipmediaplayer/model/OnlineVideo.java: -------------------------------------------------------------------------------- 1 | package com.mx.vipmediaplayer.model; 2 | 3 | import java.util.ArrayList; 4 | 5 | import com.j256.ormlite.field.DatabaseField; 6 | import com.j256.ormlite.table.DatabaseTable; 7 | 8 | /** 9 | * Online video class 10 | * 11 | * @author Xiao Mei 12 | * @weibo http://weibo.com/u/1675796095 13 | * 14 | */ 15 | 16 | @DatabaseTable(tableName = "online_live") 17 | public class OnlineVideo { 18 | @DatabaseField(generatedId = true) 19 | public String id; 20 | /** Title of online video */ 21 | @DatabaseField 22 | public String title; 23 | /** description */ 24 | @DatabaseField 25 | public String desc; 26 | /** LOGO */ 27 | @DatabaseField 28 | public int iconId = 0; 29 | @DatabaseField 30 | public String icon_url; 31 | /** play url link */ 32 | @DatabaseField 33 | public String url; 34 | /** backup url links */ 35 | public ArrayList backup_url; 36 | /** whether this is a category */ 37 | @DatabaseField 38 | public boolean is_category = false; 39 | /** 0 indicates video 1 indicates online tv */ 40 | @DatabaseField 41 | public int category; 42 | /** the level of current video */ 43 | @DatabaseField 44 | public int level = 1; 45 | 46 | public OnlineVideo() { 47 | } 48 | 49 | public OnlineVideo(String title, int iconId, int category) { 50 | this.title = title; 51 | this.iconId = iconId; 52 | this.category = category; 53 | } 54 | 55 | public OnlineVideo(String title, int iconId, int category, String url) { 56 | this.title = title; 57 | this.iconId = iconId; 58 | this.category = category; 59 | this.url = url; 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/com/mx/vipmediaplayer/model/VIPMedia.java: -------------------------------------------------------------------------------- 1 | package com.mx.vipmediaplayer.model; 2 | 3 | import java.io.File; 4 | 5 | import com.j256.ormlite.field.DatabaseField; 6 | import com.j256.ormlite.table.DatabaseTable; 7 | 8 | /** 9 | * VIP video class 10 | * 11 | * @author Xiao Mei 12 | * @weibo http://weibo.com/u/1675796095 13 | * @email tss_chs@126.com 14 | * 15 | */ 16 | @DatabaseTable(tableName = "media") 17 | public class VIPMedia { 18 | @DatabaseField(generatedId = true) 19 | public long _id; 20 | /** Video title */ 21 | @DatabaseField 22 | public String title; 23 | /** Video title pinyin */ 24 | @DatabaseField 25 | public String title_key; 26 | /** Video path */ 27 | @DatabaseField 28 | public String path; 29 | /** Last time for accessing */ 30 | @DatabaseField 31 | public long last_access_time; 32 | /** Last time for modifying */ 33 | @DatabaseField 34 | public long last_modify_time; 35 | /** Video duration */ 36 | @DatabaseField 37 | public int duration; 38 | /** Video current position */ 39 | @DatabaseField 40 | public int position; 41 | /** Video thumb path */ 42 | @DatabaseField 43 | public String thumb_path; 44 | /** Video file size */ 45 | @DatabaseField 46 | public long file_size; 47 | /** Video width */ 48 | @DatabaseField 49 | public int width; 50 | /** Video height */ 51 | @DatabaseField 52 | public int height; 53 | /** 0 as local video, 1 as online video*/ 54 | @DatabaseField 55 | public int filetype; 56 | /** MIME type */ 57 | public String mime_type; 58 | 59 | /** 文件状态0 - 10 分别代表 下载 0-100% */ 60 | public int status = -1; 61 | /** 文件临时大小 用于下载 */ 62 | public long temp_file_size = -1L; 63 | 64 | public VIPMedia() { 65 | 66 | } 67 | 68 | public VIPMedia(File f, int type) { 69 | title = f.getName(); 70 | path = f.getAbsolutePath(); 71 | last_modify_time = f.lastModified(); 72 | file_size = f.length(); 73 | this.filetype = type; 74 | } 75 | 76 | public VIPMedia(String path, String mimeType, int type) { 77 | this(new File(path), type); 78 | this.mime_type = mimeType; 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /src/com/mx/vipmediaplayer/model/VIPMediaBitmap.java: -------------------------------------------------------------------------------- 1 | package com.mx.vipmediaplayer.model; 2 | 3 | import android.graphics.Bitmap; 4 | 5 | /** 6 | * VIP Media & Bitmap pack class 7 | * 8 | * @author Xiao Mei 9 | * @weibo http://weibo.com/u/1675796095 10 | * @email tss_chs@126.com 11 | * 12 | */ 13 | public class VIPMediaBitmap { 14 | private Bitmap img; 15 | private VIPMedia vipmedia; 16 | 17 | public VIPMediaBitmap(Bitmap img, VIPMedia argmedia) { 18 | this.img = img; 19 | this.vipmedia = argmedia; 20 | } 21 | 22 | public Bitmap getImg() { 23 | return img; 24 | } 25 | 26 | public void setImg(Bitmap img) { 27 | this.img = img; 28 | } 29 | 30 | public VIPMedia getVipmedia() { 31 | return vipmedia; 32 | } 33 | 34 | public void setVipmedia(VIPMedia vipmedia) { 35 | this.vipmedia = vipmedia; 36 | } 37 | 38 | /** 39 | * 一个像素(int)占四个byte 40 | * 41 | * @return 42 | */ 43 | public int getImgSize() { 44 | if (img != null) { 45 | return img.getWidth() * img.getHeight() * 4; 46 | } 47 | return 0; 48 | } 49 | 50 | @Override 51 | public boolean equals(Object o) { 52 | if (o.getClass() == this.getClass()) 53 | return this.vipmedia.path 54 | .equals(((VIPMediaBitmap) o).getVipmedia().path); 55 | return false; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/com/mx/vipmediaplayer/services/MediaScanService.java: -------------------------------------------------------------------------------- 1 | package com.mx.vipmediaplayer.services; 2 | 3 | import io.vov.vitamio.ThumbnailUtils; 4 | 5 | import java.io.File; 6 | import java.io.FileNotFoundException; 7 | import java.io.FileOutputStream; 8 | import java.util.ArrayList; 9 | import java.util.HashMap; 10 | import java.util.Map; 11 | import java.util.Map.Entry; 12 | import java.util.Set; 13 | import java.util.UUID; 14 | import java.util.concurrent.ConcurrentHashMap; 15 | 16 | import android.app.ActivityManager; 17 | import android.app.ActivityManager.RunningServiceInfo; 18 | import android.app.Service; 19 | import android.content.Context; 20 | import android.content.Intent; 21 | import android.graphics.Bitmap; 22 | import android.os.Binder; 23 | import android.os.Bundle; 24 | import android.os.Handler; 25 | import android.os.IBinder; 26 | import android.os.Message; 27 | import android.provider.MediaStore; 28 | 29 | import com.mx.vipmediaplayer.Logger; 30 | import com.mx.vipmediaplayer.VIPMediaPlayerApplication; 31 | import com.mx.vipmediaplayer.VipPreference; 32 | import com.mx.vipmediaplayer.database.DatabaseHelper; 33 | import com.mx.vipmediaplayer.model.VIPMedia; 34 | import com.mx.vipmediaplayer.util.ConvertUtils; 35 | import com.mx.vipmediaplayer.util.FileUtils; 36 | import com.mx.vipmediaplayer.util.PinyinUtils; 37 | import com.mx.vipmediaplayer.util.StringUtils; 38 | 39 | /** 40 | * Media Scan service class 41 | * 42 | * @author Xiao Mei 43 | * @weibo http://weibo.com/u/1675796095 44 | * @email tss_chs@126.com 45 | * 46 | */ 47 | public class MediaScanService extends Service implements Runnable { 48 | 49 | private static final String SERVICE_NAME = "com.mx.vipmediaplayer.services.MediaScannerService"; 50 | /** scan directory*/ 51 | public static final String EXTRA_DIRECTORY = "scan_directory"; 52 | /** scan file */ 53 | public static final String EXTRA_FILE_PATH = "scan_file"; 54 | public static final String EXTRA_MIME_TYPE = "mimetype"; 55 | public static final String EXTRA_FILE_TYPE = "file_type"; 56 | 57 | public static final int SCAN_INVALID_FILE_TYPE = -1; 58 | /* 59 | * scan video files 60 | */ 61 | public static final int SCAN_VIDEO_FILE_TYPE = 0; 62 | 63 | /** 64 | * scan audio files 65 | */ 66 | public static final int SCAN_AUDIO_FILE_TYPE = 1; 67 | 68 | public static final int SCAN_STATUS_NORMAL = -1; 69 | /** 开始扫描 */ 70 | public static final int SCAN_STATUS_START = 0; 71 | /** 正在扫描 扫描到一个视频文件 */ 72 | public static final int SCAN_STATUS_RUNNING = 1; 73 | /** 扫描完成 */ 74 | public static final int SCAN_STATUS_END = 2; 75 | /** */ 76 | private ArrayList observers = new ArrayList(); 77 | private ConcurrentHashMap mScanMap = new ConcurrentHashMap(); 78 | 79 | /** 当前状态 */ 80 | private volatile int mServiceStatus = SCAN_STATUS_NORMAL; 81 | private DatabaseHelper mDbHelper; 82 | private Map mDbWhere = new HashMap(2); 83 | private int scanfiletype = SCAN_INVALID_FILE_TYPE; 84 | 85 | @Override 86 | public void onCreate() { 87 | super.onCreate(); 88 | 89 | mDbHelper = new DatabaseHelper(); 90 | } 91 | 92 | /** 是否正在运行 */ 93 | public static boolean isRunning() { 94 | ActivityManager manager = (ActivityManager) VIPMediaPlayerApplication 95 | .getContext().getSystemService(Context.ACTIVITY_SERVICE); 96 | for (RunningServiceInfo service : manager 97 | .getRunningServices(Integer.MAX_VALUE)) { 98 | if (SERVICE_NAME.equals(service.service.getClassName())) 99 | return true; 100 | } 101 | return false; 102 | } 103 | 104 | @Override 105 | public int onStartCommand(Intent intent, int flags, int startId) { 106 | Logger.d("start service ============================================== "); 107 | if (intent != null) 108 | parseIntent(intent); 109 | 110 | return super.onStartCommand(intent, flags, startId); 111 | } 112 | 113 | /** 解析Intent */ 114 | private void parseIntent(final Intent intent) { 115 | final Bundle arguments = intent.getExtras(); 116 | if (arguments != null) { 117 | scanfiletype = arguments.getInt(EXTRA_FILE_TYPE, SCAN_INVALID_FILE_TYPE); 118 | if (arguments.containsKey(EXTRA_DIRECTORY)) { 119 | String directory = arguments.getString(EXTRA_DIRECTORY); 120 | Logger.i("onStartCommand:" + directory); 121 | // 扫描文件夹 122 | if (!mScanMap.containsKey(directory)) 123 | mScanMap.put(directory, ""); 124 | } else if (arguments.containsKey(EXTRA_FILE_PATH)) { 125 | // 单文件 126 | String filePath = arguments.getString(EXTRA_FILE_PATH); 127 | Logger.i("onStartCommand:" + filePath); 128 | if (!StringUtils.isEmpty(filePath)) { 129 | if (!mScanMap.containsKey(filePath)) 130 | mScanMap.put(filePath, 131 | arguments.getString(EXTRA_MIME_TYPE)); 132 | // scanFile(filePath, arguments.getString(EXTRA_MIME_TYPE)); 133 | } 134 | } 135 | } 136 | 137 | if (mServiceStatus == SCAN_STATUS_NORMAL 138 | || mServiceStatus == SCAN_STATUS_END) { 139 | new Thread(this).start(); 140 | // scan(); 141 | } 142 | } 143 | 144 | @Override 145 | public void run() { 146 | scan(); 147 | } 148 | 149 | /** 扫描 */ 150 | private void scan() { 151 | mServiceStatus = SCAN_STATUS_START; 152 | // 开始扫描 153 | notifyObservers(SCAN_STATUS_START, null); 154 | 155 | Set> mSet = mScanMap.entrySet(); 156 | for (Entry mEntry : mSet) { 157 | mServiceStatus = SCAN_STATUS_RUNNING; 158 | String path = mEntry.getKey(); 159 | String mimeType = mEntry.getValue(); 160 | if ("".equals(mimeType)) { 161 | scanDirectory(path); 162 | } else { 163 | scanFile(path, mimeType); 164 | } 165 | 166 | // 任务之间歇息一秒 167 | try { 168 | Thread.sleep(1000); 169 | } catch (InterruptedException e) { 170 | Logger.e(e); 171 | } 172 | } 173 | mScanMap.clear(); 174 | 175 | // 全部扫描完成 176 | notifyObservers(SCAN_STATUS_END, null); 177 | mServiceStatus = SCAN_STATUS_END; 178 | 179 | // 第一次扫描 180 | VipPreference pref = new VipPreference(this); 181 | if (pref.getBoolean(VIPMediaPlayerApplication.PREF_KEY_FIRST, true)) 182 | pref.putBooleanAndCommit(VIPMediaPlayerApplication.PREF_KEY_FIRST, 183 | false); 184 | 185 | // 停止服务 186 | stopSelf(); 187 | } 188 | 189 | private Handler mHandler = new Handler() { 190 | @Override 191 | public void handleMessage(Message msg) { 192 | super.handleMessage(msg); 193 | for (IMediaScanObserver s : observers) { 194 | if (s != null) { 195 | s.update(msg.what, (VIPMedia) msg.obj, scanfiletype); 196 | } 197 | } 198 | } 199 | }; 200 | 201 | /** 扫描文件 */ 202 | private void scanFile(String path, String mimeType) { 203 | if (scanfiletype == SCAN_INVALID_FILE_TYPE) { 204 | if (FileUtils.isVideo(path)) 205 | save(new VIPMedia(path, mimeType, SCAN_VIDEO_FILE_TYPE)); 206 | else if (FileUtils.isAudio(path)) 207 | save(new VIPMedia(path, mimeType, SCAN_AUDIO_FILE_TYPE)); 208 | } else if (FileUtils.isVideo(path) 209 | && scanfiletype == SCAN_VIDEO_FILE_TYPE) 210 | save(new VIPMedia(path, mimeType, SCAN_VIDEO_FILE_TYPE)); 211 | else if (FileUtils.isAudio(path) 212 | && scanfiletype == SCAN_AUDIO_FILE_TYPE) 213 | save(new VIPMedia(path, mimeType, SCAN_AUDIO_FILE_TYPE)); 214 | } 215 | 216 | /** 扫描文件夹 */ 217 | private void scanDirectory(String path) { 218 | eachAllMedias(new File(path)); 219 | } 220 | 221 | /** 递归查找视频 */ 222 | private void eachAllMedias(File f) { 223 | if (f != null && f.exists() && f.isDirectory()) { 224 | File[] files = f.listFiles(); 225 | if (files != null) { 226 | for (File file : f.listFiles()) { 227 | // Logger.i(f.getAbsolutePath()); 228 | if (file.isDirectory()) { 229 | // 忽略.开头的文件夹 230 | if (!file.getAbsolutePath().startsWith(".")) 231 | eachAllMedias(file); 232 | } else if (file.exists() && file.canRead() 233 | ) { 234 | if (scanfiletype == SCAN_INVALID_FILE_TYPE) { 235 | if(FileUtils.isVideo(file)) save(new VIPMedia(file, SCAN_VIDEO_FILE_TYPE)); 236 | else if(FileUtils.isAudio(file)) save(new VIPMedia(file, SCAN_AUDIO_FILE_TYPE)); 237 | } else if(FileUtils.isVideo(file) && scanfiletype == SCAN_VIDEO_FILE_TYPE) { 238 | save(new VIPMedia(file, SCAN_VIDEO_FILE_TYPE)); 239 | } else if (FileUtils.isAudio(file) && scanfiletype == SCAN_AUDIO_FILE_TYPE) { 240 | save(new VIPMedia(file, SCAN_AUDIO_FILE_TYPE)); 241 | } 242 | } 243 | } 244 | } 245 | } 246 | } 247 | 248 | /** 249 | * 保存入库 250 | * 251 | * @throws FileNotFoundException 252 | */ 253 | private void save(VIPMedia media) { 254 | mDbWhere.put("path", media.path); 255 | mDbWhere.put("last_modify_time", media.last_modify_time); 256 | // 检测 257 | if (!mDbHelper.exists(media, mDbWhere)) { 258 | try { 259 | if (media.title != null && media.title.length() > 0) 260 | media.title_key = PinyinUtils.chineneToSpell(media.title 261 | .charAt(0) + ""); 262 | } catch (Exception ex) { 263 | Logger.e(ex); 264 | } 265 | media.last_access_time = System.currentTimeMillis(); 266 | 267 | // 提取缩略图 268 | extractThumbnail(media); 269 | media.mime_type = FileUtils.getMimeType(media.path); 270 | 271 | // 入库 272 | mDbHelper.create(media); 273 | 274 | // 扫描到一个 275 | notifyObservers(SCAN_STATUS_RUNNING, media); 276 | } 277 | } 278 | 279 | /** 提取生成缩略图 */ 280 | public static void extractThumbnail(VIPMedia media) { 281 | final Context ctx = VIPMediaPlayerApplication.getContext(); 282 | // ThumbnailUtils. 283 | Bitmap bitmap = null; 284 | /* ThumbnailUtils.createVideoThumbnail(ctx, media.path, 285 | MediaStore.Video.Thumbnails.MINI_KIND); */ 286 | try { 287 | if (bitmap == null) { 288 | // 缩略图创建失败 289 | bitmap = Bitmap.createBitmap( 290 | ThumbnailUtils.TARGET_SIZE_MINI_THUMBNAIL_WIDTH, 291 | ThumbnailUtils.TARGET_SIZE_MINI_THUMBNAIL_HEIGHT, 292 | Bitmap.Config.RGB_565); 293 | } 294 | 295 | media.width = bitmap.getWidth(); 296 | media.height = bitmap.getHeight(); 297 | 298 | // 缩略图 299 | bitmap = ThumbnailUtils.extractThumbnail(bitmap, ConvertUtils 300 | .dipToPX(ctx, 301 | ThumbnailUtils.TARGET_SIZE_MICRO_THUMBNAIL_WIDTH), 302 | ConvertUtils.dipToPX(ctx, 303 | ThumbnailUtils.TARGET_SIZE_MICRO_THUMBNAIL_HEIGHT), 304 | ThumbnailUtils.OPTIONS_RECYCLE_INPUT); 305 | if (bitmap != null) { 306 | // 将缩略图存到视频当前路径 307 | File thum = new File( 308 | VIPMediaPlayerApplication.VIPPLAYER_VIDEO_THUMB, UUID 309 | .randomUUID().toString()); 310 | media.thumb_path = thum.getAbsolutePath(); 311 | // thum.createNewFile(); 312 | FileOutputStream iStream = new FileOutputStream(thum); 313 | bitmap.compress(Bitmap.CompressFormat.JPEG, 85, iStream); 314 | iStream.close(); 315 | } 316 | 317 | // 入库 318 | 319 | } catch (Exception ex) { 320 | Logger.e(ex); 321 | } finally { 322 | if (bitmap != null) 323 | bitmap.recycle(); 324 | 325 | } 326 | } 327 | 328 | // ~~~ 状态改变 329 | 330 | /** 通知状态改变 */ 331 | private void notifyObservers(int flag, VIPMedia media) { 332 | mHandler.sendMessage(mHandler.obtainMessage(flag, media)); 333 | } 334 | 335 | /** 增加观察者 */ 336 | public void addObserver(IMediaScanObserver s) { 337 | synchronized (this) { 338 | if (!observers.contains(s)) { 339 | observers.add(s); 340 | } 341 | } 342 | } 343 | 344 | /** 删除观察者 */ 345 | public synchronized void deleteObserver(IMediaScanObserver s) { 346 | observers.remove(s); 347 | } 348 | 349 | /** 删除所有观察者 */ 350 | public synchronized void deleteObservers() { 351 | observers.clear(); 352 | } 353 | 354 | public interface IMediaScanObserver { 355 | /** 356 | * 357 | * @param flag 358 | * 0 开始扫描 1 正在扫描 2 扫描完成 359 | * @param file 360 | * 扫描到的视频文件 361 | * @param scanfiletype 362 | * 0 indicates Video file, 1 indicates audio file 363 | */ 364 | public void update(int flag, VIPMedia media, int scanfiletype); 365 | } 366 | 367 | // ~~~ Binder 368 | 369 | private final MediaScanServiceBinder mBinder = new MediaScanServiceBinder(); 370 | 371 | public class MediaScanServiceBinder extends Binder { 372 | public MediaScanService getService() { 373 | return MediaScanService.this; 374 | } 375 | } 376 | 377 | @Override 378 | public IBinder onBind(Intent intent) { 379 | return mBinder; 380 | } 381 | 382 | } 383 | -------------------------------------------------------------------------------- /src/com/mx/vipmediaplayer/ui/AddOnlineActivity.java: -------------------------------------------------------------------------------- 1 | package com.mx.vipmediaplayer.ui; 2 | 3 | import android.app.Activity; 4 | 5 | /** 6 | * Interface for administer to add online tv class 7 | * 8 | * @author Xiao Mei 9 | * @weibo http://weibo.com/u/1675796095 10 | * @email tss_chs@126.com 11 | * 12 | */ 13 | public class AddOnlineActivity extends Activity { 14 | 15 | } 16 | -------------------------------------------------------------------------------- /src/com/mx/vipmediaplayer/ui/ContentGridView.java: -------------------------------------------------------------------------------- 1 | package com.mx.vipmediaplayer.ui; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | import android.app.Activity; 7 | import android.app.Service; 8 | import android.content.Context; 9 | import android.content.Intent; 10 | import android.graphics.Bitmap; 11 | import android.os.Bundle; 12 | import android.os.Handler; 13 | import android.os.Message; 14 | import android.util.AttributeSet; 15 | import android.util.DisplayMetrics; 16 | import android.view.LayoutInflater; 17 | import android.view.View; 18 | import android.view.ViewGroup; 19 | import android.widget.AdapterView; 20 | import android.widget.BaseAdapter; 21 | import android.widget.GridView; 22 | import android.widget.ImageView; 23 | import android.widget.TextView; 24 | 25 | import com.mx.vipmediaplayer.R; 26 | import com.mx.vipmediaplayer.model.VIPMedia; 27 | import com.mx.vipmediaplayer.model.VIPMediaBitmap; 28 | import com.mx.vipmediaplayer.services.MediaScanService; 29 | import com.mx.vipmediaplayer.util.ImageLoadUtils; 30 | import com.mx.vipmediaplayer.util.MethodHandler; 31 | /** 32 | * Content GridView class 33 | * 34 | * @author Xiao Mei 35 | * @weibo http://weibo.com/u/1675796095 36 | * @email tss_chs@126.com 37 | * 38 | */ 39 | public class ContentGridView extends GridView implements AdapterView.OnItemClickListener{ 40 | 41 | private List mList = new ArrayList(); 42 | private LayoutInflater mInflater = null; 43 | private Context context = null; 44 | private int filetype = MediaScanService.SCAN_INVALID_FILE_TYPE; 45 | private int horizontalspacing = 0, columnwidth = 0; 46 | private Activity activity; 47 | 48 | private Handler mHandler = new Handler() { 49 | 50 | @Override 51 | public void handleMessage(Message msg) { 52 | switch (msg.what) { 53 | case 0: 54 | mAdapter.notifyDataSetChanged(); 55 | break; 56 | case 1: 57 | if (filetype != MediaScanService.SCAN_INVALID_FILE_TYPE) { 58 | if (msg.obj != null) 59 | mList.add((VIPMedia) msg.obj); 60 | mAdapter.notifyDataSetChanged(); 61 | } 62 | break; 63 | } 64 | } 65 | }; 66 | 67 | public void setActivity(Activity activity) { 68 | this.activity = activity; 69 | } 70 | 71 | public void setFileType(int argfiletype) { 72 | this.filetype = argfiletype; 73 | } 74 | 75 | public Handler getHandler() { 76 | return mHandler; 77 | } 78 | 79 | public void setList(List arglist) { 80 | mList = arglist; 81 | } 82 | 83 | public ContentGridView(Context context, AttributeSet attrs, int defStyle) { 84 | super(context, attrs, defStyle); 85 | initView(context); 86 | } 87 | 88 | public ContentGridView(Context context, AttributeSet attrs) { 89 | this(context, attrs, 0); 90 | } 91 | 92 | public ContentGridView(Context context) { 93 | super(context); 94 | initView(context); 95 | } 96 | 97 | private void initView(Context ctx) { 98 | context = ctx; 99 | mInflater = (LayoutInflater) ctx.getApplicationContext() 100 | .getSystemService(Service.LAYOUT_INFLATER_SERVICE); 101 | mList.clear(); 102 | this.setAdapter(mAdapter); 103 | mAdapter.notifyDataSetChanged(); 104 | /** 105 | * try to define the spacing and column width 106 | * column width define 10 times of spcaing 107 | * with 3 columns and 2 spacings and 2 paddings(one left, one right) 108 | * ********** ********** ********** 109 | * * * * * * * 110 | * * * * * * * 111 | * * * * * * * 112 | * ********** ********** ********** 113 | */ 114 | DisplayMetrics dm = context.getResources().getDisplayMetrics(); 115 | horizontalspacing = (int)Math.ceil(dm.widthPixels / 34d); 116 | columnwidth = (int)Math.floor((dm.widthPixels - 4 * horizontalspacing) / 3d); 117 | setHorizontalSpacing(horizontalspacing); 118 | setVerticalSpacing(horizontalspacing); 119 | setColumnWidth(columnwidth); 120 | setNumColumns(3); 121 | setStretchMode(GridView.STRETCH_COLUMN_WIDTH); 122 | setPadding(horizontalspacing, 0, horizontalspacing, 0); 123 | setOnItemClickListener(this); 124 | } 125 | 126 | private BaseAdapter mAdapter = new BaseAdapter() { 127 | 128 | @Override 129 | public View getView(int position, View convertView, ViewGroup parent) { 130 | if (convertView == null) { 131 | convertView = mInflater.inflate(R.layout.content_griditem, null); 132 | } 133 | 134 | final View cv = convertView; 135 | VIPMedia item = mList.get(position); 136 | convertView.setTag(item); 137 | ImageView image = (ImageView) convertView 138 | .findViewById(R.id.IVThumbNail); 139 | TextView text = (TextView) convertView.findViewById(R.id.TVDesc); 140 | Bitmap bt = ImageLoadUtils.readImg(item); 141 | text.setText(item.title); 142 | if (bt != null) { 143 | image.setImageBitmap(bt); 144 | } else { 145 | ImageLoadUtils.readBitmapAsync(item, 146 | new MethodHandler() { 147 | public void process(VIPMediaBitmap para) { 148 | Message msg = mMethodHandler.obtainMessage(0, 149 | cv); 150 | Bundle data = new Bundle(); 151 | data.putString("path", para.getVipmedia().path); 152 | msg.setData(data); 153 | msg.sendToTarget(); 154 | } 155 | }); 156 | } 157 | 158 | return convertView; 159 | } 160 | 161 | @Override 162 | public long getItemId(int position) { 163 | return 0; 164 | } 165 | 166 | @Override 167 | public Object getItem(int position) { 168 | if (mList != null) { 169 | try { 170 | return mList.get(position); 171 | } catch (Exception e) { 172 | return null; 173 | } 174 | } 175 | return null; 176 | } 177 | 178 | @Override 179 | public int getCount() { 180 | if (mList != null) 181 | return mList.size(); 182 | return 0; 183 | } 184 | }; 185 | 186 | private Handler mMethodHandler = new Handler() { 187 | public void handleMessage(Message msg) { 188 | 189 | View view = (View) msg.obj; 190 | VIPMedia item = null; 191 | try { 192 | item = (VIPMedia) view.getTag(); 193 | } catch (Exception e) { 194 | } 195 | String filepath = null; 196 | try { 197 | filepath = msg.getData().getString("path"); 198 | } catch (Exception e) { 199 | } 200 | if (view != null && item != null && item.path.equals(filepath)) { 201 | ((ImageView) view.findViewById(R.id.IVThumbNail)) 202 | .setImageBitmap(ImageLoadUtils.readImg(item)); 203 | } 204 | } 205 | }; 206 | 207 | @Override 208 | public void onItemClick(AdapterView arg0, View view, int arg2, long arg3) { 209 | final VIPMedia f = (VIPMedia) view.getTag(); 210 | Intent intent = new Intent(activity, VideoPlayerActivity.class); 211 | intent.putExtra("path", f.path); 212 | intent.putExtra("title", f.title); 213 | activity.startActivity(intent); 214 | } 215 | } 216 | -------------------------------------------------------------------------------- /src/com/mx/vipmediaplayer/ui/ContentListView.java: -------------------------------------------------------------------------------- 1 | package com.mx.vipmediaplayer.ui; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | import android.app.Activity; 7 | import android.app.Service; 8 | import android.content.Context; 9 | import android.content.Intent; 10 | import android.util.AttributeSet; 11 | import android.view.LayoutInflater; 12 | import android.view.View; 13 | import android.view.ViewGroup; 14 | import android.widget.AdapterView; 15 | import android.widget.BaseAdapter; 16 | import android.widget.ImageView; 17 | import android.widget.ListView; 18 | import android.widget.TextView; 19 | 20 | import com.mx.vipmediaplayer.R; 21 | import com.mx.vipmediaplayer.model.OnlineVideo; 22 | import com.mx.vipmediaplayer.ui.helper.XmlReaderHelper; 23 | 24 | 25 | /** 26 | * Content ListView class 27 | * 28 | * @author Xiao Mei 29 | * @weibo http://weibo.com/u/1675796095 30 | * @email tss_chs@126.com 31 | * 32 | */ 33 | public class ContentListView extends ListView implements AdapterView.OnItemClickListener{ 34 | private List mList = new ArrayList(); 35 | 36 | private Activity activity = null; 37 | private Context context = null; 38 | private LayoutInflater mInflater; 39 | 40 | private int level = 1; 41 | 42 | private final static ArrayList root = new ArrayList(); 43 | private ArrayList tvs; 44 | private final static ArrayList videos = new ArrayList(); 45 | 46 | private OnOnlineVideoClickListener mOnlineVideoClickListener = null; 47 | 48 | static { 49 | 50 | // private final static String[] CATEGORY = { "电视直播", "视频网站" }; 51 | root.add(new OnlineVideo("Live TV", R.drawable.logo_live, 1)); 52 | root.add(new OnlineVideo("Video Sites", R.drawable.logo_youku, 0)); 53 | 54 | videos.add(new OnlineVideo("Youku", R.drawable.logo_youku, 0, 55 | "http://3g.youku.com")); 56 | videos.add(new OnlineVideo("Sohu", R.drawable.logo_sohu, 0, 57 | "http://m.tv.sohu.com")); 58 | videos.add(new OnlineVideo("LETV", R.drawable.logo_letv, 0, 59 | "http://m.letv.com")); 60 | videos.add(new OnlineVideo("IQIYI", R.drawable.logo_iqiyi, 0, 61 | "http://3g.iqiyi.com/")); 62 | videos.add(new OnlineVideo("PPTV", R.drawable.logo_pptv, 0, 63 | "http://m.pptv.com/")); 64 | videos.add(new OnlineVideo("Tencent", R.drawable.logo_qq, 0, 65 | "http://3g.v.qq.com/")); 66 | videos.add(new OnlineVideo("56.com", R.drawable.logo_56, 0, 67 | "http://m.56.com/")); 68 | videos.add(new OnlineVideo("Sina", R.drawable.logo_sina, 0, 69 | "http://video.sina.cn/")); 70 | videos.add(new OnlineVideo("Tomato", R.drawable.logo_tudou, 0, 71 | "http://m.tudou.com")); 72 | } 73 | 74 | public ContentListView(Context context, AttributeSet attrs, int defStyle) { 75 | super(context, attrs, defStyle); 76 | initView(context); 77 | } 78 | 79 | public ContentListView(Context context, AttributeSet attrs) { 80 | this(context, attrs, 0); 81 | } 82 | 83 | public ContentListView(Context context) { 84 | super(context); 85 | initView(context); 86 | } 87 | 88 | public void setActivity(Activity activity) { 89 | this.activity = activity; 90 | } 91 | 92 | public void setOnlineVideoClickListener(OnOnlineVideoClickListener listener) { 93 | mOnlineVideoClickListener = listener; 94 | } 95 | 96 | private void initView(Context ctx) { 97 | context = ctx; 98 | mInflater = (LayoutInflater) ctx.getApplicationContext() 99 | .getSystemService(Service.LAYOUT_INFLATER_SERVICE); 100 | mList.clear(); 101 | this.setAdapter(mAdapter); 102 | mAdapter.notifyDataSetChanged(); 103 | this.setOnItemClickListener(this); 104 | mAdapter.replace(root); 105 | level = 1; 106 | mAdapter.notifyDataSetChanged(); 107 | } 108 | 109 | private DataAdapter mAdapter = new DataAdapter(); 110 | 111 | public class DataAdapter extends BaseAdapter { 112 | 113 | private List datalist; 114 | 115 | @Override 116 | public int getCount() { 117 | if (datalist != null) 118 | return datalist.size(); 119 | return 0; 120 | } 121 | 122 | @Override 123 | public Object getItem(int position) { 124 | try { 125 | return datalist.get(position); 126 | }catch (Exception e) { 127 | } 128 | return null; 129 | } 130 | 131 | @Override 132 | public long getItemId(int position) { 133 | return 0; 134 | } 135 | 136 | @Override 137 | public View getView(int position, View convertView, ViewGroup parent) { 138 | final OnlineVideo item = (OnlineVideo)getItem(position); 139 | if (item == null) return null; 140 | if (convertView == null) { 141 | convertView = mInflater 142 | .inflate(R.layout.content_listitem, null); 143 | } 144 | ImageView thumbnail = (ImageView) convertView 145 | .findViewById(R.id.thumbnail); 146 | if (item.iconId > 0) 147 | thumbnail.setImageResource(item.iconId); 148 | else 149 | thumbnail.setImageDrawable(null); 150 | ((TextView) convertView.findViewById(R.id.title)) 151 | .setText(item.title); 152 | 153 | return convertView; 154 | } 155 | 156 | public void replace(ArrayList list) { 157 | if (list == null) 158 | list = new ArrayList(); 159 | datalist = list; 160 | } 161 | }; 162 | 163 | @Override 164 | public void onItemClick(AdapterView parent, View arg1, int position, long arg3) { 165 | // Intent intent = new Intent(activity, VideoPlayerActivity.class); 166 | // intent.putExtra("path", "mms://yayin.canlitv.com/showtv"); 167 | // intent.putExtra("title", "zhongwen"); 168 | // activity.startActivity(intent); 169 | final OnlineVideo item = (OnlineVideo)mAdapter.getItem(position); 170 | switch (level) { 171 | case 1:// level 1 172 | level = 2; 173 | if (position == 0) { 174 | // live tv 175 | if (tvs == null) 176 | tvs = XmlReaderHelper.getAllCategory(activity); 177 | mAdapter.replace(tvs); 178 | } else { 179 | // online video 180 | mAdapter.replace(videos); 181 | } 182 | mAdapter.notifyDataSetChanged(); 183 | break; 184 | case 2:// level 2 185 | level = 3; 186 | if (item.id != null) { 187 | // live tv 188 | mAdapter.replace(XmlReaderHelper.getVideos(activity, item.id)); 189 | mAdapter.notifyDataSetChanged(); 190 | } else { 191 | if (mOnlineVideoClickListener != null) 192 | mOnlineVideoClickListener.clearAndLoad(item.url); 193 | } 194 | break; 195 | case 3: // level 3 196 | level = 4; 197 | // clearAndLoad(item.url); 198 | Intent intent = new Intent(activity, VideoPlayerActivity.class); 199 | intent.putExtra("path", item.url); 200 | intent.putExtra("title", item.title); 201 | activity.startActivity(intent); 202 | break; 203 | case 4: // level 4 204 | level = 4; 205 | Intent anotherIntent = new Intent(activity, 206 | VideoPlayerActivity.class); 207 | anotherIntent.putExtra("path", item.url); 208 | anotherIntent.putExtra("title", item.title); 209 | activity.startActivity(anotherIntent); 210 | break; 211 | } 212 | } 213 | 214 | public static interface OnOnlineVideoClickListener { 215 | public void clearAndLoad(String url); 216 | } 217 | } 218 | -------------------------------------------------------------------------------- /src/com/mx/vipmediaplayer/ui/MenuListView.java: -------------------------------------------------------------------------------- 1 | package com.mx.vipmediaplayer.ui; 2 | 3 | import android.app.Service; 4 | import android.content.Context; 5 | import android.util.AttributeSet; 6 | import android.view.LayoutInflater; 7 | import android.view.View; 8 | import android.view.ViewGroup; 9 | import android.widget.AdapterView; 10 | import android.widget.BaseAdapter; 11 | import android.widget.ImageView; 12 | import android.widget.LinearLayout; 13 | import android.widget.ListView; 14 | import android.widget.TextView; 15 | 16 | import com.mx.vipmediaplayer.R; 17 | 18 | /** 19 | * Menu ListView class 20 | * 21 | * @author Xiao Mei 22 | * @weibo http://weibo.com/u/1675796095 23 | * @email tss_chs@126.com 24 | * 25 | */ 26 | public class MenuListView extends ListView implements 27 | android.widget.AdapterView.OnItemClickListener { 28 | 29 | public static final int POSITION_PLAYLIST = 0; 30 | public static final int POSITION_LOCALVIDEO = 1; 31 | public static final int POSITION_LOCALAUDIO = 2; 32 | 33 | public static MenuItem[] datalist = { 34 | new MenuItem(POSITION_PLAYLIST, 0, R.string.playlist), 35 | new MenuItem(POSITION_LOCALVIDEO, 0, R.string.localvideo), 36 | new MenuItem(POSITION_LOCALAUDIO, 0, R.string.localmusic) }; 37 | 38 | private OnMenuClickListener mMenuClickListenr = null; 39 | private LayoutInflater mInflator = null; 40 | 41 | @Override 42 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 43 | 44 | LinearLayout.LayoutParams params = (LinearLayout.LayoutParams)this.getLayoutParams(); 45 | super.onMeasure(widthMeasureSpec, heightMeasureSpec); 46 | } 47 | 48 | public MenuListView(Context context, AttributeSet attrs, int defStyle) { 49 | super(context, attrs, defStyle); 50 | initViews(context); 51 | } 52 | 53 | public MenuListView(Context context, AttributeSet attrs) { 54 | this(context, attrs, 0); 55 | } 56 | 57 | public MenuListView(Context context) { 58 | super(context); 59 | initViews(context); 60 | } 61 | 62 | private void initViews(Context ctx) { 63 | mInflator = (LayoutInflater) ctx 64 | .getSystemService(Service.LAYOUT_INFLATER_SERVICE); 65 | this.setOnItemClickListener(this); 66 | this.setAdapter(mAdapter); 67 | mAdapter.notifyDataSetChanged(); 68 | } 69 | 70 | BaseAdapter mAdapter = new BaseAdapter() { 71 | 72 | @Override 73 | public View getView(int position, View convertView, ViewGroup parent) { 74 | if (convertView == null) { 75 | convertView = mInflator.inflate(R.layout.menu_item, null); 76 | } 77 | 78 | MenuItem mi = datalist[position]; 79 | ImageView ivicon = (ImageView) convertView 80 | .findViewById(R.id.IVIcon); 81 | TextView tvtext = (TextView) convertView.findViewById(R.id.TVText); 82 | convertView.setTag(datalist[position]); 83 | if (mi.iconResId != 0) 84 | ivicon.setImageResource(mi.iconResId); 85 | if (mi.textId != 0) 86 | tvtext.setText(mi.textId); 87 | else 88 | tvtext.setText("null"); 89 | return convertView; 90 | } 91 | 92 | @Override 93 | public long getItemId(int position) { 94 | return 0; 95 | } 96 | 97 | @Override 98 | public Object getItem(int arg0) { 99 | if (datalist != null) { 100 | try { 101 | return datalist[arg0]; 102 | } catch (Exception e) { 103 | return null; 104 | } 105 | } 106 | return null; 107 | } 108 | 109 | @Override 110 | public int getCount() { 111 | return datalist.length; 112 | } 113 | }; 114 | 115 | public void setOnMenuClickListener(OnMenuClickListener argListener) { 116 | this.mMenuClickListenr = argListener; 117 | } 118 | 119 | @Override 120 | public void onItemClick(AdapterView parent, View view, int position, 121 | long id) { 122 | switch (position) { 123 | case POSITION_PLAYLIST: 124 | if (mMenuClickListenr != null) 125 | mMenuClickListenr.onPlaylistClicked(); 126 | break; 127 | case POSITION_LOCALVIDEO: 128 | if (mMenuClickListenr != null) 129 | mMenuClickListenr.onLocalVideoClicked(); 130 | break; 131 | case POSITION_LOCALAUDIO: 132 | if (mMenuClickListenr != null) 133 | mMenuClickListenr.onLocalAudioClicked(); 134 | break; 135 | } 136 | } 137 | 138 | public interface OnMenuClickListener { 139 | public void onPlaylistClicked(); 140 | 141 | public void onLocalVideoClicked(); 142 | 143 | public void onLocalAudioClicked(); 144 | } 145 | 146 | public static class MenuItem { 147 | public MenuItem(int argPosition, int argIconResId, int argTextId) { 148 | position = argPosition; 149 | iconResId = argIconResId; 150 | textId = argTextId; 151 | } 152 | 153 | public int position = -1; 154 | public int iconResId = 0; 155 | public int textId = 0; 156 | } 157 | } 158 | -------------------------------------------------------------------------------- /src/com/mx/vipmediaplayer/ui/VideoPlayerActivity.java: -------------------------------------------------------------------------------- 1 | 2 | package com.mx.vipmediaplayer.ui; 3 | 4 | import io.vov.vitamio.LibsChecker; 5 | import io.vov.vitamio.MediaPlayer; 6 | import io.vov.vitamio.MediaPlayer.OnCompletionListener; 7 | import io.vov.vitamio.MediaPlayer.OnInfoListener; 8 | import io.vov.vitamio.widget.MediaController; 9 | import io.vov.vitamio.widget.VideoView; 10 | import android.app.Activity; 11 | import android.content.Context; 12 | import android.content.Intent; 13 | import android.content.pm.ActivityInfo; 14 | import android.content.res.Configuration; 15 | import android.media.AudioManager; 16 | import android.net.Uri; 17 | import android.os.Bundle; 18 | import android.os.Environment; 19 | import android.os.Handler; 20 | import android.os.Message; 21 | import android.text.TextUtils; 22 | import android.view.Display; 23 | import android.view.GestureDetector; 24 | import android.view.GestureDetector.SimpleOnGestureListener; 25 | import android.view.MotionEvent; 26 | import android.view.View; 27 | import android.view.ViewGroup; 28 | import android.view.WindowManager; 29 | import android.widget.ImageView; 30 | 31 | import com.mx.vipmediaplayer.Logger; 32 | import com.mx.vipmediaplayer.R; 33 | 34 | /** 35 | * Video player activity class 36 | * 37 | * @author Xiao Mei 38 | * @weibo http://weibo.com/u/1675796095 39 | * @email tss_chs@126.com 40 | * 41 | */ 42 | public class VideoPlayerActivity extends Activity implements OnCompletionListener, OnInfoListener { 43 | 44 | private String mPath; 45 | private String mTitle; 46 | private VideoView mVideoView; 47 | private View mVolumeBrightnessLayout; 48 | private ImageView mOperationBg; 49 | private ImageView mOperationPercent; 50 | private AudioManager mAudioManager; 51 | /** 最大声音 */ 52 | private int mMaxVolume; 53 | /** 当前声音 */ 54 | private int mVolume = -1; 55 | /** 当前亮度 */ 56 | private float mBrightness = -1f; 57 | /** 当前缩放模式 */ 58 | private int mLayout = VideoView.VIDEO_LAYOUT_ZOOM; 59 | private GestureDetector mGestureDetector; 60 | private MediaController mMediaController; 61 | private View mLoadingView; 62 | 63 | @Override 64 | public void onCreate(Bundle bundle) { 65 | super.onCreate(bundle); 66 | 67 | // ~~~ 检测Vitamio是否解压解码包 68 | if (!LibsChecker.checkVitamioLibs(this)) 69 | return; 70 | 71 | // ~~~ 获取播放地址和标题 72 | Intent intent = getIntent(); 73 | mPath = intent.getStringExtra("path"); 74 | mTitle = intent.getStringExtra("title"); 75 | if (TextUtils.isEmpty(mPath)) { 76 | mPath = Environment.getExternalStorageDirectory() + "/video/你太猖狂.flv"; 77 | 78 | } else if (intent.getData() != null) 79 | mPath = intent.getData().toString(); 80 | 81 | // ~~~ 绑定控件 82 | setContentView(R.layout.videoview); 83 | mVideoView = (VideoView) findViewById(R.id.surface_view); 84 | mVolumeBrightnessLayout = findViewById(R.id.operation_volume_brightness); 85 | mOperationBg = (ImageView) findViewById(R.id.operation_bg); 86 | mOperationPercent = (ImageView) findViewById(R.id.operation_percent); 87 | mLoadingView = findViewById(R.id.video_loading); 88 | 89 | // ~~~ 绑定事件 90 | mVideoView.setOnCompletionListener(this); 91 | mVideoView.setOnInfoListener(this); 92 | 93 | // ~~~ 绑定数据 94 | mAudioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE); 95 | mMaxVolume = mAudioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC); 96 | if (mPath.startsWith("http:")) 97 | mVideoView.setVideoURI(Uri.parse(mPath)); 98 | else 99 | mVideoView.setVideoPath(mPath); 100 | 101 | //设置显示名称 102 | mMediaController = new MediaController(this); 103 | mMediaController.setFileName(mTitle); 104 | mVideoView.setMediaController(mMediaController); 105 | mVideoView.requestFocus(); 106 | 107 | mGestureDetector = new GestureDetector(this, new MyGestureListener()); 108 | setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE); 109 | } 110 | 111 | @Override 112 | protected void onPause() { 113 | super.onPause(); 114 | if (mVideoView != null) 115 | mVideoView.pause(); 116 | } 117 | 118 | @Override 119 | protected void onResume() { 120 | super.onResume(); 121 | if (mVideoView != null) 122 | mVideoView.resume(); 123 | } 124 | 125 | @Override 126 | protected void onDestroy() { 127 | super.onDestroy(); 128 | if (mVideoView != null) 129 | mVideoView.stopPlayback(); 130 | } 131 | 132 | @Override 133 | public boolean onTouchEvent(MotionEvent event) { 134 | if (mGestureDetector.onTouchEvent(event)) 135 | return true; 136 | 137 | // 处理手势结束 138 | switch (event.getAction() & MotionEvent.ACTION_MASK) { 139 | case MotionEvent.ACTION_UP: 140 | endGesture(); 141 | break; 142 | } 143 | 144 | return super.onTouchEvent(event); 145 | } 146 | 147 | /** 手势结束 */ 148 | private void endGesture() { 149 | mVolume = -1; 150 | mBrightness = -1f; 151 | 152 | // 隐藏 153 | mDismissHandler.removeMessages(0); 154 | mDismissHandler.sendEmptyMessageDelayed(0, 500); 155 | } 156 | 157 | private class MyGestureListener extends SimpleOnGestureListener { 158 | 159 | /** 双击 */ 160 | @Override 161 | public boolean onDoubleTap(MotionEvent e) { 162 | if (mLayout == VideoView.VIDEO_LAYOUT_ZOOM) 163 | mLayout = VideoView.VIDEO_LAYOUT_ORIGIN; 164 | else 165 | mLayout++; 166 | if (mVideoView != null) 167 | mVideoView.setVideoLayout(mLayout, 0); 168 | return true; 169 | } 170 | 171 | /** 滑动 */ 172 | @Override 173 | public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { 174 | float mOldX = e1.getX(), mOldY = e1.getY(); 175 | int y = (int) e2.getRawY(); 176 | Display disp = getWindowManager().getDefaultDisplay(); 177 | int windowWidth = disp.getWidth(); 178 | int windowHeight = disp.getHeight(); 179 | 180 | if (mOldX > windowWidth * 4.0 / 5)// 右边滑动 181 | onVolumeSlide((mOldY - y) / windowHeight); 182 | else if (mOldX < windowWidth / 5.0)// 左边滑动 183 | onBrightnessSlide((mOldY - y) / windowHeight); 184 | 185 | return super.onScroll(e1, e2, distanceX, distanceY); 186 | } 187 | } 188 | 189 | /** 定时隐藏 */ 190 | private Handler mDismissHandler = new Handler() { 191 | @Override 192 | public void handleMessage(Message msg) { 193 | mVolumeBrightnessLayout.setVisibility(View.GONE); 194 | } 195 | }; 196 | 197 | /** 198 | * 滑动改变声音大小 199 | * 200 | * @param percent 201 | */ 202 | private void onVolumeSlide(float percent) { 203 | if (mVolume == -1) { 204 | mVolume = mAudioManager.getStreamVolume(AudioManager.STREAM_MUSIC); 205 | if (mVolume < 0) 206 | mVolume = 0; 207 | 208 | // 显示 209 | mOperationBg.setImageResource(R.drawable.video_volumn_bg); 210 | mVolumeBrightnessLayout.setVisibility(View.VISIBLE); 211 | } 212 | 213 | int index = (int) (percent * mMaxVolume) + mVolume; 214 | if (index > mMaxVolume) 215 | index = mMaxVolume; 216 | else if (index < 0) 217 | index = 0; 218 | 219 | // 变更声音 220 | mAudioManager.setStreamVolume(AudioManager.STREAM_MUSIC, index, 0); 221 | 222 | // 变更进度条 223 | ViewGroup.LayoutParams lp = mOperationPercent.getLayoutParams(); 224 | lp.width = findViewById(R.id.operation_full).getLayoutParams().width * index / mMaxVolume; 225 | mOperationPercent.setLayoutParams(lp); 226 | } 227 | 228 | /** 229 | * 滑动改变亮度 230 | * 231 | * @param percent 232 | */ 233 | private void onBrightnessSlide(float percent) { 234 | if (mBrightness < 0) { 235 | mBrightness = getWindow().getAttributes().screenBrightness; 236 | if (mBrightness <= 0.00f) 237 | mBrightness = 0.50f; 238 | if (mBrightness < 0.01f) 239 | mBrightness = 0.01f; 240 | 241 | // 显示 242 | mOperationBg.setImageResource(R.drawable.video_brightness_bg); 243 | mVolumeBrightnessLayout.setVisibility(View.VISIBLE); 244 | } 245 | WindowManager.LayoutParams lpa = getWindow().getAttributes(); 246 | lpa.screenBrightness = mBrightness + percent; 247 | if (lpa.screenBrightness > 1.0f) 248 | lpa.screenBrightness = 1.0f; 249 | else if (lpa.screenBrightness < 0.01f) 250 | lpa.screenBrightness = 0.01f; 251 | getWindow().setAttributes(lpa); 252 | 253 | ViewGroup.LayoutParams lp = mOperationPercent.getLayoutParams(); 254 | lp.width = (int) (findViewById(R.id.operation_full).getLayoutParams().width * lpa.screenBrightness); 255 | mOperationPercent.setLayoutParams(lp); 256 | } 257 | 258 | @Override 259 | public void onConfigurationChanged(Configuration newConfig) { 260 | if (mVideoView != null) 261 | mVideoView.setVideoLayout(mLayout, 0); 262 | super.onConfigurationChanged(newConfig); 263 | } 264 | 265 | @Override 266 | public void onCompletion(MediaPlayer player) { 267 | finish(); 268 | } 269 | 270 | private void stopPlayer() { 271 | if (mVideoView != null) 272 | mVideoView.pause(); 273 | } 274 | 275 | private void startPlayer() { 276 | if (mVideoView != null) 277 | mVideoView.start(); 278 | } 279 | 280 | private boolean isPlaying() { 281 | return mVideoView != null && mVideoView.isPlaying(); 282 | } 283 | 284 | /** 是否需要自动恢复播放,用于自动暂停,恢复播放 */ 285 | private boolean needResume; 286 | 287 | @Override 288 | public boolean onInfo(MediaPlayer arg0, int arg1, int arg2) { 289 | switch (arg1) { 290 | case MediaPlayer.MEDIA_INFO_BUFFERING_START: 291 | //开始缓存,暂停播放 292 | if (isPlaying()) { 293 | stopPlayer(); 294 | needResume = true; 295 | } 296 | mLoadingView.setVisibility(View.VISIBLE); 297 | break; 298 | case MediaPlayer.MEDIA_INFO_BUFFERING_END: 299 | //缓存完成,继续播放 300 | if (needResume) 301 | startPlayer(); 302 | mLoadingView.setVisibility(View.GONE); 303 | break; 304 | case MediaPlayer.MEDIA_INFO_DOWNLOAD_RATE_CHANGED: 305 | //显示 下载速度 306 | Logger.e("download rate:" + arg2); 307 | //mListener.onDownloadRateChanged(arg2); 308 | break; 309 | } 310 | return true; 311 | } 312 | } 313 | -------------------------------------------------------------------------------- /src/com/mx/vipmediaplayer/ui/helper/XmlReaderHelper.java: -------------------------------------------------------------------------------- 1 | package com.mx.vipmediaplayer.ui.helper; 2 | 3 | import java.io.IOException; 4 | import java.util.ArrayList; 5 | 6 | import javax.xml.parsers.DocumentBuilder; 7 | import javax.xml.parsers.DocumentBuilderFactory; 8 | import javax.xml.parsers.ParserConfigurationException; 9 | 10 | import org.w3c.dom.Document; 11 | import org.w3c.dom.Element; 12 | import org.w3c.dom.NamedNodeMap; 13 | import org.w3c.dom.Node; 14 | import org.w3c.dom.NodeList; 15 | import org.xml.sax.SAXException; 16 | 17 | import android.content.Context; 18 | 19 | import com.mx.vipmediaplayer.model.OnlineVideo; 20 | 21 | /** 22 | * Xml reader class 23 | * 24 | * @author Xiao Mei 25 | * @weibo http://weibo.com/u/1675796095 26 | * @email tss_chs@126.com 27 | * 28 | * 29 | * read tv programs from online.xml 30 | */ 31 | public class XmlReaderHelper { 32 | 33 | /** get all the categories of all tv programs */ 34 | public static ArrayList getAllCategory(final Context context) { 35 | ArrayList result = new ArrayList(); 36 | DocumentBuilderFactory docBuilderFactory = null; 37 | DocumentBuilder docBuilder = null; 38 | Document doc = null; 39 | try { 40 | docBuilderFactory = DocumentBuilderFactory.newInstance(); 41 | docBuilder = docBuilderFactory.newDocumentBuilder(); 42 | // xml file is set in 'assets' folder 43 | doc = docBuilder.parse(context.getResources().getAssets() 44 | .open("online.xml")); 45 | // root element 46 | Element root = doc.getDocumentElement(); 47 | NodeList nodeList = root.getElementsByTagName("category"); 48 | for (int i = 0; i < nodeList.getLength(); i++) { 49 | Node node = nodeList.item(i);// category 50 | OnlineVideo ov = new OnlineVideo(); 51 | NamedNodeMap attr = node.getAttributes(); 52 | ov.title = attr.getNamedItem("name").getNodeValue(); 53 | ov.id = attr.getNamedItem("id").getNodeValue(); 54 | ov.category = 1; 55 | ov.level = 2; 56 | ov.is_category = true; 57 | result.add(ov); 58 | // Read Node 59 | } 60 | } catch (IOException e) { 61 | } catch (SAXException e) { 62 | } catch (ParserConfigurationException e) { 63 | } finally { 64 | doc = null; 65 | docBuilder = null; 66 | docBuilderFactory = null; 67 | } 68 | return result; 69 | } 70 | 71 | /** retrieve all the tv programs url links with different category id */ 72 | public static ArrayList getVideos(final Context context, 73 | String categoryId) { 74 | ArrayList result = new ArrayList(); 75 | DocumentBuilderFactory docBuilderFactory = null; 76 | DocumentBuilder docBuilder = null; 77 | Document doc = null; 78 | try { 79 | docBuilderFactory = DocumentBuilderFactory.newInstance(); 80 | docBuilder = docBuilderFactory.newDocumentBuilder(); 81 | // xml file is set in assets folder 82 | doc = docBuilder.parse(context.getResources().getAssets() 83 | .open("online.xml")); 84 | // root element 85 | Element root = doc.getElementById(categoryId); 86 | if (root != null) { 87 | NodeList nodeList = root.getChildNodes(); 88 | for (int i = 0, j = nodeList.getLength(); i < j; i++) { 89 | Node baseNode = nodeList.item(i); 90 | 91 | if (!"item".equals(baseNode.getNodeName())) 92 | continue; 93 | String id = baseNode.getFirstChild().getNodeValue(); 94 | if (id == null) 95 | continue; 96 | OnlineVideo ov = new OnlineVideo(); 97 | ov.id = id; 98 | 99 | Element el = doc.getElementById(ov.id); 100 | if (el != null) { 101 | ov.title = el.getAttribute("title"); 102 | ov.icon_url = el.getAttribute("image"); 103 | ov.level = 3; 104 | ov.category = 1; 105 | NodeList nodes = el.getChildNodes(); 106 | for (int m = 0, n = nodes.getLength(); m < n; m++) { 107 | Node node = nodes.item(m); 108 | if (!"ref".equals(node.getNodeName())) 109 | continue; 110 | String href = node.getAttributes() 111 | .getNamedItem("href").getNodeValue(); 112 | if (ov.url == null) { 113 | ov.url = href; 114 | } else { 115 | if (ov.backup_url == null) 116 | ov.backup_url = new ArrayList(); 117 | ov.backup_url.add(href); 118 | } 119 | } 120 | if (ov.url != null) 121 | result.add(ov); 122 | } 123 | } 124 | } 125 | } catch (IOException e) { 126 | e.printStackTrace(); 127 | } catch (SAXException e) { 128 | e.printStackTrace(); 129 | } catch (ParserConfigurationException e) { 130 | e.printStackTrace(); 131 | } finally { 132 | doc = null; 133 | docBuilder = null; 134 | docBuilderFactory = null; 135 | } 136 | return result; 137 | } 138 | } 139 | -------------------------------------------------------------------------------- /src/com/mx/vipmediaplayer/util/ConvertUtils.java: -------------------------------------------------------------------------------- 1 | package com.mx.vipmediaplayer.util; 2 | 3 | import android.content.Context; 4 | 5 | /** 6 | * Data convert class 7 | * 8 | * @author Xiao Mei 9 | * @weibo http://weibo.com/u/1675796095 10 | * @email tss_chs@126.com 11 | * 12 | */ 13 | public final class ConvertUtils { 14 | 15 | private static final float UNIT = 1000.0F; 16 | 17 | /** 18 | * 毫秒转秒 19 | * 20 | * @param time 毫秒 21 | * @return 22 | */ 23 | public static float ms2s(long time) { 24 | return time / UNIT; 25 | } 26 | 27 | /** 28 | * 微秒转秒 29 | * 30 | * @param time 微秒 31 | * @return 32 | */ 33 | public static float us2s(long time) { 34 | return time / UNIT / UNIT; 35 | } 36 | 37 | /** 38 | * 纳秒转秒 39 | * 40 | * @param time 纳秒 41 | * @return 42 | */ 43 | public static float ns2s(long time) { 44 | return time / UNIT / UNIT / UNIT; 45 | } 46 | 47 | /** 48 | * 转换字符串为boolean 49 | * 50 | * @param str 51 | * @return 52 | */ 53 | public static boolean toBoolean(String str) { 54 | return toBoolean(str, false); 55 | } 56 | 57 | /** 58 | * 转换字符串为boolean 59 | * 60 | * @param str 61 | * @param def 62 | * @return 63 | */ 64 | public static boolean toBoolean(String str, boolean def) { 65 | if (StringUtils.isEmpty(str)) 66 | return def; 67 | if ("false".equalsIgnoreCase(str) || "0".equals(str)) 68 | return false; 69 | else if ("true".equalsIgnoreCase(str) || "1".equals(str)) 70 | return true; 71 | else 72 | return def; 73 | } 74 | 75 | /** 76 | * 转换字符串为float 77 | * 78 | * @param str 79 | * @return 80 | */ 81 | public static float toFloat(String str) { 82 | return toFloat(str, 0F); 83 | } 84 | 85 | /** 86 | * 转换字符串为float 87 | * 88 | * @param str 89 | * @param def 90 | * @return 91 | */ 92 | public static float toFloat(String str, float def) { 93 | if (StringUtils.isEmpty(str)) 94 | return def; 95 | try { 96 | return Float.parseFloat(str); 97 | } catch (NumberFormatException e) { 98 | return def; 99 | } 100 | } 101 | 102 | /** 103 | * 转换字符串为long 104 | * 105 | * @param str 106 | * @return 107 | */ 108 | public static long toLong(String str) { 109 | return toLong(str, 0L); 110 | } 111 | 112 | /** 113 | * 转换字符串为long 114 | * 115 | * @param str 116 | * @param def 117 | * @return 118 | */ 119 | public static long toLong(String str, long def) { 120 | if (StringUtils.isEmpty(str)) 121 | return def; 122 | try { 123 | return Long.parseLong(str); 124 | } catch (NumberFormatException e) { 125 | return def; 126 | } 127 | } 128 | 129 | /** 130 | * 转换字符串为short 131 | * 132 | * @param str 133 | * @return 134 | */ 135 | public static short toShort(String str) { 136 | return toShort(str, (short) 0); 137 | } 138 | 139 | /** 140 | * 转换字符串为short 141 | * 142 | * @param str 143 | * @param def 144 | * @return 145 | */ 146 | public static short toShort(String str, short def) { 147 | if (StringUtils.isEmpty(str)) 148 | return def; 149 | try { 150 | return Short.parseShort(str); 151 | } catch (NumberFormatException e) { 152 | return def; 153 | } 154 | } 155 | 156 | /** 157 | * 转换字符串为int 158 | * 159 | * @param str 160 | * @return 161 | */ 162 | public static int toInt(String str) { 163 | return toInt(str, 0); 164 | } 165 | 166 | /** 167 | * 转换字符串为int 168 | * 169 | * @param str 170 | * @param def 171 | * @return 172 | */ 173 | public static int toInt(String str, int def) { 174 | if (StringUtils.isEmpty(str)) 175 | return def; 176 | try { 177 | return Integer.parseInt(str); 178 | } catch (NumberFormatException e) { 179 | return def; 180 | } 181 | } 182 | 183 | public static String toString(Object o) { 184 | return toString(o, ""); 185 | } 186 | 187 | public static String toString(Object o, String def) { 188 | if (o == null) 189 | return def; 190 | 191 | return o.toString(); 192 | } 193 | 194 | public static int dipToPX(final Context ctx, int dip) { 195 | float scale = ctx.getResources().getDisplayMetrics().density; 196 | return (int) (dip / 1.5D * scale + 0.5D); 197 | } 198 | } 199 | -------------------------------------------------------------------------------- /src/com/mx/vipmediaplayer/util/FileUtils.java: -------------------------------------------------------------------------------- 1 | package com.mx.vipmediaplayer.util; 2 | 3 | import java.io.File; 4 | import java.sql.SQLException; 5 | import java.util.ArrayList; 6 | import java.util.Arrays; 7 | import java.util.HashMap; 8 | import java.util.HashSet; 9 | import java.util.List; 10 | import java.util.Map; 11 | 12 | import android.os.Environment; 13 | import android.os.StatFs; 14 | import android.util.Log; 15 | 16 | import com.j256.ormlite.dao.Dao; 17 | import com.j256.ormlite.stmt.QueryBuilder; 18 | import com.mx.vipmediaplayer.Logger; 19 | import com.mx.vipmediaplayer.database.SqliteHelperOrm; 20 | import com.mx.vipmediaplayer.model.VIPMedia; 21 | 22 | /** 23 | * File Utils class 24 | * 25 | * @author Xiao Mei 26 | * @weibo http://weibo.com/u/1675796095 27 | * @email tss_chs@126.com 28 | * 29 | */ 30 | public class FileUtils { 31 | // http://www.fileinfo.com/filetypes/video , "dat" , "bin" , "rms" 32 | public static final String[] VIDEO_EXTENSIONS = { "264", "3g2", "3gp", 33 | "3gp2", "3gpp", "3gpp2", "3mm", "3p2", "60d", "aep", "ajp", "amv", 34 | "amx", "arf", "asf", "asx", "avb", "avd", "avi", "avs", "avs", 35 | "axm", "bdm", "bdmv", "bik", "bix", "bmk", "box", "bs4", "bsf", 36 | "byu", "camre", "clpi", "cpi", "cvc", "d2v", "d3v", "dav", "dce", 37 | "dck", "ddat", "dif", "dir", "divx", "dlx", "dmb", "dmsm", "dmss", 38 | "dnc", "dpg", "dream", "dsy", "dv", "dv-avi", "dv4", "dvdmedia", 39 | "dvr-ms", "dvx", "dxr", "dzm", "dzp", "dzt", "evo", "eye", "f4p", 40 | "f4v", "fbr", "fbr", "fbz", "fcp", "flc", "flh", "fli", "flv", 41 | "flx", "gl", "grasp", "gts", "gvi", "gvp", "hdmov", "hkm", "ifo", 42 | "imovi", "imovi", "iva", "ivf", "ivr", "ivs", "izz", "izzy", "jts", 43 | "lsf", "lsx", "m15", "m1pg", "m1v", "m21", "m21", "m2a", "m2p", 44 | "m2t", "m2ts", "m2v", "m4e", "m4u", "m4v", "m75", "meta", "mgv", 45 | "mj2", "mjp", "mjpg", "mkv", "mmv", "mnv", "mod", "modd", "moff", 46 | "moi", "moov", "mov", "movie", "mp21", "mp21", "mp2v", "mp4", 47 | "mp4v", "mpe", "mpeg", "mpeg4", "mpf", "mpg", "mpg2", "mpgin", 48 | "mpl", "mpls", "mpv", "mpv2", "mqv", "msdvd", "msh", "mswmm", 49 | "mts", "mtv", "mvb", "mvc", "mvd", "mve", "mvp", "mxf", "mys", 50 | "ncor", "nsv", "nvc", "ogm", "ogv", "ogx", "osp", "par", "pds", 51 | "pgi", "piv", "playlist", "pmf", "prel", "pro", "prproj", "psh", 52 | "pva", "pvr", "pxv", "qt", "qtch", "qtl", "qtm", "qtz", 53 | "rcproject", "rdb", "rec", "rm", "rmd", "rmp", "rmvb", "roq", "rp", 54 | "rts", "rts", "rum", "rv", "sbk", "sbt", "scm", "scm", "scn", 55 | "sec", "seq", "sfvidcap", "smil", "smk", "sml", "smv", "spl", 56 | "ssm", "str", "stx", "svi", "swf", "swi", "swt", "tda3mt", "tivo", 57 | "tix", "tod", "tp", "tp0", "tpd", "tpr", "trp", "ts", "tvs", "vc1", 58 | "vcr", "vcv", "vdo", "vdr", "veg", "vem", "vf", "vfw", "vfz", 59 | "vgz", "vid", "viewlet", "viv", "vivo", "vlab", "vob", "vp3", 60 | "vp6", "vp7", "vpj", "vro", "vsp", "w32", "wcp", "webm", "wm", 61 | "wmd", "wmmp", "wmv", "wmx", "wp3", "wpl", "wtv", "wvx", "xfl", 62 | "xvid", "yuv", "zm1", "zm2", "zm3", "zmv" }; 63 | // http://www.fileinfo.com/filetypes/audio , "spx" , "mid" , "sf" 64 | public static final String[] AUDIO_EXTENSIONS = { "4mp", "669", "6cm", 65 | "8cm", "8med", "8svx", "a2m", "aa", "aa3", "aac", "aax", "abc", 66 | "abm", "ac3", "acd", "acd-bak", "acd-zip", "acm", "act", "adg", 67 | "afc", "agm", "ahx", "aif", "aifc", "aiff", "ais", "akp", "al", 68 | "alaw", "all", "amf", "amr", "ams", "ams", "aob", "ape", "apf", 69 | "apl", "ase", "at3", "atrac", "au", "aud", "aup", "avr", "awb", 70 | "band", "bap", "bdd", "box", "bun", "bwf", "c01", "caf", "cda", 71 | "cdda", "cdr", "cel", "cfa", "cidb", "cmf", "copy", "cpr", "cpt", 72 | "csh", "cwp", "d00", "d01", "dcf", "dcm", "dct", "ddt", "dewf", 73 | "df2", "dfc", "dig", "dig", "dls", "dm", "dmf", "dmsa", "dmse", 74 | "drg", "dsf", "dsm", "dsp", "dss", "dtm", "dts", "dtshd", "dvf", 75 | "dwd", "ear", "efa", "efe", "efk", "efq", "efs", "efv", "emd", 76 | "emp", "emx", "esps", "f2r", "f32", "f3r", "f4a", "f64", "far", 77 | "fff", "flac", "flp", "fls", "frg", "fsm", "fzb", "fzf", "fzv", 78 | "g721", "g723", "g726", "gig", "gp5", "gpk", "gsm", "gsm", "h0", 79 | "hdp", "hma", "hsb", "ics", "iff", "imf", "imp", "ins", "ins", 80 | "it", "iti", "its", "jam", "k25", "k26", "kar", "kin", "kit", 81 | "kmp", "koz", "koz", "kpl", "krz", "ksc", "ksf", "kt2", "kt3", 82 | "ktp", "l", "la", "lqt", "lso", "lvp", "lwv", "m1a", "m3u", "m4a", 83 | "m4b", "m4p", "m4r", "ma1", "mdl", "med", "mgv", "midi", "miniusf", 84 | "mka", "mlp", "mmf", "mmm", "mmp", "mo3", "mod", "mp1", "mp2", 85 | "mp3", "mpa", "mpc", "mpga", "mpu", "mp_", "mscx", "mscz", "msv", 86 | "mt2", "mt9", "mte", "mti", "mtm", "mtp", "mts", "mus", "mws", 87 | "mxl", "mzp", "nap", "nki", "nra", "nrt", "nsa", "nsf", "nst", 88 | "ntn", "nvf", "nwc", "odm", "oga", "ogg", "okt", "oma", "omf", 89 | "omg", "omx", "ots", "ove", "ovw", "pac", "pat", "pbf", "pca", 90 | "pcast", "pcg", "pcm", "peak", "phy", "pk", "pla", "pls", "pna", 91 | "ppc", "ppcx", "prg", "prg", "psf", "psm", "ptf", "ptm", "pts", 92 | "pvc", "qcp", "r", "r1m", "ra", "ram", "raw", "rax", "rbs", "rcy", 93 | "rex", "rfl", "rmf", "rmi", "rmj", "rmm", "rmx", "rng", "rns", 94 | "rol", "rsn", "rso", "rti", "rtm", "rts", "rvx", "rx2", "s3i", 95 | "s3m", "s3z", "saf", "sam", "sb", "sbg", "sbi", "sbk", "sc2", "sd", 96 | "sd", "sd2", "sd2f", "sdat", "sdii", "sds", "sdt", "sdx", "seg", 97 | "seq", "ses", "sf2", "sfk", "sfl", "shn", "sib", "sid", "sid", 98 | "smf", "smp", "snd", "snd", "snd", "sng", "sng", "sou", "sppack", 99 | "sprg", "sseq", "sseq", "ssnd", "stm", "stx", "sty", "svx", "sw", 100 | "swa", "syh", "syw", "syx", "td0", "tfmx", "thx", "toc", "tsp", 101 | "txw", "u", "ub", "ulaw", "ult", "ulw", "uni", "usf", "usflib", 102 | "uw", "uwf", "vag", "val", "vc3", "vmd", "vmf", "vmf", "voc", 103 | "voi", "vox", "vpm", "vqf", "vrf", "vyf", "w01", "wav", "wav", 104 | "wave", "wax", "wfb", "wfd", "wfp", "wma", "wow", "wpk", "wproj", 105 | "wrk", "wus", "wut", "wv", "wvc", "wve", "wwu", "xa", "xa", "xfs", 106 | "xi", "xm", "xmf", "xmi", "xmz", "xp", "xrns", "xsb", "xspf", "xt", 107 | "xwb", "ym", "zvd", "zvr" }; 108 | 109 | private static final HashSet mHashVideo; 110 | private static final HashSet mHashAudio; 111 | private static final double KB = 1024.0; 112 | private static final double MB = KB * KB; 113 | private static final double GB = KB * KB * KB; 114 | 115 | static { 116 | mHashVideo = new HashSet(Arrays.asList(VIDEO_EXTENSIONS)); 117 | mHashAudio = new HashSet(Arrays.asList(AUDIO_EXTENSIONS)); 118 | } 119 | 120 | /** 是否是音频或者视频 */ 121 | public static boolean isVideoOrAudio(File f) { 122 | final String ext = getFileExtension(f); 123 | return mHashVideo.contains(ext) || mHashAudio.contains(ext); 124 | } 125 | 126 | public static boolean isVideoOrAudio(String f) { 127 | final String ext = getUrlExtension(f); 128 | return mHashVideo.contains(ext) || mHashAudio.contains(ext); 129 | } 130 | 131 | public static boolean isVideo(String f) { 132 | final String ext = getUrlExtension(f); 133 | return mHashVideo.contains(ext); 134 | } 135 | 136 | public static boolean isVideo(File f) { 137 | final String ext = getFileExtension(f); 138 | return mHashVideo.contains(ext); 139 | } 140 | 141 | public static boolean isAudio(File f) { 142 | final String ext = getFileExtension(f); 143 | return mHashAudio.contains(ext); 144 | } 145 | 146 | public static boolean isAudio(String f) { 147 | final String ext = getUrlExtension(f); 148 | return mHashAudio.contains(ext); 149 | } 150 | 151 | /** 获取文件后缀 */ 152 | public static String getFileExtension(File f) { 153 | if (f != null) { 154 | String filename = f.getName(); 155 | int i = filename.lastIndexOf('.'); 156 | if (i > 0 && i < filename.length() - 1) { 157 | return filename.substring(i + 1).toLowerCase(); 158 | } 159 | } 160 | return null; 161 | } 162 | 163 | public static String getUrlFileName(String url) { 164 | int slashIndex = url.lastIndexOf('/'); 165 | int dotIndex = url.lastIndexOf('.'); 166 | String filenameWithoutExtension; 167 | if (dotIndex == -1) { 168 | filenameWithoutExtension = url.substring(slashIndex + 1); 169 | } else { 170 | filenameWithoutExtension = url.substring(slashIndex + 1, dotIndex); 171 | } 172 | return filenameWithoutExtension; 173 | } 174 | 175 | public static String getUrlExtension(String url) { 176 | if (!StringUtils.isEmpty(url)) { 177 | int i = url.lastIndexOf('.'); 178 | if (i > 0 && i < url.length() - 1) { 179 | return url.substring(i + 1).toLowerCase(); 180 | } 181 | } 182 | return ""; 183 | } 184 | 185 | public static String getFileNameNoEx(String filename) { 186 | if ((filename != null) && (filename.length() > 0)) { 187 | int dot = filename.lastIndexOf('.'); 188 | if ((dot > -1) && (dot < (filename.length()))) { 189 | return filename.substring(0, dot); 190 | } 191 | } 192 | return filename; 193 | } 194 | 195 | public static String showFileSize(long size) { 196 | String fileSize; 197 | if (size < KB) 198 | fileSize = size + "B"; 199 | else if (size < MB) 200 | fileSize = String.format("%.1f", size / KB) + "KB"; 201 | else if (size < GB) 202 | fileSize = String.format("%.1f", size / MB) + "MB"; 203 | else 204 | fileSize = String.format("%.1f", size / GB) + "GB"; 205 | 206 | return fileSize; 207 | } 208 | 209 | /** 显示SD卡剩余空间 */ 210 | public static String showFileAvailable() { 211 | String result = ""; 212 | if (Environment.MEDIA_MOUNTED.equals(Environment 213 | .getExternalStorageState())) { 214 | StatFs sf = new StatFs(Environment.getExternalStorageDirectory() 215 | .getPath()); 216 | long blockSize = sf.getBlockSize(); 217 | long blockCount = sf.getBlockCount(); 218 | long availCount = sf.getAvailableBlocks(); 219 | return showFileSize(availCount * blockSize) + " / " 220 | + showFileSize(blockSize * blockCount); 221 | } 222 | return result; 223 | } 224 | 225 | /** 如果不存在就创建 */ 226 | public static boolean createIfNoExists(String path) { 227 | File file = new File(path); 228 | boolean mk = false; 229 | if (!file.exists()) { 230 | mk = file.mkdirs(); 231 | } 232 | return mk; 233 | } 234 | 235 | private static HashMap mMimeType = new HashMap(); 236 | static { 237 | mMimeType.put("M1V", "video/mpeg"); 238 | mMimeType.put("MP2", "video/mpeg"); 239 | mMimeType.put("MPE", "video/mpeg"); 240 | mMimeType.put("MPG", "video/mpeg"); 241 | mMimeType.put("MPEG", "video/mpeg"); 242 | mMimeType.put("MP4", "video/mp4"); 243 | mMimeType.put("M4V", "video/mp4"); 244 | mMimeType.put("3GP", "video/3gpp"); 245 | mMimeType.put("3GPP", "video/3gpp"); 246 | mMimeType.put("3G2", "video/3gpp2"); 247 | mMimeType.put("3GPP2", "video/3gpp2"); 248 | mMimeType.put("MKV", "video/x-matroska"); 249 | mMimeType.put("WEBM", "video/x-matroska"); 250 | mMimeType.put("MTS", "video/mp2ts"); 251 | mMimeType.put("TS", "video/mp2ts"); 252 | mMimeType.put("TP", "video/mp2ts"); 253 | mMimeType.put("WMV", "video/x-ms-wmv"); 254 | mMimeType.put("ASF", "video/x-ms-asf"); 255 | mMimeType.put("ASX", "video/x-ms-asf"); 256 | mMimeType.put("FLV", "video/x-flv"); 257 | mMimeType.put("MOV", "video/quicktime"); 258 | mMimeType.put("QT", "video/quicktime"); 259 | mMimeType.put("RM", "video/x-pn-realvideo"); 260 | mMimeType.put("RMVB", "video/x-pn-realvideo"); 261 | mMimeType.put("VOB", "video/dvd"); 262 | mMimeType.put("DAT", "video/dvd"); 263 | mMimeType.put("AVI", "video/x-divx"); 264 | mMimeType.put("OGV", "video/ogg"); 265 | mMimeType.put("OGG", "video/ogg"); 266 | mMimeType.put("VIV", "video/vnd.vivo"); 267 | mMimeType.put("VIVO", "video/vnd.vivo"); 268 | mMimeType.put("WTV", "video/wtv"); 269 | mMimeType.put("AVS", "video/avs-video"); 270 | mMimeType.put("SWF", "video/x-shockwave-flash"); 271 | mMimeType.put("YUV", "video/x-raw-yuv"); 272 | } 273 | 274 | /** 获取MIME */ 275 | public static String getMimeType(String path) { 276 | int lastDot = path.lastIndexOf("."); 277 | if (lastDot < 0) 278 | return null; 279 | 280 | return mMimeType.get(path.substring(lastDot + 1).toUpperCase()); 281 | } 282 | 283 | /** 多个SD卡时 取外置SD卡 */ 284 | public static String getExternalStorageDirectory() { 285 | // 参考文章 286 | // http://blog.csdn.net/bbmiku/article/details/7937745 287 | Map map = System.getenv(); 288 | String[] values = new String[map.values().size()]; 289 | map.values().toArray(values); 290 | String path = values[values.length - 1]; 291 | Log.e("VIPPlayer", "FileUtils.getExternalStorageDirectory : " + path); 292 | if (path.startsWith("/mnt/") 293 | && !Environment.getExternalStorageDirectory().getAbsolutePath() 294 | .equals(path)) 295 | return path; 296 | else 297 | return null; 298 | } 299 | 300 | public static List getAllSortFiles(int type) { 301 | SqliteHelperOrm db = new SqliteHelperOrm(); 302 | try { 303 | Dao dao = db.getDao(VIPMedia.class); 304 | QueryBuilder query = dao.queryBuilder(); 305 | query.orderBy("title_key", true); 306 | query.where().eq("filetype", type); 307 | return dao.query(query.prepare()); 308 | } catch (SQLException e) { 309 | Logger.e(e); 310 | } finally { 311 | if (db != null) 312 | db.close(); 313 | } 314 | return new ArrayList(); 315 | // new DbHelper().queryForAll(POMedia.class); 316 | } 317 | } 318 | -------------------------------------------------------------------------------- /src/com/mx/vipmediaplayer/util/ImageBuffer.java: -------------------------------------------------------------------------------- 1 | package com.mx.vipmediaplayer.util; 2 | 3 | import java.io.File; 4 | import java.io.FilenameFilter; 5 | import java.util.ArrayList; 6 | import java.util.Collections; 7 | import java.util.Comparator; 8 | import java.util.LinkedList; 9 | import java.util.List; 10 | import java.util.regex.Matcher; 11 | import java.util.regex.Pattern; 12 | 13 | import android.graphics.Bitmap; 14 | import android.graphics.BitmapFactory; 15 | 16 | import com.mx.vipmediaplayer.Logger; 17 | import com.mx.vipmediaplayer.VIPMediaPlayerApplication; 18 | import com.mx.vipmediaplayer.model.VIPMedia; 19 | import com.mx.vipmediaplayer.model.VIPMediaBitmap; 20 | 21 | /** 22 | * Image Buffer class 23 | * 24 | * @author Xiao Mei 25 | * @weibo http://weibo.com/u/1675796095 26 | * @email tss_chs@126.com 27 | * 28 | */ 29 | 30 | public class ImageBuffer { 31 | // private static Context context; 32 | private static File bufferFolder = new File(VIPMediaPlayerApplication.VIPPLAYER_VIDEO_THUMB); 33 | 34 | public final static int MaxBufferSize = (int) (5 * 1024 * 1024); 35 | private static List bufferImgs; 36 | private static int curBufferSize; 37 | 38 | public final static int MaxMemorySize = (int) (10 * 1024 * 1024); 39 | private static List memoryImgs; 40 | public static int curMemorySize; 41 | 42 | static { 43 | initBuffer(); 44 | } 45 | 46 | private static void initBuffer() { 47 | bufferImgs = new ArrayList(); 48 | File[] imgs = bufferFolder.listFiles(new FilenameFilter() { 49 | @Override 50 | public boolean accept(File dir, String filename) { 51 | if (filename.endsWith(".jpg") || filename.endsWith(".jpeg") 52 | || filename.endsWith(".gif") 53 | || filename.endsWith(".png") 54 | || filename.endsWith(".bmp")) 55 | return true; 56 | return false; 57 | } 58 | }); 59 | curBufferSize = 0; 60 | for (File f : imgs) { 61 | bufferImgs.add(f); 62 | curBufferSize += f.length(); 63 | } 64 | Collections.sort(bufferImgs, new FileTimeComparator()); 65 | memoryImgs = new LinkedList(); 66 | curMemorySize = 0; 67 | } 68 | 69 | /** 70 | * add a file to buffer 71 | */ 72 | private static void addFile(File file) { 73 | bufferImgs.add(file); 74 | curBufferSize += file.length(); 75 | if (curBufferSize > MaxBufferSize) 76 | deleteFileByTime(); 77 | } 78 | 79 | /** 80 | * add a bitmap to memory 81 | */ 82 | private static void addThumBitmap(VIPMediaBitmap ub) { 83 | memoryImgs.add(ub); 84 | curMemorySize += ub.getImgSize(); 85 | if (curMemorySize > MaxMemorySize) 86 | deleteHalfMemoryImg(); 87 | } 88 | 89 | /** 90 | * delete half files in buffer 91 | */ 92 | private static void deleteFileByTime() { 93 | int halfCount = bufferImgs.size() / 2; 94 | for (int i = 0; i < halfCount; i++) { 95 | curBufferSize -= bufferImgs.get(0).length(); 96 | bufferImgs.get(0).delete(); 97 | bufferImgs.remove(0); 98 | } 99 | } 100 | 101 | /** 102 | * delete half reference in memory 103 | */ 104 | public static void deleteHalfMemoryImg() { 105 | int halfCount = memoryImgs.size() / 2; 106 | for (int i = 0; i < halfCount; i++) { 107 | curMemorySize -= memoryImgs.get(0).getImgSize(); 108 | VIPMediaBitmap u = memoryImgs.remove(0); 109 | u.getImg().recycle(); 110 | } 111 | } 112 | 113 | private static Object readLock = new Object(); 114 | 115 | private static final int MaxSingleFileSize = 400 * 1024; 116 | 117 | private static final int MaxSingleGIFFileSize = 2 * 1024 * 1024; 118 | 119 | /*** 120 | * first try to read url from memory. if not exists then try to read it from 121 | * buffer. if still not exists then return null. 122 | */ 123 | public static Bitmap readImg(VIPMedia media) { 124 | if (media.path == null || media.path.length() == 0) 125 | return null; 126 | try { 127 | synchronized (readLock) { 128 | VIPMediaBitmap ub = readImgFromMem(media.thumb_path); 129 | if (ub != null) { 130 | Logger.d("Read from memory: " + media.thumb_path); 131 | return ub.getImg(); 132 | } 133 | File file = new File(media.thumb_path); 134 | if (!file.exists()) 135 | return null; 136 | if (file.length() > MaxSingleFileSize 137 | && !media.thumb_path.toLowerCase().endsWith("gif") 138 | || file.length() > MaxSingleGIFFileSize) { 139 | Logger.d("File cannot be loaded, file size: " 140 | + file.length() + ", file thumpath:" + media.thumb_path); 141 | return null; 142 | } 143 | Bitmap bt = BitmapFactory.decodeFile(media.thumb_path); 144 | // Bitmap bt = BitmapFactory.decodeFile(pathName); 145 | 146 | if (bt != null) { 147 | if (bt.getWidth() <= 200 && bt.getHeight() <= 200) { 148 | addThumBitmap(new VIPMediaBitmap(bt, media)); 149 | Logger.d("Read from file: " + media.thumb_path); 150 | } 151 | } else { 152 | deleteFileFromBuffer(media.thumb_path); 153 | throw new Exception("Cannot decode " + media.thumb_path); 154 | } 155 | return bt; 156 | } 157 | } catch (OutOfMemoryError err) { 158 | Logger.d(err.getMessage()); 159 | } catch (Exception e) { 160 | Logger.d("Error in reading " + media.thumb_path + ", Error: " 161 | + e.getClass().toString() + " " + e.getMessage()); 162 | } 163 | return null; 164 | } 165 | 166 | /** 167 | * try to read img from memory 168 | */ 169 | private static VIPMediaBitmap readImgFromMem(String thumpath) { 170 | VIPMediaBitmap res = null; 171 | for (VIPMediaBitmap ub : memoryImgs) 172 | if (ub.getVipmedia().thumb_path.equals(thumpath)) 173 | res = ub; 174 | if (res != null) { 175 | memoryImgs.remove(res); 176 | memoryImgs.add(res); 177 | } 178 | return res; 179 | } 180 | 181 | /** 182 | * read img async, try to download it if the img doesn't exist in local. 183 | */ 184 | // public static void readBitmapAsync(String url, 185 | // MethodHandler handler) { 186 | // Bitmap bt = readImg(url); 187 | // if (bt == null) { 188 | // LoadImgThread thread = new LoadImgThread(url, handler); 189 | // thread.start(); 190 | // } else 191 | // handler.process(new UrlBitmap(bt, url)); 192 | // } 193 | 194 | public static void deleteBitmap(String thumpath) { 195 | deleteFileFromMemory(thumpath); 196 | deleteFileFromBuffer(thumpath); 197 | File file = new File(thumpath); 198 | file.delete(); 199 | } 200 | 201 | private static void deleteFileFromMemory(String thumpath) { 202 | for (VIPMediaBitmap ub : memoryImgs) { 203 | if (ub.getVipmedia().thumb_path.equals(thumpath)) { 204 | memoryImgs.remove(ub); 205 | curMemorySize -= ub.getImgSize(); 206 | ub.getImg().recycle(); 207 | break; 208 | } 209 | } 210 | } 211 | 212 | /** 213 | * delete specified file by url. 214 | * 215 | * @param url 216 | */ 217 | private static void deleteFileFromBuffer(String url) { 218 | String name = getNameFromUrl(url); 219 | File file = null; 220 | for (File f : bufferImgs) 221 | if (f.getName().equals(name)) { 222 | file = f; 223 | break; 224 | } 225 | if (file != null) { 226 | bufferImgs.remove(file); 227 | curBufferSize -= file.length(); 228 | file.delete(); 229 | } 230 | } 231 | 232 | /** 233 | * read img async, try to download it if the img doesn't exist in local. 234 | */ 235 | // public static void readSameBitmapAsync(String url, 236 | // MethodHandler handler) { 237 | // Bitmap bt = readImg(url); 238 | // if (bt == null) { 239 | // LoadSameImgThread thread = new LoadSameImgThread(url, handler); 240 | // ThreadPool.execute(thread); 241 | // } else 242 | // handler.process(new UrlBitmap(bt, url)); 243 | // } 244 | 245 | private static Pattern FileNamePattern = Pattern.compile("[^\\d\\w\\._]+"); 246 | 247 | private static String getNameFromUrl(String url) { 248 | String res = url; 249 | Matcher m = FileNamePattern.matcher(res); 250 | res = m.replaceAll("_"); 251 | return res; 252 | } 253 | 254 | public static class FileTimeComparator implements Comparator { 255 | 256 | public int compare(File object1, File object2) { 257 | long i1 = object1.lastModified(); 258 | long i2 = object2.lastModified(); 259 | if(i1 > i2) 260 | return -1; 261 | else if(i1 < i2) 262 | return 1; 263 | return 0; 264 | } 265 | } 266 | } 267 | -------------------------------------------------------------------------------- /src/com/mx/vipmediaplayer/util/ImageLoadUtils.java: -------------------------------------------------------------------------------- 1 | package com.mx.vipmediaplayer.util; 2 | 3 | import java.util.concurrent.ArrayBlockingQueue; 4 | import java.util.concurrent.ThreadPoolExecutor; 5 | import java.util.concurrent.TimeUnit; 6 | 7 | import android.graphics.Bitmap; 8 | import android.graphics.BitmapFactory; 9 | 10 | import com.mx.vipmediaplayer.model.VIPMedia; 11 | import com.mx.vipmediaplayer.model.VIPMediaBitmap; 12 | import com.mx.vipmediaplayer.services.MediaScanService; 13 | 14 | /** 15 | * Image Load class 16 | * 17 | * @author Xiao Mei 18 | * @weibo http://weibo.com/u/1675796095 19 | * @email tss_chs@126.com 20 | * 21 | */ 22 | public class ImageLoadUtils { 23 | 24 | static ThreadPoolExecutor threadPool = new ThreadPoolExecutor(20, 40, 3, 25 | TimeUnit.SECONDS, new ArrayBlockingQueue(50), 26 | new ThreadPoolExecutor.DiscardOldestPolicy()); 27 | 28 | public static class LoadImgThread extends Thread { 29 | 30 | private VIPMedia media; 31 | private MethodHandler handler; 32 | 33 | public LoadImgThread(VIPMedia argmedia, 34 | MethodHandler arghandler) { 35 | media = argmedia; 36 | handler = arghandler; 37 | } 38 | 39 | @Override 40 | public void run() { 41 | MediaScanService.extractThumbnail(media); 42 | Bitmap bt = BitmapFactory.decodeFile(media.thumb_path); 43 | VIPMediaBitmap tb = new VIPMediaBitmap(bt, media); 44 | handler.process(tb); 45 | } 46 | } 47 | 48 | public static void readBitmapAsync(VIPMedia media, 49 | MethodHandler handler) { 50 | Bitmap bt = readImg(media); 51 | if (bt == null) { 52 | LoadImgThread thread = new LoadImgThread(media, handler); 53 | threadPool.execute(thread); 54 | } else { 55 | if (handler != null) { 56 | handler.process(new VIPMediaBitmap(bt, media)); 57 | } 58 | } 59 | } 60 | 61 | public static Bitmap readImg(VIPMedia media) { 62 | return ImageBuffer.readImg(media); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/com/mx/vipmediaplayer/util/MethodHandler.java: -------------------------------------------------------------------------------- 1 | package com.mx.vipmediaplayer.util; 2 | 3 | /** 4 | * Method Handler class 5 | * 6 | * @author Xiao Mei 7 | * @weibo http://weibo.com/u/1675796095 8 | * @email tss_chs@126.com 9 | * 10 | */ 11 | public interface MethodHandler

{ 12 | public void process(P para); 13 | 14 | } 15 | -------------------------------------------------------------------------------- /src/com/mx/vipmediaplayer/util/PinyinUtils.java: -------------------------------------------------------------------------------- 1 | package com.mx.vipmediaplayer.util; 2 | 3 | import net.sourceforge.pinyin4j.PinyinHelper; 4 | import net.sourceforge.pinyin4j.format.HanyuPinyinCaseType; 5 | import net.sourceforge.pinyin4j.format.HanyuPinyinOutputFormat; 6 | import net.sourceforge.pinyin4j.format.HanyuPinyinToneType; 7 | import net.sourceforge.pinyin4j.format.exception.BadHanyuPinyinOutputFormatCombination; 8 | 9 | /** 10 | * Pinyi Utils class 11 | * 12 | * @author Xiao Mei 13 | * @weibo http://weibo.com/u/1675796095 14 | * @email tss_chs@126.com 15 | * 16 | */ 17 | public final class PinyinUtils { 18 | 19 | private static HanyuPinyinOutputFormat spellFormat = new HanyuPinyinOutputFormat(); 20 | 21 | static { 22 | spellFormat.setCaseType(HanyuPinyinCaseType.LOWERCASE); 23 | spellFormat.setToneType(HanyuPinyinToneType.WITHOUT_TONE); 24 | //spellFormat.setVCharType(HanyuPinyinVCharType.WITH_V); 25 | } 26 | 27 | public static String chineneToSpell(String chineseStr) throws BadHanyuPinyinOutputFormatCombination { 28 | StringBuffer result = new StringBuffer(); 29 | for (char c : chineseStr.toCharArray()) { 30 | if (c > 128) { 31 | String[] array = PinyinHelper.toHanyuPinyinStringArray(c, spellFormat); 32 | if (array != null && array.length > 0) 33 | result.append(array[0]); 34 | else 35 | result.append(" "); 36 | } else 37 | result.append(c); 38 | } 39 | return result.toString(); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/com/mx/vipmediaplayer/util/StringUtils.java: -------------------------------------------------------------------------------- 1 | package com.mx.vipmediaplayer.util; 2 | 3 | import java.text.SimpleDateFormat; 4 | import java.util.ArrayList; 5 | import java.util.Date; 6 | 7 | /** 8 | * String Utils class 9 | * 10 | * @author Xiao Mei 11 | * @weibo http://weibo.com/u/1675796095 12 | * @email tss_chs@126.com 13 | * 14 | */ 15 | public class StringUtils { 16 | private static final String DEFAULT_DATE_PATTERN = "yyyy-MM-dd"; 17 | private static final String DEFAULT_DATETIME_PATTERN = "yyyy-MM-dd hh:mm:ss"; 18 | public final static String EMPTY = ""; 19 | 20 | /** 21 | * 格式化日期字符串 22 | * 23 | * @param date 24 | * @param pattern 25 | * @return 26 | */ 27 | public static String formatDate(Date date, String pattern) { 28 | SimpleDateFormat format = new SimpleDateFormat(pattern); 29 | return format.format(date); 30 | } 31 | 32 | /** 33 | * 格式化日期字符串 34 | * 35 | * @param date 36 | * @return 例如2011-3-24 37 | */ 38 | public static String formatDate(Date date) { 39 | return formatDate(date, DEFAULT_DATE_PATTERN); 40 | } 41 | 42 | /** 43 | * 获取当前时间 格式为yyyy-MM-dd 例如2011-07-08 44 | * 45 | * @return 46 | */ 47 | public static String getDate() { 48 | return formatDate(new Date(), DEFAULT_DATE_PATTERN); 49 | } 50 | 51 | /** 52 | * 获取当前时间 53 | * 54 | * @return 55 | */ 56 | public static String getDateTime() { 57 | return formatDate(new Date(), DEFAULT_DATETIME_PATTERN); 58 | } 59 | 60 | /** 61 | * 格式化日期时间字符串 62 | * 63 | * @param date 64 | * @return 例如2011-11-30 16:06:54 65 | */ 66 | public static String formatDateTime(Date date) { 67 | return formatDate(date, DEFAULT_DATETIME_PATTERN); 68 | } 69 | 70 | public static String join(final ArrayList array, String separator) { 71 | StringBuffer result = new StringBuffer(); 72 | if (array != null && array.size() > 0) { 73 | for (String str : array) { 74 | result.append(str); 75 | result.append(separator); 76 | } 77 | result.delete(result.length() - 1, result.length()); 78 | } 79 | return result.toString(); 80 | } 81 | 82 | public static boolean isEmpty(String str) { 83 | return str == null || str.length() == 0; 84 | } 85 | 86 | // public static String trim(String str) { 87 | // if (IsUtil.isNullOrEmpty(str)) { 88 | // return ""; 89 | // } 90 | // return str.trim(); 91 | // } 92 | // 93 | // /** 将中文转换成unicode编码 */ 94 | // public static String gbEncoding(final String gbString) { 95 | // char[] utfBytes = gbString.toCharArray(); 96 | // String unicodeBytes = ""; 97 | // for (char utfByte : utfBytes) { 98 | // String hexB = Integer.toHexString(utfByte); 99 | // if (hexB.length() <= 2) { 100 | // hexB = "00" + hexB; 101 | // } 102 | // unicodeBytes = unicodeBytes + "\\u" + hexB; 103 | // } 104 | // //System.out.println("unicodeBytes is: " + unicodeBytes); 105 | // return unicodeBytes; 106 | // } 107 | // 108 | // /** 将unicode编码转换成中�?*/ 109 | // public static String decodeUnicode(final String dataStr) { 110 | // int start = 0; 111 | // int end = 0; 112 | // final StringBuffer buffer = new StringBuffer(); 113 | // while (start > -1) { 114 | // end = dataStr.indexOf("\\u", start + 2); 115 | // String charStr = ""; 116 | // if (end == -1) { 117 | // charStr = dataStr.substring(start + 2, dataStr.length()); 118 | // } else { 119 | // charStr = dataStr.substring(start + 2, end); 120 | // } 121 | // char letter = (char) Integer.parseInt(charStr, 16); // 16进制parse整形字符串�? 122 | // buffer.append(new Character(letter).toString()); 123 | // start = end; 124 | // } 125 | // //System.out.println(buffer.toString()); 126 | // return buffer.toString(); 127 | // } 128 | 129 | } 130 | -------------------------------------------------------------------------------- /src/io/vov/vitamio/.svn/all-wcprops: -------------------------------------------------------------------------------- 1 | K 25 2 | svn:wc:ra_dav:version-url 3 | V 56 4 | /svn/oplayer/!svn/ver/8/trunk/OPlayer/src/io/vov/vitamio 5 | END 6 | R.java 7 | K 25 8 | svn:wc:ra_dav:version-url 9 | V 63 10 | /svn/oplayer/!svn/ver/8/trunk/OPlayer/src/io/vov/vitamio/R.java 11 | END 12 | -------------------------------------------------------------------------------- /src/io/vov/vitamio/.svn/entries: -------------------------------------------------------------------------------- 1 | 10 2 | 3 | dir 4 | 11 5 | http://code.taobao.org/svn/oplayer/trunk/OPlayer/src/io/vov/vitamio 6 | http://code.taobao.org/svn/oplayer 7 | 8 | 9 | 10 | 2012-11-07T09:11:36.592339Z 11 | 8 12 | over140@gmail.com 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 11631169-8b53-4088-bc37-abf19808aea1 28 | 29 | R.java 30 | file 31 | 32 | 33 | 34 | 35 | 2013-07-19T13:52:20.234375Z 36 | a821d8bb44a90d63c0dd58d478818128 37 | 2012-11-07T09:11:36.592339Z 38 | 8 39 | over140@gmail.com 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 206 62 | 63 | widget 64 | dir 65 | 66 | -------------------------------------------------------------------------------- /src/io/vov/vitamio/.svn/text-base/R.java.svn-base: -------------------------------------------------------------------------------- 1 | package io.vov.vitamio; 2 | 3 | public class R { 4 | public static final class raw { 5 | public static final int libarm = com.nmbb.oplayer.R.raw.libarm; 6 | public static final int pub = com.nmbb.oplayer.R.raw.pub; 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/io/vov/vitamio/R.java: -------------------------------------------------------------------------------- 1 | package io.vov.vitamio; 2 | 3 | public class R { 4 | public static final class raw { 5 | public static final int libarm = com.mx.vipmediaplayer.R.raw.libarm; 6 | public static final int pub = com.mx.vipmediaplayer.R.raw.pub; 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/io/vov/vitamio/activity/InitActivity.java: -------------------------------------------------------------------------------- 1 | package io.vov.vitamio.activity; 2 | 3 | import io.vov.vitamio.Vitamio; 4 | import android.app.Activity; 5 | import android.app.ProgressDialog; 6 | import android.content.Intent; 7 | import android.os.AsyncTask; 8 | import android.os.Bundle; 9 | import android.os.Handler; 10 | import android.os.Message; 11 | import android.view.WindowManager; 12 | 13 | import com.mx.vipmediaplayer.R; 14 | 15 | public class InitActivity extends Activity { 16 | public static final String FROM_ME = "fromVitamioInitActivity"; 17 | public static final String EXTRA_MSG = "EXTRA_MSG"; 18 | public static final String EXTRA_FILE = "EXTRA_FILE"; 19 | private ProgressDialog mPD; 20 | 21 | @Override 22 | protected void onCreate(Bundle savedInstanceState) { 23 | super.onCreate(savedInstanceState); 24 | getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); 25 | 26 | new AsyncTask() { 27 | @Override 28 | protected void onPreExecute() { 29 | mPD = new ProgressDialog(InitActivity.this); 30 | mPD.setCancelable(false); 31 | mPD.setMessage(getText(R.string.init_decoders)); 32 | mPD.show(); 33 | } 34 | 35 | @Override 36 | protected Object doInBackground(Object... params) { 37 | 38 | Vitamio.initialize(getApplicationContext()); 39 | // if (Vitamio.isInitialized(getApplicationContext())) 40 | // return null; 41 | // 42 | // //反射解压 43 | // try { 44 | // Class c = Class.forName("io.vov.vitamio.Vitamio"); 45 | // Method extractLibs = c.getDeclaredMethod("extractLibs", new Class[] { android.content.Context.class, int.class }); 46 | // extractLibs.setAccessible(true); 47 | // extractLibs.invoke(c, new Object[] { getApplicationContext(), R.raw.libarm }); 48 | // 49 | //// Field vitamioLibraryPath = c.getDeclaredField("vitamioLibraryPath"); 50 | //// 51 | //// AndroidContextUtils.getDataDir(ctx) + "libs/" 52 | // 53 | // } catch (NoSuchMethodException e) { 54 | // Log.e("extractLibs", e); 55 | // e.printStackTrace(); 56 | // } catch (IllegalArgumentException e) { 57 | // e.printStackTrace(); 58 | // } catch (IllegalAccessException e) { 59 | // e.printStackTrace(); 60 | // } catch (InvocationTargetException e) { 61 | // e.printStackTrace(); 62 | // } catch (ClassNotFoundException e) { 63 | // e.printStackTrace(); 64 | // } 65 | 66 | uiHandler.sendEmptyMessage(0); 67 | return null; 68 | } 69 | }.execute(); 70 | } 71 | 72 | private Handler uiHandler = new Handler() { 73 | @Override 74 | public void handleMessage(Message msg) { 75 | mPD.dismiss(); 76 | Intent src = getIntent(); 77 | Intent i = new Intent(); 78 | i.setClassName(src.getStringExtra("package"), src.getStringExtra("className")); 79 | i.setData(src.getData()); 80 | i.putExtras(src); 81 | i.putExtra(FROM_ME, true); 82 | startActivity(i); 83 | 84 | finish(); 85 | } 86 | }; 87 | } 88 | -------------------------------------------------------------------------------- /src/io/vov/vitamio/widget/CenterLayout.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2011 VOV IO (http://vov.io/) 3 | */ 4 | 5 | package io.vov.vitamio.widget; 6 | 7 | import android.content.Context; 8 | import android.util.AttributeSet; 9 | import android.view.View; 10 | import android.view.ViewGroup; 11 | import android.widget.RemoteViews.RemoteView; 12 | 13 | @RemoteView 14 | public class CenterLayout extends ViewGroup { 15 | private int mPaddingLeft = 0; 16 | private int mPaddingRight = 0; 17 | private int mPaddingTop = 0; 18 | private int mPaddingBottom = 0; 19 | private int mWidth, mHeight; 20 | 21 | public CenterLayout(Context context) { 22 | super(context); 23 | } 24 | 25 | public CenterLayout(Context context, AttributeSet attrs) { 26 | super(context, attrs); 27 | } 28 | 29 | public CenterLayout(Context context, AttributeSet attrs, int defStyle) { 30 | super(context, attrs, defStyle); 31 | } 32 | 33 | @Override 34 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 35 | int count = getChildCount(); 36 | 37 | int maxHeight = 0; 38 | int maxWidth = 0; 39 | 40 | measureChildren(widthMeasureSpec, heightMeasureSpec); 41 | 42 | for (int i = 0; i < count; i++) { 43 | View child = getChildAt(i); 44 | if (child.getVisibility() != GONE) { 45 | int childRight; 46 | int childBottom; 47 | 48 | CenterLayout.LayoutParams lp = (CenterLayout.LayoutParams) child.getLayoutParams(); 49 | 50 | childRight = lp.x + child.getMeasuredWidth(); 51 | childBottom = lp.y + child.getMeasuredHeight(); 52 | 53 | maxWidth = Math.max(maxWidth, childRight); 54 | maxHeight = Math.max(maxHeight, childBottom); 55 | } 56 | } 57 | 58 | maxWidth += mPaddingLeft + mPaddingRight; 59 | maxHeight += mPaddingTop + mPaddingBottom; 60 | 61 | maxHeight = Math.max(maxHeight, getSuggestedMinimumHeight()); 62 | maxWidth = Math.max(maxWidth, getSuggestedMinimumWidth()); 63 | 64 | setMeasuredDimension(resolveSize(maxWidth, widthMeasureSpec), resolveSize(maxHeight, heightMeasureSpec)); 65 | } 66 | 67 | @Override 68 | protected void onLayout(boolean changed, int l, int t, int r, int b) { 69 | int count = getChildCount(); 70 | mWidth = getMeasuredWidth(); 71 | mHeight = getMeasuredHeight(); 72 | for (int i = 0; i < count; i++) { 73 | View child = getChildAt(i); 74 | if (child.getVisibility() != GONE) { 75 | CenterLayout.LayoutParams lp = (CenterLayout.LayoutParams) child.getLayoutParams(); 76 | int childLeft = mPaddingLeft + lp.x; 77 | if (lp.width > 0) 78 | childLeft += (int) ((mWidth - lp.width) / 2.0); 79 | else 80 | childLeft += (int) ((mWidth - child.getMeasuredWidth()) / 2.0); 81 | int childTop = mPaddingTop + lp.y; 82 | if (lp.height > 0) 83 | childTop += (int) ((mHeight - lp.height) / 2.0); 84 | else 85 | childTop += (int) ((mHeight - child.getMeasuredHeight()) / 2.0); 86 | child.layout(childLeft, childTop, childLeft + child.getMeasuredWidth(), childTop + child.getMeasuredHeight()); 87 | } 88 | } 89 | } 90 | 91 | @Override 92 | protected boolean checkLayoutParams(ViewGroup.LayoutParams p) { 93 | return p instanceof CenterLayout.LayoutParams; 94 | } 95 | 96 | @Override 97 | protected ViewGroup.LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) { 98 | return new LayoutParams(p); 99 | } 100 | 101 | public static class LayoutParams extends ViewGroup.LayoutParams { 102 | public int x; 103 | public int y; 104 | 105 | public LayoutParams(int width, int height, int x, int y) { 106 | super(width, height); 107 | this.x = x; 108 | this.y = y; 109 | } 110 | 111 | public LayoutParams(ViewGroup.LayoutParams source) { 112 | super(source); 113 | } 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /src/io/vov/vitamio/widget/MediaController.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2011 VOV IO (http://vov.io/) 3 | */ 4 | 5 | package io.vov.vitamio.widget; 6 | 7 | import io.vov.utils.Log; 8 | import io.vov.utils.StringUtils; 9 | import android.content.Context; 10 | import android.graphics.Rect; 11 | import android.media.AudioManager; 12 | import android.os.Handler; 13 | import android.os.Message; 14 | import android.util.AttributeSet; 15 | import android.view.Gravity; 16 | import android.view.KeyEvent; 17 | import android.view.LayoutInflater; 18 | import android.view.MotionEvent; 19 | import android.view.View; 20 | import android.widget.FrameLayout; 21 | import android.widget.ImageButton; 22 | import android.widget.PopupWindow; 23 | import android.widget.ProgressBar; 24 | import android.widget.SeekBar; 25 | import android.widget.SeekBar.OnSeekBarChangeListener; 26 | import android.widget.TextView; 27 | 28 | import com.mx.vipmediaplayer.R; 29 | 30 | 31 | /** 32 | * A view containing controls for a MediaPlayer. Typically contains the buttons 33 | * like "Play/Pause" and a progress slider. It takes care of synchronizing the 34 | * controls with the state of the MediaPlayer. 35 | *

36 | * The way to use this class is to a) instantiate it programatically or b) 37 | * create it in your xml layout. 38 | * 39 | * a) The MediaController will create a default set of controls and put them in 40 | * a window floating above your application. Specifically, the controls will 41 | * float above the view specified with setAnchorView(). By default, the window 42 | * will disappear if left idle for three seconds and reappear when the user 43 | * touches the anchor view. To customize the MediaController's style, layout and 44 | * controls you should extend MediaController and override the {#link 45 | * {@link #makeControllerView()} method. 46 | * 47 | * b) The MediaController is a FrameLayout, you can put it in your layout xml 48 | * and get it through {@link #findViewById(int)}. 49 | * 50 | * NOTES: In each way, if you want customize the MediaController, the SeekBar's 51 | * id must be mediacontroller_progress, the Play/Pause's must be 52 | * mediacontroller_pause, current time's must be mediacontroller_time_current, 53 | * total time's must be mediacontroller_time_total, file name's must be 54 | * mediacontroller_file_name. And your resources must have a pause_button 55 | * drawable and a play_button drawable. 56 | *

57 | * Functions like show() and hide() have no effect when MediaController is 58 | * created in an xml layout. 59 | */ 60 | public class MediaController extends FrameLayout { 61 | private MediaPlayerControl mPlayer; 62 | private Context mContext; 63 | private PopupWindow mWindow; 64 | private int mAnimStyle; 65 | private View mAnchor; 66 | private View mRoot; 67 | private ProgressBar mProgress; 68 | private TextView mEndTime, mCurrentTime; 69 | private TextView mFileName; 70 | private OutlineTextView mInfoView; 71 | private String mTitle; 72 | private long mDuration; 73 | private boolean mShowing; 74 | private boolean mDragging; 75 | private boolean mInstantSeeking = true; 76 | private static final int sDefaultTimeout = 3000; 77 | private static final int FADE_OUT = 1; 78 | private static final int SHOW_PROGRESS = 2; 79 | private boolean mFromXml = false; 80 | private ImageButton mPauseButton; 81 | 82 | private AudioManager mAM; 83 | 84 | public MediaController(Context context, AttributeSet attrs) { 85 | super(context, attrs); 86 | mRoot = this; 87 | mFromXml = true; 88 | initController(context); 89 | } 90 | 91 | public MediaController(Context context) { 92 | super(context); 93 | if (!mFromXml && initController(context)) 94 | initFloatingWindow(); 95 | } 96 | 97 | private boolean initController(Context context) { 98 | mContext = context; 99 | mAM = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE); 100 | return true; 101 | } 102 | 103 | @Override 104 | public void onFinishInflate() { 105 | if (mRoot != null) 106 | initControllerView(mRoot); 107 | } 108 | 109 | private void initFloatingWindow() { 110 | mWindow = new PopupWindow(mContext); 111 | mWindow.setFocusable(false); 112 | mWindow.setBackgroundDrawable(null); 113 | mWindow.setOutsideTouchable(true); 114 | // mAnimStyle = android.R.style.Animation; 115 | mAnimStyle = R.style.MediaController_anim_style; 116 | } 117 | 118 | /** 119 | * Set the view that acts as the anchor for the control view. This can for 120 | * example be a VideoView, or your Activity's main view. 121 | * 122 | * @param view The view to which to anchor the controller when it is visible. 123 | */ 124 | public void setAnchorView(View view) { 125 | mAnchor = view; 126 | if (!mFromXml) { 127 | removeAllViews(); 128 | mRoot = makeControllerView(); 129 | mWindow.setContentView(mRoot); 130 | mWindow.setWidth(android.view.ViewGroup.LayoutParams.MATCH_PARENT); 131 | mWindow.setHeight(android.view.ViewGroup.LayoutParams.WRAP_CONTENT); 132 | } 133 | initControllerView(mRoot); 134 | } 135 | 136 | /** 137 | * Create the view that holds the widgets that control playback. Derived 138 | * classes can override this to create their own. 139 | * 140 | * @return The controller view. 141 | */ 142 | protected View makeControllerView() { 143 | return ((LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE)).inflate(R.layout.mediacontroller, this); 144 | } 145 | 146 | private void initControllerView(View v) { 147 | mPauseButton = (ImageButton) v.findViewById(R.id.mediacontroller_play_pause); 148 | if (mPauseButton != null) { 149 | mPauseButton.requestFocus(); 150 | mPauseButton.setOnClickListener(mPauseListener); 151 | } 152 | 153 | mProgress = (ProgressBar) v.findViewById(R.id.mediacontroller_seekbar); 154 | if (mProgress != null) { 155 | if (mProgress instanceof SeekBar) { 156 | SeekBar seeker = (SeekBar) mProgress; 157 | seeker.setOnSeekBarChangeListener(mSeekListener); 158 | seeker.setThumbOffset(1); 159 | } 160 | mProgress.setMax(1000); 161 | } 162 | 163 | mEndTime = (TextView) v.findViewById(R.id.mediacontroller_time_total); 164 | mCurrentTime = (TextView) v.findViewById(R.id.mediacontroller_time_current); 165 | mFileName = (TextView) v.findViewById(R.id.mediacontroller_file_name); 166 | if (mFileName != null) 167 | mFileName.setText(mTitle); 168 | } 169 | 170 | public void setMediaPlayer(MediaPlayerControl player) { 171 | mPlayer = player; 172 | updatePausePlay(); 173 | } 174 | 175 | /** 176 | * Control the action when the seekbar dragged by user 177 | * 178 | * @param seekWhenDragging True the media will seek periodically 179 | */ 180 | public void setInstantSeeking(boolean seekWhenDragging) { 181 | mInstantSeeking = seekWhenDragging; 182 | } 183 | 184 | public void show() { 185 | show(sDefaultTimeout); 186 | } 187 | 188 | /** 189 | * Set the content of the file_name TextView 190 | * 191 | * @param name 192 | */ 193 | public void setFileName(String name) { 194 | mTitle = name; 195 | if (mFileName != null) 196 | mFileName.setText(mTitle); 197 | } 198 | 199 | /** 200 | * Set the View to hold some information when interact with the 201 | * MediaController 202 | * 203 | * @param v 204 | */ 205 | public void setInfoView(OutlineTextView v) { 206 | mInfoView = v; 207 | } 208 | 209 | private void disableUnsupportedButtons() { 210 | try { 211 | if (mPauseButton != null && !mPlayer.canPause()) 212 | mPauseButton.setEnabled(false); 213 | } catch (IncompatibleClassChangeError ex) { 214 | } 215 | } 216 | 217 | /** 218 | *

219 | * Change the animation style resource for this controller. 220 | *

221 | * 222 | *

223 | * If the controller is showing, calling this method will take effect only the 224 | * next time the controller is shown. 225 | *

226 | * 227 | * @param animationStyle animation style to use when the controller appears 228 | * and disappears. Set to -1 for the default animation, 0 for no animation, or 229 | * a resource identifier for an explicit animation. 230 | * 231 | */ 232 | public void setAnimationStyle(int animationStyle) { 233 | mAnimStyle = animationStyle; 234 | } 235 | 236 | /** 237 | * Show the controller on screen. It will go away automatically after 238 | * 'timeout' milliseconds of inactivity. 239 | * 240 | * @param timeout The timeout in milliseconds. Use 0 to show the controller 241 | * until hide() is called. 242 | */ 243 | public void show(int timeout) { 244 | if (!mShowing && mAnchor != null && mAnchor.getWindowToken() != null) { 245 | if (mPauseButton != null) 246 | mPauseButton.requestFocus(); 247 | disableUnsupportedButtons(); 248 | 249 | if (mFromXml) { 250 | setVisibility(View.VISIBLE); 251 | } else { 252 | int[] location = new int[2]; 253 | 254 | mAnchor.getLocationOnScreen(location); 255 | Rect anchorRect = new Rect(location[0], location[1], location[0] + mAnchor.getWidth(), location[1] + mAnchor.getHeight()); 256 | 257 | mWindow.setAnimationStyle(mAnimStyle); 258 | mWindow.showAtLocation(mAnchor, Gravity.NO_GRAVITY, anchorRect.left, anchorRect.bottom); 259 | } 260 | mShowing = true; 261 | if (mShownListener != null) 262 | mShownListener.onShown(); 263 | } 264 | updatePausePlay(); 265 | mHandler.sendEmptyMessage(SHOW_PROGRESS); 266 | 267 | if (timeout != 0) { 268 | mHandler.removeMessages(FADE_OUT); 269 | mHandler.sendMessageDelayed(mHandler.obtainMessage(FADE_OUT), timeout); 270 | } 271 | } 272 | 273 | public boolean isShowing() { 274 | return mShowing; 275 | } 276 | 277 | public void hide() { 278 | if (mAnchor == null) 279 | return; 280 | 281 | if (mShowing) { 282 | try { 283 | mHandler.removeMessages(SHOW_PROGRESS); 284 | if (mFromXml) 285 | setVisibility(View.GONE); 286 | else 287 | mWindow.dismiss(); 288 | } catch (IllegalArgumentException ex) { 289 | Log.d("MediaController already removed"); 290 | } 291 | mShowing = false; 292 | if (mHiddenListener != null) 293 | mHiddenListener.onHidden(); 294 | } 295 | } 296 | 297 | public interface OnShownListener { 298 | public void onShown(); 299 | } 300 | 301 | private OnShownListener mShownListener; 302 | 303 | public void setOnShownListener(OnShownListener l) { 304 | mShownListener = l; 305 | } 306 | 307 | public interface OnHiddenListener { 308 | public void onHidden(); 309 | } 310 | 311 | private OnHiddenListener mHiddenListener; 312 | 313 | public void setOnHiddenListener(OnHiddenListener l) { 314 | mHiddenListener = l; 315 | } 316 | 317 | private Handler mHandler = new Handler() { 318 | @Override 319 | public void handleMessage(Message msg) { 320 | long pos; 321 | switch (msg.what) { 322 | case FADE_OUT: 323 | hide(); 324 | break; 325 | case SHOW_PROGRESS: 326 | pos = setProgress(); 327 | if (!mDragging && mShowing) { 328 | msg = obtainMessage(SHOW_PROGRESS); 329 | sendMessageDelayed(msg, 1000 - (pos % 1000)); 330 | updatePausePlay(); 331 | } 332 | break; 333 | } 334 | } 335 | }; 336 | 337 | private long setProgress() { 338 | if (mPlayer == null || mDragging) 339 | return 0; 340 | 341 | long position = mPlayer.getCurrentPosition(); 342 | long duration = mPlayer.getDuration(); 343 | if (mProgress != null) { 344 | if (duration > 0) { 345 | long pos = 1000L * position / duration; 346 | mProgress.setProgress((int) pos); 347 | } 348 | int percent = mPlayer.getBufferPercentage(); 349 | mProgress.setSecondaryProgress(percent * 10); 350 | } 351 | 352 | mDuration = duration; 353 | 354 | if (mEndTime != null) 355 | mEndTime.setText(StringUtils.generateTime(mDuration)); 356 | if (mCurrentTime != null) 357 | mCurrentTime.setText(StringUtils.generateTime(position)); 358 | 359 | return position; 360 | } 361 | 362 | @Override 363 | public boolean onTouchEvent(MotionEvent event) { 364 | show(sDefaultTimeout); 365 | return true; 366 | } 367 | 368 | @Override 369 | public boolean onTrackballEvent(MotionEvent ev) { 370 | show(sDefaultTimeout); 371 | return false; 372 | } 373 | 374 | @Override 375 | public boolean dispatchKeyEvent(KeyEvent event) { 376 | int keyCode = event.getKeyCode(); 377 | if (event.getRepeatCount() == 0 && (keyCode == KeyEvent.KEYCODE_HEADSETHOOK || keyCode == KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE || keyCode == KeyEvent.KEYCODE_SPACE)) { 378 | doPauseResume(); 379 | show(sDefaultTimeout); 380 | if (mPauseButton != null) 381 | mPauseButton.requestFocus(); 382 | return true; 383 | } else if (keyCode == KeyEvent.KEYCODE_MEDIA_STOP) { 384 | if (mPlayer.isPlaying()) { 385 | mPlayer.pause(); 386 | updatePausePlay(); 387 | } 388 | return true; 389 | } else if (keyCode == KeyEvent.KEYCODE_BACK || keyCode == KeyEvent.KEYCODE_MENU) { 390 | hide(); 391 | return true; 392 | } else { 393 | show(sDefaultTimeout); 394 | } 395 | return super.dispatchKeyEvent(event); 396 | } 397 | 398 | private View.OnClickListener mPauseListener = new View.OnClickListener() { 399 | @Override 400 | public void onClick(View v) { 401 | doPauseResume(); 402 | show(sDefaultTimeout); 403 | } 404 | }; 405 | 406 | private void updatePausePlay() { 407 | if (mRoot == null || mPauseButton == null) 408 | return; 409 | 410 | if (mPlayer.isPlaying()) 411 | mPauseButton.setImageResource(R.drawable.mediacontroller_pause_button); 412 | else 413 | mPauseButton.setImageResource(R.drawable.mediacontroller_play_button); 414 | } 415 | 416 | private void doPauseResume() { 417 | if (mPlayer.isPlaying()) 418 | mPlayer.pause(); 419 | else 420 | mPlayer.start(); 421 | updatePausePlay(); 422 | } 423 | 424 | private OnSeekBarChangeListener mSeekListener = new OnSeekBarChangeListener() { 425 | @Override 426 | public void onStartTrackingTouch(SeekBar bar) { 427 | mDragging = true; 428 | show(3600000); 429 | mHandler.removeMessages(SHOW_PROGRESS); 430 | if (mInstantSeeking) 431 | mAM.setStreamMute(AudioManager.STREAM_MUSIC, true); 432 | if (mInfoView != null) { 433 | mInfoView.setText(""); 434 | mInfoView.setVisibility(View.VISIBLE); 435 | } 436 | } 437 | 438 | @Override 439 | public void onProgressChanged(SeekBar bar, int progress, boolean fromuser) { 440 | if (!fromuser) 441 | return; 442 | 443 | long newposition = (mDuration * progress) / 1000; 444 | String time = StringUtils.generateTime(newposition); 445 | if (mInstantSeeking) 446 | mPlayer.seekTo(newposition); 447 | if (mInfoView != null) 448 | mInfoView.setText(time); 449 | if (mCurrentTime != null) 450 | mCurrentTime.setText(time); 451 | } 452 | 453 | @Override 454 | public void onStopTrackingTouch(SeekBar bar) { 455 | if (!mInstantSeeking) 456 | mPlayer.seekTo((mDuration * bar.getProgress()) / 1000); 457 | if (mInfoView != null) { 458 | mInfoView.setText(""); 459 | mInfoView.setVisibility(View.GONE); 460 | } 461 | show(sDefaultTimeout); 462 | mHandler.removeMessages(SHOW_PROGRESS); 463 | mAM.setStreamMute(AudioManager.STREAM_MUSIC, false); 464 | mDragging = false; 465 | mHandler.sendEmptyMessageDelayed(SHOW_PROGRESS, 1000); 466 | } 467 | }; 468 | 469 | @Override 470 | public void setEnabled(boolean enabled) { 471 | if (mPauseButton != null) 472 | mPauseButton.setEnabled(enabled); 473 | if (mProgress != null) 474 | mProgress.setEnabled(enabled); 475 | disableUnsupportedButtons(); 476 | super.setEnabled(enabled); 477 | } 478 | 479 | public interface MediaPlayerControl { 480 | void start(); 481 | 482 | void pause(); 483 | 484 | long getDuration(); 485 | 486 | long getCurrentPosition(); 487 | 488 | void seekTo(long pos); 489 | 490 | boolean isPlaying(); 491 | 492 | int getBufferPercentage(); 493 | 494 | boolean canPause(); 495 | 496 | boolean canSeekBackward(); 497 | 498 | boolean canSeekForward(); 499 | } 500 | 501 | } 502 | -------------------------------------------------------------------------------- /src/io/vov/vitamio/widget/OutlineTextView.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2011 Cedric Fung (wolfplanet@gmail.com) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package io.vov.vitamio.widget; 18 | 19 | import android.content.Context; 20 | import android.graphics.Canvas; 21 | import android.graphics.Paint; 22 | import android.graphics.Typeface; 23 | import android.text.Layout; 24 | import android.text.StaticLayout; 25 | import android.text.TextPaint; 26 | import android.util.AttributeSet; 27 | import android.widget.TextView; 28 | 29 | /** 30 | * Display text with border, use the same XML attrs as 31 | * {@link android.widget.TextView}, except that {@link OutlineTextView} will 32 | * transform the shadow to border 33 | */ 34 | public class OutlineTextView extends TextView { 35 | public OutlineTextView(Context context) { 36 | super(context); 37 | initPaint(); 38 | } 39 | 40 | public OutlineTextView(Context context, AttributeSet attrs) { 41 | super(context, attrs); 42 | initPaint(); 43 | } 44 | 45 | public OutlineTextView(Context context, AttributeSet attrs, int defStyle) { 46 | super(context, attrs, defStyle); 47 | initPaint(); 48 | } 49 | 50 | private void initPaint() { 51 | mTextPaint = new TextPaint(); 52 | mTextPaint.setAntiAlias(true); 53 | mTextPaint.setTextSize(getTextSize()); 54 | mTextPaint.setColor(mColor); 55 | mTextPaint.setStyle(Paint.Style.FILL); 56 | mTextPaint.setTypeface(getTypeface()); 57 | 58 | mTextPaintOutline = new TextPaint(); 59 | mTextPaintOutline.setAntiAlias(true); 60 | mTextPaintOutline.setTextSize(getTextSize()); 61 | mTextPaintOutline.setColor(mBorderColor); 62 | mTextPaintOutline.setStyle(Paint.Style.STROKE); 63 | mTextPaintOutline.setTypeface(getTypeface()); 64 | mTextPaintOutline.setStrokeWidth(mBorderSize); 65 | } 66 | 67 | public void setText(String text) { 68 | super.setText(text); 69 | mText = text.toString(); 70 | requestLayout(); 71 | invalidate(); 72 | } 73 | 74 | @Override 75 | public void setTextSize(float size) { 76 | super.setTextSize(size); 77 | requestLayout(); 78 | invalidate(); 79 | initPaint(); 80 | } 81 | 82 | @Override 83 | public void setTextColor(int color) { 84 | super.setTextColor(color); 85 | mColor = color; 86 | invalidate(); 87 | initPaint(); 88 | } 89 | 90 | @Override 91 | public void setShadowLayer(float radius, float dx, float dy, int color) { 92 | super.setShadowLayer(radius, dx, dy, color); 93 | mBorderSize = radius; 94 | mBorderColor = color; 95 | requestLayout(); 96 | invalidate(); 97 | initPaint(); 98 | } 99 | 100 | @Override 101 | public void setTypeface(Typeface tf, int style) { 102 | super.setTypeface(tf, style); 103 | requestLayout(); 104 | invalidate(); 105 | initPaint(); 106 | } 107 | 108 | @Override 109 | public void setTypeface(Typeface tf) { 110 | super.setTypeface(tf); 111 | requestLayout(); 112 | invalidate(); 113 | initPaint(); 114 | } 115 | 116 | @Override 117 | protected void onDraw(Canvas canvas) { 118 | Layout layout = new StaticLayout(getText(), mTextPaintOutline, getWidth(), Layout.Alignment.ALIGN_CENTER, mSpacingMult, mSpacingAdd, mIncludePad); 119 | layout.draw(canvas); 120 | layout = new StaticLayout(getText(), mTextPaint, getWidth(), Layout.Alignment.ALIGN_CENTER, mSpacingMult, mSpacingAdd, mIncludePad); 121 | layout.draw(canvas); 122 | } 123 | 124 | @Override 125 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 126 | Layout layout = new StaticLayout(getText(), mTextPaintOutline, measureWidth(widthMeasureSpec), Layout.Alignment.ALIGN_CENTER, mSpacingMult, mSpacingAdd, mIncludePad); 127 | int ex = (int) (mBorderSize * 2 + 1); 128 | setMeasuredDimension(measureWidth(widthMeasureSpec) + ex, measureHeight(heightMeasureSpec) * layout.getLineCount() + ex); 129 | } 130 | 131 | private int measureWidth(int measureSpec) { 132 | int result = 0; 133 | int specMode = MeasureSpec.getMode(measureSpec); 134 | int specSize = MeasureSpec.getSize(measureSpec); 135 | 136 | if (specMode == MeasureSpec.EXACTLY) { 137 | result = specSize; 138 | } else { 139 | result = (int) mTextPaintOutline.measureText(mText) + getPaddingLeft() + getPaddingRight(); 140 | if (specMode == MeasureSpec.AT_MOST) { 141 | result = Math.min(result, specSize); 142 | } 143 | } 144 | 145 | return result; 146 | } 147 | 148 | private int measureHeight(int measureSpec) { 149 | int result = 0; 150 | int specMode = MeasureSpec.getMode(measureSpec); 151 | int specSize = MeasureSpec.getSize(measureSpec); 152 | 153 | mAscent = (int) mTextPaintOutline.ascent(); 154 | if (specMode == MeasureSpec.EXACTLY) { 155 | result = specSize; 156 | } else { 157 | result = (int) (-mAscent + mTextPaintOutline.descent()) + getPaddingTop() + getPaddingBottom(); 158 | if (specMode == MeasureSpec.AT_MOST) { 159 | result = Math.min(result, specSize); 160 | } 161 | } 162 | return result; 163 | } 164 | 165 | private TextPaint mTextPaint; 166 | private TextPaint mTextPaintOutline; 167 | private String mText = ""; 168 | private int mAscent = 0; 169 | private float mBorderSize; 170 | private int mBorderColor; 171 | private int mColor; 172 | private float mSpacingMult = 1.0f; 173 | private float mSpacingAdd = 0; 174 | private boolean mIncludePad = true; 175 | } --------------------------------------------------------------------------------