Repository: over140/OPlayer Branch: master Commit: 315bc745fd96 Files: 95 Total size: 369.9 KB Directory structure: gitextract_kw23pxwu/ ├── .classpath ├── .gitignore ├── .project ├── AndroidManifest.xml ├── LICENSE ├── README.md ├── assets/ │ └── online.xml ├── libs/ │ ├── android-support-v13.jar │ ├── ormlite-android-4.42-SNAPSHOT.jar │ ├── ormlite-core-4.42-SNAPSHOT.jar │ └── pinyin4j-2.5.0.jar ├── project.properties ├── res/ │ ├── anim/ │ │ ├── slide_in_bottom.xml │ │ ├── slide_in_top.xml │ │ ├── slide_out_bottom.xml │ │ └── slide_out_top.xml │ ├── drawable/ │ │ ├── alphabet_scroller_bg.xml │ │ ├── home_btn_bg.xml │ │ ├── mediacontroller_btn_bg.xml │ │ ├── mediacontroller_pause_button.xml │ │ ├── mediacontroller_play_button.xml │ │ ├── mediacontroller_seekbar.xml │ │ ├── mediacontroller_seekbar_thumb.xml │ │ ├── scrubber_control_selector_holo.xml │ │ └── scrubber_progress_horizontal_holo_dark.xml │ ├── layout/ │ │ ├── activity_video.xml │ │ ├── brightness_volumn.xml │ │ ├── common_loading.xml │ │ ├── fragment_file.xml │ │ ├── fragment_file_item.xml │ │ ├── fragment_online.xml │ │ ├── fragment_online_item.xml │ │ ├── fragment_pager.xml │ │ ├── mediacontroller.xml │ │ ├── mediaplayer.xml │ │ ├── my_media_controller.xml │ │ └── videoview.xml │ ├── values/ │ │ ├── colors.xml │ │ ├── dimens.xml │ │ ├── strings.xml │ │ └── styles.xml │ ├── values-large/ │ │ └── dimens.xml │ ├── values-small/ │ │ └── dimens.xml │ ├── values-sw600dp/ │ │ └── dimens.xml │ ├── values-v11/ │ │ └── styles.xml │ ├── values-v14/ │ │ └── styles.xml │ └── values-xlarge/ │ └── dimens.xml └── src/ └── com/ └── nmbb/ └── oplayer/ ├── OPlayerApplication.java ├── OPreference.java ├── business/ │ └── FileBusiness.java ├── database/ │ ├── DbHelper.java │ └── SQLiteHelperOrm.java ├── exception/ │ └── Logger.java ├── po/ │ ├── OnlineVideo.java │ ├── PFile.java │ └── POMedia.java ├── preference/ │ └── PreferenceUtils.java ├── receiver/ │ └── MediaScannerReceiver.java ├── service/ │ ├── FileDownloadService.java │ └── MediaScannerService.java ├── ui/ │ ├── FragmentBase.java │ ├── FragmentFileOld.java │ ├── FragmentOnline.java │ ├── MainActivity.java │ ├── PlayerActivity.java │ ├── VideoPlayerActivity.java │ ├── adapter/ │ │ ├── FileAdapter.java │ │ └── FileDownloadAdapter.java │ ├── base/ │ │ ├── ArrayAdapter.java │ │ ├── FilterArrayAdapter.java │ │ └── ThreadPool.java │ ├── helper/ │ │ ├── FileDownloadHelper.java │ │ ├── VideoHelper.java │ │ └── XmlReaderHelper.java │ ├── player/ │ │ ├── CommonGestures.java │ │ ├── MediaController.java │ │ ├── PlayerService.java │ │ ├── VP.java │ │ ├── VideoActivity.java │ │ └── VideoView.java │ └── vitamio/ │ ├── InitActivity.java │ └── LibsChecker.java ├── util/ │ ├── ApplicationUtils.java │ ├── ArrayUtils.java │ ├── ConvertUtils.java │ ├── DeviceUtils.java │ ├── FileUtils.java │ ├── FractionalTouchDelegate.java │ ├── ImageUtils.java │ ├── IntentHelper.java │ ├── MediaUtils.java │ ├── PinyinUtils.java │ ├── StringUtils.java │ └── ToastUtils.java └── video/ └── VideoThumbnailUtils.java ================================================ FILE CONTENTS ================================================ ================================================ FILE: .classpath ================================================ ================================================ FILE: .gitignore ================================================ # built application files *.apk *.ap_ # files for the dex VM *.dex # Java class files *.class # generated files bin/ gen/ # Local configuration file (sdk path, etc) local.properties ================================================ FILE: .project ================================================ OPlayer com.android.ide.eclipse.adt.ResourceManagerBuilder com.android.ide.eclipse.adt.PreCompilerBuilder org.eclipse.jdt.core.javabuilder com.android.ide.eclipse.adt.ApkBuilder com.android.ide.eclipse.adt.AndroidNature org.eclipse.jdt.core.javanature ================================================ FILE: AndroidManifest.xml ================================================ ================================================ FILE: LICENSE ================================================ ================================================ FILE: README.md ================================================ OPlayer ======= Android平台基于Vitamio的开源播放器 支持以下协议的音频和视频播放: * MMS * RTSP (RTP, SDP) * HTTP流式传输(progressive streaming) * HTTP Live Streaming (M3U8), Android 2.1+ Vitamio集成了许多音频和视频的解码包,相比Android内置默认的媒体格式,这里列出其中的一些: * divx/xvid * wmv * flv * ts * rmvb * mkv * mov * m4v * avi * mp4 * 3gp == Vitamio官网: http://vitamio.org == 我的博客: http://www.cnblogs.com/over140/ == Vitamio系列文章: http://www.cnblogs.com/over140/category/409230.html == 依赖Vitamio,下载最新的Vitamio: https://github.com/yixia/VitamioBundle ================================================ FILE: assets/online.xml ================================================ 1.1.0 default stream 001 002 003 004 005 006 007 008 009 010 011 012 013 014 214 216 072 073 366 370 018 027 036 037 038 039 042 043 044 045 046 047 048 049 050 051 052 053 054 055 056 057 058 059 061 064 170 171 172 174 286 016 017 068 070 075 107 159 160 161 162 163 164 231 294 203 204 208 209 212 213 201 277 005 015 094 126 140 322 366 367 368 277 369 018 022 112 113 114 027 108 111 126 127 128 130 131 132 133 372 373 240 320 368 036 085 086 087 088 089 090 094 056 115 116 117 118 119 202 337 338 339 340 341 342 040 134 140 141 225 064 015 060 061 062 065 066 123 124 165 191 192 193 194 195 196 197 198 199 200 234 235 334 335 369 055 295 296 297 298 299 300 301 057 323 324 325 326 327 328 329 059 302 303 304 305 306 307 308 170 226 345 346 347 348 349 350 286 042 322 332 047 310 311 312 063 352 353 354 355 356 171 045 187 236 ================================================ FILE: project.properties ================================================ # This file is automatically generated by Android Tools. # Do not modify this file -- YOUR CHANGES WILL BE ERASED! # # This file must be checked in Version Control Systems. # # To customize properties used by the Ant build system use, # "ant.properties", and override values to adapt the script to your # project structure. # Project target. target=android-17 android.library.reference.1=../VitamioBundle ================================================ FILE: res/anim/slide_in_bottom.xml ================================================ ================================================ FILE: res/anim/slide_in_top.xml ================================================ ================================================ FILE: res/anim/slide_out_bottom.xml ================================================ ================================================ FILE: res/anim/slide_out_top.xml ================================================ ================================================ FILE: res/drawable/alphabet_scroller_bg.xml ================================================ ================================================ FILE: res/drawable/home_btn_bg.xml ================================================ ================================================ FILE: res/drawable/mediacontroller_btn_bg.xml ================================================ ================================================ FILE: res/drawable/mediacontroller_pause_button.xml ================================================ ================================================ FILE: res/drawable/mediacontroller_play_button.xml ================================================ ================================================ FILE: res/drawable/mediacontroller_seekbar.xml ================================================ ================================================ FILE: res/drawable/mediacontroller_seekbar_thumb.xml ================================================ ================================================ FILE: res/drawable/scrubber_control_selector_holo.xml ================================================ ================================================ FILE: res/drawable/scrubber_progress_horizontal_holo_dark.xml ================================================ ================================================ FILE: res/layout/activity_video.xml ================================================ ================================================ FILE: res/layout/brightness_volumn.xml ================================================ ================================================ FILE: res/layout/common_loading.xml ================================================ ================================================ FILE: res/layout/fragment_file.xml ================================================ ================================================ FILE: res/layout/fragment_file_item.xml ================================================ ================================================ FILE: res/layout/fragment_online.xml ================================================ ================================================ FILE: res/layout/fragment_online_item.xml ================================================ ================================================ FILE: res/layout/fragment_pager.xml ================================================ ================================================ FILE: res/layout/mediacontroller.xml ================================================ ================================================ FILE: res/layout/mediaplayer.xml ================================================ ================================================ FILE: res/layout/my_media_controller.xml ================================================ ================================================ FILE: res/layout/videoview.xml ================================================ ================================================ FILE: res/values/colors.xml ================================================ #ffffffff #ff000000 #ff0000ff #ff00ff00 #ffff0000 #ff0078f0 #ff7d7d7d #ffc3ddea #ffffcc00 #ff274462 #808080ff #00000000 #ff53c1bd #99000000 #f4f4f4 ================================================ FILE: res/values/dimens.xml ================================================ 16.0dip 15.0dip 18.0dip 14.0dip 13.0dip 30.0dip 49.0dip 40.0dip 48dp 32dp 2dp 0dp ================================================ FILE: res/values/strings.xml ================================================ 开播视频 1.0 本地视频 在线视频 初始化播放器... 载入中,请稍后... 文件操作 重命名 重命名失败 文件已存在 删除 确定删除 (%s) ? 正在缓冲... VPlayer codec Cannot play video Sorry, this video is not valid for streaming to this device. 对不起,这个视频不能播放。 OK Play/Pause 锁定 100% 全屏 拉伸 裁剪 屏幕已锁定 屏幕锁定已解除 缓冲: %.2f%% 对不起,这个视频不能播放。 SD卡无法读取 截图存放在 %s. 截图失败 正在退出… ================================================ FILE: res/values/styles.xml ================================================ ================================================ FILE: res/values-large/dimens.xml ================================================ 48.0dip ================================================ FILE: res/values-small/dimens.xml ================================================ 32.0dip ================================================ FILE: res/values-sw600dp/dimens.xml ================================================ 56dp 8dp 2dp ================================================ FILE: res/values-v11/styles.xml ================================================ ================================================ FILE: res/values-v14/styles.xml ================================================ ================================================ FILE: res/values-xlarge/dimens.xml ================================================ 64.0dip 56dp ================================================ FILE: src/com/nmbb/oplayer/OPlayerApplication.java ================================================ package com.nmbb.oplayer; import android.app.Application; import android.content.Context; import android.os.Environment; import com.nmbb.oplayer.util.FileUtils; public class OPlayerApplication extends Application { private static OPlayerApplication mApplication; /** OPlayer SD卡缓存路径 */ public static final String OPLAYER_CACHE_BASE = Environment.getExternalStorageDirectory() + "/oplayer"; /** 视频截图缓冲路径 */ public static final String OPLAYER_VIDEO_THUMB = OPLAYER_CACHE_BASE + "/thumb/"; /** 首次扫描 */ public static final String PREF_KEY_FIRST = "application_first"; @Override public void onCreate() { super.onCreate(); mApplication = this; init(); } private void init() { //创建缓存目录 FileUtils.createIfNoExists(OPLAYER_CACHE_BASE); FileUtils.createIfNoExists(OPLAYER_VIDEO_THUMB); } public static OPlayerApplication getApplication() { return mApplication; } public static Context getContext() { return mApplication; } /** 销毁 */ public void destory() { mApplication = null; } } ================================================ FILE: src/com/nmbb/oplayer/OPreference.java ================================================ package com.nmbb.oplayer; import java.util.Map.Entry; import android.content.ContentValues; import android.content.Context; import android.content.SharedPreferences; /** 存储系统设置 */ public class OPreference { private static final String PREFERENCE_NAME = "preference.db"; private SharedPreferences mPreference; public OPreference(Context ctx) { mPreference = ctx.getApplicationContext().getSharedPreferences(PREFERENCE_NAME, Context.MODE_PRIVATE); } public boolean putStringAndCommit(String key, String value) { return mPreference.edit().putString(key, value).commit(); } public boolean putIntAndCommit(String key, int value) { return mPreference.edit().putInt(key, value).commit(); } public boolean putBooleanAndCommit(String key, boolean value) { return mPreference.edit().putBoolean(key, value).commit(); } public boolean putIntAndCommit(ContentValues values) { SharedPreferences.Editor editor = mPreference.edit(); for (Entry value : values.valueSet()) { editor.putString(value.getKey(), value.getValue().toString()); } return editor.commit(); } public String getString(String key) { return getString(key, ""); } public String getString(String key, String defValue) { return mPreference.getString(key, defValue); } public int getInt(String key) { return getInt(key, -1); } public int getInt(String key, int defValue) { return mPreference.getInt(key, defValue); } public boolean getBoolean(String key) { return getBoolean(key, false); } public boolean getBoolean(String key, boolean defValue) { return mPreference.getBoolean(key, defValue); } } ================================================ FILE: src/com/nmbb/oplayer/business/FileBusiness.java ================================================ package com.nmbb.oplayer.business; import java.sql.SQLException; import java.util.ArrayList; import java.util.List; import com.j256.ormlite.dao.Dao; import com.j256.ormlite.stmt.QueryBuilder; import com.nmbb.oplayer.database.SQLiteHelperOrm; import com.nmbb.oplayer.exception.Logger; import com.nmbb.oplayer.po.POMedia; public final class FileBusiness { private static final String TABLE_NAME = "files"; private static final String TAG = "FileBusiness"; public static List getAllSortFiles() { SQLiteHelperOrm db = new SQLiteHelperOrm(); try { Dao dao = db.getDao(POMedia.class); QueryBuilder query = dao.queryBuilder(); query.orderBy("title_key", true); return dao.query(query.prepare()); } catch (SQLException e) { Logger.e(e); } finally { if (db != null) db.close(); } return new ArrayList(); // new DbHelper().queryForAll(POMedia.class); } // /** 获取所有已经排好序的列表 */ // public static ArrayList getAllSortFiles(final Context ctx) { // ArrayList result = new ArrayList(); // SQLiteHelper sqlite = new SQLiteHelper(ctx); // SQLiteDatabase db = sqlite.getReadableDatabase(); // Cursor c = null; // try { // c = db.rawQuery("SELECT " + FilesColumns.COL_ID + "," + FilesColumns.COL_TITLE + "," + FilesColumns.COL_TITLE_PINYIN + "," + FilesColumns.COL_PATH + "," + FilesColumns.COL_DURATION + "," + FilesColumns.COL_POSITION + "," + FilesColumns.COL_LAST_ACCESS_TIME + "," + FilesColumns.COL_THUMB + "," + FilesColumns.COL_FILE_SIZE + " FROM files", null); // while (c.moveToNext()) { // PFile po = new PFile(); // int index = 0; // po._id = c.getLong(index++); // po.title = c.getString(index++); // po.title_pinyin = c.getString(index++); // po.path = c.getString(index++); // po.duration = c.getInt(index++); // po.position = c.getInt(index++); // po.last_access_time = c.getLong(index++); // po.thumb = c.getString(index++); // po.file_size = c.getLong(index++); // result.add(po); // } // } finally { // if (c != null) // c.close(); // } // db.close(); // // Collections.sort(result, new Comparator() { // // @Override // public int compare(PFile f1, PFile f2) { // char c1 = f1.title_pinyin.length() == 0 ? ' ' : f1.title_pinyin.charAt(0); // char c2 = f2.title_pinyin.length() == 0 ? ' ' : f2.title_pinyin.charAt(0); // return c1 == c2 ? 0 : (c1 > c2 ? 1 : -1); // }//相等返回0,-1 f2 > f2,-1 // // }); // return result; // } // // /** 重命名文件 */ // public static void renameFile(final Context ctx, final PFile p) { // SQLiteHelper sqlite = new SQLiteHelper(ctx); // SQLiteDatabase db = sqlite.getWritableDatabase(); // try { // ContentValues values = new ContentValues(); // values.put(FilesColumns.COL_TITLE, p.title); // values.put(FilesColumns.COL_TITLE_PINYIN, PinyinUtils.chineneToSpell(p.title.charAt(0) + "")); // values.put(FilesColumns.COL_PATH, p.path); // db.update(TABLE_NAME, values, FilesColumns.COL_ID + " = ?", new String[] { p._id + "" }); // } catch (Exception e) { // e.printStackTrace(); // } finally { // try { // db.close(); // } catch (Exception e) { // } // } // } // // /** 删除文件 */ // public static int deleteFile(final Context ctx, final PFile p) { // SQLiteHelper sqlite = new SQLiteHelper(ctx); // SQLiteDatabase db = sqlite.getWritableDatabase(); // int result = -1; // try { // result = db.delete(TABLE_NAME, FilesColumns.COL_ID + " = ?", new String[] { p._id + "" }); // } catch (Exception e) { // e.printStackTrace(); // } finally { // try { // db.close(); // } catch (Exception e) { // } // } // return result; // } // // public static void insertFile(final Context ctx, final PFile p) { // SQLiteHelper sqlite = new SQLiteHelper(ctx); // SQLiteDatabase db = sqlite.getWritableDatabase(); // try { // ContentValues values = new ContentValues(); // values.put(FilesColumns.COL_TITLE, p.title); // values.put(FilesColumns.COL_TITLE_PINYIN, PinyinUtils.chineneToSpell(p.title.charAt(0) + "")); // values.put(FilesColumns.COL_PATH, p.path); // values.put(FilesColumns.COL_LAST_ACCESS_TIME, System.currentTimeMillis()); // values.put(FilesColumns.COL_FILE_SIZE, p.file_size); // db.insert(TABLE_NAME, "", values); // } catch (Exception e) { // e.printStackTrace(); // } finally { // try { // db.close(); // } catch (Exception e) { // } // } // } // // /** 批量提取视频的缩略图已经视频的宽高 */ // public static ArrayList batchBuildThumbnail(final Context ctx, final ArrayList files) { // ArrayList result = new ArrayList(); // // for (File f : files) { // PFile pf = new PFile(); // try { // if (f.exists() && f.canRead()) { // //取出视频的一帧图像 //// Bitmap bitmap = ThumbnailUtils.createVideoThumbnail(ctx, f.getAbsolutePath(), Video.Thumbnails.MINI_KIND); //// if (bitmap == null) { //// //缩略图创建失败 //// bitmap = Bitmap.createBitmap(ThumbnailUtils.TARGET_SIZE_MINI_THUMBNAIL_WIDTH, ThumbnailUtils.TARGET_SIZE_MINI_THUMBNAIL_HEIGHT, Bitmap.Config.RGB_565); //// Log.e(TAG, "batchBuildThumbnail createBitmap faild : " + f.getAbsolutePath()); //// } //// //// pf.width = bitmap.getWidth(); //// pf.height = bitmap.getHeight(); //// //// //缩略图 //// bitmap = ThumbnailUtils.extractThumbnail(bitmap, ThumbnailUtils.dipToPX(ctx, ThumbnailUtils.TARGET_SIZE_MICRO_THUMBNAIL_WIDTH), ThumbnailUtils.dipToPX(ctx, ThumbnailUtils.TARGET_SIZE_MICRO_THUMBNAIL_HEIGHT), ThumbnailUtils.OPTIONS_RECYCLE_INPUT); //// if (bitmap != null) { //// File thum = new File(f.getParent(), f.getName() + ".jpg"); //// pf.thumb = thum.getAbsolutePath(); //// //thum.createNewFile(); //// FileOutputStream iStream = new FileOutputStream(thum); //// bitmap.compress(Bitmap.CompressFormat.JPEG, 85, iStream); //// iStream.close(); //// } //// //// if (bitmap != null) //// bitmap.recycle(); // // } // } catch (Exception e) { // Log.e(TAG, e); // continue; // } finally { // result.add(pf); // } // } // // return result; // } // // /** 批量插入数据 */ // public static void batchInsertFiles(final Context ctx, final ArrayList files) { // SQLiteHelper sqlite = new SQLiteHelper(ctx); // SQLiteDatabase db = sqlite.getWritableDatabase(); // try { // db.beginTransaction(); // // SQLiteStatement stat = db.compileStatement("INSERT INTO files(" + FilesColumns.COL_TITLE + "," + FilesColumns.COL_TITLE_PINYIN + "," + FilesColumns.COL_PATH + "," + FilesColumns.COL_LAST_ACCESS_TIME + "," + FilesColumns.COL_FILE_SIZE + ") VALUES(?,?,?,?,?)"); // for (File f : files) { // String name = f.getName(); // int index = 1; // stat.bindString(index++, name);// title // stat.bindString(index++, PinyinUtils.chineneToSpell(name.charAt(0) + ""));// title_pinyin // stat.bindString(index++, f.getPath());// path // stat.bindLong(index++, System.currentTimeMillis());// last_access_time // stat.bindLong(index++, f.length()); // stat.execute(); // } // db.setTransactionSuccessful(); // } catch (BadHanyuPinyinOutputFormatCombination e) { // e.printStackTrace(); // } catch (Exception e) { // e.printStackTrace(); // } finally { // db.endTransaction(); // try { // db.close(); // } catch (Exception e) { // } // } // } } ================================================ FILE: src/com/nmbb/oplayer/database/DbHelper.java ================================================ package com.nmbb.oplayer.database; import java.sql.SQLException; import java.util.ArrayList; import java.util.List; import java.util.Map; import android.content.ContentValues; import com.j256.ormlite.dao.Dao; import com.j256.ormlite.stmt.UpdateBuilder; import com.nmbb.oplayer.exception.Logger; @SuppressWarnings({ "unchecked", "rawtypes" }) public class DbHelper { /** 新增一条记录 */ public int create(T po) { SQLiteHelperOrm db = new SQLiteHelperOrm(); try { Dao dao = db.getDao(po.getClass()); return dao.create(po); } catch (SQLException e) { Logger.e(e); } finally { if (db != null) db.close(); } return -1; } public boolean exists(T po, Map where) { SQLiteHelperOrm db = new SQLiteHelperOrm(); try { Dao dao = db.getDao(po.getClass()); if (dao.queryForFieldValues(where).size() > 0) { return true; } } catch (SQLException e) { Logger.e(e); } finally { if (db != null) db.close(); } return false; } public int createIfNotExists(T po, Map where) { SQLiteHelperOrm db = new SQLiteHelperOrm(); try { Dao dao = db.getDao(po.getClass()); if (dao.queryForFieldValues(where).size() < 1) { return dao.create(po); } } catch (SQLException e) { Logger.e(e); } finally { if (db != null) db.close(); } return -1; } /** 查询一条记录 */ public List queryForEq(Class c, String fieldName, Object value) { SQLiteHelperOrm db = new SQLiteHelperOrm(); try { Dao dao = db.getDao(c); return dao.queryForEq(fieldName, value); } catch (SQLException e) { Logger.e(e); } finally { if (db != null) db.close(); } return new ArrayList(); } /** 删除一条记录 */ public int remove(T po) { SQLiteHelperOrm db = new SQLiteHelperOrm(); try { Dao dao = db.getDao(po.getClass()); return dao.delete(po); } catch (SQLException e) { Logger.e(e); } finally { if (db != null) db.close(); } return -1; } /** * 根据特定条件更新特定字段 * * @param c * @param values * @param columnName where字段 * @param value where值 * @return */ public int update(Class c, ContentValues values, String columnName, Object value) { SQLiteHelperOrm db = new SQLiteHelperOrm(); try { Dao dao = db.getDao(c); UpdateBuilder updateBuilder = dao.updateBuilder(); updateBuilder.where().eq(columnName, value); for (String key : values.keySet()) { updateBuilder.updateColumnValue(key, values.get(key)); } return updateBuilder.update(); } catch (SQLException e) { Logger.e(e); } finally { if (db != null) db.close(); } return -1; } /** 更新一条记录 */ public int update(T po) { SQLiteHelperOrm db = new SQLiteHelperOrm(); try { Dao dao = db.getDao(po.getClass()); return dao.update(po); } catch (SQLException e) { Logger.e(e); } finally { if (db != null) db.close(); } return -1; } /** 查询所有记录 */ public List queryForAll(Class c) { SQLiteHelperOrm db = new SQLiteHelperOrm(); try { Dao dao = db.getDao(c); return dao.queryForAll(); } catch (SQLException e) { Logger.e(e); } finally { if (db != null) db.close(); } return new ArrayList(); } } ================================================ FILE: src/com/nmbb/oplayer/database/SQLiteHelperOrm.java ================================================ package com.nmbb.oplayer.database; import java.sql.SQLException; import android.content.Context; import android.database.sqlite.SQLiteDatabase; import com.j256.ormlite.android.apptools.OrmLiteSqliteOpenHelper; import com.j256.ormlite.support.ConnectionSource; import com.j256.ormlite.table.TableUtils; import com.nmbb.oplayer.OPlayerApplication; import com.nmbb.oplayer.exception.Logger; import com.nmbb.oplayer.po.POMedia; public class SQLiteHelperOrm extends OrmLiteSqliteOpenHelper { private static final String DATABASE_NAME = "oplayer.db"; private static final int DATABASE_VERSION = 1; public SQLiteHelperOrm(Context context) { super(context, DATABASE_NAME, null, DATABASE_VERSION); } public SQLiteHelperOrm() { super(OPlayerApplication.getContext(), DATABASE_NAME, null, DATABASE_VERSION); } @Override public void onCreate(SQLiteDatabase db, ConnectionSource connectionSource) { try { TableUtils.createTable(connectionSource, POMedia.class); } catch (SQLException e) { Logger.e(e); } } @Override public void onUpgrade(SQLiteDatabase db, ConnectionSource connectionSource, int arg2, int arg3) { try { TableUtils.dropTable(connectionSource, POMedia.class, true); onCreate(db, connectionSource); } catch (SQLException e) { Logger.e(e); } } } ================================================ FILE: src/com/nmbb/oplayer/exception/Logger.java ================================================ package com.nmbb.oplayer.exception; import android.util.Log; public class Logger { private static boolean isLog = true; private static final String TAG = "OPlayer"; public static void setLog(boolean isLog) { Logger.isLog = isLog; } public static boolean getIsLog() { return isLog; } public static void d(String tag, String msg) { if (isLog) { Log.d(tag, msg); } } public static void d(String msg) { Log.d(TAG, msg); } /** * Send a {@link #DEBUG} log message and log the exception. * * @param tag Used to identify the source of a log message. It usually * identifies the class or activity where the log call occurs. * @param msg The message you would like logged. * @param tr An exception to log */ public static void d(String tag, String msg, Throwable tr) { if (isLog) { Log.d(tag, msg, tr); } } public static void e(Throwable tr) { if (isLog) { Log.e(TAG, "", tr); } } public static void i(String msg) { if (isLog) { Log.i(TAG, msg); } } public static void i(String tag, String msg) { if (isLog) { Log.i(tag, msg); } } /** * Send a {@link #INFO} log message and log the exception. * * @param tag Used to identify the source of a log message. It usually * identifies the class or activity where the log call occurs. * @param msg The message you would like logged. * @param tr An exception to log */ public static void i(String tag, String msg, Throwable tr) { if (isLog) { Log.i(tag, msg, tr); } } /** * Send an {@link #ERROR} log message. * * @param tag Used to identify the source of a log message. It usually * identifies the class or activity where the log call occurs. * @param msg The message you would like logged. */ public static void e(String tag, String msg) { if (isLog) { Log.e(tag, msg); } } public static void e(String msg) { if (isLog) { Log.e(TAG, msg); } } /** * Send a {@link #ERROR} log message and log the exception. * * @param tag Used to identify the source of a log message. It usually * identifies the class or activity where the log call occurs. * @param msg The message you would like logged. * @param tr An exception to log */ public static void e(String tag, String msg, Throwable tr) { if (isLog) { Log.e(tag, msg, tr); } } public static void e(String msg, Throwable tr) { if (isLog) { Log.e(TAG, msg, tr); } } public static void systemErr(String msg) { // if (true) { if (isLog) { if (msg != null) { Log.e(TAG, msg); } } } } ================================================ FILE: src/com/nmbb/oplayer/po/OnlineVideo.java ================================================ package com.nmbb.oplayer.po; import java.util.ArrayList; public class OnlineVideo { public String id; /** 标题 */ public String title; public String desc; /** LOGO */ public int iconId = 0; public String icon_url; /** 播放地址 */ public String url; /** 备用链接 */ public ArrayList backup_url; /** 是否目录 */ public boolean is_category = false; /** 0视频 1电视 */ public int category; /** */ public int level = 1; public OnlineVideo() { } public OnlineVideo(String title, int iconId, int category) { this.title = title; this.iconId = iconId; this.category = category; } public OnlineVideo(String title, int iconId, int category, String url) { this.title = title; this.iconId = iconId; this.category = category; this.url = url; } } ================================================ FILE: src/com/nmbb/oplayer/po/PFile.java ================================================ package com.nmbb.oplayer.po; import android.content.Context; import android.database.Cursor; import android.graphics.Bitmap; public final class PFile { public long _id; /** 视频标题 */ public String title; /** 视频标题拼音 */ public String title_pinyin; /** 视频路径 */ public String path; /** 最后一次访问时间 */ public long last_access_time; /** 视频时长 */ public int duration; /** 视频播放进度 */ public int position; /** 视频缩略图 */ public String thumb; /** 文件大小 */ public long file_size; /** 文件状态0 - 10 分别代表 下载 0-100% */ public int status = -1; /** 文件临时大小 用于下载 */ public long temp_file_size = -1L; /** 视频宽度 */ public int width; /** 视频高度 */ public int height; public PFile() { } public PFile(Cursor c) { //Video.Media._ID, Video.Media.TITLE, Video.Media.TITLE_KEY, Video.Media.SIZE, Video.Media.DURATION, Video.Media.DATA, Video.Media.WIDTH, Video.Media.HEIGHT _id = c.getLong(0); title = c.getString(1); title_pinyin = c.getString(2); file_size = c.getLong(3); duration = c.getInt(4); path = c.getString(5); width = c.getInt(6); height = c.getInt(7); } /** 获取缩略图 */ public Bitmap getThumb(Context ctx) { return null; // return Video.Thumbnails.getThumbnail(ctx.getApplicationContext(), ctx.getContentResolver(), _id, Video.Thumbnails.MICRO_KIND, null); } } ================================================ FILE: src/com/nmbb/oplayer/po/POMedia.java ================================================ package com.nmbb.oplayer.po; import java.io.File; import com.j256.ormlite.field.DatabaseField; import com.j256.ormlite.table.DatabaseTable; /** * 视频PO类 * * @author 农民伯伯 * @see http://www.cnblogs.com/over140 * */ @DatabaseTable(tableName = "media") public class POMedia { @DatabaseField(generatedId = true) public long _id; /** 视频标题 */ @DatabaseField public String title; /** 视频标题拼音 */ @DatabaseField public String title_key; /** 视频路径 */ @DatabaseField public String path; /** 最后一次访问时间 */ @DatabaseField public long last_access_time; /** 最后一次修改时间 */ @DatabaseField public long last_modify_time; /** 视频时长 */ @DatabaseField public int duration; /** 视频播放进度 */ @DatabaseField public int position; /** 视频缩略图路径 */ @DatabaseField public String thumb_path; /** 文件大小 */ @DatabaseField public long file_size; /** 视频宽度 */ @DatabaseField public int width; /** 视频高度 */ @DatabaseField public int height; /** MIME类型 */ public String mime_type; /** 0 本地视频 1 网络视频 */ public int type = 0; /** 文件状态0 - 10 分别代表 下载 0-100% */ public int status = -1; /** 文件临时大小 用于下载 */ public long temp_file_size = -1L; public POMedia() { } public POMedia(File f) { title = f.getName(); path = f.getAbsolutePath(); last_modify_time = f.lastModified(); file_size = f.length(); } public POMedia(String path, String mimeType) { this(new File(path)); this.mime_type = mimeType; } } ================================================ FILE: src/com/nmbb/oplayer/preference/PreferenceUtils.java ================================================ package com.nmbb.oplayer.preference; import android.content.Context; import android.content.SharedPreferences; import android.content.SharedPreferences.Editor; import android.preference.PreferenceManager; import com.nmbb.oplayer.OPlayerApplication; public final class PreferenceUtils { /** 清空数据 */ public static void reset(final Context ctx) { SharedPreferences.Editor edit = PreferenceManager.getDefaultSharedPreferences(ctx).edit(); edit.clear(); edit.commit(); } public static String getString(String key, String defValue) { return PreferenceManager.getDefaultSharedPreferences(OPlayerApplication.getContext()).getString(key, defValue); } public static long getLong(String key, long defValue) { return PreferenceManager.getDefaultSharedPreferences(OPlayerApplication.getContext()).getLong(key, defValue); } public static float getFloat(String key, float defValue) { return PreferenceManager.getDefaultSharedPreferences(OPlayerApplication.getContext()).getFloat(key, defValue); } public static void put(String key, String value) { putString(key, value); } public static void put(String key, int value) { putInt(key, value); } public static void put(String key, float value) { putFloat(key, value); } public static void put(String key, boolean value) { putBoolean(key, value); } public static void putFloat(String key, float value) { SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(OPlayerApplication.getContext()); Editor editor = sharedPreferences.edit(); editor.putFloat(key, value); editor.commit(); } public static SharedPreferences getPreferences() { return PreferenceManager.getDefaultSharedPreferences(OPlayerApplication.getContext()); } public static int getInt(String key, int defValue) { return PreferenceManager.getDefaultSharedPreferences(OPlayerApplication.getContext()).getInt(key, defValue); } public static boolean getBoolean(String key, boolean defValue) { return PreferenceManager.getDefaultSharedPreferences(OPlayerApplication.getContext()).getBoolean(key, defValue); } public static void putStringProcess(String key, String value) { SharedPreferences sharedPreferences = OPlayerApplication.getContext().getSharedPreferences("preference_mu", Context.MODE_MULTI_PROCESS); Editor editor = sharedPreferences.edit(); editor.putString(key, value); editor.commit(); } public static String getStringProcess(String key, String defValue) { SharedPreferences sharedPreferences = OPlayerApplication.getContext().getSharedPreferences("preference_mu", Context.MODE_MULTI_PROCESS); return sharedPreferences.getString(key, defValue); } public static boolean hasString(String key) { SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(OPlayerApplication.getContext()); return sharedPreferences.contains(key); } public static void putString(String key, String value) { SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(OPlayerApplication.getContext()); Editor editor = sharedPreferences.edit(); editor.putString(key, value); editor.commit(); } public static void putLong(String key, long value) { SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(OPlayerApplication.getContext()); Editor editor = sharedPreferences.edit(); editor.putLong(key, value); editor.commit(); } public static void putBoolean(String key, boolean value) { SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(OPlayerApplication.getContext()); Editor editor = sharedPreferences.edit(); editor.putBoolean(key, value); editor.commit(); } public static void putInt(String key, int value) { SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(OPlayerApplication.getContext()); Editor editor = sharedPreferences.edit(); editor.putInt(key, value); editor.commit(); } public static void remove(String... keys) { if (keys != null) { SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(OPlayerApplication.getContext()); Editor editor = sharedPreferences.edit(); for (String key : keys) { editor.remove(key); } editor.commit(); } } } ================================================ FILE: src/com/nmbb/oplayer/receiver/MediaScannerReceiver.java ================================================ package com.nmbb.oplayer.receiver; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.net.Uri; import android.os.Bundle; import android.os.Environment; import com.nmbb.oplayer.service.MediaScannerService; /** 文件扫描 */ public class MediaScannerReceiver extends BroadcastReceiver { public static final String ACTION_MEDIA_SCANNER_SCAN_FILE = ""; public static final String ACTION_MEDIA_SCANNER_SCAN_DIRECTORY = ""; @Override public void onReceive(Context context, Intent intent) { String action = intent.getAction(); Uri uri = intent.getData(); if (action.equals(Intent.ACTION_BOOT_COMPLETED)) { //扫描整个SD卡目录 //FIXME 处理多个SD卡的问题 // Environment.getExternalStorageDirectory().getParentFile(); scanDirectory(context, Environment.getExternalStorageDirectory().getAbsolutePath()); } else if (uri.getScheme().equals("file")) { String path = uri.getPath(); if (action.equals(Intent.ACTION_MEDIA_MOUNTED)) { scanDirectory(context, path); } else if (action.equals(ACTION_MEDIA_SCANNER_SCAN_FILE) && path != null) { scanFile(context, path); } else if (action.equals(ACTION_MEDIA_SCANNER_SCAN_DIRECTORY) && path != null) { scanDirectory(context, path); } } } /** 扫描文件夹 */ private void scanDirectory(Context context, String volume) { Bundle args = new Bundle(); args.putString(MediaScannerService.EXTRA_DIRECTORY, volume); context.startService(new Intent(context, MediaScannerService.class).putExtras(args)); } private void scanFile(Context context, String path) { Bundle args = new Bundle(); args.putString(MediaScannerService.EXTRA_FILE_PATH, path); context.startService(new Intent(context, MediaScannerService.class).putExtras(args)); } // private static boolean isScanning = false; // // private boolean isScanningStarted = false; // private IReceiverNotify mNotify; // // public MediaScannerReceiver() { // } // // public MediaScannerReceiver(IReceiverNotify notify) { // mNotify = notify; // } // // public static boolean isScanning(Context ctx) { // return isServiceRunning(ctx, "io.vov.vitamio.MediaScannerService"); // } // // @Override // public void onReceive(Context context, Intent intent) { // final String action = intent.getAction(); // Log.i("MediaScannerReceiver", action); // } // // /** 服务是否正在运行 */ // public static boolean isServiceRunning(Context ctx, String name) { // ActivityManager manager = (ActivityManager) ctx.getSystemService(Context.ACTIVITY_SERVICE); // for (RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) { // if (name.equals(service.service.getClassName())) // return true; // } // return false; // } } ================================================ FILE: src/com/nmbb/oplayer/service/FileDownloadService.java ================================================ package com.nmbb.oplayer.service; import android.app.Service; import android.content.Intent; import android.os.IBinder; public class FileDownloadService extends Service { @Override public IBinder onBind(Intent intent) { return null; } } ================================================ FILE: src/com/nmbb/oplayer/service/MediaScannerService.java ================================================ package com.nmbb.oplayer.service; import java.io.File; import java.io.FileNotFoundException; import java.util.ArrayList; import java.util.HashMap; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import android.app.ActivityManager; import android.app.ActivityManager.RunningServiceInfo; import android.app.Service; import android.content.Context; import android.content.Intent; import android.os.Binder; import android.os.Bundle; import android.os.Handler; import android.os.IBinder; import android.os.Message; import com.nmbb.oplayer.OPlayerApplication; import com.nmbb.oplayer.OPreference; import com.nmbb.oplayer.database.DbHelper; import com.nmbb.oplayer.exception.Logger; import com.nmbb.oplayer.po.POMedia; import com.nmbb.oplayer.util.FileUtils; import com.nmbb.oplayer.util.PinyinUtils; import com.nmbb.oplayer.util.StringUtils; /** 媒体扫描 */ public class MediaScannerService extends Service implements Runnable { private static final String SERVICE_NAME = "com.nmbb.oplayer.service.MediaScannerService"; /** 扫描文件夹 */ public static final String EXTRA_DIRECTORY = "scan_directory"; /** 扫描文件 */ public static final String EXTRA_FILE_PATH = "scan_file"; public static final String EXTRA_MIME_TYPE = "mimetype"; public static final int SCAN_STATUS_NORMAL = -1; /** 开始扫描 */ public static final int SCAN_STATUS_START = 0; /** 正在扫描 扫描到一个视频文件 */ public static final int SCAN_STATUS_RUNNING = 1; /** 扫描完成 */ public static final int SCAN_STATUS_END = 2; /** */ private ArrayList observers = new ArrayList(); private ConcurrentHashMap mScanMap = new ConcurrentHashMap(); /** 当前状态 */ private volatile int mServiceStatus = SCAN_STATUS_NORMAL; private DbHelper mDbHelper; private Map mDbWhere = new HashMap(2); @Override public void onCreate() { super.onCreate(); mDbHelper = new DbHelper(); } /** 是否正在运行 */ public static boolean isRunning() { ActivityManager manager = (ActivityManager) OPlayerApplication.getContext().getSystemService(Context.ACTIVITY_SERVICE); for (RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) { if (SERVICE_NAME.equals(service.service.getClassName())) return true; } return false; } @Override public int onStartCommand(Intent intent, int flags, int startId) { if (intent != null) parseIntent(intent); return super.onStartCommand(intent, flags, startId); } /** 解析Intent */ private void parseIntent(final Intent intent) { final Bundle arguments = intent.getExtras(); if (arguments != null) { if (arguments.containsKey(EXTRA_DIRECTORY)) { String directory = arguments.getString(EXTRA_DIRECTORY); Logger.i("onStartCommand:" + directory); //扫描文件夹 if (!mScanMap.containsKey(directory)) mScanMap.put(directory, ""); } else if (arguments.containsKey(EXTRA_FILE_PATH)) { //单文件 String filePath = arguments.getString(EXTRA_FILE_PATH); Logger.i("onStartCommand:" + filePath); if (!StringUtils.isEmpty(filePath)) { if (!mScanMap.containsKey(filePath)) mScanMap.put(filePath, arguments.getString(EXTRA_MIME_TYPE)); // scanFile(filePath, arguments.getString(EXTRA_MIME_TYPE)); } } } if (mServiceStatus == SCAN_STATUS_NORMAL || mServiceStatus == SCAN_STATUS_END) { new Thread(this).start(); //scan(); } } @Override public void run() { scan(); } /** 扫描 */ private void scan() { //开始扫描 notifyObservers(SCAN_STATUS_START, null); while (mScanMap.keySet().size() > 0) { String path = ""; for (String key : mScanMap.keySet()) { path = key; break; } if (mScanMap.containsKey(path)) { String mimeType = mScanMap.get(path); if ("".equals(mimeType)) { scanDirectory(path); } else { scanFile(path, mimeType); } //扫描完成一个 mScanMap.remove(path); } //任务之间歇息一秒 try { Thread.sleep(1000); } catch (InterruptedException e) { Logger.e(e); } } //全部扫描完成 notifyObservers(SCAN_STATUS_END, null); //第一次扫描 OPreference pref = new OPreference(this); if (pref.getBoolean(OPlayerApplication.PREF_KEY_FIRST, true)) pref.putBooleanAndCommit(OPlayerApplication.PREF_KEY_FIRST, false); //停止服务 stopSelf(); } private Handler mHandler = new Handler() { @Override public void handleMessage(Message msg) { super.handleMessage(msg); for (IMediaScannerObserver s : observers) { if (s != null) { s.update(msg.what, (POMedia) msg.obj); } } } }; /** 扫描文件 */ private void scanFile(String path, String mimeType) { save(new POMedia(path, mimeType)); } /** 扫描文件夹 */ private void scanDirectory(String path) { eachAllMedias(new File(path)); } /** 递归查找视频 */ private void eachAllMedias(File f) { if (f != null && f.exists() && f.isDirectory()) { File[] files = f.listFiles(); if (files != null) { for (File file : f.listFiles()) { // Logger.i(f.getAbsolutePath()); if (file.isDirectory()) { //忽略.开头的文件夹 if (!file.getAbsolutePath().startsWith(".")) eachAllMedias(file); } else if (file.exists() && file.canRead() && FileUtils.isVideo(file)) { save(new POMedia(file)); } } } } } /** * 保存入库 * * @throws FileNotFoundException */ private void save(POMedia media) { mDbWhere.put("path", media.path); mDbWhere.put("last_modify_time", media.last_modify_time); //检测 if (!mDbHelper.exists(media, mDbWhere)) { try { if (media.title != null && media.title.length() > 0) media.title_key = PinyinUtils.chineneToSpell(media.title.charAt(0) + ""); } catch (Exception ex) { Logger.e(ex); } media.last_access_time = System.currentTimeMillis(); //提取缩略图 // extractThumbnail(media); media.mime_type = FileUtils.getMimeType(media.path); //入库 mDbHelper.create(media); //扫描到一个 notifyObservers(SCAN_STATUS_RUNNING, media); } } /** 提取生成缩略图 */ private void extractThumbnail(POMedia media) { // final Context ctx = OPlayerApplication.getContext(); // // ThumbnailUtils. // Bitmap bitmap = ThumbnailUtils.createVideoThumbnail(media.path, Images.Thumbnails.MINI_KIND); // try { // if (bitmap == null) { // //缩略图创建失败 // bitmap = Bitmap.createBitmap(ThumbnailUtils.TARGET_SIZE_MINI_THUMBNAIL_WIDTH, ThumbnailUtils.TARGET_SIZE_MINI_THUMBNAIL_HEIGHT, Bitmap.Config.RGB_565); // } // // media.width = bitmap.getWidth(); // media.height = bitmap.getHeight(); // // //缩略图 // bitmap = ThumbnailUtils.extractThumbnail(bitmap, ConvertUtils.dipToPX(ctx, ThumbnailUtils.TARGET_SIZE_MICRO_THUMBNAIL_WIDTH), ConvertUtils.dipToPX(ctx, ThumbnailUtils.TARGET_SIZE_MICRO_THUMBNAIL_HEIGHT), ThumbnailUtils.OPTIONS_RECYCLE_INPUT); // if (bitmap != null) { // //将缩略图存到视频当前路径 // File thum = new File(OPlayerApplication.OPLAYER_VIDEO_THUMB, UUID.randomUUID().toString()); // media.thumb_path = thum.getAbsolutePath(); // //thum.createNewFile(); // FileOutputStream iStream = new FileOutputStream(thum); // bitmap.compress(Bitmap.CompressFormat.JPEG, 85, iStream); // iStream.close(); // } // // //入库 // // } catch (Exception ex) { // Logger.e(ex); // } finally { // if (bitmap != null) // bitmap.recycle(); // // } } // ~~~ 状态改变 /** 通知状态改变 */ private void notifyObservers(int flag, POMedia media) { mHandler.sendMessage(mHandler.obtainMessage(flag, media)); } /** 增加观察者 */ public void addObserver(IMediaScannerObserver s) { synchronized (this) { if (!observers.contains(s)) { observers.add(s); } } } /** 删除观察者 */ public synchronized void deleteObserver(IMediaScannerObserver s) { observers.remove(s); } /** 删除所有观察者 */ public synchronized void deleteObservers() { observers.clear(); } public interface IMediaScannerObserver { /** * * @param flag 0 开始扫描 1 正在扫描 2 扫描完成 * @param file 扫描到的视频文件 */ public void update(int flag, POMedia media); } // ~~~ Binder private final MediaScannerServiceBinder mBinder = new MediaScannerServiceBinder(); public class MediaScannerServiceBinder extends Binder { public MediaScannerService getService() { return MediaScannerService.this; } } @Override public IBinder onBind(Intent intent) { return mBinder; } } ================================================ FILE: src/com/nmbb/oplayer/ui/FragmentBase.java ================================================ package com.nmbb.oplayer.ui; import com.nmbb.oplayer.R; import android.content.BroadcastReceiver; import android.content.IntentFilter; import android.database.ContentObserver; import android.net.Uri; import android.os.Bundle; import android.support.v4.app.Fragment; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.ListView; public class FragmentBase extends Fragment { protected ListView mListView; protected View mLoadingLayout; protected MainActivity mParent; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mParent = (MainActivity) getActivity(); } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View v = inflater.inflate(R.layout.fragment_file, container, false); mListView = (ListView) v.findViewById(android.R.id.list); mLoadingLayout = v.findViewById(R.id.loading); return v; } public boolean onBackPressed() { return false; } public void registerReceiver(BroadcastReceiver receiver, IntentFilter filter) { if (mParent != null) mParent.registerReceiver(receiver, filter); } public void unregisterReceiver(BroadcastReceiver receiver) { if (mParent != null) mParent.unregisterReceiver(receiver); } public void registerContentObserver(Uri uri, boolean notifyForDescendents, ContentObserver observer) { if (mParent != null) mParent.getContentResolver().registerContentObserver(uri, notifyForDescendents, observer); } public void unregisterContentObserver(ContentObserver observer) { if (mParent != null) mParent.getContentResolver().unregisterContentObserver(observer); } } ================================================ FILE: src/com/nmbb/oplayer/ui/FragmentFileOld.java ================================================ package com.nmbb.oplayer.ui; import java.io.File; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import android.app.AlertDialog; import android.content.ComponentName; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.content.ServiceConnection; import android.net.Uri; import android.os.AsyncTask; import android.os.Bundle; import android.os.Handler; import android.os.IBinder; import android.os.Message; import android.view.ContextMenu; import android.view.ContextMenu.ContextMenuInfo; import android.view.LayoutInflater; import android.view.MenuItem; import android.view.MotionEvent; import android.view.View; import android.view.View.OnTouchListener; import android.view.ViewGroup; import android.widget.AdapterView; import android.widget.AdapterView.OnItemClickListener; import android.widget.EditText; import android.widget.ImageView; import android.widget.ListView; import android.widget.TextView; import android.widget.Toast; import com.nmbb.oplayer.R; import com.nmbb.oplayer.business.FileBusiness; import com.nmbb.oplayer.database.DbHelper; import com.nmbb.oplayer.po.POMedia; import com.nmbb.oplayer.service.MediaScannerService; import com.nmbb.oplayer.service.MediaScannerService.IMediaScannerObserver; import com.nmbb.oplayer.service.MediaScannerService.MediaScannerServiceBinder; import com.nmbb.oplayer.ui.base.ArrayAdapter; import com.nmbb.oplayer.ui.helper.FileDownloadHelper; import com.nmbb.oplayer.ui.player.VideoActivity; import com.nmbb.oplayer.util.FileUtils; public class FragmentFileOld extends FragmentBase implements OnItemClickListener, IMediaScannerObserver { private FileAdapter mAdapter; private FileAdapter mDownloadAdapter; private TextView first_letter_overlay; private ImageView alphabet_scroller; /** 临时列表 */ private ListView mTempListView; private MainActivity mParent; private TextView mSDAvailable; /** 左下角进度显示 */ private View mProgress; private MediaScannerService mMediaScannerService; private ServiceConnection mMediaScannerServiceConnection = new ServiceConnection() { @Override public void onServiceDisconnected(ComponentName name) { mMediaScannerService = null; } @Override public void onServiceConnected(ComponentName name, IBinder service) { mMediaScannerService = ((MediaScannerServiceBinder) service) .getService(); mMediaScannerService.addObserver(FragmentFileOld.this); // Toast.makeText(ComponentServiceActivity.this, "Service绑定成功!", // Toast.LENGTH_SHORT).show(); } }; @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View v = super.onCreateView(inflater, container, savedInstanceState); // ~~~~~~~~~ 绑定控件 first_letter_overlay = (TextView) v .findViewById(R.id.first_letter_overlay); alphabet_scroller = (ImageView) v.findViewById(R.id.alphabet_scroller); mTempListView = (ListView) v.findViewById(R.id.templist); mSDAvailable = (TextView) v.findViewById(R.id.sd_block); mProgress = v.findViewById(android.R.id.progress); // ~~~~~~~~~ 绑定事件 alphabet_scroller.setClickable(true); alphabet_scroller.setOnTouchListener(asOnTouch); mListView.setOnItemClickListener(this); mTempListView.setOnItemClickListener(this); mListView.setOnCreateContextMenuListener(OnListViewMenu); mTempListView.setOnCreateContextMenuListener(OnTempListViewMenu); // ~~~~~~~~~ 加载数据 mParent = (MainActivity) getActivity(); // if (new SQLiteHelper(getActivity()).isEmpty()) // new ScanVideoTask().execute(); // else new DataTask().execute(); getActivity().bindService( new Intent(getActivity().getApplicationContext(), MediaScannerService.class), mMediaScannerServiceConnection, Context.BIND_AUTO_CREATE); return v; } @Override public void onStart() { super.onStart(); } @Override public void onDestroy() { getActivity().unbindService(mMediaScannerServiceConnection); super.onDestroy(); } /** * * @param flag * 0 开始扫描 1 正在扫描 2 扫描完成 * @param file * 扫描到的视频文件 */ @Override public void update(int flag, POMedia media) { // Logger.i(flag + " " + media.path); switch (flag) { case MediaScannerService.SCAN_STATUS_START: break; case MediaScannerService.SCAN_STATUS_END:// 扫描完成 if (mProgress != null) mProgress.setVisibility(View.GONE); new DataTask().execute(); break; case MediaScannerService.SCAN_STATUS_RUNNING:// 扫到一个文件 if (mAdapter != null && media != null) { mAdapter.add(media); mAdapter.notifyDataSetChanged(); } break; } } @Override public void onResume() { super.onResume(); // SD卡剩余数量 mSDAvailable.setText(FileUtils.showFileAvailable()); if (MediaScannerService.isRunning()) mProgress.setVisibility(View.VISIBLE); else mProgress.setVisibility(View.GONE); } ListView.OnCreateContextMenuListener OnListViewMenu = new ListView.OnCreateContextMenuListener() { @Override public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) { menu.setHeaderTitle(R.string.file_oper); menu.add(0, 0, 0, R.string.file_rename); menu.add(0, 1, 0, R.string.file_delete); } }; ListView.OnCreateContextMenuListener OnTempListViewMenu = new ListView.OnCreateContextMenuListener() { @Override public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) { menu.setHeaderTitle(R.string.file_oper); menu.add(0, 2, 0, R.string.file_rename); menu.add(0, 3, 0, R.string.file_delete); } }; @Override public boolean onContextItemSelected(MenuItem item) { ContextMenuInfo info = item.getMenuInfo(); AdapterView.AdapterContextMenuInfo contextMenuInfo = (AdapterView.AdapterContextMenuInfo) info; int position = contextMenuInfo.position; switch (item.getItemId()) { case 0: renameFile(mAdapter, mAdapter.getItem(position), position); break; case 1: deleteFile(mAdapter, mAdapter.getItem(position), position); break; case 2: renameFile(mDownloadAdapter, mDownloadAdapter.getItem(position), position); break; case 3: deleteFile(mDownloadAdapter, mDownloadAdapter.getItem(position), position); break; } return super.onContextItemSelected(item); }; /** 删除文件 */ private void deleteFile(final FileAdapter adapter, final POMedia f, final int position) { new AlertDialog.Builder(getActivity()) .setIcon(android.R.drawable.ic_dialog_alert) .setTitle(R.string.file_delete) .setMessage(getString(R.string.file_delete_confirm, f.title)) .setNegativeButton(android.R.string.yes, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { try { File file = new File(f.path); if (file.canRead() && file.exists()) file.delete(); // FileBusiness.deleteFile(getActivity(), // f); new DbHelper().remove(f); adapter.delete(position); } catch (Exception e) { } } }).setPositiveButton(android.R.string.no, null).show(); } /** 重命名文件 */ private void renameFile(final FileAdapter adapter, final POMedia f, final int position) { final EditText et = new EditText(getActivity()); et.setText(f.title); new AlertDialog.Builder(getActivity()) .setTitle(R.string.file_rename) .setIcon(android.R.drawable.ic_dialog_info) .setView(et) .setNegativeButton(android.R.string.yes, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { String name = et.getText().toString().trim(); if (name == null || name.trim().equals("") || name.trim().equals(f.title)) return; try { File fromFile = new File(f.path); File nf = new File(fromFile.getParent(), name.trim()); if (nf.exists()) { Toast.makeText(getActivity(), R.string.file_rename_exists, Toast.LENGTH_LONG).show(); } else if (fromFile.renameTo(nf)) { f.title = name; f.path = nf.getPath(); // FileBusiness.renameFile(getActivity(), // f); new DbHelper().update(f); adapter.notifyDataSetChanged(); } } catch (SecurityException se) { Toast.makeText(getActivity(), R.string.file_rename_failed, Toast.LENGTH_LONG).show(); } } }).setPositiveButton(android.R.string.no, null).show(); } public Handler mDownloadHandler = new Handler() { @Override public void handleMessage(Message msg) { POMedia p; String url = msg.obj.toString(); switch (msg.what) { case FileDownloadHelper.MESSAGE_START:// 开始下载 p = new POMedia(); p.path = mParent.mFileDownload.mDownloadUrls.get(url); p.title = new File(p.path).getName(); p.status = 0; p.file_size = 0; if (mDownloadAdapter == null) { mDownloadAdapter = new FileAdapter(getActivity(), new ArrayList()); mDownloadAdapter.add(p, url); mTempListView.setAdapter(mDownloadAdapter); mTempListView.setVisibility(View.VISIBLE); } else { mDownloadAdapter.add(p, url); mDownloadAdapter.notifyDataSetChanged(); } break; case FileDownloadHelper.MESSAGE_PROGRESS:// 正在下载 p = mDownloadAdapter.getItem(url); p.temp_file_size = msg.arg1; p.file_size = msg.arg2; int status = (int) ((msg.arg1 * 1.0 / msg.arg2) * 10); if (status > 10) status = 10; p.status = status; mDownloadAdapter.notifyDataSetChanged(); break; case FileDownloadHelper.MESSAGE_STOP:// 下载结束 p = mDownloadAdapter.getItem(url); new DbHelper().create(p); // FileBusiness.insertFile(getActivity(), p); break; case FileDownloadHelper.MESSAGE_ERROR: Toast.makeText(getActivity(), url, Toast.LENGTH_LONG).show(); break; } super.handleMessage(msg); } }; /** 单击启动播放 */ @Override public void onItemClick(AdapterView parent, View view, int position, long id) { final POMedia f = parent == mListView ? mAdapter.getItem(position) : mDownloadAdapter.getItem(position); Intent intent = new Intent(getActivity(), VideoActivity.class); intent.setData(Uri.parse(f.path)); // intent.putExtra("path", f.path); intent.putExtra("displayName", f.title); startActivity(intent); } private class DataTask extends AsyncTask> { @Override protected void onPreExecute() { super.onPreExecute(); mLoadingLayout.setVisibility(View.VISIBLE); mListView.setVisibility(View.GONE); } @Override protected List doInBackground(Void... params) { return FileBusiness.getAllSortFiles(); } @Override protected void onPostExecute(List result) { super.onPostExecute(result); mAdapter = new FileAdapter(getActivity(), result); mListView.setAdapter(mAdapter); mLoadingLayout.setVisibility(View.GONE); mListView.setVisibility(View.VISIBLE); } } private class FileAdapter extends ArrayAdapter { private HashMap maps = new HashMap(); public FileAdapter(Context ctx, List l) { super(ctx, l); maps.clear(); } @Override public View getView(int position, View convertView, ViewGroup parent) { final POMedia f = getItem(position); if (convertView == null) { final LayoutInflater mInflater = getActivity() .getLayoutInflater(); convertView = mInflater.inflate(R.layout.fragment_file_item, null); } ((TextView) convertView.findViewById(R.id.title)).setText(f.title); // 显示文件大小 String file_size; if (f.temp_file_size > 0) { file_size = FileUtils.showFileSize(f.temp_file_size) + " / " + FileUtils.showFileSize(f.file_size); } else { file_size = FileUtils.showFileSize(f.file_size); } ((TextView) convertView.findViewById(R.id.file_size)) .setText(file_size); // 显示进度表 final ImageView status = (ImageView) convertView .findViewById(R.id.status); if (f.status > -1) { int resStauts = getStatusImage(f.status); if (resStauts > 0) { if (status.getVisibility() != View.VISIBLE) status.setVisibility(View.VISIBLE); status.setImageResource(resStauts); } } else { if (status.getVisibility() != View.GONE) status.setVisibility(View.GONE); } return convertView; } public void add(POMedia item, String url) { super.add(item); if (!maps.containsKey(url)) maps.put(url, item); } public void delete(int position) { synchronized (mLock) { mObjects.remove(position); } notifyDataSetChanged(); } public POMedia getItem(String url) { return maps.get(url); } } private int getStatusImage(int status) { int resStauts = -1; switch (status) { case 0: resStauts = R.drawable.down_btn_0; break; case 1: resStauts = R.drawable.down_btn_1; break; case 2: resStauts = R.drawable.down_btn_2; break; case 3: resStauts = R.drawable.down_btn_3; break; case 4: resStauts = R.drawable.down_btn_4; break; case 5: resStauts = R.drawable.down_btn_5; break; case 6: resStauts = R.drawable.down_btn_6; break; case 7: resStauts = R.drawable.down_btn_7; break; case 8: resStauts = R.drawable.down_btn_8; break; case 9: resStauts = R.drawable.down_btn_9; break; case 10: resStauts = R.drawable.down_btn_10; break; } return resStauts; } /** * A-Z */ private OnTouchListener asOnTouch = new OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_DOWN:// 0 alphabet_scroller.setPressed(true); first_letter_overlay.setVisibility(View.VISIBLE); mathScrollerPosition(event.getY()); break; case MotionEvent.ACTION_UP:// 1 alphabet_scroller.setPressed(false); first_letter_overlay.setVisibility(View.GONE); break; case MotionEvent.ACTION_MOVE: mathScrollerPosition(event.getY()); break; } return false; } }; /** * 显示字符 * * @param y */ private void mathScrollerPosition(float y) { int height = alphabet_scroller.getHeight(); float charHeight = height / 28.0f; char c = 'A'; if (y < 0) y = 0; else if (y > height) y = height; int index = (int) (y / charHeight) - 1; if (index < 0) index = 0; else if (index > 25) index = 25; String key = String.valueOf((char) (c + index)); first_letter_overlay.setText(key); int position = 0; if (index == 0) mListView.setSelection(0); else if (index == 25) mListView.setSelection(mAdapter.getCount() - 1); else { if (mAdapter != null && mAdapter.getAll() != null) { for (POMedia item : mAdapter.getAll()) { if (item.title_key.startsWith(key)) { mListView.setSelection(position); break; } position++; } } } } // ~~~~~~~~~~~~~~ 后续弃用,直接使用Vitamio提供的 // /** 扫描SD卡 */ // private class ScanVideoTask extends AsyncTask> { // private ProgressDialog pd; // private ArrayList files = new ArrayList(); // // @Override // protected void onPreExecute() { // super.onPreExecute(); // pd = new ProgressDialog(getActivity()); // pd.setMessage("正在扫描视频文件..."); // pd.setCanceledOnTouchOutside(false); // pd.setCancelable(false); // pd.show(); // } // // @Override // protected ArrayList doInBackground(Void... params) { // // ~~~ 遍历文件夹 // eachAllMedias(Environment.getExternalStorageDirectory()); // // // ~~~ 提取缩略图、视频尺寸等。 // FileBusiness.batchBuildThumbnail(getActivity(), files); // // // ~~~ 入库 // FileBusiness.batchInsertFiles(getActivity(), files); // // // ~~~ 查询数据 // return FileBusiness.getAllSortFiles(getActivity()); // } // // @Override // protected void onProgressUpdate(final File... values) { // pd.setMessage(values[0].getName()); // } // // /** 遍历所有文件夹,查找出视频文件 */ // public void eachAllMedias(File f) { // if (f != null && f.exists() && f.isDirectory()) { // File[] files = f.listFiles(); // if (files != null) { // for (File file : f.listFiles()) { // if (file.isDirectory()) { // eachAllMedias(file); // } else if (file.exists() && file.canRead() && FileUtils.isVideo(file)) { // this.files.add(file); // } // publishProgress(file); // } // } // } // } // // @Override // protected void onPostExecute(ArrayList result) { // super.onPostExecute(result); // mAdapter = new FileAdapter(getActivity(), result); // mListView.setAdapter(mAdapter); // pd.dismiss(); // } // } } ================================================ FILE: src/com/nmbb/oplayer/ui/FragmentOnline.java ================================================ package com.nmbb.oplayer.ui; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.List; import com.nmbb.oplayer.R; import com.nmbb.oplayer.po.OnlineVideo; import com.nmbb.oplayer.ui.base.ArrayAdapter; import com.nmbb.oplayer.ui.helper.XmlReaderHelper; import com.nmbb.oplayer.ui.player.VideoActivity; import com.nmbb.oplayer.util.FileUtils; import android.app.AlertDialog; import android.app.Dialog; import android.content.Context; import android.content.DialogInterface; import android.content.DialogInterface.OnClickListener; import android.content.Intent; import android.graphics.Bitmap; import android.net.Uri; import android.os.Bundle; import android.os.Environment; import android.text.TextUtils; import android.view.KeyEvent; import android.view.LayoutInflater; import android.view.View; import android.view.View.OnKeyListener; import android.view.ViewGroup; import android.webkit.WebView; import android.webkit.WebViewClient; import android.widget.AdapterView; import android.widget.AdapterView.OnItemClickListener; import android.widget.ImageView; import android.widget.ListView; import android.widget.TextView; import android.widget.Toast; public class FragmentOnline extends FragmentBase implements OnItemClickListener { /** 缓存视频列表 */ private static ArrayList mOnlineList = new ArrayList(); /** 缓存视频LOGO列表 */ private static ArrayList mOnlineLogoList = new ArrayList(); private WebView mWebView; private ListView mListView; /** 网页正在加载 */ private View mLoading; /** 历史记录 */ private List mHistory = new ArrayList(); /** 显示当前正在加载的url */ private TextView mUrl; private String mTitle; private final static ArrayList root = new ArrayList(); private ArrayList tvs; private final static ArrayList videos = new ArrayList(); private int level = 1; private DataAdapter mAdapter; @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View mView = inflater.inflate(R.layout.fragment_online, container, false); mListView = (ListView) mView.findViewById(android.R.id.list); mWebView = (WebView) mView.findViewById(R.id.webview); mUrl = (TextView) mView.findViewById(R.id.url); mLoading = mView.findViewById(R.id.loading); mListView.setOnItemClickListener(this); initWebView(); mAdapter = new DataAdapter(getActivity()); mListView.setAdapter(new DataAdapter(getActivity())); return mView; } @Override public void onItemClick(AdapterView parent, View view, int position, long id) { final OnlineVideo item = mAdapter.getItem(position); switch (level) { case 1:// 顶级 level = 2; if (position == 0) { // 直播  if (tvs == null) tvs = XmlReaderHelper.getAllCategory(getActivity()); mAdapter.replace(tvs); } else { // 视频  mAdapter.replace(videos); } mListView.setAdapter(mAdapter); break; case 2:// level = 3; if (item.id != null) { // 直播 mAdapter.replace(XmlReaderHelper.getVideos(getActivity(), item.id)); mListView.setAdapter(mAdapter); } else { clearAndLoad(item.url); } break; case 3: level = 4; // clearAndLoad(item.url); Intent intent = new Intent(getActivity(), VideoActivity.class); intent.setData(Uri.parse(item.url)); // intent.putExtra("path", item.url); intent.putExtra( "displayName ", item.title); startActivity(intent); break; } } private void clearAndLoad(String url) { mLoading.setVisibility(View.VISIBLE); mWebView.setVisibility(View.GONE); mListView.setVisibility(View.GONE); mHistory.clear(); mWebView.clearView(); mWebView.loadUrl(url); } @Override public boolean onBackPressed() { switch (level) { case 1: return super.onBackPressed(); case 2: level = 1; mAdapter.replace(root); break; case 3:// level = 2; if (mListView == null || mListView.getVisibility() == View.VISIBLE) { mAdapter.replace(tvs); } else { switchWebViewToListView(); } break; case 4: level = 3; switchWebViewToListView(); break; } mListView.setAdapter(mAdapter); return true; } private void switchWebViewToListView() { mWebView.clearView(); mUrl.setVisibility(View.GONE); mListView.setVisibility(View.VISIBLE); mWebView.setVisibility(View.GONE); mLoading.setVisibility(View.GONE); } /** 初始化WebView */ private void initWebView() { mWebView.setScrollBarStyle(View.SCROLLBARS_OUTSIDE_OVERLAY); mWebView.getSettings().setJavaScriptEnabled(true); mWebView.getSettings().setPluginsEnabled(true); mWebView.setWebViewClient(new WebViewClient() { /** 页面开始加载 */ @Override public void onPageStarted(WebView view, String url, Bitmap favicon) { super.onPageStarted(view, url, favicon); mUrl.setText(url); mUrl.setVisibility(View.VISIBLE); } /** 页面加载完成 */ @Override public void onPageFinished(WebView view, String url) { super.onPageFinished(view, url); mLoading.setVisibility(View.GONE); mWebView.setVisibility(View.VISIBLE); if (!mHistory.contains(url)) mHistory.add(0, url); mUrl.setVisibility(View.GONE); // 取得title mTitle = view.getTitle(); }; /** 页面跳转 */ @Override public boolean shouldOverrideUrlLoading(WebView view, final String url) { if (FileUtils.isVideoOrAudio(url)) { Dialog dialog = new AlertDialog.Builder(getActivity()) .setIcon(android.R.drawable.btn_star) .setTitle("播放/下载").setMessage(url) .setPositiveButton("播放", new OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { Intent intent = new Intent(getActivity(), VideoPlayerActivity.class); intent.putExtra("path", url); intent.putExtra("title", mTitle); startActivity(intent); } }).setNeutralButton("下载", new OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { if (Environment.MEDIA_MOUNTED .equals(Environment .getExternalStorageState())) { MainActivity activity = (MainActivity) getActivity(); String savePath = Environment .getExternalStorageDirectory() + "/"; if (TextUtils.isEmpty(mTitle)) savePath += FileUtils .getUrlFileName(url); else { savePath += mTitle + "." + FileUtils .getUrlExtension(url); } activity.mFileDownload.newDownloadFile( url, savePath); Toast.makeText( getActivity(), "正在下载 .." + FileUtils .getUrlFileName(savePath) + " ,可从本地视频查看进度!", Toast.LENGTH_LONG).show(); } else { Toast.makeText(getActivity(), "请检测SD卡!", Toast.LENGTH_LONG) .show(); } } }).setNegativeButton("取消", null).create(); dialog.show(); return true; } return false; }; }); /** 处理后退键 */ mWebView.setOnKeyListener(new OnKeyListener() { @Override public boolean onKey(View v, int keyCode, KeyEvent event) { if ((keyCode == KeyEvent.KEYCODE_BACK) && mWebView != null && mWebView.canGoBack()) { if (mHistory.size() > 1) { mHistory.remove(0); mWebView.loadUrl(mHistory.get(0)); return true; } } return false; } }); } /** 数据适配 */ private class DataAdapter extends ArrayAdapter { public DataAdapter(Context ctx) { super(ctx, root); } @Override public View getView(int position, View convertView, ViewGroup parent) { final OnlineVideo item = getItem(position); if (convertView == null) { final LayoutInflater mInflater = getActivity() .getLayoutInflater(); convertView = mInflater.inflate(R.layout.fragment_online_item, null); } ImageView thumbnail = (ImageView) convertView .findViewById(R.id.thumbnail); if (item.iconId > 0) thumbnail.setImageResource(item.iconId); else thumbnail.setImageDrawable(null); ((TextView) convertView.findViewById(R.id.title)) .setText(item.title); return convertView; } } // ~~~~~~~~~~~~~处理FLASH退出的问题 ~~~~~~~~ private void callHiddenWebViewMethod(String name) { if (mWebView != null) { try { Method method = WebView.class.getMethod(name); method.invoke(mWebView); } catch (NoSuchMethodException e) { } catch (IllegalAccessException e) { } catch (InvocationTargetException e) { } } } @Override public void onPause() { super.onPause(); if (mWebView != null) { mWebView.pauseTimers(); if (getActivity().isFinishing()) { mWebView.loadUrl("about:blank"); } callHiddenWebViewMethod("onPause"); } } @Override public void onResume() { super.onResume(); if (mWebView != null) { mWebView.resumeTimers(); callHiddenWebViewMethod("onResume"); } } static { // private final static String[] CATEGORY = { "电视直播", "视频网站" }; root.add(new OnlineVideo("电视直播", R.drawable.logo_cntv, 1)); root.add(new OnlineVideo("视频网站", R.drawable.logo_youku, 0)); videos.add(new OnlineVideo("优酷视频", R.drawable.logo_youku, 0, "http://3g.youku.com")); videos.add(new OnlineVideo("搜狐视频", R.drawable.logo_sohu, 0, "http://m.tv.sohu.com")); videos.add(new OnlineVideo("乐视TV", R.drawable.logo_letv, 0, "http://m.letv.com")); videos.add(new OnlineVideo("爱奇异", R.drawable.logo_iqiyi, 0, "http://3g.iqiyi.com/")); videos.add(new OnlineVideo("PPTV", R.drawable.logo_pptv, 0, "http://m.pptv.com/")); videos.add(new OnlineVideo("腾讯视频", R.drawable.logo_qq, 0, "http://3g.v.qq.com/")); videos.add(new OnlineVideo("56.com", R.drawable.logo_56, 0, "http://m.56.com/")); videos.add(new OnlineVideo("新浪视频", R.drawable.logo_sina, 0, "http://video.sina.cn/")); videos.add(new OnlineVideo("土豆视频", R.drawable.logo_tudou, 0, "http://m.tudou.com")); } } /* * private boolean loadVideo(final String url) { if (StringUtils.isEmpty(url)) * return false; * * mCurrentUrl = url; * * new AsyncTask() { * * @Override protected OnlineVideo doInBackground(Void... params) { * Log.d("Youku", url); if (url.startsWith("http://m.youku.com")) { return * VideoHelper.getYoukuVideo(url); } return null; } * * @Override protected void onPostExecute(OnlineVideo result) { * super.onPostExecute(result); if (result != null) { Intent intent = new * Intent(getActivity(), VideoPlayerActivity.class); intent.putExtra("path", * result.url); intent.putExtra("title", result.title); startActivity(intent); } * else { mWebView.loadUrl(url); } } }.execute(); return true; } */ ================================================ FILE: src/com/nmbb/oplayer/ui/MainActivity.java ================================================ package com.nmbb.oplayer.ui; import android.content.Intent; import android.os.Bundle; import android.os.Environment; import android.support.v4.app.Fragment; import android.support.v4.app.FragmentActivity; import android.support.v4.app.FragmentPagerAdapter; import android.support.v4.view.ViewPager; import android.view.View; import android.view.View.OnClickListener; import android.widget.RadioButton; import com.nmbb.oplayer.OPlayerApplication; import com.nmbb.oplayer.OPreference; import com.nmbb.oplayer.R; import com.nmbb.oplayer.service.MediaScannerService; import com.nmbb.oplayer.ui.helper.FileDownloadHelper; import com.nmbb.oplayer.ui.vitamio.LibsChecker; public class MainActivity extends FragmentActivity implements OnClickListener { private ViewPager mPager; private RadioButton mRadioFile; private RadioButton mRadioOnline; public FileDownloadHelper mFileDownload; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); if (!LibsChecker.checkVitamioLibs(this, R.string.init_decoders)) return; OPreference pref = new OPreference(this); // 首次运行,扫描SD卡 if (pref.getBoolean(OPlayerApplication.PREF_KEY_FIRST, true)) { getApplicationContext().startService(new Intent(getApplicationContext(), MediaScannerService.class).putExtra(MediaScannerService.EXTRA_DIRECTORY, Environment.getExternalStorageDirectory().getAbsolutePath())); } setContentView(R.layout.fragment_pager); // ~~~~~~ 绑定控件 mPager = (ViewPager) findViewById(R.id.pager); mRadioFile = (RadioButton) findViewById(R.id.radio_file); mRadioOnline = (RadioButton) findViewById(R.id.radio_online); // ~~~~~~ 绑定事件 mRadioFile.setOnClickListener(this); mRadioOnline.setOnClickListener(this); mPager.setOnPageChangeListener(mPagerListener); // ~~~~~~ 绑定数据 mPager.setAdapter(mAdapter); } @Override public void onBackPressed() { if (getFragmentByPosition(mPager.getCurrentItem()).onBackPressed()) return; else super.onBackPressed(); } @Override protected void onDestroy() { super.onDestroy(); if (mFileDownload != null) mFileDownload.stopALl(); } /** 查找Fragment */ private FragmentBase getFragmentByPosition(int position) { return (FragmentBase) getSupportFragmentManager().findFragmentByTag("android:switcher:" + mPager.getId() + ":" + position); } private FragmentPagerAdapter mAdapter = new FragmentPagerAdapter(getSupportFragmentManager()) { /** 仅执行一次 */ @Override public Fragment getItem(int position) { Fragment result = null; switch (position) { case 1: result = new FragmentOnline();// 在线视频 break; case 0: default: result = new FragmentFileOld();// 本地视频 mFileDownload = new FileDownloadHelper(((FragmentFileOld) result).mDownloadHandler); break; } return result; } @Override public int getCount() { return 2; } }; private ViewPager.SimpleOnPageChangeListener mPagerListener = new ViewPager.SimpleOnPageChangeListener() { @Override public void onPageSelected(int position) { switch (position) { case 0:// 本地视频 mRadioFile.setChecked(true); break; case 1:// 在线视频 mRadioOnline.setChecked(true); break; } } }; @Override public void onClick(View v) { switch (v.getId()) { case R.id.radio_file: mPager.setCurrentItem(0); break; case R.id.radio_online: mPager.setCurrentItem(1); break; } } } ================================================ FILE: src/com/nmbb/oplayer/ui/PlayerActivity.java ================================================ /* * Copyright (C) 2011 VOV IO (http://vov.io/) */ package com.nmbb.oplayer.ui; import com.nmbb.oplayer.R; import io.vov.vitamio.MediaPlayer; import io.vov.vitamio.MediaPlayer.OnBufferingUpdateListener; import io.vov.vitamio.MediaPlayer.OnCompletionListener; import io.vov.vitamio.MediaPlayer.OnPreparedListener; import io.vov.vitamio.MediaPlayer.OnVideoSizeChangedListener; import android.app.Activity; import android.os.Bundle; import android.os.Environment; import android.util.Log; import android.view.SurfaceHolder; import android.view.SurfaceView; public class PlayerActivity extends Activity implements OnBufferingUpdateListener, OnCompletionListener, OnPreparedListener, OnVideoSizeChangedListener, SurfaceHolder.Callback { private static final String TAG = "MediaPlayerDemo"; private int mVideoWidth; private int mVideoHeight; private MediaPlayer mMediaPlayer; private SurfaceView mPreview; private SurfaceHolder holder; private String path = Environment.getExternalStorageDirectory() + "/Moon.mp4"; private boolean mIsVideoSizeKnown = false; private boolean mIsVideoReadyToBePlayed = false; @Override public void onCreate(Bundle icicle) { super.onCreate(icicle); setContentView(R.layout.mediaplayer); mPreview = (SurfaceView) findViewById(R.id.surface); holder = mPreview.getHolder(); holder.addCallback(this); } private void playVideo() { doCleanUp(); try { mMediaPlayer = new MediaPlayer(this); mMediaPlayer.setDataSource(path); mMediaPlayer.setDisplay(holder); mMediaPlayer.prepareAsync(); mMediaPlayer.setScreenOnWhilePlaying(true); mMediaPlayer.setOnBufferingUpdateListener(this); mMediaPlayer.setOnCompletionListener(this); mMediaPlayer.setOnPreparedListener(this); mMediaPlayer.setOnVideoSizeChangedListener(this); } catch (Exception e) { Log.e(TAG, "error: " + e.getMessage(), e); } } @Override public void onBufferingUpdate(MediaPlayer arg0, int percent) { Log.d(TAG, "onBufferingUpdate percent:" + percent); } @Override public void onCompletion(MediaPlayer arg0) { Log.d(TAG, "onCompletion called"); mMediaPlayer.release(); } @Override public void onVideoSizeChanged(MediaPlayer mp, int width, int height) { Log.v(TAG, "onVideoSizeChanged called"); if (width == 0 || height == 0) { Log.e(TAG, "invalid video width(" + width + ") or height(" + height + ")"); return; } mIsVideoSizeKnown = true; mVideoWidth = width; mVideoHeight = height; if (mIsVideoReadyToBePlayed && mIsVideoSizeKnown) { startVideoPlayback(); } } @Override public void onPrepared(MediaPlayer mediaplayer) { Log.d(TAG, "onPrepared called"); mIsVideoReadyToBePlayed = true; if (mIsVideoReadyToBePlayed && mIsVideoSizeKnown) { startVideoPlayback(); } } @Override public void surfaceChanged(SurfaceHolder surfaceholder, int i, int j, int k) { Log.d(TAG, "surfaceChanged called" + i + " " + j + " " + k); } @Override public void surfaceDestroyed(SurfaceHolder surfaceholder) { Log.d(TAG, "surfaceDestroyed called"); } @Override public void surfaceCreated(SurfaceHolder holder) { Log.d(TAG, "surfaceCreated called"); playVideo(); } @Override protected void onPause() { super.onPause(); releaseMediaPlayer(); doCleanUp(); } @Override protected void onDestroy() { super.onDestroy(); releaseMediaPlayer(); doCleanUp(); } private void releaseMediaPlayer() { if (mMediaPlayer != null) { mMediaPlayer.release(); mMediaPlayer = null; } } private void doCleanUp() { mVideoWidth = 0; mVideoHeight = 0; mIsVideoReadyToBePlayed = false; mIsVideoSizeKnown = false; } private void startVideoPlayback() { Log.v(TAG, "startVideoPlayback"); holder.setFixedSize(mVideoWidth, mVideoHeight); mMediaPlayer.start(); } } ================================================ FILE: src/com/nmbb/oplayer/ui/VideoPlayerActivity.java ================================================ /* * Copyright (C) 2011 VOV IO (http://vov.io/) */ package com.nmbb.oplayer.ui; import com.nmbb.oplayer.R; import com.nmbb.oplayer.exception.Logger; import com.nmbb.oplayer.ui.vitamio.LibsChecker; import io.vov.vitamio.MediaPlayer; import io.vov.vitamio.MediaPlayer.OnCompletionListener; import io.vov.vitamio.MediaPlayer.OnInfoListener; import io.vov.vitamio.widget.MediaController; import io.vov.vitamio.widget.VideoView; import android.app.Activity; import android.content.Context; import android.content.Intent; import android.content.pm.ActivityInfo; import android.content.res.Configuration; import android.media.AudioManager; import android.net.Uri; import android.os.Bundle; import android.os.Environment; import android.os.Handler; import android.os.Message; import android.text.TextUtils; import android.view.Display; import android.view.GestureDetector.SimpleOnGestureListener; import android.view.GestureDetector; import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; import android.view.WindowManager; import android.widget.ImageView; public class VideoPlayerActivity extends Activity implements OnCompletionListener, OnInfoListener { private String mPath; private String mTitle; private VideoView mVideoView; private View mVolumeBrightnessLayout; private ImageView mOperationBg; private ImageView mOperationPercent; private AudioManager mAudioManager; /** 最大声音 */ private int mMaxVolume; /** 当前声音 */ private int mVolume = -1; /** 当前亮度 */ private float mBrightness = -1f; /** 当前缩放模式 */ private int mLayout = VideoView.VIDEO_LAYOUT_ZOOM; private GestureDetector mGestureDetector; private MediaController mMediaController; private View mLoadingView; @Override public void onCreate(Bundle bundle) { super.onCreate(bundle); // ~~~ 检测Vitamio是否解压解码包 if (!LibsChecker.checkVitamioLibs(this, R.string.init_decoders)) return; // ~~~ 获取播放地址和标题 Intent intent = getIntent(); mPath = intent.getStringExtra("path"); mTitle = intent.getStringExtra("title"); if (TextUtils.isEmpty(mPath)) { mPath = Environment.getExternalStorageDirectory() + "/video/你太猖狂.flv"; } else if (intent.getData() != null) mPath = intent.getData().toString(); // ~~~ 绑定控件 setContentView(R.layout.videoview); mVideoView = (VideoView) findViewById(R.id.surface_view); mVolumeBrightnessLayout = findViewById(R.id.operation_volume_brightness); mOperationBg = (ImageView) findViewById(R.id.operation_bg); mOperationPercent = (ImageView) findViewById(R.id.operation_percent); mLoadingView = findViewById(R.id.video_loading); // ~~~ 绑定事件 mVideoView.setOnCompletionListener(this); mVideoView.setOnInfoListener(this); // ~~~ 绑定数据 mAudioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE); mMaxVolume = mAudioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC); if (mPath.startsWith("http:")) mVideoView.setVideoURI(Uri.parse(mPath)); else mVideoView.setVideoPath(mPath); //设置显示名称 mMediaController = new MediaController(this); mMediaController.setFileName(mTitle); mVideoView.setMediaController(mMediaController); mVideoView.requestFocus(); mGestureDetector = new GestureDetector(this, new MyGestureListener()); setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE); } @Override protected void onPause() { super.onPause(); if (mVideoView != null) mVideoView.pause(); } @Override protected void onResume() { super.onResume(); if (mVideoView != null) mVideoView.resume(); } @Override protected void onDestroy() { super.onDestroy(); if (mVideoView != null) mVideoView.stopPlayback(); } @Override public boolean onTouchEvent(MotionEvent event) { if (mGestureDetector.onTouchEvent(event)) return true; // 处理手势结束 switch (event.getAction() & MotionEvent.ACTION_MASK) { case MotionEvent.ACTION_UP: endGesture(); break; } return super.onTouchEvent(event); } /** 手势结束 */ private void endGesture() { mVolume = -1; mBrightness = -1f; // 隐藏 mDismissHandler.removeMessages(0); mDismissHandler.sendEmptyMessageDelayed(0, 500); } private class MyGestureListener extends SimpleOnGestureListener { /** 双击 */ @Override public boolean onDoubleTap(MotionEvent e) { if (mLayout == VideoView.VIDEO_LAYOUT_ZOOM) mLayout = VideoView.VIDEO_LAYOUT_ORIGIN; else mLayout++; if (mVideoView != null) mVideoView.setVideoLayout(mLayout, 0); return true; } /** 滑动 */ @Override public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { float mOldX = e1.getX(), mOldY = e1.getY(); int y = (int) e2.getRawY(); Display disp = getWindowManager().getDefaultDisplay(); int windowWidth = disp.getWidth(); int windowHeight = disp.getHeight(); if (mOldX > windowWidth * 4.0 / 5)// 右边滑动 onVolumeSlide((mOldY - y) / windowHeight); else if (mOldX < windowWidth / 5.0)// 左边滑动 onBrightnessSlide((mOldY - y) / windowHeight); return super.onScroll(e1, e2, distanceX, distanceY); } } /** 定时隐藏 */ private Handler mDismissHandler = new Handler() { @Override public void handleMessage(Message msg) { mVolumeBrightnessLayout.setVisibility(View.GONE); } }; /** * 滑动改变声音大小 * * @param percent */ private void onVolumeSlide(float percent) { if (mVolume == -1) { mVolume = mAudioManager.getStreamVolume(AudioManager.STREAM_MUSIC); if (mVolume < 0) mVolume = 0; // 显示 mOperationBg.setImageResource(R.drawable.video_volumn_bg); mVolumeBrightnessLayout.setVisibility(View.VISIBLE); } int index = (int) (percent * mMaxVolume) + mVolume; if (index > mMaxVolume) index = mMaxVolume; else if (index < 0) index = 0; // 变更声音 mAudioManager.setStreamVolume(AudioManager.STREAM_MUSIC, index, 0); // 变更进度条 ViewGroup.LayoutParams lp = mOperationPercent.getLayoutParams(); lp.width = findViewById(R.id.operation_full).getLayoutParams().width * index / mMaxVolume; mOperationPercent.setLayoutParams(lp); } /** * 滑动改变亮度 * * @param percent */ private void onBrightnessSlide(float percent) { if (mBrightness < 0) { mBrightness = getWindow().getAttributes().screenBrightness; if (mBrightness <= 0.00f) mBrightness = 0.50f; if (mBrightness < 0.01f) mBrightness = 0.01f; // 显示 mOperationBg.setImageResource(R.drawable.video_brightness_bg); mVolumeBrightnessLayout.setVisibility(View.VISIBLE); } WindowManager.LayoutParams lpa = getWindow().getAttributes(); lpa.screenBrightness = mBrightness + percent; if (lpa.screenBrightness > 1.0f) lpa.screenBrightness = 1.0f; else if (lpa.screenBrightness < 0.01f) lpa.screenBrightness = 0.01f; getWindow().setAttributes(lpa); ViewGroup.LayoutParams lp = mOperationPercent.getLayoutParams(); lp.width = (int) (findViewById(R.id.operation_full).getLayoutParams().width * lpa.screenBrightness); mOperationPercent.setLayoutParams(lp); } @Override public void onConfigurationChanged(Configuration newConfig) { if (mVideoView != null) mVideoView.setVideoLayout(mLayout, 0); super.onConfigurationChanged(newConfig); } @Override public void onCompletion(MediaPlayer player) { finish(); } private void stopPlayer() { if (mVideoView != null) mVideoView.pause(); } private void startPlayer() { if (mVideoView != null) mVideoView.start(); } private boolean isPlaying() { return mVideoView != null && mVideoView.isPlaying(); } /** 是否需要自动恢复播放,用于自动暂停,恢复播放 */ private boolean needResume; @Override public boolean onInfo(MediaPlayer arg0, int arg1, int arg2) { switch (arg1) { case MediaPlayer.MEDIA_INFO_BUFFERING_START: //开始缓存,暂停播放 if (isPlaying()) { stopPlayer(); needResume = true; } mLoadingView.setVisibility(View.VISIBLE); break; case MediaPlayer.MEDIA_INFO_BUFFERING_END: //缓存完成,继续播放 if (needResume) startPlayer(); mLoadingView.setVisibility(View.GONE); break; case MediaPlayer.MEDIA_INFO_DOWNLOAD_RATE_CHANGED: //显示 下载速度 Logger.e("download rate:" + arg2); //mListener.onDownloadRateChanged(arg2); break; } return true; } } ================================================ FILE: src/com/nmbb/oplayer/ui/adapter/FileAdapter.java ================================================ package com.nmbb.oplayer.ui.adapter; import java.util.ArrayList; import com.nmbb.oplayer.R; import com.nmbb.oplayer.po.PFile; import com.nmbb.oplayer.util.FileUtils; import android.content.Context; import android.database.Cursor; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.CursorAdapter; import android.widget.ImageView; import android.widget.TextView; public class FileAdapter extends CursorAdapter { private LayoutInflater mInflater; private ArrayList mKey = new ArrayList(); public FileAdapter(Context context, Cursor c) { super(context, c, false); mInflater = LayoutInflater.from(context); } @Override public View newView(Context context, Cursor cursor, ViewGroup parent) { return mInflater.inflate(R.layout.fragment_file_item, null); } @Override public void changeCursor(Cursor cursor) { initKeys(cursor); super.changeCursor(cursor); } private void initKeys(Cursor c) { if (c != null && !c.isClosed()) { mKey.clear(); while (c.moveToNext()) { String title_key = c.getString(2); mKey.add(title_key.charAt(0)); } } } /** 根据拼音名称获取位置 */ public int getPositionByName(char key) { return mKey.indexOf(key); } @Override public PFile getItem(int position) { if (getCursor().moveToPosition(position)) return new PFile(getCursor()); else return null; } @Override public void bindView(View convertView, Context context, Cursor cursor) { final PFile f = new PFile(cursor); //显示名称 ((TextView) convertView.findViewById(R.id.title)).setText(f.title); //显示文件大小 String file_size; if (f.temp_file_size > 0) { file_size = FileUtils.showFileSize(f.temp_file_size) + " / " + FileUtils.showFileSize(f.file_size); } else { file_size = FileUtils.showFileSize(f.file_size); } ((TextView) convertView.findViewById(R.id.file_size)).setText(file_size); //显示缩略图 ((ImageView) convertView.findViewById(R.id.thumbnail)).setImageBitmap(f.getThumb(context)); } } ================================================ FILE: src/com/nmbb/oplayer/ui/adapter/FileDownloadAdapter.java ================================================ package com.nmbb.oplayer.ui.adapter; import java.util.ArrayList; import java.util.HashMap; import android.content.Context; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.ImageView; import android.widget.TextView; import com.nmbb.oplayer.R; import com.nmbb.oplayer.po.PFile; import com.nmbb.oplayer.ui.base.ArrayAdapter; import com.nmbb.oplayer.util.FileUtils; public class FileDownloadAdapter extends ArrayAdapter { private HashMap maps = new HashMap(); private LayoutInflater mInflater; public FileDownloadAdapter(Context ctx, ArrayList l) { super(ctx, l); mInflater = LayoutInflater.from(ctx); maps.clear(); } @Override public View getView(int position, View convertView, ViewGroup parent) { final PFile f = getItem(position); if (convertView == null) { convertView = mInflater.inflate(R.layout.fragment_file_item, null); } ((TextView) convertView.findViewById(R.id.title)).setText(f.title); //显示文件大小 String file_size; if (f.temp_file_size > 0) { file_size = FileUtils.showFileSize(f.temp_file_size) + " / " + FileUtils.showFileSize(f.file_size); } else { file_size = FileUtils.showFileSize(f.file_size); } ((TextView) convertView.findViewById(R.id.file_size)).setText(file_size); //显示进度表 final ImageView status = (ImageView) convertView.findViewById(R.id.status); if (f.status > -1) { int resStauts = getStatusImage(f.status); if (resStauts > 0) { if (status.getVisibility() != View.VISIBLE) status.setVisibility(View.VISIBLE); status.setImageResource(resStauts); } } else { if (status.getVisibility() != View.GONE) status.setVisibility(View.GONE); } return convertView; } private int getStatusImage(int status) { int resStauts = -1; switch (status) { case 0: resStauts = R.drawable.down_btn_0; break; case 1: resStauts = R.drawable.down_btn_1; break; case 2: resStauts = R.drawable.down_btn_2; break; case 3: resStauts = R.drawable.down_btn_3; break; case 4: resStauts = R.drawable.down_btn_4; break; case 5: resStauts = R.drawable.down_btn_5; break; case 6: resStauts = R.drawable.down_btn_6; break; case 7: resStauts = R.drawable.down_btn_7; break; case 8: resStauts = R.drawable.down_btn_8; break; case 9: resStauts = R.drawable.down_btn_9; break; case 10: resStauts = R.drawable.down_btn_10; break; } return resStauts; } public void add(PFile item, String url) { super.add(item); if (!maps.containsKey(url)) maps.put(url, item); } public void delete(int position) { synchronized (mLock) { mObjects.remove(position); } notifyDataSetChanged(); } public PFile getItem(String url) { return maps.get(url); } } ================================================ FILE: src/com/nmbb/oplayer/ui/base/ArrayAdapter.java ================================================ package com.nmbb.oplayer.ui.base; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.List; import android.content.Context; import android.view.LayoutInflater; import android.widget.BaseAdapter; public abstract class ArrayAdapter extends BaseAdapter { // 数据 protected ArrayList mObjects; protected LayoutInflater mInflater; protected final Object mLock = new Object(); public ArrayAdapter(final Context ctx, final ArrayList l) { mObjects = l == null ? new ArrayList() : l; mInflater = (LayoutInflater) ctx.getSystemService(Context.LAYOUT_INFLATER_SERVICE); } public ArrayAdapter(final Context ctx, final T... l) { mObjects = new ArrayList(); mObjects.addAll(Arrays.asList(l)); mInflater = (LayoutInflater) ctx.getSystemService(Context.LAYOUT_INFLATER_SERVICE); } public ArrayAdapter(final Context ctx, final List l) { mObjects = new ArrayList(); if (l != null) mObjects.addAll(l); mInflater = (LayoutInflater) ctx.getSystemService(Context.LAYOUT_INFLATER_SERVICE); } public ArrayAdapter(final Context ctx, final Collection l) { mObjects = new ArrayList(); if (l != null) mObjects.addAll(l); mInflater = (LayoutInflater) ctx.getSystemService(Context.LAYOUT_INFLATER_SERVICE); } @Override public int getCount() { return mObjects.size(); } @Override public T getItem(int position) { return mObjects.get(position); } @Override public long getItemId(int position) { return 0; } public void add(T item) { this.mObjects.add(item); } public void replace(ArrayList newObjects) { if (newObjects == null) newObjects = new ArrayList(); this.mObjects = newObjects; } /** * Adds the specified items at the end of the array. * * @param items The items to add at the end of the array. */ public void addAll(T... items) { ArrayList values = this.mObjects; for (T item : items) { values.add(item); } this.mObjects = values; } /** * * @param collection */ public void addAll(Collection collection) { mObjects.addAll(collection); } /** * Remove all elements from the list. */ public void clear() { mObjects.clear(); } /** * 获取所有数据 * * @return */ public final ArrayList getAll() { return mObjects; } } ================================================ FILE: src/com/nmbb/oplayer/ui/base/FilterArrayAdapter.java ================================================ package com.nmbb.oplayer.ui.base; import java.util.ArrayList; import android.content.Context; import android.graphics.Color; import android.text.SpannableStringBuilder; import android.text.Spanned; import android.text.TextUtils; import android.text.style.ForegroundColorSpan; import android.widget.Filter; public abstract class FilterArrayAdapter extends ArrayAdapter { private String mFilterString; private Object mLock = new Object(); private ListFilter mFilter; private ArrayList mOriginalValues; protected final ForegroundColorSpan redSpan = new ForegroundColorSpan( Color.RED); public FilterArrayAdapter(Context ctx, ArrayList l) { super(ctx, l); } public Filter getFilter() { if (mFilter == null) { mFilter = new ListFilter(); } return mFilter; } /** * 获取搜索字符串 * * @return */ public String getFilterString() { return mFilterString; } /** * 高亮文本 * * @param text * 文本 * @return */ public CharSequence highlightText(String text) { CharSequence result; final String key = mFilterString; int index = TextUtils.isEmpty(key) ? -1 : text.toLowerCase().indexOf(key.toLowerCase()); if (index > -1) { SpannableStringBuilder nameStyle = new SpannableStringBuilder(text); nameStyle.setSpan(redSpan, index, index + key.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); result = nameStyle; } else result = text; return result; } /** * 过滤 * * @param values * @param prefixString * @return */ public abstract ArrayList filter(final ArrayList values, CharSequence prefixString); /** *

* An array filter constrains the content of the array adapter with a prefix. * Each item that does not start with the supplied prefix is removed from the * list. *

*/ private class ListFilter extends Filter { @Override protected FilterResults performFiltering(CharSequence prefix) { FilterResults results = new FilterResults(); if (mOriginalValues == null) { synchronized (mLock) { mOriginalValues = new ArrayList(mObjects); } } if (prefix == null || prefix.length() == 0) { mFilterString = ""; synchronized (mLock) { ArrayList list = new ArrayList(mOriginalValues); results.values = list; results.count = list.size(); } } else { mFilterString = prefix.toString(); final ArrayList newValues = FilterArrayAdapter.this.filter(mOriginalValues, prefix); results.values = newValues; results.count = newValues.size(); } return results; } @SuppressWarnings("unchecked") @Override protected void publishResults(CharSequence constraint, FilterResults results) { mObjects = (ArrayList) results.values; //filterComplate(); if (results.count > 0) { notifyDataSetChanged(); } else { notifyDataSetInvalidated(); } } } } ================================================ FILE: src/com/nmbb/oplayer/ui/base/ThreadPool.java ================================================ package com.nmbb.oplayer.ui.base; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.ThreadFactory; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; import android.os.Build; public class ThreadPool { private AtomicBoolean mStopped = new AtomicBoolean(Boolean.FALSE); private ThreadPoolExecutor mQueue; public ThreadPool() { if (Build.VERSION.SDK_INT > 8) { mQueue = new ThreadPoolExecutor(10, 10, 60, TimeUnit.SECONDS, new LinkedBlockingQueue(), sThreadFactory); mQueue.allowCoreThreadTimeOut(true); } else { mQueue = new ThreadPoolExecutor(2, 10, 60, TimeUnit.SECONDS, new LinkedBlockingQueue(), sThreadFactory); } } public void start(Runnable run) { mQueue.execute(run); } public void stop() { if (!mStopped.get()) { mQueue.shutdownNow(); mStopped.set(Boolean.TRUE); } } private static final ThreadFactory sThreadFactory = new ThreadFactory() { private final AtomicInteger mCount = new AtomicInteger(1); @Override public Thread newThread(Runnable r) { return new Thread(r, "ThreadPool #" + mCount.getAndIncrement()); } }; } ================================================ FILE: src/com/nmbb/oplayer/ui/helper/FileDownloadHelper.java ================================================ package com.nmbb.oplayer.ui.helper; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.util.HashMap; import java.util.Timer; import java.util.TimerTask; import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; import org.apache.http.client.HttpClient; import org.apache.http.client.methods.HttpGet; import org.apache.http.impl.client.DefaultHttpClient; import android.os.Handler; import android.util.Log; import com.nmbb.oplayer.ui.base.ThreadPool; public class FileDownloadHelper { private static final String TAG = "FileDownloadHelper"; /** 线程池 */ private ThreadPool mPool = new ThreadPool(); /** 开始下载 */ public static final int MESSAGE_START = 0; /** 更新进度 */ public static final int MESSAGE_PROGRESS = 1; /** 下载结束 */ public static final int MESSAGE_STOP = 2; /** 下载出错 */ public static final int MESSAGE_ERROR = 3; /** 中途终止 */ private volatile boolean mIsStop = false; private Handler mHandler; public volatile HashMap mDownloadUrls = new HashMap(); public FileDownloadHelper(Handler handler) { if (handler == null) throw new IllegalArgumentException("handler不能为空!"); this.mHandler = handler; } public void stopALl() { mIsStop = true; mPool.stop(); } /** * 下载一个新的文件 * * @param url * @param savePath */ public void newDownloadFile(final String url, final String savePath) { if (mDownloadUrls.containsKey(url)) return; else mDownloadUrls.put(url, savePath); mPool.start(new Runnable() { @Override public void run() { mHandler.sendMessage(mHandler.obtainMessage(MESSAGE_START, url)); HttpClient client = new DefaultHttpClient(); HttpGet get = new HttpGet(url); InputStream inputStream = null; FileOutputStream outputStream = null; try { HttpResponse response = client.execute(get); HttpEntity entity = response.getEntity(); final int size = (int) entity.getContentLength(); inputStream = entity.getContent(); if (size > 0 && inputStream != null) { outputStream = new FileOutputStream(savePath); int ch = -1; byte[] buf = new byte[1024]; //每秒更新一次进度 new Timer().schedule(new TimerTask() { @Override public void run() { try { FileInputStream fis = new FileInputStream(new File(savePath)); int downloadedSize = fis.available(); if (downloadedSize >= size) cancel(); mHandler.sendMessage(mHandler.obtainMessage(MESSAGE_PROGRESS, downloadedSize, size, url)); } catch (Exception e) { } } }, 50, 1000); while ((ch = inputStream.read(buf)) != -1 && !mIsStop) { outputStream.write(buf, 0, ch); } outputStream.flush(); } } catch (Exception e) { Log.e(TAG, e.getMessage(), e); mHandler.sendMessage(mHandler.obtainMessage(MESSAGE_ERROR, url + ":" + e.getMessage())); } finally { try { if (outputStream != null) outputStream.close(); } catch (IOException ex) { } try { if (inputStream != null) inputStream.close(); } catch (IOException ex) { } } mDownloadUrls.remove(url); mHandler.sendMessage(mHandler.obtainMessage(MESSAGE_STOP, url)); } }); } } ================================================ FILE: src/com/nmbb/oplayer/ui/helper/VideoHelper.java ================================================ package com.nmbb.oplayer.ui.helper; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.net.HttpURLConnection; import java.net.MalformedURLException; import java.net.URL; import com.nmbb.oplayer.util.StringUtils; import android.os.Build; import android.text.Html; public class VideoHelper { /** 在线视频对象 */ public static class OnlineVideo { public String url; public String title; public OnlineVideo() { } public OnlineVideo(String url) { this.url = url; } } /** 获取优酷视频m3u8地址 */ public static OnlineVideo getYoukuVideo(String url) { OnlineVideo result = null; String vid = ""; //提取vid vid = substring(url, "vid=", "&"); if (!StringUtils.isEmpty(vid)) { String title = ""; String html = connect(url); if (!StringUtils.isEmpty(html)) { //获取title title = substring(html, "", ""); title = substring(title, "", "-优酷3G", title); title = Html.fromHtml(title).toString(); } result = new OnlineVideo(); result.url = "http://v.youku.com/player/getRealM3U8/vid/" + vid + "/type//video.m3u8"; result.title = title; } return result; } public static String substring(String search, String start, String end, String defaultValue) { int s_len = start.length(); int s_pos = StringUtils.isEmpty(start) ? 0 : search.indexOf(start); if (s_pos > -1) { int end_pos = StringUtils.isEmpty(end) ? -1 : search.indexOf(end, s_pos + s_len); if (end_pos > -1) return search.substring(s_pos + start.length(), end_pos); else return search.substring(s_pos + start.length()); } return defaultValue; } public static String substring(String search, String start, String end) { return substring(search, start, end, ""); } private static String connect(String uri) { return connect(uri, "UTF8"); } private static String connect(String uri, String charsetName) { String result = ""; try { URL url = new URL(uri); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); conn.setConnectTimeout(5 * 1000); if (Integer.parseInt(Build.VERSION.SDK) < 8) { System.setProperty("http.keepAlive", "false"); } if (conn.getResponseCode() == 200) { InputStream is = conn.getInputStream(); result = readData(is, charsetName); } conn.disconnect(); } catch (MalformedURLException e) { } catch (IOException e) { } catch (Exception e) { } return result; } public static String readData(InputStream inSream, String charsetName) throws Exception { ByteArrayOutputStream outStream = new ByteArrayOutputStream(); byte[] buffer = new byte[1024]; int len = -1; while ((len = inSream.read(buffer)) != -1) { outStream.write(buffer, 0, len); } byte[] data = outStream.toByteArray(); outStream.close(); inSream.close(); return new String(data, charsetName); } } ================================================ FILE: src/com/nmbb/oplayer/ui/helper/XmlReaderHelper.java ================================================ package com.nmbb.oplayer.ui.helper; import java.io.IOException; import java.util.ArrayList; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.NamedNodeMap; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import org.xml.sax.SAXException; import android.content.Context; import com.nmbb.oplayer.po.OnlineVideo; /** 从XML读取电视台节目 */ public class XmlReaderHelper { /** 获取所有电视分类 */ public static ArrayList getAllCategory(final Context context) { ArrayList result = new ArrayList(); DocumentBuilderFactory docBuilderFactory = null; DocumentBuilder docBuilder = null; Document doc = null; try { docBuilderFactory = DocumentBuilderFactory.newInstance(); docBuilder = docBuilderFactory.newDocumentBuilder(); // xml file 放到 assets目录中的 doc = docBuilder.parse(context.getResources().getAssets() .open("online.xml")); // root element Element root = doc.getDocumentElement(); NodeList nodeList = root.getElementsByTagName("category"); for (int i = 0; i < nodeList.getLength(); i++) { Node node = nodeList.item(i);// category OnlineVideo ov = new OnlineVideo(); NamedNodeMap attr = node.getAttributes(); ov.title = attr.getNamedItem("name").getNodeValue(); ov.id = attr.getNamedItem("id").getNodeValue(); ov.category = 1; ov.level = 2; ov.is_category = true; result.add(ov); // Read Node } } catch (IOException e) { } catch (SAXException e) { } catch (ParserConfigurationException e) { } finally { doc = null; docBuilder = null; docBuilderFactory = null; } return result; } /** 读取分类下所有电视地址 */ public static ArrayList getVideos(final Context context, String categoryId) { ArrayList result = new ArrayList(); DocumentBuilderFactory docBuilderFactory = null; DocumentBuilder docBuilder = null; Document doc = null; try { docBuilderFactory = DocumentBuilderFactory.newInstance(); docBuilder = docBuilderFactory.newDocumentBuilder(); // xml file 放到 assets目录中的 doc = docBuilder.parse(context.getResources().getAssets() .open("online.xml")); // root element Element root = doc.getElementById(categoryId); if (root != null) { NodeList nodeList = root.getChildNodes(); for (int i = 0, j = nodeList.getLength(); i < j; i++) { Node baseNode = nodeList.item(i); if (!"item".equals(baseNode.getNodeName())) continue; String id = baseNode.getFirstChild().getNodeValue(); if (id == null) continue; OnlineVideo ov = new OnlineVideo(); ov.id = id; Element el = doc.getElementById(ov.id); if (el != null) { ov.title = el.getAttribute("title"); ov.icon_url = el.getAttribute("image"); ov.level = 3; ov.category = 1; NodeList nodes = el.getChildNodes(); for (int m = 0, n = nodes.getLength(); m < n; m++) { Node node = nodes.item(m); if (!"ref".equals(node.getNodeName())) continue; String href = node.getAttributes() .getNamedItem("href").getNodeValue(); if (ov.url == null) { ov.url = href; } else { if (ov.backup_url == null) ov.backup_url = new ArrayList(); ov.backup_url.add(href); } } if (ov.url != null) result.add(ov); } } } } catch (IOException e) { e.printStackTrace(); } catch (SAXException e) { e.printStackTrace(); } catch (ParserConfigurationException e) { e.printStackTrace(); } finally { doc = null; docBuilder = null; docBuilderFactory = null; } return result; } } ================================================ FILE: src/com/nmbb/oplayer/ui/player/CommonGestures.java ================================================ /* * Copyright (C) 2012 YIXIA.COM * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.nmbb.oplayer.ui.player; import android.annotation.SuppressLint; import android.app.Activity; import android.support.v4.view.GestureDetectorCompat; import android.view.GestureDetector.SimpleOnGestureListener; import android.view.MotionEvent; import android.view.ScaleGestureDetector; import com.nmbb.oplayer.util.DeviceUtils; public class CommonGestures { public static final int SCALE_STATE_BEGIN = 0; public static final int SCALE_STATE_SCALEING = 1; public static final int SCALE_STATE_END = 2; private boolean mGestureEnabled; private GestureDetectorCompat mDoubleTapGestureDetector; private GestureDetectorCompat mTapGestureDetector; private ScaleGestureDetector mScaleDetector; private Activity mContext; public CommonGestures(Activity ctx) { mContext = ctx; mDoubleTapGestureDetector = new GestureDetectorCompat(mContext, new DoubleTapGestureListener()); mTapGestureDetector = new GestureDetectorCompat(mContext, new TapGestureListener()); mScaleDetector = new ScaleGestureDetector(mContext, new ScaleDetectorListener()); } public boolean onTouchEvent(MotionEvent event) { if (mListener == null) return false; if (mTapGestureDetector.onTouchEvent(event)) return true; if (event.getPointerCount() > 1) { try { if (mScaleDetector != null && mScaleDetector.onTouchEvent(event)) return true; } catch (Exception e) { e.printStackTrace(); } } if (mDoubleTapGestureDetector.onTouchEvent(event)) return true; switch (event.getAction() & MotionEvent.ACTION_MASK) { case MotionEvent.ACTION_UP: mListener.onGestureEnd(); break; } return false; } private class TapGestureListener extends SimpleOnGestureListener { @Override public boolean onSingleTapConfirmed(MotionEvent event) { if (mListener != null) mListener.onSingleTap(); return true; } @Override public void onLongPress(MotionEvent e) { if (mListener != null && mGestureEnabled) mListener.onLongPress(); } } @SuppressLint("NewApi") private class ScaleDetectorListener implements ScaleGestureDetector.OnScaleGestureListener { @Override public boolean onScale(ScaleGestureDetector detector) { if (mListener != null && mGestureEnabled) mListener.onScale(detector.getScaleFactor(), SCALE_STATE_SCALEING); return true; } @Override public void onScaleEnd(ScaleGestureDetector detector) { if (mListener != null && mGestureEnabled) mListener.onScale(0F, SCALE_STATE_END); } @Override public boolean onScaleBegin(ScaleGestureDetector detector) { if (mListener != null && mGestureEnabled) mListener.onScale(0F, SCALE_STATE_BEGIN); return true; } } private class DoubleTapGestureListener extends SimpleOnGestureListener { private boolean mDown = false; @Override public boolean onDown(MotionEvent event) { mDown = true; return super.onDown(event); } @Override public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { if (mListener != null && mGestureEnabled && e1 != null && e2 != null) { if (mDown) { mListener.onGestureBegin(); mDown = false; } float mOldX = e1.getX(), mOldY = e1.getY(); int windowWidth = DeviceUtils.getScreenWidth(mContext); int windowHeight = DeviceUtils.getScreenHeight(mContext); if (Math.abs(e2.getY(0) - mOldY) * 2 > Math.abs(e2.getX(0) - mOldX)) { if (mOldX > windowWidth * 4.0 / 5) { mListener.onRightSlide((mOldY - e2.getY(0)) / windowHeight); } else if (mOldX < windowWidth / 5.0) { mListener.onLeftSlide((mOldY - e2.getY(0)) / windowHeight); } } } return super.onScroll(e1, e2, distanceX, distanceY); } @Override public boolean onDoubleTap(MotionEvent event) { if (mListener != null && mGestureEnabled) mListener.onDoubleTap(); return super.onDoubleTap(event); } } public void setTouchListener(TouchListener l, boolean enable) { mListener = l; mGestureEnabled = enable; } private TouchListener mListener; public interface TouchListener { public void onGestureBegin(); public void onGestureEnd(); public void onLeftSlide(float percent); public void onRightSlide(float percent); public void onSingleTap(); public void onDoubleTap(); public void onScale(float scaleFactor, int state); public void onLongPress(); } } ================================================ FILE: src/com/nmbb/oplayer/ui/player/MediaController.java ================================================ /* * Copyright (C) 2012 YIXIA.COM * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.nmbb.oplayer.ui.player; import java.lang.ref.WeakReference; import java.lang.reflect.Field; import java.lang.reflect.Method; import android.annotation.SuppressLint; import android.annotation.TargetApi; import android.app.Activity; import android.content.Context; import android.graphics.Rect; import android.graphics.RectF; import android.media.AudioManager; import android.os.Handler; import android.os.Message; import android.view.Gravity; import android.view.KeyEvent; import android.view.LayoutInflater; import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; import android.view.Window; import android.view.WindowManager; import android.view.animation.Animation; import android.view.animation.Animation.AnimationListener; import android.view.animation.AnimationUtils; import android.widget.FrameLayout; import android.widget.ImageButton; import android.widget.ImageView; import android.widget.PopupWindow; import android.widget.SeekBar; import android.widget.SeekBar.OnSeekBarChangeListener; import android.widget.TextView; import com.nmbb.oplayer.R; import com.nmbb.oplayer.exception.Logger; import com.nmbb.oplayer.ui.player.CommonGestures.TouchListener; import com.nmbb.oplayer.util.DeviceUtils; import com.nmbb.oplayer.util.FractionalTouchDelegate; import com.nmbb.oplayer.util.StringUtils; public class MediaController extends FrameLayout { private MediaPlayerControl mPlayer; private Activity mContext; private PopupWindow mWindow; private View mAnchor; private View mRoot; private ImageButton mLock; private ImageButton mScreenToggle; private ImageButton mSnapshot; private SeekBar mProgress; private TextView mEndTime, mCurrentTime; private long mDuration; private boolean mShowing; private boolean mScreenLocked = false; private boolean mDragging; private boolean mInstantSeeking = true; private static final int DEFAULT_TIME_OUT = 3000; private static final int DEFAULT_LONG_TIME_SHOW = 120000; private static final int DEFAULT_SEEKBAR_VALUE = 1000; private static final int TIME_TICK_INTERVAL = 1000; private ImageButton mPauseButton; private View mMediaController; private View mControlsLayout; private View mSystemInfoLayout; private View mControlsButtons; private View mMenu; private TextView mDateTime; private TextView mDownloadRate; private TextView mFileName; private TextView mBatteryLevel; private TextView mOperationInfo; private View mOperationVolLum; private ImageView mVolLumNum; private ImageView mVolLumBg; private AudioManager mAM; private int mMaxVolume; private float mBrightness = 0.01f; private int mVolume = 0; private Handler mHandler; private Animation mAnimSlideInTop; private Animation mAnimSlideInBottom; private Animation mAnimSlideOutTop; private Animation mAnimSlideOutBottom; private CommonGestures mGestures; private int mVideoMode; public MediaController(Context context) { super(context); mContext = (Activity) context; initFloatingWindow(); initResources(); } public MediaController(Context context, boolean locked) { this(context); mScreenLocked = locked; lock(mScreenLocked); } private void initFloatingWindow() { mWindow = new PopupWindow(mContext); mWindow.setFocusable(true); mWindow.setBackgroundDrawable(null); mWindow.setOutsideTouchable(true); } @TargetApi(11) public void setWindowLayoutType() { if (DeviceUtils.hasICS()) { try { mAnchor.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION); Method setWindowLayoutType = PopupWindow.class.getMethod("setWindowLayoutType", new Class[] { int.class }); setWindowLayoutType.invoke(mWindow, WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG); } catch (Exception e) { Logger.e(e); } } } @SuppressLint("NewApi") private void initResources() { mHandler = new MHandler(this); mAM = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE); mMaxVolume = mAM.getStreamMaxVolume(AudioManager.STREAM_MUSIC); mGestures = new CommonGestures(mContext); mGestures.setTouchListener(mTouchListener, true); mAnimSlideOutBottom = AnimationUtils.loadAnimation(mContext, R.anim.slide_out_bottom); mAnimSlideOutTop = AnimationUtils.loadAnimation(mContext, R.anim.slide_out_top); mAnimSlideInBottom = AnimationUtils.loadAnimation(mContext, R.anim.slide_in_bottom); mAnimSlideInTop = AnimationUtils.loadAnimation(mContext, R.anim.slide_in_top); mAnimSlideOutBottom.setAnimationListener(new AnimationListener() { @Override public void onAnimationStart(Animation animation) { } @Override public void onAnimationEnd(Animation animation) { mMediaController.setVisibility(View.GONE); showButtons(false); mHandler.removeMessages(MSG_HIDE_SYSTEM_UI); mHandler.sendEmptyMessageDelayed(MSG_HIDE_SYSTEM_UI, DEFAULT_TIME_OUT); } @Override public void onAnimationRepeat(Animation animation) { } }); removeAllViews(); mRoot = inflateLayout(); mWindow.setContentView(mRoot); mWindow.setWidth(android.view.ViewGroup.LayoutParams.MATCH_PARENT); mWindow.setHeight(android.view.ViewGroup.LayoutParams.MATCH_PARENT); findViewItems(mRoot); showSystemUi(false); if (DeviceUtils.hasHoneycomb()) { mRoot.setOnSystemUiVisibilityChangeListener(new View.OnSystemUiVisibilityChangeListener() { @Override public void onSystemUiVisibilityChange(int visibility) { if ((visibility & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) == 0) { mHandler.sendEmptyMessageDelayed(MSG_HIDE_SYSTEM_UI, DEFAULT_TIME_OUT); } } }); } } private View inflateLayout() { return ((LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE)).inflate(R.layout.mediacontroller, this); } private void findViewItems(View v) { mMediaController = v.findViewById(R.id.mediacontroller); mSystemInfoLayout = v.findViewById(R.id.info_panel); mEndTime = (TextView) v.findViewById(R.id.mediacontroller_time_total); mCurrentTime = (TextView) v.findViewById(R.id.mediacontroller_time_current); mMenu = v.findViewById(R.id.video_menu); mMenu.setOnClickListener(mMenuListener); FractionalTouchDelegate.setupDelegate(mSystemInfoLayout, mMenu, new RectF(1.0f, 1f, 1.2f, 1.2f)); mFileName = (TextView) v.findViewById(R.id.mediacontroller_file_name); mDateTime = (TextView) v.findViewById(R.id.date_time); mDownloadRate = (TextView) v.findViewById(R.id.download_rate); mBatteryLevel = (TextView) v.findViewById(R.id.battery_level); mControlsLayout = v.findViewById(R.id.mediacontroller_controls); mControlsButtons = v.findViewById(R.id.mediacontroller_controls_buttons); mOperationInfo = (TextView) v.findViewById(R.id.operation_info); mOperationVolLum = v.findViewById(R.id.operation_volume_brightness); mVolLumBg = (ImageView) v.findViewById(R.id.operation_bg); mVolLumNum = (ImageView) v.findViewById(R.id.operation_percent); mLock = (ImageButton) v.findViewById(R.id.mediacontroller_lock); mLock.setOnClickListener(mLockClickListener); FractionalTouchDelegate.setupDelegate(mSystemInfoLayout, mLock, new RectF(1.0f, 1f, 1.2f, 1.2f)); mScreenToggle = (ImageButton) v.findViewById(R.id.mediacontroller_screen_size); mScreenToggle.setOnClickListener(mScreenToggleListener); mSnapshot = (ImageButton) v.findViewById(R.id.mediacontroller_snapshot); mSnapshot.setOnClickListener(mSnapshotListener); mPauseButton = (ImageButton) v.findViewById(R.id.mediacontroller_play_pause); mPauseButton.setOnClickListener(mPauseListener); mProgress = (SeekBar) v.findViewById(R.id.mediacontroller_seekbar); mProgress.setOnSeekBarChangeListener(mSeekListener); mProgress.setMax(DEFAULT_SEEKBAR_VALUE); } public void setAnchorView(View view) { mAnchor = view; int[] location = new int[2]; mAnchor.getLocationOnScreen(location); Rect anchorRect = new Rect(location[0], location[1], location[0] + mAnchor.getWidth(), location[1] + mAnchor.getHeight()); setWindowLayoutType(); mWindow.showAtLocation(mAnchor, Gravity.NO_GRAVITY, anchorRect.left, anchorRect.bottom); } public void release() { if (mWindow != null) { mWindow.dismiss(); mWindow = null; } } private View.OnClickListener mMenuListener = new View.OnClickListener() { @Override public void onClick(View v) { mPlayer.showMenu(); } }; private void setOperationInfo(String info, long time) { mOperationInfo.setText(info); mOperationInfo.setVisibility(View.VISIBLE); mHandler.removeMessages(MSG_HIDE_OPERATION_INFO); mHandler.sendEmptyMessageDelayed(MSG_HIDE_OPERATION_INFO, time); } private void setBrightnessScale(float scale) { setGraphicOperationProgress(R.drawable.video_brightness_bg, scale); } private void setVolumeScale(float scale) { setGraphicOperationProgress(R.drawable.video_volumn_bg, scale); } private void setGraphicOperationProgress(int bgID, float scale) { mVolLumBg.setImageResource(bgID); mOperationInfo.setVisibility(View.GONE); mOperationVolLum.setVisibility(View.VISIBLE); ViewGroup.LayoutParams lp = mVolLumNum.getLayoutParams(); lp.width = (int) (findViewById(R.id.operation_full).getLayoutParams().width * scale); mVolLumNum.setLayoutParams(lp); } public void setFileName(String name) { mFileName.setText(name); } public void setDownloadRate(String rate) { mDownloadRate.setVisibility(View.VISIBLE); mDownloadRate.setText(rate); } public void setBatteryLevel(String level) { mBatteryLevel.setVisibility(View.VISIBLE); mBatteryLevel.setText(level); } public void setMediaPlayer(MediaPlayerControl player) { mPlayer = player; updatePausePlay(); } public void show() { show(DEFAULT_TIME_OUT); } public void show(int timeout) { if (timeout != 0) { mHandler.removeMessages(MSG_FADE_OUT); mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_FADE_OUT), timeout); } if (!mShowing) { showButtons(true); mHandler.removeMessages(MSG_HIDE_SYSTEM_UI); showSystemUi(true); mPauseButton.requestFocus(); mControlsLayout.startAnimation(mAnimSlideInTop); mSystemInfoLayout.startAnimation(mAnimSlideInBottom); mMediaController.setVisibility(View.VISIBLE); updatePausePlay(); mHandler.sendEmptyMessage(MSG_TIME_TICK); mHandler.sendEmptyMessage(MSG_SHOW_PROGRESS); mShowing = true; } } public void hide() { if (mShowing) { try { mHandler.removeMessages(MSG_TIME_TICK); mHandler.removeMessages(MSG_SHOW_PROGRESS); mControlsLayout.startAnimation(mAnimSlideOutTop); mSystemInfoLayout.startAnimation(mAnimSlideOutBottom); } catch (IllegalArgumentException ex) { Logger.d("MediaController already removed"); } mShowing = false; } } private void toggleVideoMode(boolean larger, boolean recycle) { if (larger) { if (mVideoMode < VideoView.VIDEO_LAYOUT_ZOOM) mVideoMode++; else if (recycle) mVideoMode = VideoView.VIDEO_LAYOUT_ORIGIN; } else { if (mVideoMode > VideoView.VIDEO_LAYOUT_ORIGIN) mVideoMode--; else if (recycle) mVideoMode = VideoView.VIDEO_LAYOUT_ZOOM; } switch (mVideoMode) { case VideoView.VIDEO_LAYOUT_ORIGIN: setOperationInfo(mContext.getString(R.string.video_original), 500); mScreenToggle.setImageResource(R.drawable.mediacontroller_sreen_size_100); break; case VideoView.VIDEO_LAYOUT_SCALE: setOperationInfo(mContext.getString(R.string.video_fit_screen), 500); mScreenToggle.setImageResource(R.drawable.mediacontroller_screen_fit); break; case VideoView.VIDEO_LAYOUT_STRETCH: setOperationInfo(mContext.getString(R.string.video_stretch), 500); mScreenToggle.setImageResource(R.drawable.mediacontroller_screen_size); break; case VideoView.VIDEO_LAYOUT_ZOOM: setOperationInfo(mContext.getString(R.string.video_crop), 500); mScreenToggle.setImageResource(R.drawable.mediacontroller_sreen_size_crop); break; } mPlayer.toggleVideoMode(mVideoMode); } private void lock(boolean toLock) { if (toLock) { mLock.setImageResource(R.drawable.mediacontroller_lock); mMenu.setVisibility(View.GONE); mControlsButtons.setVisibility(View.GONE); mProgress.setEnabled(false); if (mScreenLocked != toLock) setOperationInfo(mContext.getString(R.string.video_screen_locked), 1000); } else { mLock.setImageResource(R.drawable.mediacontroller_unlock); // If you wanna to show, set mMenu visible mMenu.setVisibility(View.GONE); mControlsButtons.setVisibility(View.VISIBLE); mProgress.setEnabled(true); if (mScreenLocked != toLock) setOperationInfo(mContext.getString(R.string.video_screen_unlocked), 1000); } mScreenLocked = toLock; mGestures.setTouchListener(mTouchListener, !mScreenLocked); } public boolean isLocked() { return mScreenLocked; } private static final int MSG_FADE_OUT = 1; private static final int MSG_SHOW_PROGRESS = 2; private static final int MSG_HIDE_SYSTEM_UI = 3; private static final int MSG_TIME_TICK = 4; private static final int MSG_HIDE_OPERATION_INFO = 5; private static final int MSG_HIDE_OPERATION_VOLLUM = 6; private static class MHandler extends Handler { private WeakReference mc; public MHandler(MediaController mc) { this.mc = new WeakReference(mc); } @Override public void handleMessage(Message msg) { MediaController c = mc.get(); if (c == null) return; switch (msg.what) { case MSG_FADE_OUT: c.hide(); break; case MSG_SHOW_PROGRESS: long pos = c.setProgress(); if (!c.mDragging && c.mShowing) { msg = obtainMessage(MSG_SHOW_PROGRESS); sendMessageDelayed(msg, 1000 - (pos % 1000)); c.updatePausePlay(); } break; case MSG_HIDE_SYSTEM_UI: if (!c.mShowing) c.showSystemUi(false); break; case MSG_TIME_TICK: c.mDateTime.setText(StringUtils.currentTimeString()); sendEmptyMessageDelayed(MSG_TIME_TICK, TIME_TICK_INTERVAL); break; case MSG_HIDE_OPERATION_INFO: c.mOperationInfo.setVisibility(View.GONE); break; case MSG_HIDE_OPERATION_VOLLUM: c.mOperationVolLum.setVisibility(View.GONE); break; } } }; private long setProgress() { if (mPlayer == null || mDragging) return 0; long position = mPlayer.getCurrentPosition(); long duration = mPlayer.getDuration(); if (duration > 0) { long pos = 1000L * position / duration; mProgress.setProgress((int) pos); } int percent = mPlayer.getBufferPercentage(); mProgress.setSecondaryProgress(percent * 10); mDuration = duration; mEndTime.setText(StringUtils.generateTime(mDuration)); mCurrentTime.setText(StringUtils.generateTime(position)); return position; } @Override public boolean onTouchEvent(MotionEvent event) { mHandler.removeMessages(MSG_HIDE_SYSTEM_UI); mHandler.sendEmptyMessageDelayed(MSG_HIDE_SYSTEM_UI, DEFAULT_TIME_OUT); return mGestures.onTouchEvent(event) || super.onTouchEvent(event); } private TouchListener mTouchListener = new TouchListener() { @Override public void onGestureBegin() { mBrightness = mContext.getWindow().getAttributes().screenBrightness; mVolume = mAM.getStreamVolume(AudioManager.STREAM_MUSIC); if (mBrightness <= 0.00f) mBrightness = 0.50f; if (mBrightness < 0.01f) mBrightness = 0.01f; if (mVolume < 0) mVolume = 0; } @Override public void onGestureEnd() { mOperationVolLum.setVisibility(View.GONE); } @Override public void onLeftSlide(float percent) { setBrightness(mBrightness + percent); setBrightnessScale(mContext.getWindow().getAttributes().screenBrightness); } @Override public void onRightSlide(float percent) { int v = (int) (percent * mMaxVolume) + mVolume; setVolume(v); } @Override public void onSingleTap() { if (mShowing) hide(); else show(); if (mPlayer.getBufferPercentage() >= 100) mPlayer.removeLoadingView(); } @Override public void onDoubleTap() { toggleVideoMode(true, true); } @Override public void onLongPress() { doPauseResume(); } @Override public void onScale(float scaleFactor, int state) { switch (state) { case CommonGestures.SCALE_STATE_BEGIN: mVideoMode = VideoView.VIDEO_LAYOUT_SCALE_ZOOM; mScreenToggle.setImageResource(R.drawable.mediacontroller_sreen_size_100); mPlayer.toggleVideoMode(mVideoMode); break; case CommonGestures.SCALE_STATE_SCALEING: float currentRatio = mPlayer.scale(scaleFactor); setOperationInfo((int) (currentRatio * 100) + "%", 500); break; case CommonGestures.SCALE_STATE_END: break; } } }; private void setVolume(int v) { if (v > mMaxVolume) v = mMaxVolume; else if (v < 0) v = 0; mAM.setStreamVolume(AudioManager.STREAM_MUSIC, v, 0); setVolumeScale((float) v / mMaxVolume); } private void setBrightness(float f) { WindowManager.LayoutParams lp = mContext.getWindow().getAttributes(); lp.screenBrightness = f; if (lp.screenBrightness > 1.0f) lp.screenBrightness = 1.0f; else if (lp.screenBrightness < 0.01f) lp.screenBrightness = 0.01f; mContext.getWindow().setAttributes(lp); } @Override public boolean onTrackballEvent(MotionEvent ev) { show(DEFAULT_TIME_OUT); return false; } @Override public boolean dispatchKeyEvent(KeyEvent event) { int keyCode = event.getKeyCode(); switch (keyCode) { case KeyEvent.KEYCODE_VOLUME_MUTE: return super.dispatchKeyEvent(event); case KeyEvent.KEYCODE_VOLUME_UP: case KeyEvent.KEYCODE_VOLUME_DOWN: mVolume = mAM.getStreamVolume(AudioManager.STREAM_MUSIC); int step = keyCode == KeyEvent.KEYCODE_VOLUME_UP ? 1 : -1; setVolume(mVolume + step); mHandler.removeMessages(MSG_HIDE_OPERATION_VOLLUM); mHandler.sendEmptyMessageDelayed(MSG_HIDE_OPERATION_VOLLUM, 500); return true; } if (isLocked()) { show(); return true; } if (event.getRepeatCount() == 0 && (keyCode == KeyEvent.KEYCODE_HEADSETHOOK || keyCode == KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE || keyCode == KeyEvent.KEYCODE_SPACE)) { doPauseResume(); show(DEFAULT_TIME_OUT); return true; } else if (keyCode == KeyEvent.KEYCODE_MEDIA_STOP) { if (mPlayer.isPlaying()) { mPlayer.pause(); updatePausePlay(); } return true; } else if (keyCode == KeyEvent.KEYCODE_BACK) { release(); mPlayer.stop(); return true; } else { show(DEFAULT_TIME_OUT); } return super.dispatchKeyEvent(event); } @TargetApi(11) private void showSystemUi(boolean visible) { if (DeviceUtils.hasHoneycomb()) { int flag = visible ? 0 : View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_LOW_PROFILE; mRoot.setSystemUiVisibility(flag); } } private void showButtons(boolean showButtons) { Window window = mContext.getWindow(); WindowManager.LayoutParams layoutParams = window.getAttributes(); float val = showButtons ? -1 : 0; try { Field buttonBrightness = layoutParams.getClass().getField("buttonBrightness"); buttonBrightness.set(layoutParams, val); } catch (Exception e) { Logger.e("dimButtons", e); } window.setAttributes(layoutParams); } private void updatePausePlay() { if (mPlayer.isPlaying()) mPauseButton.setImageResource(R.drawable.mediacontroller_pause); else mPauseButton.setImageResource(R.drawable.mediacontroller_play); } private void doPauseResume() { if (mPlayer.isPlaying()) mPlayer.pause(); else mPlayer.start(); updatePausePlay(); } private View.OnClickListener mPauseListener = new View.OnClickListener() { @Override public void onClick(View v) { if (mPlayer.isPlaying()) show(DEFAULT_LONG_TIME_SHOW); else show(); doPauseResume(); } }; private View.OnClickListener mLockClickListener = new View.OnClickListener() { @Override public void onClick(View v) { hide(); lock(!mScreenLocked); show(); } }; private View.OnClickListener mScreenToggleListener = new View.OnClickListener() { @Override public void onClick(View v) { show(DEFAULT_TIME_OUT); toggleVideoMode(true, true); } }; private View.OnClickListener mSnapshotListener = new View.OnClickListener() { @Override public void onClick(View v) { show(DEFAULT_TIME_OUT); mSnapshot.setEnabled(false); mPlayer.snapshot(); mSnapshot.setEnabled(true); } }; private OnSeekBarChangeListener mSeekListener = new OnSeekBarChangeListener() { private boolean wasStopped = false; @Override public void onStartTrackingTouch(SeekBar bar) { mDragging = true; show(3600000); mHandler.removeMessages(MSG_SHOW_PROGRESS); wasStopped = !mPlayer.isPlaying(); if (mInstantSeeking) { mAM.setStreamMute(AudioManager.STREAM_MUSIC, true); if (wasStopped) { mPlayer.start(); } } } @Override public void onProgressChanged(SeekBar bar, int progress, boolean fromuser) { if (!fromuser) return; long newposition = (mDuration * progress) / 1000; String time = StringUtils.generateTime(newposition); if (mInstantSeeking) mPlayer.seekTo(newposition); setOperationInfo(time, 1500); mCurrentTime.setText(time); } @Override public void onStopTrackingTouch(SeekBar bar) { if (!mInstantSeeking) { mPlayer.seekTo((mDuration * bar.getProgress()) / 1000); } else if (wasStopped) { mPlayer.pause(); } mOperationInfo.setVisibility(View.GONE); show(DEFAULT_TIME_OUT); mHandler.removeMessages(MSG_SHOW_PROGRESS); mAM.setStreamMute(AudioManager.STREAM_MUSIC, false); mDragging = false; mHandler.sendEmptyMessageDelayed(MSG_SHOW_PROGRESS, 1000); } }; public interface MediaPlayerControl { void start(); void pause(); void stop(); void seekTo(long pos); boolean isPlaying(); long getDuration(); long getCurrentPosition(); int getBufferPercentage(); void previous(); void next(); long goForward(); long goBack(); void toggleVideoMode(int mode); void showMenu(); void removeLoadingView(); float scale(float scale); void snapshot(); } } ================================================ FILE: src/com/nmbb/oplayer/ui/player/PlayerService.java ================================================ /* * Copyright (C) 2012 YIXIA.COM * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.nmbb.oplayer.ui.player; import io.vov.vitamio.MediaPlayer; import io.vov.vitamio.MediaPlayer.OnBufferingUpdateListener; import io.vov.vitamio.MediaPlayer.OnCompletionListener; import io.vov.vitamio.MediaPlayer.OnErrorListener; import io.vov.vitamio.MediaPlayer.OnHWRenderFailedListener; import io.vov.vitamio.MediaPlayer.OnInfoListener; import io.vov.vitamio.MediaPlayer.OnPreparedListener; import io.vov.vitamio.MediaPlayer.OnSeekCompleteListener; import io.vov.vitamio.MediaPlayer.OnTimedTextListener; import io.vov.vitamio.MediaPlayer.OnVideoSizeChangedListener; import io.vov.vitamio.Vitamio; import io.vov.vitamio.utils.Log; import java.io.File; import java.io.IOException; import java.util.ArrayList; import android.app.Service; import android.content.Context; import android.content.Intent; import android.graphics.Bitmap; import android.net.Uri; import android.os.Binder; import android.os.IBinder; import android.telephony.PhoneStateListener; import android.telephony.TelephonyManager; import android.view.SurfaceHolder; import com.nmbb.oplayer.exception.Logger; import com.nmbb.oplayer.util.FileUtils; public class PlayerService extends Service implements OnBufferingUpdateListener, OnCompletionListener, OnPreparedListener, OnVideoSizeChangedListener, OnErrorListener, OnInfoListener, OnSeekCompleteListener, OnTimedTextListener { private MediaPlayer mPlayer; private VPlayerListener mListener; private Uri mUri; private Uri mOldUri; private float mSeekTo = -1f; private boolean mFromNotification; private String[] mSubPaths; private boolean mInitialized; private final IBinder mBinder = new LocalBinder(); private TelephonyManager mTelephonyManager; private int mCurrentState; private SurfaceHolder mSurfaceHolder; public static final int VPLYAER_NOTIFICATION_ID = 1; public static final int STATE_PREPARED = -1; public static final int STATE_PLAYING = 0; public static final int STATE_NEED_RESUME = 1; public static final int STATE_STOPPED = 2; public static final int STATE_RINGING = 3; private int mLastAudioTrack = -1; private String mLastSubTrack; private int mLastSubTrackId = -1; private long mMediaId = -1l; public class LocalBinder extends Binder { public PlayerService getService() { return PlayerService.this; } } @Override public void onCreate() { super.onCreate(); mInitialized = false; mTelephonyManager = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE); mTelephonyManager.listen(mPhoneListener, PhoneStateListener.LISTEN_CALL_STATE); } @Override public int onStartCommand(Intent intent, int flags, int startId) { if (Vitamio.isInitialized(this)) { vplayerInit(intent.getBooleanExtra("isHWCodec", false)); } else { stopSelf(); } Log.d("CREATE OK"); return super.onStartCommand(intent, flags, startId); } private void vplayerInit(boolean isHWCodec) { mPlayer = new MediaPlayer(PlayerService.this.getApplicationContext(), isHWCodec); mPlayer.setOnHWRenderFailedListener(new OnHWRenderFailedListener() { @Override public void onFailed() { if (mListener != null) mListener.onHWRenderFailed(); } }); mPlayer.setOnBufferingUpdateListener(PlayerService.this); mPlayer.setOnCompletionListener(PlayerService.this); mPlayer.setOnPreparedListener(PlayerService.this); mPlayer.setOnVideoSizeChangedListener(PlayerService.this); mPlayer.setOnErrorListener(PlayerService.this); mPlayer.setOnInfoListener(PlayerService.this); } public void releaseContext() { if (mPlayer != null) mPlayer.release(); mPlayer = null; } @Override public IBinder onBind(Intent intent) { Log.d("BIND OK : " + intent.getPackage()); return mBinder; } @Override public void onDestroy() { super.onDestroy(); release(true); releaseContext(); } public boolean isInitialized() { return mInitialized; } private String mTitle; public boolean initialize(Uri filePath, String displayName, boolean saveUri, float startPos, VPlayerListener listener, int parentId, boolean isHWCodec) { if (mPlayer == null) vplayerInit(isHWCodec); mTitle = displayName; mListener = listener; mOldUri = mUri; mUri = filePath; mSeekTo = startPos; mMediaId = -1; mLastAudioTrack = -1; mLastSubTrackId = -1; mLastSubTrack = ""; setMediaTrack(); Log.i("%s ==> %s, %s, %s, %s", mOldUri, mUri, mInitialized, mPrepared, mVideoSizeKnown); mFromNotification = mInitialized && mUri != null && mUri.equals(mOldUri); mListener.onOpenStart(); if (!mFromNotification) openVideo(); else openSuccess(); return mInitialized; } private void setMediaTrack() { } private void openVideo() { if (mUri == null || mPlayer == null) return; mPlayer.reset(); mInitialized = false; mPrepared = false; mVideoSizeKnown = false; try { mPlayer.setScreenOnWhilePlaying(true); mPlayer.setDataSource(PlayerService.this, mUri); // if (mLastAudioTrack != -1) // mPlayer.setInitialAudioTrack(mLastAudioTrack); // if (mLastSubTrackId != -1) // mPlayer.setInitialSubTrack(mLastSubTrackId); if (mSurfaceHolder != null && mSurfaceHolder.getSurface() != null && mSurfaceHolder.getSurface().isValid()) mPlayer.setDisplay(mSurfaceHolder); mPlayer.prepareAsync(); } catch (IllegalArgumentException e) { Logger.e("openVideo", e); } catch (IllegalStateException e) { Logger.e("openVideo", e); } catch (IOException e) { Logger.e("openVideo", e); } } public Uri getUri() { return mUri; } public long getMediaId() { return mMediaId; } public int getLastAudioTrack() { return mLastAudioTrack; } public String getLastSubTrack() { return mLastSubTrack; } public int getLastSubTrackId() { return mLastSubTrackId; } public void setVPlayerListener(VPlayerListener listener) { mListener = listener; } public void setState(int state) { mCurrentState = state; } public boolean needResume() { return mInitialized && (mCurrentState == STATE_NEED_RESUME || mCurrentState == STATE_PREPARED); } public boolean ringingState() { return mInitialized && mCurrentState == STATE_RINGING; } public void release() { release(true); } private void release(boolean all) { if (mPlayer != null) { if (mListener != null) mListener.onCloseStart(); mPlayer.reset(); mInitialized = false; mPrepared = false; mVideoSizeKnown = false; if (mListener != null) mListener.onCloseComplete(); } if (all) { mListener = null; mUri = null; } } public void stop() { if (mInitialized) { mPlayer.pause(); } } public void start() { if (mInitialized) { mPlayer.start(); setState(STATE_PLAYING); } } public void setDisplay(SurfaceHolder surface) { mSurfaceHolder = surface; if (mPlayer != null) mPlayer.setDisplay(surface); } public void releaseSurface() { if (mInitialized) mPlayer.releaseDisplay(); } public boolean isPlaying() { return (mInitialized && mPlayer.isPlaying()); } public int getVideoWidth() { if (mInitialized) return mPlayer.getVideoWidth(); return 0; } public int getVideoHeight() { if (mInitialized) return mPlayer.getVideoHeight(); return 0; } public float getVideoAspectRatio() { if (mInitialized) return mPlayer.getVideoAspectRatio(); return 0f; } public long getDuration() { if (mInitialized) return mPlayer.getDuration(); return 0; } public long getCurrentPosition() { if (mInitialized) return mPlayer.getCurrentPosition(); return 0; } public Bitmap getCurrentFrame() { if (mInitialized) return mPlayer.getCurrentFrame(); return null; } public float getBufferProgress() { if (mInitialized) return mPlayer.getBufferProgress(); return 0f; } public void seekTo(float percent) { if (mInitialized) mPlayer.seekTo((int) (percent * getDuration())); } public String getMetaEncoding() { if (mInitialized) return mPlayer.getMetaEncoding(); return null; } public void setAudioTrack(int num) { if (mInitialized) mPlayer.selectTrack(num); // mPlayer.setAudioTrack(num); } public int getAudioTrack() { if (mInitialized) return mPlayer.getAudioTrack(); return 0; } // public HashMap getAudioTrackMap() { // if (!mInitialized) // return null; // String enc = VP.DEFAULT_META_ENCODING; // return mPlayer.getAudioTrackMap(enc.equals(VP.DEFAULT_META_ENCODING) ? // getMetaEncoding() : enc); // } // // public HashMap getSubTrackMap() { // if (!mInitialized) // return null; // String enc = VP.DEFAULT_SUB_ENCODING; // HashMap trackMap = new HashMap(); // HashMap m = // mPlayer.getSubTrackMap(enc.equals(VP.DEFAULT_SUB_ENCODING) ? // getMetaEncoding() : enc); // if (m != null) // for (String k : m.keySet()) // trackMap.put(k, m.get(k)); // // if (mSubPaths != null) // for (String s : mSubPaths) // trackMap.put(new File(s).getName(), s); // // return trackMap; // } // // public int getSubTrack() { // if (mInitialized) // return mPlayer.getSubTrack(); // return 0; // } // // public void setSubTrack(int id) { // if (mInitialized) // mPlayer.setSubTrack(id); // } // // public String getSubPath() { // if (mInitialized) // return mPlayer.getSubPath(); // return null; // } public void setSubShown(boolean shown) { if (mInitialized) mPlayer.setTimedTextShown(shown);// setSubtitleShown -> // setTimedTextShown 4.0 } protected boolean isBuffering() { return (mInitialized && mPlayer.isBuffering()); } protected void setBuffer(int bufSize) { if (mInitialized) mPlayer.setBufferSize(bufSize); } protected void setVolume(float left, float right) { if (mInitialized) { if (left <= 0f) left = 0f; else if (left >= 1f) left = 1f; if (right <= 0f) right = 0f; else if (right >= 1f) right = 1f; mPlayer.setVolume(left, right); } } protected void setVideoQuality(int quality) { if (mInitialized) mPlayer.setVideoQuality(quality); } protected void setDeinterlace(boolean deinterlace) { if (mInitialized) mPlayer.setDeinterlace(deinterlace); } // public int getSubLocation() { // if (mInitialized) // return mPlayer.getSubLocation(); // return -1; // } // protected void setSubEncoding(String encoding) { if (mInitialized) { String enc = encoding.equals(VP.DEFAULT_SUB_ENCODING) ? null : encoding; mPlayer.setTimedTextEncoding(enc);// setSubEncoding -> // setTimedTextEncoding } } public void setSubPath(String subPath) { if (mInitialized) mPlayer.addTimedTextSource(subPath); // mPlayer.setSubPath(subPath); } public static interface VPlayerListener { public void onHWRenderFailed(); public void onVideoSizeChanged(int width, int height); public void onSubChanged(String text); public void onSubChanged(byte[] pixels, int width, int height); public void onOpenStart(); public void onOpenSuccess(); public void onOpenFailed(); public void onBufferStart(); public void onBufferComplete(); public void onDownloadRateChanged(int kbPerSec); public void onPlaybackComplete(); public void onCloseStart(); public void onCloseComplete(); } private PhoneStateListener mPhoneListener = new PhoneStateListener() { @Override public void onCallStateChanged(int state, String incomingNumber) { switch (state) { case TelephonyManager.CALL_STATE_IDLE: break; case TelephonyManager.CALL_STATE_OFFHOOK: case TelephonyManager.CALL_STATE_RINGING: if (isPlaying()) { stop(); setState(STATE_RINGING); } break; default: break; } } }; private boolean mVideoSizeKnown = false; private boolean mPrepared = false; @Override public void onVideoSizeChanged(MediaPlayer arg0, int arg1, int arg2) { mVideoSizeKnown = true; if (mListener != null) mListener.onVideoSizeChanged(arg1, arg2); } @Override public void onPrepared(MediaPlayer arg0) { mPrepared = true; openSuccess(); } private void openSuccess() { mInitialized = true; if (!mFromNotification && mSeekTo > 0 && mSeekTo < 1) seekTo(mSeekTo); mSeekTo = -1; mListener.onOpenSuccess(); if (!mFromNotification) { setSubEncoding(VP.DEFAULT_SUB_ENCODING); if (mUri != null) mSubPaths = getSubFiles(mUri.getPath()); if (mSubPaths != null) setSubPath(FileUtils.getCanonical(new File(mSubPaths[0]))); setSubShown(VP.DEFAULT_SUB_SHOWN); } } @Override public void onCompletion(MediaPlayer arg0) { if (mListener != null) { mListener.onPlaybackComplete(); } else { release(true); } } @Override public void onBufferingUpdate(MediaPlayer arg0, int arg1) { } @Override public void onSeekComplete(MediaPlayer arg0) { } @Override public boolean onInfo(MediaPlayer arg0, int arg1, int arg2) { switch (arg1) { case MediaPlayer.MEDIA_INFO_BUFFERING_START: if (mListener != null) mListener.onBufferStart(); else mPlayer.pause(); break; case MediaPlayer.MEDIA_INFO_BUFFERING_END: if (mListener != null) mListener.onBufferComplete(); else mPlayer.start(); break; case MediaPlayer.MEDIA_INFO_DOWNLOAD_RATE_CHANGED: if (mListener != null) mListener.onDownloadRateChanged(arg2); break; } return true; } @Override public boolean onError(MediaPlayer arg0, int arg1, int arg2) { mListener.onOpenFailed(); return true; } private String[] getSubFiles(String videoPath) { ArrayList files = new ArrayList(); for (String ext : MediaPlayer.SUB_TYPES) { File s = new File(videoPath.substring(0, videoPath.lastIndexOf('.') > 0 ? videoPath.lastIndexOf('.') : videoPath.length()) + ext); if (s.exists() && s.isFile() && s.canRead()) files.add(s.getAbsolutePath()); } if (files.isEmpty()) return null; else return files.toArray(new String[files.size()]); } @Override public void onTimedText(String text) { if (mListener != null) mListener.onSubChanged(text); } @Override public void onTimedTextUpdate(byte[] pixels, int width, int height) { if (mListener != null) mListener.onSubChanged(pixels, width, height); } // @Override // public void onSubtitleUpdate(String arg0) { // if (mListener != null) // mListener.onSubChanged(arg0); // } // // @Override // public void onSubtitleUpdate(byte[] arg0, int arg1, int arg2) { // if (mListener != null) // mListener.onSubChanged(arg0, arg1, arg2); // } } ================================================ FILE: src/com/nmbb/oplayer/ui/player/VP.java ================================================ package com.nmbb.oplayer.ui.player; import io.vov.vitamio.MediaPlayer; import android.graphics.Typeface; public class VP { public static final String SNAP_SHOT_PATH = "/Player"; public static final String SESSION_LAST_POSITION_SUFIX = ".last"; // key public static final String SUB_SHADOW_COLOR = "vplayer_sub_shadow_color"; public static final String SUB_POSITION = "vplayer_sub_position"; public static final String SUB_SIZE = "vplayer_sub_size"; public static final String SUB_SHADOW_RADIUS = "vplayer_sub_shadow_radius"; public static final String SUB_ENABLED = "vplayer_sub_enabled"; public static final String SUB_SHADOW_ENABLED = "vplayer_sub_shadow_enabled"; public static final String SUB_TEXT_KEY = "sub_text"; public static final String SUB_PIXELS_KEY = "sub_pixels"; public static final String SUB_WIDTH_KEY = "sub_width"; public static final String SUB_HEIGHT_KEY = "sub_height"; // default value 1024 public static final int DEFAULT_BUF_SIZE = 512 * 1024; public static final int DEFAULT_VIDEO_QUALITY = MediaPlayer.VIDEOQUALITY_MEDIUM; public static final boolean DEFAULT_DEINTERLACE = false; public static final float DEFAULT_ASPECT_RATIO = 0f; public static final float DEFAULT_STEREO_VOLUME = 1.0f; public static final String DEFAULT_META_ENCODING = "auto"; public static final String DEFAULT_SUB_ENCODING = "auto"; public static final int DEFAULT_SUB_STYLE = Typeface.BOLD; public static final int DEFAULT_SUB_COLOR = 0xffffffff; public static final int DEFAULT_SUB_SHADOWCOLOR = 0xff000000; public static final float DEFAULT_SUB_SHADOWRADIUS = 2.0f; public static final float DEFAULT_SUB_SIZE = 18.0f; public static final float DEFAULT_SUB_POS = 10.0f; public static final int DEFAULT_TYPEFACE_INT = 0; public static final boolean DEFAULT_SUB_SHOWN = true; public static final boolean DEFAULT_SUB_SHADOW = true; public static final Typeface DEFAULT_TYPEFACE = Typeface.DEFAULT; public static Typeface getTypeface(int type) { switch (type) { case 0: return Typeface.DEFAULT; case 1: return Typeface.SANS_SERIF; case 2: return Typeface.SERIF; case 3: return Typeface.MONOSPACE; default: return DEFAULT_TYPEFACE; } } } ================================================ FILE: src/com/nmbb/oplayer/ui/player/VideoActivity.java ================================================ /* * Copyright (C) 2012 YIXIA.COM * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.nmbb.oplayer.ui.player; import io.vov.vitamio.utils.FileUtils; import io.vov.vitamio.utils.Log; import io.vov.vitamio.widget.OutlineTextView; import java.io.File; import java.nio.ByteBuffer; import java.text.SimpleDateFormat; import java.util.Date; import java.util.concurrent.atomic.AtomicBoolean; import android.annotation.SuppressLint; import android.app.Activity; import android.app.KeyguardManager; import android.content.BroadcastReceiver; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.ServiceConnection; import android.content.res.Configuration; import android.graphics.Bitmap; import android.media.AudioManager; import android.net.Uri; import android.os.BatteryManager; import android.os.Build; import android.os.Bundle; import android.os.Environment; import android.os.Handler; import android.os.IBinder; import android.os.Message; import android.text.TextUtils; import android.view.SurfaceHolder; import android.view.View; import android.view.ViewGroup.MarginLayoutParams; import android.view.WindowManager; import android.widget.ImageView; import android.widget.TextView; import com.nmbb.oplayer.R; import com.nmbb.oplayer.preference.PreferenceUtils; import com.nmbb.oplayer.util.ApplicationUtils; import com.nmbb.oplayer.util.DeviceUtils; import com.nmbb.oplayer.util.ImageUtils; import com.nmbb.oplayer.util.IntentHelper; import com.nmbb.oplayer.util.MediaUtils; import com.nmbb.oplayer.util.StringUtils; import com.nmbb.oplayer.util.ToastUtils; @SuppressLint("HandlerLeak") public class VideoActivity extends Activity implements MediaController.MediaPlayerControl, VideoView.SurfaceCallback { public static final int RESULT_FAILED = -7; private static final IntentFilter USER_PRESENT_FILTER = new IntentFilter( Intent.ACTION_USER_PRESENT); private static final IntentFilter SCREEN_FILTER = new IntentFilter( Intent.ACTION_SCREEN_ON); private static final IntentFilter HEADSET_FILTER = new IntentFilter( Intent.ACTION_HEADSET_PLUG); private static final IntentFilter BATTERY_FILTER = new IntentFilter( Intent.ACTION_BATTERY_CHANGED); private boolean mCreated = false; private boolean mNeedLock; private String mDisplayName; private String mBatteryLevel; private boolean mFromStart; private int mLoopCount; private boolean mSaveUri; private int mParentId; private float mStartPos; private boolean mEnd = false; private String mSubPath; private boolean mSubShown; private View mViewRoot; private VideoView mVideoView; private View mVideoLoadingLayout; private TextView mVideoLoadingText; private View mSubtitleContainer; private OutlineTextView mSubtitleText; private ImageView mSubtitleImage; private Uri mUri; private ScreenReceiver mScreenReceiver; private HeadsetPlugReceiver mHeadsetPlugReceiver; private UserPresentReceiver mUserPresentReceiver; private BatteryReceiver mBatteryReceiver; private boolean mReceiverRegistered = false; private boolean mHeadsetPlaying = false; private boolean mCloseComplete = false; private boolean mIsHWCodec = false; private MediaController mMediaController; private PlayerService vPlayer; private ServiceConnection vPlayerServiceConnection; // private Animation mLoadingAnimation; // private View mLoadingProgressView; static { SCREEN_FILTER.addAction(Intent.ACTION_SCREEN_OFF); } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN); if (!io.vov.vitamio.LibsChecker.checkVitamioLibs(this)) return; vPlayerServiceConnection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { vPlayer = ((PlayerService.LocalBinder) service).getService(); mServiceConnected = true; if (mSurfaceCreated) vPlayerHandler.sendEmptyMessage(OPEN_FILE); } @Override public void onServiceDisconnected(ComponentName name) { vPlayer = null; mServiceConnected = false; } }; setVolumeControlStream(AudioManager.STREAM_MUSIC); parseIntent(getIntent()); loadView(R.layout.activity_video); manageReceivers(); mCreated = true; } private void attachMediaController() { if (mMediaController != null) { mNeedLock = mMediaController.isLocked(); mMediaController.release(); } mMediaController = new MediaController(this, mNeedLock); mMediaController.setMediaPlayer(this); mMediaController.setAnchorView(mVideoView.getRootView()); setFileName(); setBatteryLevel(); } @Override public void onStart() { super.onStart(); if (!mCreated) return; Intent serviceIntent = new Intent(this, PlayerService.class); serviceIntent.putExtra("isHWCodec", mIsHWCodec); bindService(serviceIntent, vPlayerServiceConnection, Context.BIND_AUTO_CREATE); } @Override public void onResume() { super.onResume(); if (!mCreated) return; if (isInitialized()) { KeyguardManager keyguardManager = (KeyguardManager) getSystemService(KEYGUARD_SERVICE); if (!keyguardManager.inKeyguardRestrictedInputMode()) { startPlayer(); } } else { if (mCloseComplete) { reOpen(); } } } @Override public void onPause() { super.onPause(); if (!mCreated) return; if (isInitialized()) { savePosition(); if (vPlayer != null && vPlayer.isPlaying()) { stopPlayer(); } } } @Override public void onStop() { super.onStop(); if (!mCreated) return; if (isInitialized()) { vPlayer.releaseSurface(); } if (mServiceConnected) { unbindService(vPlayerServiceConnection); mServiceConnected = false; } } @Override public void onDestroy() { super.onDestroy(); if (!mCreated) return; manageReceivers(); if (isInitialized() && !vPlayer.isPlaying()) release(); if (mMediaController != null) mMediaController.release(); } @Override public void onConfigurationChanged(Configuration newConfig) { if (isInitialized()) { setVideoLayout(); attachMediaController(); } super.onConfigurationChanged(newConfig); } @Override public void onBackPressed() { super.onBackPressed(); } @Override protected void onSaveInstanceState(Bundle outState) { // http://code.google.com/p/android/issues/detail?id=19917 outState.putString("WORKAROUND_FOR_BUG_19917_KEY", "WORKAROUND_FOR_BUG_19917_VALUE"); super.onSaveInstanceState(outState); } @Override public void showMenu() { } private void loadView(int id) { setContentView(id); getWindow().setBackgroundDrawable(null); mViewRoot = findViewById(R.id.video_root); mVideoView = (VideoView) findViewById(R.id.video); mVideoView.initialize(this, this, mIsHWCodec); mSubtitleContainer = findViewById(R.id.subtitle_container); mSubtitleText = (OutlineTextView) findViewById(R.id.subtitle_text); mSubtitleImage = (ImageView) findViewById(R.id.subtitle_image); mVideoLoadingText = (TextView) findViewById(R.id.video_loading_text); mVideoLoadingLayout = findViewById(R.id.video_loading); // mLoadingProgressView = // mVideoLoadingLayout.findViewById(R.id.video_loading_progress); // mLoadingAnimation = AnimationUtils.loadAnimation(VideoActivity.this, // R.anim.loading_rotate); getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); } private void parseIntent(Intent i) { Uri dat = IntentHelper.getIntentUri(i); if (dat == null) resultFinish(RESULT_FAILED); String datString = dat.toString(); if (!datString.equals(dat.toString())) dat = Uri.parse(datString); mUri = dat; mNeedLock = i.getBooleanExtra("lockScreen", false); mDisplayName = i.getStringExtra("displayName"); mFromStart = i.getBooleanExtra("fromStart", false); mSaveUri = i.getBooleanExtra("saveUri", true); mStartPos = i.getFloatExtra("startPosition", -1.0f); mLoopCount = i.getIntExtra("loopCount", 1); mParentId = i.getIntExtra("parentId", 0); mSubPath = i.getStringExtra("subPath"); mSubShown = i.getBooleanExtra("subShown", true); mIsHWCodec = i.getBooleanExtra("hwCodec", false); Log.i("L: %b, N: %s, S: %b, P: %f, LP: %d", mNeedLock, mDisplayName, mFromStart, mStartPos, mLoopCount); } private void manageReceivers() { if (!mReceiverRegistered) { mScreenReceiver = new ScreenReceiver(); registerReceiver(mScreenReceiver, SCREEN_FILTER); mUserPresentReceiver = new UserPresentReceiver(); registerReceiver(mUserPresentReceiver, USER_PRESENT_FILTER); mBatteryReceiver = new BatteryReceiver(); registerReceiver(mBatteryReceiver, BATTERY_FILTER); mHeadsetPlugReceiver = new HeadsetPlugReceiver(); registerReceiver(mHeadsetPlugReceiver, HEADSET_FILTER); mReceiverRegistered = true; } else { try { if (mScreenReceiver != null) unregisterReceiver(mScreenReceiver); if (mUserPresentReceiver != null) unregisterReceiver(mUserPresentReceiver); if (mHeadsetPlugReceiver != null) unregisterReceiver(mHeadsetPlugReceiver); if (mBatteryReceiver != null) unregisterReceiver(mBatteryReceiver); } catch (IllegalArgumentException e) { } mReceiverRegistered = false; } } private void setFileName() { if (mUri != null) { String name = null; if (mUri.getScheme() == null || mUri.getScheme().equals("file")) name = FileUtils.getName(mUri.toString()); else name = mUri.getLastPathSegment(); if (name == null) name = "null"; if (mDisplayName == null) mDisplayName = name; mMediaController.setFileName(mDisplayName); } } private void applyResult(int resultCode) { vPlayerHandler.removeMessages(BUFFER_PROGRESS); Intent i = new Intent(); i.putExtra("filePath", mUri.toString()); if (isInitialized()) { i.putExtra("position", (double) vPlayer.getCurrentPosition() / vPlayer.getDuration()); i.putExtra("duration", vPlayer.getDuration()); savePosition(); } switch (resultCode) { case RESULT_FAILED: ToastUtils.showLongToast(R.string.video_cannot_play); break; case RESULT_CANCELED: case RESULT_OK: break; } setResult(resultCode, i); } private void resultFinish(int resultCode) { applyResult(resultCode); if (DeviceUtils.hasICS() && resultCode != RESULT_FAILED) { android.os.Process.killProcess(android.os.Process.myPid()); } else { finish(); } } private void release() { if (vPlayer != null) { if (DeviceUtils.hasICS()) { android.os.Process.killProcess(android.os.Process.myPid()); } else { vPlayer.release(); vPlayer.releaseContext(); } } } private void reOpen(Uri path, String name, boolean fromStart) { if (isInitialized()) { savePosition(); vPlayer.release(); vPlayer.releaseContext(); } Intent i = getIntent(); if (mMediaController != null) i.putExtra("lockScreen", mMediaController.isLocked()); i.putExtra("startPosition", PreferenceUtils.getFloat(mUri + VP.SESSION_LAST_POSITION_SUFIX, 7.7f)); i.putExtra("fromStart", fromStart); i.putExtra("displayName", name); i.setData(path); parseIntent(i); mUri = path; if (mViewRoot != null) mViewRoot.invalidate(); if (mOpened != null) mOpened.set(false); } public void reOpen() { reOpen(mUri, mDisplayName, false); } protected void startPlayer() { if (isInitialized() && mScreenReceiver.screenOn && !vPlayer.isBuffering()) { Log.i("VideoActivity#startPlayer"); if (!vPlayer.isPlaying()) { vPlayer.start(); } } } protected void stopPlayer() { if (isInitialized()) { vPlayer.stop(); } } private void setBatteryLevel() { if (mMediaController != null) mMediaController.setBatteryLevel(mBatteryLevel); } private class BatteryReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { int level = intent.getIntExtra(BatteryManager.EXTRA_LEVEL, 0); int scale = intent.getIntExtra(BatteryManager.EXTRA_SCALE, 100); int percent = scale > 0 ? level * 100 / scale : 0; if (percent > 100) percent = 100; mBatteryLevel = String.valueOf(percent) + "%"; setBatteryLevel(); } } private class UserPresentReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { if (isRootActivity()) { startPlayer(); } } } private boolean isRootActivity() { return ApplicationUtils.isTopActivity(getApplicationContext(), getClass().getName()); // ActivityManager activity = (ActivityManager) // getSystemService(Context.ACTIVITY_SERVICE); // return // activity.getRunningTasks(1).get(0).topActivity.flattenToString().endsWith("io.vov.vitamio.activity.VideoActivity"); } public class HeadsetPlugReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { if (intent != null && intent.hasExtra("state")) { int state = intent.getIntExtra("state", -1); if (state == 0) { mHeadsetPlaying = isPlaying(); stopPlayer(); } else if (state == 1) { if (mHeadsetPlaying) startPlayer(); } } }; } private class ScreenReceiver extends BroadcastReceiver { private boolean screenOn = true; @Override public void onReceive(Context context, Intent intent) { if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) { screenOn = false; stopPlayer(); } else if (intent.getAction().equals(Intent.ACTION_SCREEN_ON)) { screenOn = true; } } } private void loadVPlayerPrefs() { if (!isInitialized()) return; vPlayer.setBuffer(VP.DEFAULT_BUF_SIZE); vPlayer.setVideoQuality(VP.DEFAULT_VIDEO_QUALITY); vPlayer.setDeinterlace(VP.DEFAULT_DEINTERLACE); vPlayer.setVolume(VP.DEFAULT_STEREO_VOLUME, VP.DEFAULT_STEREO_VOLUME); vPlayer.setSubEncoding(VP.DEFAULT_SUB_ENCODING); MarginLayoutParams lp = (MarginLayoutParams) mSubtitleContainer .getLayoutParams(); lp.bottomMargin = (int) VP.DEFAULT_SUB_POS; mSubtitleContainer.setLayoutParams(lp); vPlayer.setSubShown(mSubShown); setTextViewStyle(mSubtitleText); if (!TextUtils.isEmpty(mSubPath)) vPlayer.setSubPath(mSubPath); if (mVideoView != null && isInitialized()) setVideoLayout(); } private void setTextViewStyle(OutlineTextView v) { v.setTextColor(VP.DEFAULT_SUB_COLOR); v.setTypeface(VP.getTypeface(VP.DEFAULT_TYPEFACE_INT), VP.DEFAULT_SUB_STYLE); v.setShadowLayer(VP.DEFAULT_SUB_SHADOWRADIUS, 0, 0, VP.DEFAULT_SUB_SHADOWCOLOR); } private boolean isInitialized() { return (mCreated && vPlayer != null && vPlayer.isInitialized()); } private Handler mSubHandler = new Handler() { Bundle data; String text; byte[] pixels; int width = 0, height = 0; Bitmap bm = null; int oldType = SUBTITLE_TEXT; @Override public void handleMessage(Message msg) { data = msg.getData(); switch (msg.what) { case SUBTITLE_TEXT: if (oldType != SUBTITLE_TEXT) { mSubtitleImage.setVisibility(View.GONE); mSubtitleText.setVisibility(View.VISIBLE); oldType = SUBTITLE_TEXT; } text = data.getString(VP.SUB_TEXT_KEY); mSubtitleText.setText(text == null ? "" : text.trim()); break; case SUBTITLE_BITMAP: if (oldType != SUBTITLE_BITMAP) { mSubtitleText.setVisibility(View.GONE); mSubtitleImage.setVisibility(View.VISIBLE); oldType = SUBTITLE_BITMAP; } pixels = data.getByteArray(VP.SUB_PIXELS_KEY); if (bm == null || width != data.getInt(VP.SUB_WIDTH_KEY) || height != data.getInt(VP.SUB_HEIGHT_KEY)) { width = data.getInt(VP.SUB_WIDTH_KEY); height = data.getInt(VP.SUB_HEIGHT_KEY); bm = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); } if (pixels != null) bm.copyPixelsFromBuffer(ByteBuffer.wrap(pixels)); mSubtitleImage.setImageBitmap(bm); break; } } }; private AtomicBoolean mOpened = new AtomicBoolean(Boolean.FALSE); private boolean mSurfaceCreated = false; private boolean mServiceConnected = false; private Object mOpenLock = new Object(); private static final int OPEN_FILE = 0; private static final int OPEN_START = 1; private static final int OPEN_SUCCESS = 2; private static final int OPEN_FAILED = 3; private static final int HW_FAILED = 4; private static final int LOAD_PREFS = 5; private static final int BUFFER_START = 11; private static final int BUFFER_PROGRESS = 12; private static final int BUFFER_COMPLETE = 13; private static final int CLOSE_START = 21; private static final int CLOSE_COMPLETE = 22; private static final int SUBTITLE_TEXT = 0; private static final int SUBTITLE_BITMAP = 1; private Handler vPlayerHandler = new Handler() { @Override public void handleMessage(Message msg) { switch (msg.what) { case OPEN_FILE: synchronized (mOpenLock) { if (!mOpened.get() && vPlayer != null) { mOpened.set(true); vPlayer.setVPlayerListener(vPlayerListener); if (vPlayer.isInitialized()) mUri = vPlayer.getUri(); if (mVideoView != null) vPlayer.setDisplay(mVideoView.getHolder()); if (mUri != null) vPlayer.initialize(mUri, mDisplayName, mSaveUri, getStartPosition(), vPlayerListener, mParentId, mIsHWCodec); } } break; case OPEN_START: mVideoLoadingText.setText(R.string.video_layout_loading); setVideoLoadingLayoutVisibility(View.VISIBLE); break; case OPEN_SUCCESS: loadVPlayerPrefs(); setVideoLoadingLayoutVisibility(View.GONE); setVideoLayout(); vPlayer.start(); attachMediaController(); break; case OPEN_FAILED: resultFinish(RESULT_FAILED); break; case BUFFER_START: setVideoLoadingLayoutVisibility(View.VISIBLE); vPlayerHandler.sendEmptyMessageDelayed(BUFFER_PROGRESS, 1000); break; case BUFFER_PROGRESS: if (vPlayer.getBufferProgress() >= 100) { setVideoLoadingLayoutVisibility(View.GONE); } else { mVideoLoadingText.setText(getString( R.string.video_layout_buffering_progress, vPlayer.getBufferProgress())); vPlayerHandler.sendEmptyMessageDelayed(BUFFER_PROGRESS, 1000); stopPlayer(); } break; case BUFFER_COMPLETE: setVideoLoadingLayoutVisibility(View.GONE); vPlayerHandler.removeMessages(BUFFER_PROGRESS); break; case CLOSE_START: mVideoLoadingText.setText(R.string.closing_file); setVideoLoadingLayoutVisibility(View.VISIBLE); break; case CLOSE_COMPLETE: mCloseComplete = true; break; case HW_FAILED: if (mVideoView != null) { mVideoView.setVisibility(View.GONE); mVideoView.setVisibility(View.VISIBLE); mVideoView.initialize(VideoActivity.this, VideoActivity.this, false); } break; case LOAD_PREFS: loadVPlayerPrefs(); break; } } }; private void setVideoLoadingLayoutVisibility(int visibility) { if (mVideoLoadingLayout != null) { // if (visibility == View.VISIBLE) // mLoadingProgressView.startAnimation(mLoadingAnimation); mVideoLoadingLayout.setVisibility(visibility); } } private PlayerService.VPlayerListener vPlayerListener = new PlayerService.VPlayerListener() { @Override public void onHWRenderFailed() { if (Build.VERSION.SDK_INT < 11 && mIsHWCodec) { vPlayerHandler.sendEmptyMessage(HW_FAILED); vPlayerHandler.sendEmptyMessageDelayed(HW_FAILED, 200); } } @Override public void onSubChanged(String sub) { Message msg = new Message(); Bundle b = new Bundle(); b.putString(VP.SUB_TEXT_KEY, sub); msg.setData(b); msg.what = SUBTITLE_TEXT; mSubHandler.sendMessage(msg); } @Override public void onSubChanged(byte[] pixels, int width, int height) { Message msg = new Message(); Bundle b = new Bundle(); b.putByteArray(VP.SUB_PIXELS_KEY, pixels); b.putInt(VP.SUB_WIDTH_KEY, width); b.putInt(VP.SUB_HEIGHT_KEY, height); msg.setData(b); msg.what = SUBTITLE_BITMAP; mSubHandler.sendMessage(msg); } @Override public void onOpenStart() { vPlayerHandler.sendEmptyMessage(OPEN_START); } @Override public void onOpenSuccess() { vPlayerHandler.sendEmptyMessage(OPEN_SUCCESS); } @Override public void onOpenFailed() { vPlayerHandler.sendEmptyMessage(OPEN_FAILED); } @Override public void onBufferStart() { vPlayerHandler.sendEmptyMessage(BUFFER_START); stopPlayer(); } @Override public void onBufferComplete() { Log.i("VideoActivity#onBufferComplete " + vPlayer.needResume()); vPlayerHandler.sendEmptyMessage(BUFFER_COMPLETE); if (vPlayer != null && !vPlayer.needResume()) startPlayer(); } @Override public void onPlaybackComplete() { mEnd = true; if (mLoopCount == 0 || mLoopCount-- > 1) { vPlayer.start(); vPlayer.seekTo(0); } else { resultFinish(RESULT_OK); } } @Override public void onCloseStart() { vPlayerHandler.sendEmptyMessage(CLOSE_START); } @Override public void onCloseComplete() { vPlayerHandler.sendEmptyMessage(CLOSE_COMPLETE); } @Override public void onVideoSizeChanged(int width, int height) { if (mVideoView != null) { setVideoLayout(); } } @Override public void onDownloadRateChanged(int kbPerSec) { if (!MediaUtils.isNative(mUri.toString()) && mMediaController != null) { mMediaController.setDownloadRate(String.format("%dKB/s", kbPerSec)); } } }; private int mVideoMode = VideoView.VIDEO_LAYOUT_SCALE; private void setVideoLayout() { mVideoView.setVideoLayout(mVideoMode, VP.DEFAULT_ASPECT_RATIO, vPlayer.getVideoWidth(), vPlayer.getVideoHeight(), vPlayer.getVideoAspectRatio()); } private void savePosition() { if (vPlayer != null && mUri != null) { PreferenceUtils.put( mUri.toString(), StringUtils.generateTime((int) (0.5 + vPlayer .getCurrentPosition())) + " / " + StringUtils.generateTime(vPlayer.getDuration())); if (mEnd) PreferenceUtils .put(mUri + VP.SESSION_LAST_POSITION_SUFIX, 1.0f); else PreferenceUtils .put(mUri + VP.SESSION_LAST_POSITION_SUFIX, (float) (vPlayer.getCurrentPosition() / (double) vPlayer .getDuration())); } } private float getStartPosition() { if (mFromStart) return 1.1f; if (mStartPos <= 0.0f || mStartPos >= 1.0f) return PreferenceUtils.getFloat(mUri + VP.SESSION_LAST_POSITION_SUFIX, 7.7f); return mStartPos; } @Override public int getBufferPercentage() { if (isInitialized()) return (int) (vPlayer.getBufferProgress() * 100); return 0; } @Override public long getCurrentPosition() { if (isInitialized()) return vPlayer.getCurrentPosition(); return (long) (getStartPosition() * vPlayer.getDuration()); } @Override public long getDuration() { if (isInitialized()) return vPlayer.getDuration(); return 0; } @Override public boolean isPlaying() { if (isInitialized()) return vPlayer.isPlaying(); return false; } @Override public void pause() { if (isInitialized()) vPlayer.stop(); } @Override public void seekTo(long arg0) { if (isInitialized()) vPlayer.seekTo((float) ((double) arg0 / vPlayer.getDuration())); } @Override public void start() { if (isInitialized()) vPlayer.start(); } @Override public void previous() { } @Override public void next() { } private static final int VIDEO_MAXIMUM_HEIGHT = 2048; private static final int VIDEO_MAXIMUM_WIDTH = 2048; @Override public float scale(float scaleFactor) { float userRatio = VP.DEFAULT_ASPECT_RATIO; int videoWidth = vPlayer.getVideoWidth(); int videoHeight = vPlayer.getVideoHeight(); float videoRatio = vPlayer.getVideoAspectRatio(); float currentRatio = mVideoView.mVideoHeight / (float) videoHeight; currentRatio += (scaleFactor - 1); if (videoWidth * currentRatio >= VIDEO_MAXIMUM_WIDTH) currentRatio = VIDEO_MAXIMUM_WIDTH / (float) videoWidth; if (videoHeight * currentRatio >= VIDEO_MAXIMUM_HEIGHT) currentRatio = VIDEO_MAXIMUM_HEIGHT / (float) videoHeight; if (currentRatio < 0.5f) currentRatio = 0.5f; mVideoView.mVideoHeight = (int) (videoHeight * currentRatio); mVideoView.setVideoLayout(mVideoMode, userRatio, videoWidth, videoHeight, videoRatio); return currentRatio; } @SuppressLint("SimpleDateFormat") @Override public void snapshot() { if (!com.nmbb.oplayer.util.FileUtils.sdAvailable()) { ToastUtils.showToast(R.string.file_explorer_sdcard_not_available); } else { Uri imgUri = null; Bitmap bitmap = vPlayer.getCurrentFrame(); if (bitmap != null) { File screenshotsDirectory = new File( Environment .getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES) + VP.SNAP_SHOT_PATH); if (!screenshotsDirectory.exists()) { screenshotsDirectory.mkdirs(); } File savePath = new File( screenshotsDirectory.getPath() + "/" + new SimpleDateFormat("yyyyMMddHHmmss") .format(new Date()) + ".jpg"); if (ImageUtils.saveBitmap(savePath.getPath(), bitmap)) { imgUri = Uri.fromFile(savePath); } } if (imgUri != null) { sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, imgUri)); ToastUtils.showLongToast(getString( R.string.video_screenshot_save_in, imgUri.getPath())); } else { ToastUtils.showToast(R.string.video_screenshot_failed); } } } @Override public void toggleVideoMode(int mode) { mVideoMode = mode; setVideoLayout(); } @Override public void stop() { onBackPressed(); } @Override public long goForward() { return 0; } @Override public long goBack() { return 0; } @Override public void removeLoadingView() { mVideoLoadingLayout.setVisibility(View.GONE); } @Override public void onSurfaceCreated(SurfaceHolder holder) { Log.i("onSurfaceCreated"); mSurfaceCreated = true; if (mServiceConnected) vPlayerHandler.sendEmptyMessage(OPEN_FILE); if (vPlayer != null) vPlayer.setDisplay(holder); } @Override public void onSurfaceChanged(SurfaceHolder holder, int format, int width, int height) { if (vPlayer != null) { setVideoLayout(); } } @Override public void onSurfaceDestroyed(SurfaceHolder holder) { Log.i("onSurfaceDestroyed"); if (vPlayer != null && vPlayer.isInitialized()) { if (vPlayer.isPlaying()) { vPlayer.stop(); vPlayer.setState(PlayerService.STATE_NEED_RESUME); } vPlayer.releaseSurface(); if (vPlayer.needResume()) vPlayer.start(); } } } ================================================ FILE: src/com/nmbb/oplayer/ui/player/VideoView.java ================================================ /* * Copyright (C) 2012 YIXIA.COM * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.nmbb.oplayer.ui.player; import android.app.Activity; import android.content.Context; import android.graphics.PixelFormat; import android.util.AttributeSet; import android.view.SurfaceHolder; import android.view.SurfaceView; import android.view.ViewGroup.LayoutParams; import com.nmbb.oplayer.util.DeviceUtils; public class VideoView extends SurfaceView { private Activity mActivity; private SurfaceHolder mSurfaceHolder; private int mSurfaceWidth, mSurfaceHeight; private int mVideoMode = VIDEO_LAYOUT_SCALE; public static final int VIDEO_LAYOUT_ORIGIN = 0; public static final int VIDEO_LAYOUT_SCALE = 1; public static final int VIDEO_LAYOUT_STRETCH = 2; public static final int VIDEO_LAYOUT_ZOOM = 3; public static final int VIDEO_LAYOUT_SCALE_ZOOM = 4; public int mVideoHeight; public VideoView(Context context, AttributeSet attrs) { super(context, attrs); getHolder().addCallback(mCallback); getHolder().setFormat(PixelFormat.RGBA_8888); } @SuppressWarnings("deprecation") public void initialize(Activity activity, SurfaceCallback l, boolean push) { mActivity = activity; mListener = l; if (mSurfaceHolder == null) mSurfaceHolder = getHolder(); // These methods is set to hw decoder or sw decoder, <= 2.3 if (push) getHolder().setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); else getHolder().setType(SurfaceHolder.SURFACE_TYPE_NORMAL); } private void setSurfaceLayout(float userRatio, int videoWidth, int videoHeight, float videoAspectRatio) { LayoutParams lp = getLayoutParams(); int windowWidth = DeviceUtils.getScreenWidth(mActivity); int windowHeight = DeviceUtils.getScreenHeight(mActivity); float windowRatio = windowWidth / (float) windowHeight; float videoRatio = userRatio <= 0.01f ? videoAspectRatio : userRatio; mSurfaceHeight = videoHeight; mSurfaceWidth = videoWidth; if (VIDEO_LAYOUT_ORIGIN == mVideoMode && mSurfaceWidth < windowWidth && mSurfaceHeight < windowHeight) { lp.width = (int) (mSurfaceHeight * videoRatio); lp.height = mSurfaceHeight; } else if (mVideoMode == VIDEO_LAYOUT_ZOOM) { lp.width = windowRatio > videoRatio ? windowWidth : (int) (videoRatio * windowHeight); lp.height = windowRatio < videoRatio ? windowHeight : (int) (windowWidth / videoRatio); } else if (mVideoMode == VIDEO_LAYOUT_SCALE_ZOOM && mVideoHeight > 0) { lp.width = (int) (mVideoHeight * videoRatio); lp.height = mVideoHeight; } else { boolean full = mVideoMode == VIDEO_LAYOUT_STRETCH; lp.width = (full || windowRatio < videoRatio) ? windowWidth : (int) (videoRatio * windowHeight); lp.height = (full || windowRatio > videoRatio) ? windowHeight : (int) (windowWidth / videoRatio); } mVideoHeight = lp.height; setLayoutParams(lp); getHolder().setFixedSize(mSurfaceWidth, mSurfaceHeight); //Log.d("VIDEO: %dx%dx%f, Surface: %dx%d, LP: %dx%d, Window: %dx%dx%f", videoWidth, videoHeight, videoAspectRatio, mSurfaceWidth, mSurfaceHeight, lp.width, lp.height, windowWidth, windowHeight, windowRatio); } public void setVideoLayout(int layout, float userRatio, int videoWidth, int videoHeight, float videoRatio) { mVideoMode = layout; setSurfaceLayout(userRatio, videoWidth, videoHeight, videoRatio); } private SurfaceHolder.Callback mCallback = new SurfaceHolder.Callback() { @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { holder.setKeepScreenOn(true); if (mListener != null) mListener.onSurfaceChanged(holder, format, width, height); } @Override public void surfaceCreated(SurfaceHolder holder) { mSurfaceHolder = holder; if (mListener != null) mListener.onSurfaceCreated(holder); } @Override public void surfaceDestroyed(SurfaceHolder holder) { if (mListener != null) mListener.onSurfaceDestroyed(holder); } }; private SurfaceCallback mListener; public interface SurfaceCallback { public void onSurfaceCreated(SurfaceHolder holder); public void onSurfaceChanged(SurfaceHolder holder, int format, int width, int height); public void onSurfaceDestroyed(SurfaceHolder holder); } } ================================================ FILE: src/com/nmbb/oplayer/ui/vitamio/InitActivity.java ================================================ package com.nmbb.oplayer.ui.vitamio; import io.vov.vitamio.Vitamio; import android.app.Activity; import android.app.ProgressDialog; import android.content.Intent; import android.os.AsyncTask; import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.view.WindowManager; import com.nmbb.oplayer.R; public class InitActivity extends Activity { public static final String FROM_ME = "fromVitamioInitActivity"; public static final String EXTRA_MSG = "EXTRA_MSG"; public static final String EXTRA_FILE = "EXTRA_FILE"; private ProgressDialog mPD; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); new AsyncTask() { @Override protected void onPreExecute() { mPD = new ProgressDialog(InitActivity.this); mPD.setCancelable(false); mPD.setMessage(getText(R.string.init_decoders)); mPD.show(); } @Override protected Object doInBackground(Object... params) { Vitamio.initialize(getApplicationContext()); // if (Vitamio.isInitialized(getApplicationContext())) // return null; // // //反射解压 // try { // Class c = Class.forName("io.vov.vitamio.Vitamio"); // Method extractLibs = c.getDeclaredMethod("extractLibs", new Class[] { android.content.Context.class, int.class }); // extractLibs.setAccessible(true); // extractLibs.invoke(c, new Object[] { getApplicationContext(), R.raw.libarm }); // //// Field vitamioLibraryPath = c.getDeclaredField("vitamioLibraryPath"); //// //// AndroidContextUtils.getDataDir(ctx) + "libs/" // // } catch (NoSuchMethodException e) { // Log.e("extractLibs", e); // e.printStackTrace(); // } catch (IllegalArgumentException e) { // e.printStackTrace(); // } catch (IllegalAccessException e) { // e.printStackTrace(); // } catch (InvocationTargetException e) { // e.printStackTrace(); // } catch (ClassNotFoundException e) { // e.printStackTrace(); // } uiHandler.sendEmptyMessage(0); return null; } }.execute(); } private Handler uiHandler = new Handler() { @Override public void handleMessage(Message msg) { mPD.dismiss(); Intent src = getIntent(); Intent i = new Intent(); i.setClassName(src.getStringExtra("package"), src.getStringExtra("className")); i.setData(src.getData()); i.putExtras(src); i.putExtra(FROM_ME, true); startActivity(i); finish(); } }; } ================================================ FILE: src/com/nmbb/oplayer/ui/vitamio/LibsChecker.java ================================================ package com.nmbb.oplayer.ui.vitamio; import io.vov.vitamio.Vitamio; import android.app.Activity; import android.content.Intent; public final class LibsChecker { public static final String FROM_ME = "fromVitamioInitActivity"; // // public static final boolean checkVitamioLibs(Activity ctx, int msgID, int rawID) { // new Vitamio(). // if (!Vitamio.isInitialized(ctx) && !ctx.getIntent().getBooleanExtra(FROM_ME, false)) { // Intent i = new Intent(); // i.setClassName(Vitamio.getCompatiblePackage(), "com.nmbb.oplayer.ui.vitamio.InitActivity"); // i.putExtras(ctx.getIntent()); // i.setData(ctx.getIntent().getData()); // i.putExtra("package", ctx.getApplicationInfo().packageName); // i.putExtra("className", ctx.getClass().getName()); // i.putExtra("EXTRA_MSG", msgID); // i.putExtra("EXTRA_FILE", rawID); // ctx.startActivity(i); // ctx.finish(); // return false; // } // return true; // } public static final boolean checkVitamioLibs(Activity ctx, int msgID) { if ((!Vitamio.isInitialized(ctx)) && (!ctx.getIntent().getBooleanExtra("fromVitamioInitActivity", false))) { Intent i = new Intent(); i.setClassName(ctx.getPackageName(), "com.nmbb.oplayer.ui.vitamio.InitActivity");//io.vov.vitamio.activity.InitActivity i.putExtras(ctx.getIntent()); i.setData(ctx.getIntent().getData()); i.putExtra("package", ctx.getPackageName()); i.putExtra("className", ctx.getClass().getName()); i.putExtra("EXTRA_MSG", msgID); ctx.startActivity(i); ctx.finish(); return false; } return true; } } ================================================ FILE: src/com/nmbb/oplayer/util/ApplicationUtils.java ================================================ package com.nmbb.oplayer.util; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.util.List; import android.app.Activity; import android.app.ActivityManager; import android.content.Context; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; import android.os.Environment; import android.widget.Toast; public class ApplicationUtils { /** * 备份App 首先无需提升权限就就可以复制APK,查看权限你就会知道,在data/app下的APK权限如下:-rw-r--r-- system * system 5122972 2012-12-13 10:38 com.taobao.taobao-1.apk 我们是有读取权限的。 * * @param packageName * @param mActivity * @throws IOException */ public static void backupApp(String packageName, Activity mActivity) throws IOException { // 存放位置 String newFile = Environment.getExternalStorageDirectory() .getAbsolutePath() + File.separator; String oldFile = null; try { // 原始位置 oldFile = mActivity.getPackageManager().getApplicationInfo( packageName, 0).sourceDir; } catch (NameNotFoundException e) { e.printStackTrace(); } System.out.println(newFile); System.out.println(oldFile); File in = new File(oldFile); File out = new File(newFile + packageName + ".apk"); if (!out.exists()) { out.createNewFile(); Toast.makeText(mActivity, "文件备份成功!" + "存放于" + newFile + "目录下", 1) .show(); } else { Toast.makeText(mActivity, "文件已经存在!" + "查看" + newFile + "目录下", 1) .show(); } FileInputStream fis = new FileInputStream(in); FileOutputStream fos = new FileOutputStream(out); int count; // 文件太大的话,我觉得需要修改 byte[] buffer = new byte[256 * 1024]; while ((count = fis.read(buffer)) > 0) { fos.write(buffer, 0, count); } fis.close(); fos.flush(); fos.close(); } /** * 获取当前Apk版本号 android:versionCode * * @param context * @return */ public static int getVerCode(Context context) { int verCode = -1; try { verCode = context.getPackageManager().getPackageInfo( context.getPackageName(), 0).versionCode; } catch (NameNotFoundException e) { } return verCode; } public static String getVerName(Context context) { try { return context.getPackageManager().getPackageInfo( context.getPackageName(), 0).versionName; } catch (NameNotFoundException e) { } return ""; } /** * 返回当前的应用是否处于前台显示状态 不需要android.permission.GET_TASKS权限 * http://zengrong.net/post/1680.htm * * @param packageName * @return */ public static boolean isTopActivity(Context context, String packageName) { // _context是一个保存的上下文 ActivityManager am = (ActivityManager) context.getApplicationContext() .getSystemService(Context.ACTIVITY_SERVICE); List list = am .getRunningAppProcesses(); if (list.size() == 0) return false; for (ActivityManager.RunningAppProcessInfo process : list) { // Log.d(getTAG(), Integer.toString(__process.importance)); // Log.d(getTAG(), __process.processName); if (process.importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND && process.processName.equals(packageName)) { return true; } } return false; } /** * 检测APP是否存在 * @param context * @param packageName * @return */ public static boolean checkAppExist(Context context, String packageName) { try { ApplicationInfo info = context.getPackageManager() .getApplicationInfo(packageName, 0); return info != null && info.packageName.equals(packageName); } catch (PackageManager.NameNotFoundException e) { } catch (Exception e) { } return false; } } ================================================ FILE: src/com/nmbb/oplayer/util/ArrayUtils.java ================================================ /* * Copyright (C) 2012 YIXIA.COM * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.nmbb.oplayer.util; import java.lang.reflect.Array; public class ArrayUtils { public static T[] concat(T[] A, T[] B) { final Class typeofA = A.getClass().getComponentType(); @SuppressWarnings("unchecked") T[] C = (T[]) Array.newInstance(typeofA, A.length + B.length); System.arraycopy(A, 0, C, 0, A.length); System.arraycopy(B, 0, C, A.length, B.length); return C; } public static int indexOf(T[] array, T s) { for (int i = 0; i < array.length; i++) { if (array[i].equals(s)) { return i; } } return -1; } } ================================================ FILE: src/com/nmbb/oplayer/util/ConvertUtils.java ================================================ package com.nmbb.oplayer.util; import android.content.Context; /** * 数据转换类 * * @author 农民伯伯 * @see http://www.cnblogs.com/over140 * */ public final class ConvertUtils { private static final float UNIT = 1000.0F; /** * 毫秒转秒 * * @param time 毫秒 * @return */ public static float ms2s(long time) { return time / UNIT; } /** * 微秒转秒 * * @param time 微秒 * @return */ public static float us2s(long time) { return time / UNIT / UNIT; } /** * 纳秒转秒 * * @param time 纳秒 * @return */ public static float ns2s(long time) { return time / UNIT / UNIT / UNIT; } /** * 转换字符串为boolean * * @param str * @return */ public static boolean toBoolean(String str) { return toBoolean(str, false); } /** * 转换字符串为boolean * * @param str * @param def * @return */ public static boolean toBoolean(String str, boolean def) { if (StringUtils.isEmpty(str)) return def; if ("false".equalsIgnoreCase(str) || "0".equals(str)) return false; else if ("true".equalsIgnoreCase(str) || "1".equals(str)) return true; else return def; } /** * 转换字符串为float * * @param str * @return */ public static float toFloat(String str) { return toFloat(str, 0F); } /** * 转换字符串为float * * @param str * @param def * @return */ public static float toFloat(String str, float def) { if (StringUtils.isEmpty(str)) return def; try { return Float.parseFloat(str); } catch (NumberFormatException e) { return def; } } /** * 转换字符串为long * * @param str * @return */ public static long toLong(String str) { return toLong(str, 0L); } /** * 转换字符串为long * * @param str * @param def * @return */ public static long toLong(String str, long def) { if (StringUtils.isEmpty(str)) return def; try { return Long.parseLong(str); } catch (NumberFormatException e) { return def; } } /** * 转换字符串为short * * @param str * @return */ public static short toShort(String str) { return toShort(str, (short) 0); } /** * 转换字符串为short * * @param str * @param def * @return */ public static short toShort(String str, short def) { if (StringUtils.isEmpty(str)) return def; try { return Short.parseShort(str); } catch (NumberFormatException e) { return def; } } /** * 转换字符串为int * * @param str * @return */ public static int toInt(String str) { return toInt(str, 0); } /** * 转换字符串为int * * @param str * @param def * @return */ public static int toInt(String str, int def) { if (StringUtils.isEmpty(str)) return def; try { return Integer.parseInt(str); } catch (NumberFormatException e) { return def; } } public static String toString(Object o) { return toString(o, ""); } public static String toString(Object o, String def) { if (o == null) return def; return o.toString(); } public static int dipToPX(final Context ctx, int dip) { float scale = ctx.getResources().getDisplayMetrics().density; return (int) (dip / 1.5D * scale + 0.5D); } } ================================================ FILE: src/com/nmbb/oplayer/util/DeviceUtils.java ================================================ package com.nmbb.oplayer.util; import java.io.BufferedReader; import java.io.File; import java.io.FileReader; import java.io.IOException; import java.util.List; import android.app.Activity; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.ResolveInfo; import android.content.res.Configuration; import android.os.Build; import android.os.Environment; import android.os.StatFs; import android.util.DisplayMetrics; import android.view.Display; import android.view.View; import android.view.WindowManager; import android.view.inputmethod.InputMethodManager; import com.nmbb.oplayer.exception.Logger; /** * 系统版本信息类 * * @author tangjun * */ public class DeviceUtils { /** >=2.2 */ public static boolean hasFroyo() { return Build.VERSION.SDK_INT >= Build.VERSION_CODES.FROYO; } /** >=2.3 */ public static boolean hasGingerbread() { return Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD; } /** >=3.0 LEVEL:11 */ public static boolean hasHoneycomb() { return Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB; } /** >=3.1 */ public static boolean hasHoneycombMR1() { return Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR1; } /** >=4.0 14 */ public static boolean hasICS() { return Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH; } public static int getSDKVersionInt() { return Build.VERSION.SDK_INT; } @SuppressWarnings("deprecation") public static String getSDKVersion() { return Build.VERSION.SDK; } /** * 判断是否是平板电脑 * * @param context * @return */ public static boolean isTablet(Context context) { return (context.getResources().getConfiguration().screenLayout & Configuration.SCREENLAYOUT_SIZE_MASK) >= Configuration.SCREENLAYOUT_SIZE_LARGE; } public static boolean isHoneycombTablet(Context context) { return hasHoneycomb() && isTablet(context); } /** * 获得设备型号 * * @return */ public static String getDeviceModel() { return StringUtils.trim(Build.MODEL); } /** 检测是否魅族手机 */ public static boolean isMeizu() { return getDeviceModel().toLowerCase().indexOf("meizu") != -1; } /** 检测是否HTC手机 */ public static boolean isHTC() { return getDeviceModel().toLowerCase().indexOf("htc") != -1; } public static boolean isXiaomi() { return getDeviceModel().toLowerCase().indexOf("xiaomi") != -1; } /** * 获得设备制造商 * * @return */ public static String getManufacturer() { return StringUtils.trim(Build.MANUFACTURER); } @SuppressWarnings("deprecation") public static int getScreenHeight(Context context) { Display display = ((WindowManager) context .getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay(); return display.getHeight(); } /** 获取屏幕宽度 */ @SuppressWarnings("deprecation") public static int getScreenWidth(Context context) { Display display = ((WindowManager) context .getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay(); return display.getWidth(); } /** * 获得设备屏幕密度 */ public static float getScreenDensity(Context context) { DisplayMetrics metrics = context.getApplicationContext().getResources() .getDisplayMetrics(); return metrics.density; } public static int[] getScreenSize(int w, int h, Context context) { int phoneW = getScreenWidth(context); int phoneH = getScreenHeight(context); if (w * phoneH > phoneW * h) { phoneH = phoneW * h / w; } else if (w * phoneH < phoneW * h) { phoneW = phoneH * w / h; } return new int[] { phoneW, phoneH }; } public static int[] getScreenSize(int w, int h, int phoneW, int phoneH) { if (w * phoneH > phoneW * h) { phoneH = phoneW * h / w; } else if (w * phoneH < phoneW * h) { phoneW = phoneH * w / h; } return new int[] { phoneW, phoneH }; } /** 设置屏幕亮度 */ public static void setBrightness(final Activity context, float f) { WindowManager.LayoutParams lp = context.getWindow().getAttributes(); lp.screenBrightness = f; if (lp.screenBrightness > 1.0f) lp.screenBrightness = 1.0f; else if (lp.screenBrightness < 0.01f) lp.screenBrightness = 0.01f; context.getWindow().setAttributes(lp); } // private static final long NO_STORAGE_ERROR = -1L; private static final long CANNOT_STAT_ERROR = -2L; /** 检测磁盘状态 */ // public static int getStorageStatus(boolean mayHaveSd) { // long remaining = mayHaveSd ? getAvailableStorage() : NO_STORAGE_ERROR; // if (remaining == NO_STORAGE_ERROR) { // return CommonStatus.STORAGE_STATUS_NONE; // } // return remaining < CommonConstants.LOW_STORAGE_THRESHOLD ? // CommonStatus.STORAGE_STATUS_LOW : CommonStatus.STORAGE_STATUS_OK; // } public static long getAvailableStorage() { try { String storageDirectory = Environment.getExternalStorageDirectory() .toString(); StatFs stat = new StatFs(storageDirectory); return (long) stat.getAvailableBlocks() * (long) stat.getBlockSize(); } catch (RuntimeException ex) { // if we can't stat the filesystem then we don't know how many // free bytes exist. It might be zero but just leave it // blank since we really don't know. return CANNOT_STAT_ERROR; } } /** 隐藏软键盘 */ public static void hideSoftInput(Context ctx, View v) { InputMethodManager imm = (InputMethodManager) ctx .getSystemService(Context.INPUT_METHOD_SERVICE); // 这个方法可以实现输入法在窗口上切换显示,如果输入法在窗口上已经显示,则隐藏,如果隐藏,则显示输入法到窗口上 imm.hideSoftInputFromWindow(v.getApplicationWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS); } /** 显示软键盘 */ public static void showSoftInput(Context ctx) { InputMethodManager imm = (InputMethodManager) ctx .getSystemService(Context.INPUT_METHOD_SERVICE); imm.toggleSoftInput(0, InputMethodManager.SHOW_FORCED);// (v, // InputMethodManager.SHOW_FORCED); } /** * 软键盘是否已经打开 * * @return */ protected boolean isHardKeyboardOpen(Context ctx) { return ctx.getResources().getConfiguration().hardKeyboardHidden == Configuration.HARDKEYBOARDHIDDEN_NO; } public static String getCpuInfo() { String cpuInfo = ""; try { if (new File("/proc/cpuinfo").exists()) { FileReader fr = new FileReader("/proc/cpuinfo"); BufferedReader localBufferedReader = new BufferedReader(fr, 8192); cpuInfo = localBufferedReader.readLine(); localBufferedReader.close(); if (cpuInfo != null) { cpuInfo = cpuInfo.split(":")[1].trim().split(" ")[0]; } } } catch (IOException e) { } catch (Exception e) { } return cpuInfo; } public static void startApkActivity(final Context ctx, String packageName) { PackageManager pm = ctx.getPackageManager(); PackageInfo pi; try { pi = pm.getPackageInfo(packageName, 0); Intent intent = new Intent(Intent.ACTION_MAIN, null); intent.addCategory(Intent.CATEGORY_LAUNCHER); intent.setPackage(pi.packageName); List apps = pm.queryIntentActivities(intent, 0); ResolveInfo ri = apps.iterator().next(); if (ri != null) { String className = ri.activityInfo.name; intent.setComponent(new ComponentName(packageName, className)); ctx.startActivity(intent); } } catch (NameNotFoundException e) { Logger.e(e); } } } ================================================ FILE: src/com/nmbb/oplayer/util/FileUtils.java ================================================ package com.nmbb.oplayer.util; import java.io.File; import java.io.IOException; import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import android.os.Environment; import android.os.StatFs; import android.util.Log; public class FileUtils { // http://www.fileinfo.com/filetypes/video , "dat" , "bin" , "rms" public static final String[] VIDEO_EXTENSIONS = { "264", "3g2", "3gp", "3gp2", "3gpp", "3gpp2", "3mm", "3p2", "60d", "aep", "ajp", "amv", "amx", "arf", "asf", "asx", "avb", "avd", "avi", "avs", "avs", "axm", "bdm", "bdmv", "bik", "bix", "bmk", "box", "bs4", "bsf", "byu", "camre", "clpi", "cpi", "cvc", "d2v", "d3v", "dav", "dce", "dck", "ddat", "dif", "dir", "divx", "dlx", "dmb", "dmsm", "dmss", "dnc", "dpg", "dream", "dsy", "dv", "dv-avi", "dv4", "dvdmedia", "dvr-ms", "dvx", "dxr", "dzm", "dzp", "dzt", "evo", "eye", "f4p", "f4v", "fbr", "fbr", "fbz", "fcp", "flc", "flh", "fli", "flv", "flx", "gl", "grasp", "gts", "gvi", "gvp", "hdmov", "hkm", "ifo", "imovi", "imovi", "iva", "ivf", "ivr", "ivs", "izz", "izzy", "jts", "lsf", "lsx", "m15", "m1pg", "m1v", "m21", "m21", "m2a", "m2p", "m2t", "m2ts", "m2v", "m4e", "m4u", "m4v", "m75", "meta", "mgv", "mj2", "mjp", "mjpg", "mkv", "mmv", "mnv", "mod", "modd", "moff", "moi", "moov", "mov", "movie", "mp21", "mp21", "mp2v", "mp4", "mp4v", "mpe", "mpeg", "mpeg4", "mpf", "mpg", "mpg2", "mpgin", "mpl", "mpls", "mpv", "mpv2", "mqv", "msdvd", "msh", "mswmm", "mts", "mtv", "mvb", "mvc", "mvd", "mve", "mvp", "mxf", "mys", "ncor", "nsv", "nvc", "ogm", "ogv", "ogx", "osp", "par", "pds", "pgi", "piv", "playlist", "pmf", "prel", "pro", "prproj", "psh", "pva", "pvr", "pxv", "qt", "qtch", "qtl", "qtm", "qtz", "rcproject", "rdb", "rec", "rm", "rmd", "rmp", "rmvb", "roq", "rp", "rts", "rts", "rum", "rv", "sbk", "sbt", "scm", "scm", "scn", "sec", "seq", "sfvidcap", "smil", "smk", "sml", "smv", "spl", "ssm", "str", "stx", "svi", "swf", "swi", "swt", "tda3mt", "tivo", "tix", "tod", "tp", "tp0", "tpd", "tpr", "trp", "ts", "tvs", "vc1", "vcr", "vcv", "vdo", "vdr", "veg", "vem", "vf", "vfw", "vfz", "vgz", "vid", "viewlet", "viv", "vivo", "vlab", "vob", "vp3", "vp6", "vp7", "vpj", "vro", "vsp", "w32", "wcp", "webm", "wm", "wmd", "wmmp", "wmv", "wmx", "wp3", "wpl", "wtv", "wvx", "xfl", "xvid", "yuv", "zm1", "zm2", "zm3", "zmv" }; // http://www.fileinfo.com/filetypes/audio , "spx" , "mid" , "sf" public static final String[] AUDIO_EXTENSIONS = { "4mp", "669", "6cm", "8cm", "8med", "8svx", "a2m", "aa", "aa3", "aac", "aax", "abc", "abm", "ac3", "acd", "acd-bak", "acd-zip", "acm", "act", "adg", "afc", "agm", "ahx", "aif", "aifc", "aiff", "ais", "akp", "al", "alaw", "all", "amf", "amr", "ams", "ams", "aob", "ape", "apf", "apl", "ase", "at3", "atrac", "au", "aud", "aup", "avr", "awb", "band", "bap", "bdd", "box", "bun", "bwf", "c01", "caf", "cda", "cdda", "cdr", "cel", "cfa", "cidb", "cmf", "copy", "cpr", "cpt", "csh", "cwp", "d00", "d01", "dcf", "dcm", "dct", "ddt", "dewf", "df2", "dfc", "dig", "dig", "dls", "dm", "dmf", "dmsa", "dmse", "drg", "dsf", "dsm", "dsp", "dss", "dtm", "dts", "dtshd", "dvf", "dwd", "ear", "efa", "efe", "efk", "efq", "efs", "efv", "emd", "emp", "emx", "esps", "f2r", "f32", "f3r", "f4a", "f64", "far", "fff", "flac", "flp", "fls", "frg", "fsm", "fzb", "fzf", "fzv", "g721", "g723", "g726", "gig", "gp5", "gpk", "gsm", "gsm", "h0", "hdp", "hma", "hsb", "ics", "iff", "imf", "imp", "ins", "ins", "it", "iti", "its", "jam", "k25", "k26", "kar", "kin", "kit", "kmp", "koz", "koz", "kpl", "krz", "ksc", "ksf", "kt2", "kt3", "ktp", "l", "la", "lqt", "lso", "lvp", "lwv", "m1a", "m3u", "m4a", "m4b", "m4p", "m4r", "ma1", "mdl", "med", "mgv", "midi", "miniusf", "mka", "mlp", "mmf", "mmm", "mmp", "mo3", "mod", "mp1", "mp2", "mp3", "mpa", "mpc", "mpga", "mpu", "mp_", "mscx", "mscz", "msv", "mt2", "mt9", "mte", "mti", "mtm", "mtp", "mts", "mus", "mws", "mxl", "mzp", "nap", "nki", "nra", "nrt", "nsa", "nsf", "nst", "ntn", "nvf", "nwc", "odm", "oga", "ogg", "okt", "oma", "omf", "omg", "omx", "ots", "ove", "ovw", "pac", "pat", "pbf", "pca", "pcast", "pcg", "pcm", "peak", "phy", "pk", "pla", "pls", "pna", "ppc", "ppcx", "prg", "prg", "psf", "psm", "ptf", "ptm", "pts", "pvc", "qcp", "r", "r1m", "ra", "ram", "raw", "rax", "rbs", "rcy", "rex", "rfl", "rmf", "rmi", "rmj", "rmm", "rmx", "rng", "rns", "rol", "rsn", "rso", "rti", "rtm", "rts", "rvx", "rx2", "s3i", "s3m", "s3z", "saf", "sam", "sb", "sbg", "sbi", "sbk", "sc2", "sd", "sd", "sd2", "sd2f", "sdat", "sdii", "sds", "sdt", "sdx", "seg", "seq", "ses", "sf2", "sfk", "sfl", "shn", "sib", "sid", "sid", "smf", "smp", "snd", "snd", "snd", "sng", "sng", "sou", "sppack", "sprg", "sseq", "sseq", "ssnd", "stm", "stx", "sty", "svx", "sw", "swa", "syh", "syw", "syx", "td0", "tfmx", "thx", "toc", "tsp", "txw", "u", "ub", "ulaw", "ult", "ulw", "uni", "usf", "usflib", "uw", "uwf", "vag", "val", "vc3", "vmd", "vmf", "vmf", "voc", "voi", "vox", "vpm", "vqf", "vrf", "vyf", "w01", "wav", "wav", "wave", "wax", "wfb", "wfd", "wfp", "wma", "wow", "wpk", "wproj", "wrk", "wus", "wut", "wv", "wvc", "wve", "wwu", "xa", "xa", "xfs", "xi", "xm", "xmf", "xmi", "xmz", "xp", "xrns", "xsb", "xspf", "xt", "xwb", "ym", "zvd", "zvr" }; private static final HashSet mHashVideo; private static final HashSet mHashAudio; private static final double KB = 1024.0; private static final double MB = KB * KB; private static final double GB = KB * KB * KB; static { mHashVideo = new HashSet(Arrays.asList(VIDEO_EXTENSIONS)); mHashAudio = new HashSet(Arrays.asList(AUDIO_EXTENSIONS)); } /** 是否是音频或者视频 */ public static boolean isVideoOrAudio(File f) { final String ext = getFileExtension(f); return mHashVideo.contains(ext) || mHashAudio.contains(ext); } public static boolean isVideoOrAudio(String f) { final String ext = getUrlExtension(f); return mHashVideo.contains(ext) || mHashAudio.contains(ext); } public static boolean isVideo(File f) { final String ext = getFileExtension(f); return mHashVideo.contains(ext); } /** 获取文件后缀 */ public static String getFileExtension(File f) { if (f != null) { String filename = f.getName(); int i = filename.lastIndexOf('.'); if (i > 0 && i < filename.length() - 1) { return filename.substring(i + 1).toLowerCase(); } } return null; } public static String getUrlFileName(String url) { int slashIndex = url.lastIndexOf('/'); int dotIndex = url.lastIndexOf('.'); String filenameWithoutExtension; if (dotIndex == -1) { filenameWithoutExtension = url.substring(slashIndex + 1); } else { filenameWithoutExtension = url.substring(slashIndex + 1, dotIndex); } return filenameWithoutExtension; } public static String getUrlExtension(String url) { if (!StringUtils.isEmpty(url)) { int i = url.lastIndexOf('.'); if (i > 0 && i < url.length() - 1) { return url.substring(i + 1).toLowerCase(); } } return ""; } public static String getFileNameNoEx(String filename) { if ((filename != null) && (filename.length() > 0)) { int dot = filename.lastIndexOf('.'); if ((dot > -1) && (dot < (filename.length()))) { return filename.substring(0, dot); } } return filename; } public static String showFileSize(long size) { String fileSize; if (size < KB) fileSize = size + "B"; else if (size < MB) fileSize = String.format("%.1f", size / KB) + "KB"; else if (size < GB) fileSize = String.format("%.1f", size / MB) + "MB"; else fileSize = String.format("%.1f", size / GB) + "GB"; return fileSize; } /** 显示SD卡剩余空间 */ public static String showFileAvailable() { String result = ""; if (Environment.MEDIA_MOUNTED.equals(Environment .getExternalStorageState())) { StatFs sf = new StatFs(Environment.getExternalStorageDirectory() .getPath()); long blockSize = sf.getBlockSize(); long blockCount = sf.getBlockCount(); long availCount = sf.getAvailableBlocks(); return showFileSize(availCount * blockSize) + " / " + showFileSize(blockSize * blockCount); } return result; } /** 如果不存在就创建 */ public static boolean createIfNoExists(String path) { File file = new File(path); boolean mk = false; if (!file.exists()) { mk = file.mkdirs(); } return mk; } private static HashMap mMimeType = new HashMap(); static { mMimeType.put("M1V", "video/mpeg"); mMimeType.put("MP2", "video/mpeg"); mMimeType.put("MPE", "video/mpeg"); mMimeType.put("MPG", "video/mpeg"); mMimeType.put("MPEG", "video/mpeg"); mMimeType.put("MP4", "video/mp4"); mMimeType.put("M4V", "video/mp4"); mMimeType.put("3GP", "video/3gpp"); mMimeType.put("3GPP", "video/3gpp"); mMimeType.put("3G2", "video/3gpp2"); mMimeType.put("3GPP2", "video/3gpp2"); mMimeType.put("MKV", "video/x-matroska"); mMimeType.put("WEBM", "video/x-matroska"); mMimeType.put("MTS", "video/mp2ts"); mMimeType.put("TS", "video/mp2ts"); mMimeType.put("TP", "video/mp2ts"); mMimeType.put("WMV", "video/x-ms-wmv"); mMimeType.put("ASF", "video/x-ms-asf"); mMimeType.put("ASX", "video/x-ms-asf"); mMimeType.put("FLV", "video/x-flv"); mMimeType.put("MOV", "video/quicktime"); mMimeType.put("QT", "video/quicktime"); mMimeType.put("RM", "video/x-pn-realvideo"); mMimeType.put("RMVB", "video/x-pn-realvideo"); mMimeType.put("VOB", "video/dvd"); mMimeType.put("DAT", "video/dvd"); mMimeType.put("AVI", "video/x-divx"); mMimeType.put("OGV", "video/ogg"); mMimeType.put("OGG", "video/ogg"); mMimeType.put("VIV", "video/vnd.vivo"); mMimeType.put("VIVO", "video/vnd.vivo"); mMimeType.put("WTV", "video/wtv"); mMimeType.put("AVS", "video/avs-video"); mMimeType.put("SWF", "video/x-shockwave-flash"); mMimeType.put("YUV", "video/x-raw-yuv"); } /** 获取MIME */ public static String getMimeType(String path) { int lastDot = path.lastIndexOf("."); if (lastDot < 0) return null; return mMimeType.get(path.substring(lastDot + 1).toUpperCase()); } /** 多个SD卡时 取外置SD卡 */ public static String getExternalStorageDirectory() { // 参考文章 // http://blog.csdn.net/bbmiku/article/details/7937745 Map map = System.getenv(); String[] values = new String[map.values().size()]; map.values().toArray(values); String path = values[values.length - 1]; Log.e("nmbb", "FileUtils.getExternalStorageDirectory : " + path); if (path.startsWith("/mnt/") && !Environment.getExternalStorageDirectory().getAbsolutePath() .equals(path)) return path; else return null; } public static String getCanonical(File f) { if (f == null) return null; try { return f.getCanonicalPath(); } catch (IOException e) { return f.getAbsolutePath(); } } public static boolean sdAvailable() { return Environment.MEDIA_MOUNTED_READ_ONLY.equals(Environment .getExternalStorageState()) || Environment.MEDIA_MOUNTED.equals(Environment .getExternalStorageState()); } } ================================================ FILE: src/com/nmbb/oplayer/util/FractionalTouchDelegate.java ================================================ /* * Copyright (C) 2012 YIXIA.COM * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.nmbb.oplayer.util; import android.graphics.Rect; import android.graphics.RectF; import android.view.MotionEvent; import android.view.TouchDelegate; import android.view.View; /** * {@link TouchDelegate} that gates {@link MotionEvent} instances by comparing * then against fractional dimensions of the source view. *

* This is particularly useful when you want to define a rectangle in terms of * the source dimensions, but when those dimensions might change due to pending * or future layout passes. *

* One example is catching touches that occur in the top-right quadrant of * {@code sourceParent}, and relaying them to {@code targetChild}. This could be * done with: * FractionalTouchDelegate.setupDelegate(sourceParent, targetChild, new RectF(0.5f, 0f, 1f, 0.5f)); * */ public class FractionalTouchDelegate extends TouchDelegate { private View mSource; private View mTarget; private RectF mSourceFraction; private Rect mScrap = new Rect(); /** Cached full dimensions of {@link #mSource}. */ private Rect mSourceFull = new Rect(); /** Cached projection of {@link #mSourceFraction} onto {@link #mSource}. */ private Rect mSourcePartial = new Rect(); private boolean mDelegateTargeted; public FractionalTouchDelegate(View source, View target, RectF sourceFraction) { super(new Rect(0, 0, 0, 0), target); mSource = source; mTarget = target; mSourceFraction = sourceFraction; } /** * Helper to create and setup a {@link FractionalTouchDelegate} between the * given {@link View}. * * @param source Larger source {@link View}, usually a parent, that will be * assigned {@link View#setTouchDelegate(TouchDelegate)}. * @param target Smaller target {@link View} which will receive * {@link MotionEvent} that land in requested fractional area. * @param sourceFraction Fractional area projected onto source {@link View} * which determines when {@link MotionEvent} will be passed to * target {@link View}. */ public static void setupDelegate(View source, View target, RectF sourceFraction) { source.setTouchDelegate(new FractionalTouchDelegate(source, target, sourceFraction)); } /** * Consider updating {@link #mSourcePartial} when {@link #mSource} * dimensions have changed. */ private void updateSourcePartial() { mSource.getHitRect(mScrap); if (!mScrap.equals(mSourceFull)) { // Copy over and calculate fractional rectangle mSourceFull.set(mScrap); final int width = mSourceFull.width(); final int height = mSourceFull.height(); mSourcePartial.left = (int) (mSourceFraction.left * width); mSourcePartial.top = (int) (mSourceFraction.top * height); mSourcePartial.right = (int) (mSourceFraction.right * width); mSourcePartial.bottom = (int) (mSourceFraction.bottom * height); } } @Override public boolean onTouchEvent(MotionEvent event) { updateSourcePartial(); // The logic below is mostly copied from the parent class, since we // can't update private mBounds variable. // http://android.git.kernel.org/?p=platform/frameworks/base.git;a=blob; // f=core/java/android/view/TouchDelegate.java;hb=eclair#l98 final Rect sourcePartial = mSourcePartial; final View target = mTarget; int x = (int)event.getX(); int y = (int)event.getY(); boolean sendToDelegate = false; boolean hit = true; boolean handled = false; switch (event.getAction()) { case MotionEvent.ACTION_DOWN: if (sourcePartial.contains(x, y)) { mDelegateTargeted = true; sendToDelegate = true; } break; case MotionEvent.ACTION_UP: case MotionEvent.ACTION_MOVE: sendToDelegate = mDelegateTargeted; if (sendToDelegate) { if (!sourcePartial.contains(x, y)) { hit = false; } } break; case MotionEvent.ACTION_CANCEL: sendToDelegate = mDelegateTargeted; mDelegateTargeted = false; break; } if (sendToDelegate) { if (hit) { event.setLocation(target.getWidth() / 2, target.getHeight() / 2); } else { event.setLocation(-1, -1); } handled = target.dispatchTouchEvent(event); } return handled; } } ================================================ FILE: src/com/nmbb/oplayer/util/ImageUtils.java ================================================ package com.nmbb.oplayer.util; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import android.annotation.TargetApi; import android.content.Context; import android.graphics.Bitmap; import android.graphics.Bitmap.Config; import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.graphics.Matrix; import android.graphics.Paint; import android.graphics.PixelFormat; import android.graphics.PorterDuff.Mode; import android.graphics.PorterDuffXfermode; import android.graphics.Rect; import android.graphics.RectF; import android.graphics.drawable.Drawable; import android.net.Uri; import android.os.Build; import com.nmbb.oplayer.exception.Logger; public class ImageUtils { // http://zhuixinjian.javaeye.com/blog/743672 // 图片圆角 // 图片叠加 // 图片缩放 // 图片旋转 @TargetApi(Build.VERSION_CODES.HONEYCOMB_MR1) public static int getBitmapSize(Bitmap bitmap) { if (DeviceUtils.hasHoneycombMR1()) { return bitmap.getByteCount(); } // Pre HC-MR1 return bitmap.getRowBytes() * bitmap.getHeight(); } /** 旋转图片 */ public static Bitmap rotate(Bitmap b, int degrees) { if (degrees != 0 && b != null) { Matrix m = new Matrix(); m.setRotate(degrees, (float) b.getWidth() / 2, (float) b.getHeight() / 2); try { Bitmap b2 = Bitmap.createBitmap(b, 0, 0, b.getWidth(), b.getHeight(), m, true); if (b != b2) { b.recycle(); b = b2; } } catch (OutOfMemoryError ex) { Logger.e(ex); } catch (Exception ex) { Logger.e(ex); } } return b; } /** * Decode and sample down a bitmap from a file to the requested width and * height. * * @param filename * The full path of the file to decode * @param reqWidth * The requested width of the resulting bitmap * @param reqHeight * The requested height of the resulting bitmap * @return A bitmap sampled down from the original with the same aspect * ratio and dimensions that are equal to or greater than the * requested width and height */ public static synchronized Bitmap decodeSampledBitmapFromFile( String filename, int reqWidth, int reqHeight) { // First decode with inJustDecodeBounds=true to check dimensions final BitmapFactory.Options options = new BitmapFactory.Options(); options.inJustDecodeBounds = true; BitmapFactory.decodeFile(filename, options); // Calculate inSampleSize options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight); // Decode bitmap with inSampleSize set options.inJustDecodeBounds = false; return BitmapFactory.decodeFile(filename, options); } /** * Calculate an inSampleSize for use in a * {@link android.graphics.BitmapFactory.Options} object when decoding * bitmaps using the decode* methods from {@link BitmapFactory}. This * implementation calculates the closest inSampleSize that will result in * the final decoded bitmap having a width and height equal to or larger * than the requested width and height. This implementation does not ensure * a power of 2 is returned for inSampleSize which can be faster when * decoding but results in a larger bitmap which isn't as useful for caching * purposes. * * @param options * An options object with out* params already populated (run * through a decode* method with inJustDecodeBounds==true * @param reqWidth * The requested width of the resulting bitmap * @param reqHeight * The requested height of the resulting bitmap * @return The value to be used for inSampleSize */ public static int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) { // Raw height and width of image final int height = options.outHeight; final int width = options.outWidth; int inSampleSize = 1; if (height > reqHeight || width > reqWidth) { if (width > height) { inSampleSize = Math.round((float) height / (float) reqHeight); } else { inSampleSize = Math.round((float) width / (float) reqWidth); } // This offers some additional logic in case the image has a strange // aspect ratio. For example, a panorama may have a much larger // width than height. In these cases the total pixels might still // end up being too large to fit comfortably in memory, so we should // be more aggressive with sample down the image (=larger // inSampleSize). final float totalPixels = width * height; // Anything more than 2x the requested pixels we'll sample down // further. final float totalReqPixelsCap = reqWidth * reqHeight * 2; while (totalPixels / (inSampleSize * inSampleSize) > totalReqPixelsCap) { inSampleSize++; } } return inSampleSize; } public static boolean saveBitmap(String path, Bitmap bitmap) { return saveBitmap(new File(path), bitmap); } /** 保存图片到文件 */ public static boolean saveBitmap(File f, Bitmap bitmap) { if (bitmap == null || bitmap.isRecycled()) return false; FileOutputStream fOut = null; try { if (f.exists()) f.createNewFile(); fOut = new FileOutputStream(f); bitmap.compress(Bitmap.CompressFormat.PNG, 100, fOut); fOut.flush(); return true; } catch (FileNotFoundException e) { Logger.e(e); } catch (IOException e) { Logger.e(e); } catch (Exception e) { Logger.e(e); } finally { if (fOut != null) { try { fOut.close(); } catch (IOException e) { Logger.e(e); } } } return false; } public static Bitmap decodeUriAsBitmap(Context ctx, Uri uri) { Bitmap bitmap = null; try { final BitmapFactory.Options options = new BitmapFactory.Options(); options.inJustDecodeBounds = true; // options.outWidth = reqWidth; // options.outHeight = reqHeight; BitmapFactory.decodeStream(ctx.getContentResolver() .openInputStream(uri), null, options); Logger.i("orgi:" + options.outWidth + "x" + options.outHeight); int be = (int) (options.outHeight / (float) 350); if (be <= 0) be = 1; options.inSampleSize = be;// calculateInSampleSize(options, // reqWidth, reqHeight); Logger.i("inSampleSize:" + options.inSampleSize); options.inJustDecodeBounds = false; bitmap = BitmapFactory.decodeStream(ctx.getContentResolver() .openInputStream(uri), null, options); } catch (FileNotFoundException e) { Logger.e(e); } catch (OutOfMemoryError e) { Logger.e(e); } return bitmap; } public static Bitmap zoomBitmap(Bitmap bitmap, int w, int h) { int width = bitmap.getWidth(); int height = bitmap.getHeight(); Matrix matrix = new Matrix(); float scaleWidht = ((float) w / width); float scaleHeight = ((float) h / height); matrix.postScale(scaleWidht, scaleHeight); Bitmap newbmp = Bitmap.createBitmap(bitmap, 0, 0, width, height, matrix, true); return newbmp; } public static Bitmap drawableToBitmap(Drawable drawable) { int width = drawable.getIntrinsicWidth(); int height = drawable.getIntrinsicHeight(); Bitmap bitmap = Bitmap.createBitmap(width, height, drawable .getOpacity() != PixelFormat.OPAQUE ? Bitmap.Config.ARGB_8888 : Bitmap.Config.RGB_565); Canvas canvas = new Canvas(bitmap); drawable.setBounds(0, 0, width, height); drawable.draw(canvas); return bitmap; } /** * 获取图片圆角 * * @param bitmap * @param roundPx * 圆角度数 * @return */ public static Bitmap getRoundedCornerBitmap(Bitmap bitmap, float roundPx) { Bitmap output = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), Config.ARGB_8888); Canvas canvas = new Canvas(output); final int color = 0xff424242; final Paint paint = new Paint(); final Rect rect = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight()); final RectF rectF = new RectF(rect); paint.setAntiAlias(true); canvas.drawARGB(0, 0, 0, 0); paint.setColor(color); canvas.drawRoundRect(rectF, roundPx, roundPx, paint); paint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN)); canvas.drawBitmap(bitmap, rect, rect, paint); return output; } /** * 转行Drawable为Bitmap对象 * * @param drawable * @return */ public static Bitmap toBitmap(Drawable drawable) { int width = drawable.getIntrinsicWidth(); int height = drawable.getIntrinsicHeight(); Bitmap bitmap = Bitmap.createBitmap(width, height, drawable .getOpacity() != PixelFormat.OPAQUE ? Bitmap.Config.ARGB_8888 : Bitmap.Config.RGB_565); Canvas canvas = new Canvas(bitmap); drawable.setBounds(0, 0, width, height); drawable.draw(canvas); return bitmap; } /** * 缩放图片 * * @param src * 缩放原图 * @param dstWidth * 缩放后宽 * @param dstHeight * 缩放后高 * @return */ public static Bitmap scaledBitmap(Bitmap src, int dstWidth, int dstHeight) { // 原图不能为空也不能已经被回收掉了 Bitmap result = null; if (src != null && !src.isRecycled()) { if (src.getWidth() == dstWidth && src.getHeight() == dstHeight) { result = src; } else { result = Bitmap.createScaledBitmap(src, dstWidth, dstHeight, true); } } // ThumbnailUtils.extractThumbnail(source, width, height) return result; } /** * 按比例缩放图片 * * @param src * @param scale * 例如2 就是二分之一 * @return */ public static Bitmap scaledBitmap(Bitmap src, int scale) { if (src == null || src.isRecycled()) { return null; } int dstWidth = src.getWidth() / scale; int dstHeight = src.getHeight() / scale; return Bitmap.createScaledBitmap(src, dstWidth, dstHeight, true); } /** * 将图片转换成字节数组 * * @param bitmap * @return */ public static byte[] toBytes(Bitmap bitmap) { ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); bitmap.compress(Bitmap.CompressFormat.PNG, 100, outputStream); return outputStream.toByteArray(); } } ================================================ FILE: src/com/nmbb/oplayer/util/IntentHelper.java ================================================ /* * Copyright (C) 2012 YIXIA.COM * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.nmbb.oplayer.util; import io.vov.vitamio.utils.Log; import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.ResolveInfo; import android.net.Uri; import android.os.Parcelable; import android.text.Html; public final class IntentHelper { public static final String MEDIA_PATTERN = "(http[s]?://)+([\\w-]+\\.)+[\\w-]+([\\w-./?%&=]*)?"; private static final Pattern mMediaPattern; static { mMediaPattern = Pattern.compile(MEDIA_PATTERN); } public static Uri getIntentUri(Intent intent) { Uri result = null; if (intent != null) { result = intent.getData(); if (result == null) { final String type = intent.getType(); String sharedUrl = intent.getStringExtra(Intent.EXTRA_TEXT); if (!StringUtils.isEmpty(sharedUrl)) { if ("text/plain".equals(type) && sharedUrl != null) { result = getTextUri(sharedUrl); } else if ("text/html".equals(type) && sharedUrl != null) { result = getTextUri(Html.fromHtml(sharedUrl).toString()); } } else { Parcelable parce = intent.getParcelableExtra(Intent.EXTRA_STREAM); if (parce != null) result = (Uri) parce; } } } return result; } private static Uri getTextUri(String sharedUrl) { Matcher matcher = mMediaPattern.matcher(sharedUrl); if (matcher.find()) { sharedUrl = matcher.group(); if (!StringUtils.isEmpty(sharedUrl)) { return Uri.parse(sharedUrl); } } return null; } public static boolean existPackage(final Context ctx, String packageName) { if (!StringUtils.isEmpty(packageName)) { for (PackageInfo p : ctx.getPackageManager().getInstalledPackages(0)) { if (packageName.equals(p.packageName)) return true; } } return false; } public static void startApkActivity(final Context ctx, String packageName) { PackageManager pm = ctx.getPackageManager(); PackageInfo pi; try { pi = pm.getPackageInfo(packageName, 0); Intent intent = new Intent(Intent.ACTION_MAIN, null); intent.setPackage(pi.packageName); List apps = pm.queryIntentActivities(intent, 0); ResolveInfo ri = apps.iterator().next(); if (ri != null) { String className = ri.activityInfo.name; intent.setComponent(new ComponentName(packageName, className)); ctx.startActivity(intent); } } catch (NameNotFoundException e) { Log.e("startActivity", e); } } } ================================================ FILE: src/com/nmbb/oplayer/util/MediaUtils.java ================================================ /* * Copyright (C) 2012 YIXIA.COM * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.nmbb.oplayer.util; import java.io.File; import java.util.regex.Pattern; import android.net.Uri; public final class MediaUtils { public static final String[] EXTENSIONS; // http://www.fileinfo.com/filetypes/video public static final String[] VIDEO_EXTENSIONS = { "\\.264", "\\.3g2", "\\.3gp", "\\.3gp2", "\\.3gpp", "\\.3gpp2", "\\.3mm", "\\.3p2", "\\.60d", "\\.aep", "\\.ajp", "\\.amv", "\\.amx", "\\.arf", "\\.asf", "\\.asx", "\\.avb", "\\.avd", "\\.avi", "\\.avs", "\\.avs", "\\.axm", "\\.bdm", "\\.bdmv", "\\.bik", "\\.bin", "\\.bix", "\\.bmk", "\\.box", "\\.bs4", "\\.bsf", "\\.byu", "\\.camre", "\\.clpi", "\\.cpi", "\\.cvc", "\\.d2v", "\\.d3v", "\\.dat", "\\.dav", "\\.dce", "\\.dck", "\\.ddat", "\\.dif", "\\.dir", "\\.divx", "\\.dlx", "\\.dmb", "\\.dmsm", "\\.dmss", "\\.dnc", "\\.dpg", "\\.dream", "\\.dsy", "\\.dv", "\\.dv-avi", "\\.dv4", "\\.dvdmedia", "\\.dvr-ms", "\\.dvx", "\\.dxr", "\\.dzm", "\\.dzp", "\\.dzt", "\\.evo", "\\.eye", "\\.f4p", "\\.f4v", "\\.fbr", "\\.fbr", "\\.fbz", "\\.fcp", "\\.flc", "\\.flh", "\\.fli", "\\.flv", "\\.flx", "\\.gl", "\\.grasp", "\\.gts", "\\.gvi", "\\.gvp", "\\.hdmov", "\\.hkm", "\\.ifo", "\\.imovi", "\\.imovi", "\\.iva", "\\.ivf", "\\.ivr", "\\.ivs", "\\.izz", "\\.izzy", "\\.jts", "\\.lsf", "\\.lsx", "\\.m15", "\\.m1pg", "\\.m1v", "\\.m21", "\\.m21", "\\.m2a", "\\.m2p", "\\.m2t", "\\.m2ts", "\\.m2v", "\\.m4e", "\\.m4u", "\\.m4v", "\\.m75", "\\.meta", "\\.mgv", "\\.mj2", "\\.mjp", "\\.mjpg", "\\.mkv", "\\.mmv", "\\.mnv", "\\.mod", "\\.modd", "\\.moff", "\\.moi", "\\.moov", "\\.mov", "\\.movie", "\\.mp21", "\\.mp21", "\\.mp2v", "\\.mp4", "\\.mp4v", "\\.mpe", "\\.mpeg", "\\.mpeg4", "\\.mpf", "\\.mpg", "\\.mpg2", "\\.mpgin", "\\.mpl", "\\.mpls", "\\.mpv", "\\.mpv2", "\\.mqv", "\\.msdvd", "\\.msh", "\\.mswmm", "\\.mts", "\\.mtv", "\\.mvb", "\\.mvc", "\\.mvd", "\\.mve", "\\.mvp", "\\.mxf", "\\.mys", "\\.ncor", "\\.nsv", "\\.nvc", "\\.ogm", "\\.ogv", "\\.ogx", "\\.osp", "\\.par", "\\.pds", "\\.pgi", "\\.piv", "\\.playlist", "\\.pmf", "\\.prel", "\\.pro", "\\.prproj", "\\.psh", "\\.pva", "\\.pvr", "\\.pxv", "\\.qt", "\\.qtch", "\\.qtl", "\\.qtm", "\\.qtz", "\\.rcproject", "\\.rdb", "\\.rec", "\\.rm", "\\.rmd", "\\.rmp", "\\.rms", "\\.rmvb", "\\.roq", "\\.rp", "\\.rts", "\\.rts", "\\.rum", "\\.rv", "\\.sbk", "\\.sbt", "\\.scm", "\\.scm", "\\.scn", "\\.sec", "\\.seq", "\\.sfvidcap", "\\.smil", "\\.smk", "\\.sml", "\\.smv", "\\.spl", "\\.ssm", "\\.str", "\\.stx", "\\.svi", "\\.swf", "\\.swi", "\\.swt", "\\.tda3mt", "\\.tivo", "\\.tix", "\\.tod", "\\.tp", "\\.tp0", "\\.tpd", "\\.tpr", "\\.trp", "\\.ts", "\\.tvs", "\\.vc1", "\\.vcr", "\\.vcv", "\\.vdo", "\\.vdr", "\\.veg", "\\.vem", "\\.vf", "\\.vfw", "\\.vfz", "\\.vgz", "\\.vid", "\\.viewlet", "\\.viv", "\\.vivo", "\\.vlab", "\\.vob", "\\.vp3", "\\.vp6", "\\.vp7", "\\.vpj", "\\.vro", "\\.vsp", "\\.w32", "\\.wcp", "\\.webm", "\\.wm", "\\.wmd", "\\.wmmp", "\\.wmv", "\\.wmx", "\\.wp3", "\\.wpl", "\\.wtv", "\\.wvx", "\\.xfl", "\\.xvid", "\\.yuv", "\\.zm1", "\\.zm2", "\\.zm3", "\\.zmv" }; // http://www.fileinfo.com/filetypes/audio public static final String[] AUDIO_EXTENSIONS = { "\\.4mp", "\\.669", "\\.6cm", "\\.8cm", "\\.8med", "\\.8svx", "\\.a2m", "\\.aa", "\\.aa3", "\\.aac", "\\.aax", "\\.abc", "\\.abm", "\\.ac3", "\\.acd", "\\.acd-bak", "\\.acd-zip", "\\.acm", "\\.act", "\\.adg", "\\.afc", "\\.agm", "\\.ahx", "\\.aif", "\\.aifc", "\\.aiff", "\\.ais", "\\.akp", "\\.al", "\\.alaw", "\\.all", "\\.amf", "\\.amr", "\\.ams", "\\.ams", "\\.aob", "\\.ape", "\\.apf", "\\.apl", "\\.ase", "\\.at3", "\\.atrac", "\\.au", "\\.aud", "\\.aup", "\\.avr", "\\.awb", "\\.band", "\\.bap", "\\.bdd", "\\.box", "\\.bun", "\\.bwf", "\\.c01", "\\.caf", "\\.cda", "\\.cdda", "\\.cdr", "\\.cel", "\\.cfa", "\\.cidb", "\\.cmf", "\\.copy", "\\.cpr", "\\.cpt", "\\.csh", "\\.cwp", "\\.d00", "\\.d01", "\\.dcf", "\\.dcm", "\\.dct", "\\.ddt", "\\.dewf", "\\.df2", "\\.dfc", "\\.dig", "\\.dig", "\\.dls", "\\.dm", "\\.dmf", "\\.dmsa", "\\.dmse", "\\.drg", "\\.dsf", "\\.dsm", "\\.dsp", "\\.dss", "\\.dtm", "\\.dts", "\\.dtshd", "\\.dvf", "\\.dwd", "\\.ear", "\\.efa", "\\.efe", "\\.efk", "\\.efq", "\\.efs", "\\.efv", "\\.emd", "\\.emp", "\\.emx", "\\.esps", "\\.f2r", "\\.f32", "\\.f3r", "\\.f4a", "\\.f64", "\\.far", "\\.fff", "\\.flac", "\\.flp", "\\.fls", "\\.frg", "\\.fsm", "\\.fzb", "\\.fzf", "\\.fzv", "\\.g721", "\\.g723", "\\.g726", "\\.gig", "\\.gp5", "\\.gpk", "\\.gsm", "\\.gsm", "\\.h0", "\\.hdp", "\\.hma", "\\.hsb", "\\.ics", "\\.iff", "\\.imf", "\\.imp", "\\.ins", "\\.ins", "\\.it", "\\.iti", "\\.its", "\\.jam", "\\.k25", "\\.k26", "\\.kar", "\\.kin", "\\.kit", "\\.kmp", "\\.koz", "\\.koz", "\\.kpl", "\\.krz", "\\.ksc", "\\.ksf", "\\.kt2", "\\.kt3", "\\.ktp", "\\.l", "\\.la", "\\.lqt", "\\.lso", "\\.lvp", "\\.lwv", "\\.m1a", "\\.m3u", "\\.m4a", "\\.m4b", "\\.m4p", "\\.m4r", "\\.ma1", "\\.mdl", "\\.med", "\\.mgv", "\\.mid", "\\.midi", "\\.miniusf", "\\.mka", "\\.mlp", "\\.mmf", "\\.mmm", "\\.mmp", "\\.mo3", "\\.mod", "\\.mp1", "\\.mp2", "\\.mp3", "\\.mpa", "\\.mpc", "\\.mpga", "\\.mpu", "\\.mp_", "\\.mscx", "\\.mscz", "\\.msv", "\\.mt2", "\\.mt9", "\\.mte", "\\.mti", "\\.mtm", "\\.mtp", "\\.mts", "\\.mus", "\\.mws", "\\.mxl", "\\.mzp", "\\.nap", "\\.nki", "\\.nra", "\\.nrt", "\\.nsa", "\\.nsf", "\\.nst", "\\.ntn", "\\.nvf", "\\.nwc", "\\.odm", "\\.oga", "\\.ogg", "\\.okt", "\\.oma", "\\.omf", "\\.omg", "\\.omx", "\\.ots", "\\.ove", "\\.ovw", "\\.pac", "\\.pat", "\\.pbf", "\\.pca", "\\.pcast", "\\.pcg", "\\.pcm", "\\.peak", "\\.phy", "\\.pk", "\\.pla", "\\.pls", "\\.pna", "\\.ppc", "\\.ppcx", "\\.prg", "\\.prg", "\\.psf", "\\.psm", "\\.ptf", "\\.ptm", "\\.pts", "\\.pvc", "\\.qcp", "\\.r", "\\.r1m", "\\.ra", "\\.ram", "\\.raw", "\\.rax", "\\.rbs", "\\.rcy", "\\.rex", "\\.rfl", "\\.rmf", "\\.rmi", "\\.rmj", "\\.rmm", "\\.rmx", "\\.rng", "\\.rns", "\\.rol", "\\.rsn", "\\.rso", "\\.rti", "\\.rtm", "\\.rts", "\\.rvx", "\\.rx2", "\\.s3i", "\\.s3m", "\\.s3z", "\\.saf", "\\.sam", "\\.sb", "\\.sbg", "\\.sbi", "\\.sbk", "\\.sc2", "\\.sd", "\\.sd", "\\.sd2", "\\.sd2f", "\\.sdat", "\\.sdii", "\\.sds", "\\.sdt", "\\.sdx", "\\.seg", "\\.seq", "\\.ses", "\\.sf", "\\.sf2", "\\.sfk", "\\.sfl", "\\.shn", "\\.sib", "\\.sid", "\\.sid", "\\.smf", "\\.smp", "\\.snd", "\\.snd", "\\.snd", "\\.sng", "\\.sng", "\\.sou", "\\.sppack", "\\.sprg", "\\.spx", "\\.sseq", "\\.sseq", "\\.ssnd", "\\.stm", "\\.stx", "\\.sty", "\\.svx", "\\.sw", "\\.swa", "\\.syh", "\\.syw", "\\.syx", "\\.td0", "\\.tfmx", "\\.thx", "\\.toc", "\\.tsp", "\\.txw", "\\.u", "\\.ub", "\\.ulaw", "\\.ult", "\\.ulw", "\\.uni", "\\.usf", "\\.usflib", "\\.uw", "\\.uwf", "\\.vag", "\\.val", "\\.vc3", "\\.vmd", "\\.vmf", "\\.vmf", "\\.voc", "\\.voi", "\\.vox", "\\.vpm", "\\.vqf", "\\.vrf", "\\.vyf", "\\.w01", "\\.wav", "\\.wav", "\\.wave", "\\.wax", "\\.wfb", "\\.wfd", "\\.wfp", "\\.wma", "\\.wow", "\\.wpk", "\\.wproj", "\\.wrk", "\\.wus", "\\.wut", "\\.wv", "\\.wvc", "\\.wve", "\\.wwu", "\\.xa", "\\.xa", "\\.xfs", "\\.xi", "\\.xm", "\\.xmf", "\\.xmi", "\\.xmz", "\\.xp", "\\.xrns", "\\.xsb", "\\.xspf", "\\.xt", "\\.xwb", "\\.ym", "\\.zvd", "\\.zvr" }; public static final String[] SUBTRACK_EXTENSIONS = { ".srt", ".ssa", ".smi", ".txt", ".sub", ".ass" }; public static final Pattern VIDEO_EXTENSIONS_PATTERN; public static final Pattern AUDIO_EXTENSIONS_PATTERN; public static final Pattern EXTENSIONS_PATTERN; public static final Pattern SUBTRACK_EXTENSIONS_PATTERN; static { EXTENSIONS = ArrayUtils.concat(VIDEO_EXTENSIONS, AUDIO_EXTENSIONS); EXTENSIONS_PATTERN = generatePattern(EXTENSIONS); VIDEO_EXTENSIONS_PATTERN = generatePattern(VIDEO_EXTENSIONS); AUDIO_EXTENSIONS_PATTERN = generatePattern(AUDIO_EXTENSIONS); SUBTRACK_EXTENSIONS_PATTERN = generatePattern(SUBTRACK_EXTENSIONS); } public static boolean isVideoOrAudio(String url) { return EXTENSIONS_PATTERN.matcher(url.trim()).find(); } public static boolean isVideoOrAudio(File file) { return EXTENSIONS_PATTERN.matcher(file.getName().trim()).find(); } public static boolean isVideo(String url) { return VIDEO_EXTENSIONS_PATTERN.matcher(url.trim()).find(); } public static boolean isVideo(File file) { return VIDEO_EXTENSIONS_PATTERN.matcher(file.getName().trim()).find(); } public static boolean isAudio(String url) { return AUDIO_EXTENSIONS_PATTERN.matcher(url.trim()).find(); } public static boolean isAudio(File file) { return AUDIO_EXTENSIONS_PATTERN.matcher(file.getName().trim()).find(); } public static boolean isSubTrack(File file) { return SUBTRACK_EXTENSIONS_PATTERN.matcher(file.getName().trim()).find(); } public static boolean isNative(String uri) { uri = Uri.decode(uri); return uri != null && (uri.startsWith("/") || uri.startsWith("content:") || uri.startsWith("file:")); } private static Pattern generatePattern(String[] args) { StringBuffer sb = new StringBuffer(); for (String ext : args) { if (sb.length() > 0) sb.append("|"); sb.append(ext); } return Pattern.compile("(" + sb.toString() + ")$", Pattern.CASE_INSENSITIVE); } } ================================================ FILE: src/com/nmbb/oplayer/util/PinyinUtils.java ================================================ package com.nmbb.oplayer.util; import net.sourceforge.pinyin4j.PinyinHelper; import net.sourceforge.pinyin4j.format.HanyuPinyinCaseType; import net.sourceforge.pinyin4j.format.HanyuPinyinOutputFormat; import net.sourceforge.pinyin4j.format.HanyuPinyinToneType; import net.sourceforge.pinyin4j.format.exception.BadHanyuPinyinOutputFormatCombination; public final class PinyinUtils { private static HanyuPinyinOutputFormat spellFormat = new HanyuPinyinOutputFormat(); static { spellFormat.setCaseType(HanyuPinyinCaseType.LOWERCASE); spellFormat.setToneType(HanyuPinyinToneType.WITHOUT_TONE); //spellFormat.setVCharType(HanyuPinyinVCharType.WITH_V); } public static String chineneToSpell(String chineseStr) throws BadHanyuPinyinOutputFormatCombination { StringBuffer result = new StringBuffer(); for (char c : chineseStr.toCharArray()) { if (c > 128) { String[] array = PinyinHelper.toHanyuPinyinStringArray(c, spellFormat); if (array != null && array.length > 0) result.append(array[0]); else result.append(" "); } else result.append(c); } return result.toString(); } } ================================================ FILE: src/com/nmbb/oplayer/util/StringUtils.java ================================================ package com.nmbb.oplayer.util; import java.io.UnsupportedEncodingException; import java.net.URLEncoder; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Calendar; import java.util.Date; import java.util.Iterator; import java.util.TimeZone; import android.text.TextPaint; import com.nmbb.oplayer.exception.Logger; /** * 字符串工具类 * * @author tangjun * */ public class StringUtils { public static final String EMPTY = ""; private static final String DEFAULT_DATE_PATTERN = "yyyy-MM-dd"; private static final String DEFAULT_DATETIME_PATTERN = "yyyy-MM-dd hh:mm:ss"; /** 用于生成文件 */ private static final String DEFAULT_FILE_PATTERN = "yyyy-MM-dd-HH-mm-ss"; private static final double KB = 1024.0; private static final double MB = 1048576.0; private static final double GB = 1073741824.0; public static final SimpleDateFormat DATE_FORMAT_PART = new SimpleDateFormat( "HH:mm"); public static String currentTimeString() { return DATE_FORMAT_PART.format(Calendar.getInstance().getTime()); } public static char chatAt(String pinyin, int index) { if (pinyin != null && pinyin.length() > 0) return pinyin.charAt(index); return ' '; } /** 获取字符串宽度 */ public static float GetTextWidth(String Sentence, float Size) { if (isEmpty(Sentence)) return 0; TextPaint FontPaint = new TextPaint(); FontPaint.setTextSize(Size); return FontPaint.measureText(Sentence.trim()) + (int) (Size * 0.1); // 留点余地 } /** * 格式化日期字符串 * * @param date * @param pattern * @return */ public static String formatDate(Date date, String pattern) { SimpleDateFormat format = new SimpleDateFormat(pattern); return format.format(date); } /** * 格式化日期字符串 * * @param date * @return 例如2011-3-24 */ public static String formatDate(Date date) { return formatDate(date, DEFAULT_DATE_PATTERN); } public static String formatDate(long date) { return formatDate(new Date(date), DEFAULT_DATE_PATTERN); } /** * 获取当前时间 格式为yyyy-MM-dd 例如2011-07-08 * * @return */ public static String getDate() { return formatDate(new Date(), DEFAULT_DATE_PATTERN); } /** 生成一个文件名,不含后缀 */ public static String createFileName() { Date date = new Date(System.currentTimeMillis()); SimpleDateFormat format = new SimpleDateFormat(DEFAULT_FILE_PATTERN); return format.format(date); } /** * 获取当前时间 * * @return */ public static String getDateTime() { return formatDate(new Date(), DEFAULT_DATETIME_PATTERN); } /** * 格式化日期时间字符串 * * @param date * @return 例如2011-11-30 16:06:54 */ public static String formatDateTime(Date date) { return formatDate(date, DEFAULT_DATETIME_PATTERN); } public static String formatDateTime(long date) { return formatDate(new Date(date), DEFAULT_DATETIME_PATTERN); } /** * 格林威时间转换 * * @param gmt * @return */ public static String formatGMTDate(String gmt) { TimeZone timeZoneLondon = TimeZone.getTimeZone(gmt); return formatDate(Calendar.getInstance(timeZoneLondon) .getTimeInMillis()); } /** * 拼接数组 * * @param array * @param separator * @return */ public static String join(final ArrayList array, final String separator) { StringBuffer result = new StringBuffer(); if (array != null && array.size() > 0) { for (String str : array) { result.append(str); result.append(separator); } result.delete(result.length() - 1, result.length()); } return result.toString(); } public static String join(final Iterator iter, final String separator) { StringBuffer result = new StringBuffer(); if (iter != null) { while (iter.hasNext()) { String key = iter.next(); result.append(key); result.append(separator); } if (result.length() > 0) result.delete(result.length() - 1, result.length()); } return result.toString(); } /** * 判断字符串是否为空 * * @param str * @return */ public static boolean isEmpty(String str) { return str == null || str.length() == 0; } /** * * @param str * @return */ public static String trim(String str) { return str == null ? EMPTY : str.trim(); } /** * 转换时间显示 * * @param time * 毫秒 * @return */ public static String generateTime(long time) { int totalSeconds = (int) (time / 1000); int seconds = totalSeconds % 60; int minutes = (totalSeconds / 60) % 60; int hours = totalSeconds / 3600; return hours > 0 ? String.format("%02d:%02d:%02d", hours, minutes, seconds) : String.format("%02d:%02d", minutes, seconds); } /** 根据秒速获取时间格式 */ public static String gennerTime(int totalSeconds) { int seconds = totalSeconds % 60; int minutes = (totalSeconds / 60) % 60; return String.format("%02d:%02d", minutes, seconds); } /** * 转换文件大小 * * @param size * @return */ public static String generateFileSize(long size) { String fileSize; if (size < KB) fileSize = size + "B"; else if (size < MB) fileSize = String.format("%.1f", size / KB) + "KB"; else if (size < GB) fileSize = String.format("%.1f", size / MB) + "MB"; else fileSize = String.format("%.1f", size / GB) + "GB"; return fileSize; } public static String getTimeDiff(long time) { // Calendar cal = Calendar.getInstance(); long diff = 0; // Date dnow = cal.getTime(); String str = ""; diff = System.currentTimeMillis() - time; if (diff > 2592000000L) {// 30 * 24 * 60 * 60 * 1000=2592000000 毫秒 str = "1个月前"; } else if (diff > 1814400000) {// 21 * 24 * 60 * 60 * 1000=1814400000 毫秒 str = "3周前"; } else if (diff > 1209600000) {// 14 * 24 * 60 * 60 * 1000=1209600000 毫秒 str = "2周前"; } else if (diff > 604800000) {// 7 * 24 * 60 * 60 * 1000=604800000 毫秒 str = "1周前"; } else if (diff > 86400000) { // 24 * 60 * 60 * 1000=86400000 毫秒 // System.out.println("X天前"); str = (int) Math.floor(diff / 86400000f) + "天前"; } else if (diff > 18000000) {// 5 * 60 * 60 * 1000=18000000 毫秒 // System.out.println("X小时前"); str = (int) Math.floor(diff / 18000000f) + "小时前"; } else if (diff > 60000) {// 1 * 60 * 1000=60000 毫秒 // System.out.println("X分钟前"); str = (int) Math.floor(diff / 60000) + "分钟前"; } else { str = (int) Math.floor(diff / 1000) + "秒前"; } return str; } /** * 截取字符串 * * @param search * 待搜索的字符串 * @param start * 起始字符串 例如: * @param end * 结束字符串 例如: * @param defaultValue * @return */ public static String substring(String search, String start, String end, String defaultValue) { int start_len = start.length(); int start_pos = StringUtils.isEmpty(start) ? 0 : search.indexOf(start); if (start_pos > -1) { int end_pos = StringUtils.isEmpty(end) ? -1 : search.indexOf(end, start_pos + start_len); if (end_pos > -1) return search.substring(start_pos + start.length(), end_pos); else return search.substring(start_pos + start.length()); } return defaultValue; } /** * 截取字符串 * * @param search * 待搜索的字符串 * @param start * 起始字符串 例如: * @param end * 结束字符串 例如: * @return */ public static String substring(String search, String start, String end) { return substring(search, start, end, ""); } /** * 拼接字符串 * * @param strs * @return */ public static String concat(String... strs) { StringBuffer result = new StringBuffer(); if (strs != null) { for (String str : strs) { if (str != null) result.append(str); } } return result.toString(); } /** 获取中文字符个数 */ public static int getChineseCharCount(String str) { String tempStr; int count = 0; for (int i = 0; i < str.length(); i++) { tempStr = String.valueOf(str.charAt(i)); if (tempStr.getBytes().length == 3) { count++; } } return count; } /** 获取英文字符个数 */ public static int getEnglishCount(String str) { String tempStr; int count = 0; for (int i = 0; i < str.length(); i++) { tempStr = String.valueOf(str.charAt(i)); if (!(tempStr.getBytes().length == 3)) { count++; } } return count; } public static String encode(String url) { try { return URLEncoder.encode(url, "UTF-8"); } catch (UnsupportedEncodingException e) { Logger.e(e); } return url; } } ================================================ FILE: src/com/nmbb/oplayer/util/ToastUtils.java ================================================ package com.nmbb.oplayer.util; import android.app.Activity; import android.content.Context; import android.view.View; import android.widget.Toast; import com.nmbb.oplayer.OPlayerApplication; import com.nmbb.oplayer.R; public class ToastUtils { public static void showToast(int resID) { showToast(OPlayerApplication.getContext(), Toast.LENGTH_SHORT, resID); } public static void showToast(String text) { showToast(OPlayerApplication.getContext(), Toast.LENGTH_SHORT, text); } public static void showToast(Context ctx, int resID) { showToast(ctx, Toast.LENGTH_SHORT, resID); } public static void showToast(Context ctx, String text) { showToast(ctx, Toast.LENGTH_SHORT, text); } public static void showLongToast(Context ctx, int resID) { showToast(ctx, Toast.LENGTH_LONG, resID); } public static void showLongToast(int resID) { showToast(OPlayerApplication.getContext(), Toast.LENGTH_LONG, resID); } public static void showLongToast(Context ctx, String text) { showToast(ctx, Toast.LENGTH_LONG, text); } public static void showLongToast(String text) { showToast(OPlayerApplication.getContext(), Toast.LENGTH_LONG, text); } public static void showToast(Context ctx, int duration, int resID) { showToast(ctx, duration, ctx.getString(resID)); } public static void showToast(Context ctx, int duration, String text) { Toast toast = Toast.makeText(ctx, text, duration); View mNextView = toast.getView(); if (mNextView != null) mNextView.setBackgroundResource(R.drawable.toast_frame); toast.show(); // Toast.makeText(ctx, text, duration).show(); } // public static void showToastOnUiThread(final String text) { // showToastOnUiThread(FSAppliction.getCurrentActivity(), text); // } /** 在UI线程运行弹出 */ public static void showToastOnUiThread(final Activity ctx, final String text) { if (ctx != null) { ctx.runOnUiThread(new Runnable() { @Override public void run() { showToast(ctx, text); } }); } } } ================================================ FILE: src/com/nmbb/oplayer/video/VideoThumbnailUtils.java ================================================ package com.nmbb.oplayer.video; import android.graphics.Bitmap; public final class VideoThumbnailUtils { /** 获取视频的缩略图 */ public static Bitmap createVideoThumbnail() { return null; } /** 获取视频的时长 */ public int getDuration() { return 1; } /** 获取视频的高度 */ public int getVideoHeight() { return 1; } /** 获取视频的宽度 */ public int getVideoWidth() { return 1; } }