├── .gitignore ├── JeffVideoCache架构.png ├── LICENSE ├── README.md ├── README_EN.md ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── com │ │ └── jeffmony │ │ └── sample │ │ ├── JeffApplication.java │ │ ├── MainActivity.java │ │ ├── ScreenUtils.java │ │ ├── Size.java │ │ ├── VideoPlayActivity.java │ │ └── VideoStatus.java │ └── res │ ├── drawable-v24 │ └── ic_launcher_foreground.xml │ ├── drawable │ ├── ic_launcher_background.xml │ ├── pause_icon.png │ └── play_icon.png │ ├── layout │ ├── activity_main.xml │ └── activity_video_play.xml │ ├── mipmap-anydpi-v26 │ ├── ic_launcher.xml │ └── ic_launcher_round.xml │ ├── mipmap-hdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ ├── mipmap-mdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ ├── mipmap-xhdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ ├── mipmap-xxhdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ ├── mipmap-xxxhdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ ├── values │ ├── colors.xml │ └── strings.xml │ └── xml │ └── network_security_config.xml ├── build.gradle ├── downloadlib ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ └── java │ └── com │ └── coolerfall │ └── download │ ├── DownloadCallback.java │ ├── DownloadCallbackAdapter.java │ ├── DownloadDelivery.java │ ├── DownloadDispatcher.java │ ├── DownloadException.java │ ├── DownloadManager.java │ ├── DownloadRequest.java │ ├── DownloadRequestQueue.java │ ├── DownloadState.java │ ├── Downloader.java │ ├── Logger.java │ ├── OkHttpDownloader.java │ ├── Preconditions.java │ ├── Priority.java │ ├── URLDownloader.java │ └── Utils.java ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── playersdk ├── .gitignore ├── build.gradle ├── consumer-rules.pro ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ └── java │ └── com │ └── jeffmony │ └── playersdk │ ├── IPlayer.java │ ├── JeffPlayer.java │ ├── common │ ├── PlayerSettings.java │ ├── PlayerType.java │ └── SeekType.java │ ├── control │ └── LocalProxyVideoControl.java │ └── impl │ ├── BasePlayerImpl.java │ ├── ExoPlayerImpl.java │ └── IjkPlayerImpl.java ├── settings.gradle ├── video_list └── videocache ├── .gitignore ├── build.gradle ├── consumer-rules.pro ├── proguard-rules.pro └── src └── main ├── AndroidManifest.xml └── java └── com └── jeffmony └── videocache ├── StorageManager.java ├── VideoInfoParseManager.java ├── VideoLockManager.java ├── VideoProxyCacheManager.java ├── common ├── ProxyMessage.java ├── SourceCreator.java ├── VideoCacheConfig.java ├── VideoCacheException.java ├── VideoMime.java ├── VideoParams.java ├── VideoRequest.java └── VideoType.java ├── listener ├── IMp4CacheThreadListener.java ├── IVideoCacheListener.java ├── IVideoCacheTaskListener.java └── IVideoInfoParsedListener.java ├── m3u8 ├── Constants.java ├── M3U8.java ├── M3U8Seg.java └── M3U8Utils.java ├── model ├── VideoCacheInfo.java └── VideoRange.java ├── okhttp ├── CustomTrustManager.java ├── HttpPipelineListener.java ├── IFetchResponseListener.java ├── IHttpPipelineListener.java ├── NetworkConfig.java ├── OkHttpControl.java ├── OkHttpEventListener.java ├── OkHttpManager.java └── OkHttpUtils.java ├── proxy └── LocalProxyVideoServer.java ├── socket ├── SocketProcessTask.java ├── request │ ├── ChunkedOutputStream.java │ ├── ContentType.java │ ├── HttpRequest.java │ ├── IState.java │ ├── Method.java │ └── ResponseState.java └── response │ ├── BaseResponse.java │ ├── M3U8Response.java │ ├── M3U8SegResponse.java │ ├── M3U8SegResponseNew.java │ └── Mp4Response.java ├── task ├── FileDownloadManager.java ├── M3U8CacheTask.java ├── M3U8CacheTaskNew.java ├── Mp4CacheTask.java ├── Mp4VideoCacheThread.java └── VideoCacheTask.java └── utils ├── HttpUtils.java ├── LogUtils.java ├── Pinger.java ├── Preconditions.java ├── ProxyCacheUtils.java ├── StorageUtils.java ├── TimeUtils.java ├── UrlUtils.java ├── VideoParamsUtils.java ├── VideoProxyThreadUtils.java └── VideoRangeUtils.java /.gitignore: -------------------------------------------------------------------------------- 1 | # Built application files 2 | *.apk 3 | *.aar 4 | *.ap_ 5 | *.aab 6 | 7 | # Files for the ART/Dalvik VM 8 | *.dex 9 | 10 | # Java class files 11 | *.class 12 | 13 | # Generated files 14 | bin/ 15 | gen/ 16 | out/ 17 | # Uncomment the following line in case you need and you don't have the release build type files in your app 18 | # release/ 19 | 20 | # Gradle files 21 | .gradle/ 22 | build/ 23 | 24 | # Local configuration file (sdk path, etc) 25 | local.properties 26 | 27 | # Proguard folder generated by Eclipse 28 | proguard/ 29 | 30 | # Log Files 31 | *.log 32 | 33 | # Android Studio Navigation editor temp files 34 | .navigation/ 35 | 36 | # Android Studio captures folder 37 | captures/ 38 | 39 | # IntelliJ 40 | *.iml 41 | .idea/workspace.xml 42 | .idea/tasks.xml 43 | .idea/gradle.xml 44 | .idea/assetWizardSettings.xml 45 | .idea/dictionaries 46 | .idea/libraries 47 | # Android Studio 3 in .gitignore file. 48 | .idea/caches 49 | .idea/modules.xml 50 | # Comment next line if keeping position of elements in Navigation Editor is relevant for you 51 | .idea/navEditor.xml 52 | 53 | # Keystore files 54 | # Uncomment the following lines if you do not want to check your keystore files in. 55 | #*.jks 56 | #*.keystore 57 | 58 | # External native build folder generated in Android Studio 2.2 and later 59 | .externalNativeBuild 60 | .cxx/ 61 | 62 | # Google Services (e.g. APIs or Firebase) 63 | # google-services.json 64 | 65 | # Freeline 66 | freeline.py 67 | freeline/ 68 | freeline_project_description.json 69 | 70 | # fastlane 71 | fastlane/report.xml 72 | fastlane/Preview.html 73 | fastlane/screenshots 74 | fastlane/test_output 75 | fastlane/readme.md 76 | 77 | # Version control 78 | vcs.xml 79 | 80 | # lint 81 | lint/intermediates/ 82 | lint/generated/ 83 | lint/outputs/ 84 | lint/tmp/ 85 | # lint/reports/ 86 | -------------------------------------------------------------------------------- /JeffVideoCache架构.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JeffMony/JeffVideoCache/8e9d01a1012f464a1308859e7009588a7e2d130c/JeffVideoCache架构.png -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # JeffVideoCache 2 | Better than AndroidVideoCache 3 | 4 | Refer to the [English Development Document](./README_EN.md) 5 | 6 | #### 开发文档 7 | > * 1.实现脱离播放器的预加载功能 8 | > * 2.实现视频的边下边播功能 9 | > * 3.实现M3U8视频边下边播功能 10 | > * 4.实现MP4视频的边下边播功能 11 | > * 5.支持的播放器是exoplayer和ijkplayer 12 | > * 6.支持接入okhttp 13 | > * 7.支持拖动进度条之后继续缓存到本地的功能 14 | > * 8.支持LRU清理规则, 可以设置缓存的过期时间 15 | 16 | #### JeffVideoCache架构 17 | ![](./JeffVideoCache架构.png) 18 | 19 | JeffVideoCache 核心放在客户端, local server端和client做好数据同步的工作 20 | 21 | ##### 1.如何接入 22 | 23 | 在build.gradle中引入 24 | ``` 25 | allprojects { 26 | repositories { 27 | maven { url 'https://jitpack.io' } 28 | } 29 | } 30 | ``` 31 | 32 | 在demo中直接引用 33 | ``` 34 | dependencies { 35 | implementation 'com.github.JeffMony:JeffVideoCache:1.0.0' 36 | } 37 | ``` 38 | 39 | ###### 1.1 初始化 40 | 程序启动的时候设置JeffVideoCache ----> SDK初始化配置 41 | ``` 42 | File saveFile = StorageUtils.getVideoFileDir(this); 43 | if (!saveFile.exists()) { 44 | saveFile.mkdir(); 45 | } 46 | VideoProxyCacheManager.Builder builder = new VideoProxyCacheManager.Builder(). 47 | setFilePath(saveFile.getAbsolutePath()). //缓存存储位置 48 | setConnTimeOut(60 * 1000). //网络连接超时 49 | setReadTimeOut(60 * 1000). //网络读超时 50 | setExpireTime(2 * 24 * 60 * 60 * 1000). //2天的过期时间 51 | setMaxCacheSize(2 * 1024 * 1024 * 1024); //2G的存储上限 52 | VideoProxyCacheManager.getInstance().initProxyConfig(builder.build()); 53 | ``` 54 | 初始化配置: 55 | > * 1.设置缓存存储的路径 56 | > * 2.设置链接超时时间 57 | > * 3.设置网络读超时的时间 58 | > * 4.设置缓存的过期时间 59 | > * 5.设置最大缓存的限制 60 | > * 6.设置自定义的本地代理端口 61 | > * 7.设置是否使用okhttp;网络请求框架 62 | > * 8.设置网络请求是否忽略证书 63 | 64 | ###### 1.2 构建本地代理url 65 | ``` 66 | playUrl = ProxyCacheUtils.getProxyUrl(uri.toString(), null, null); 67 | 68 | public static String getProxyUrl(String videoUrl, Map headers, Map cacheParams) 69 | ``` 70 | 可以传入headers, 也可以传入其他额外参数,根据你们自己的需求来 71 | 72 | 构建的url主要是base64编码的 73 | 74 | ###### 1.3 发起请求 75 | ``` 76 | VideoProxyCacheManager.getInstance().startRequestVideoInfo(videoUrl, headers, extraParams); 77 | 78 | public void startRequestVideoInfo(String videoUrl, Map headers, Map extraParams) 79 | ``` 80 | 81 | ###### 1.4 设置缓存监听 82 | ``` 83 | VideoProxyCacheManager.getInstance().addCacheListener(videoUrl, mListener); 84 | 85 | 其中mListener如下: 86 | 87 | public interface IVideoCacheListener { 88 | 89 | void onCacheStart(VideoCacheInfo cacheInfo); 90 | 91 | void onCacheProgress(VideoCacheInfo cacheInfo); 92 | 93 | void onCacheError(VideoCacheInfo cacheInfo, int errorCode); 94 | 95 | void onCacheForbidden(VideoCacheInfo cacheInfo); 96 | 97 | void onCacheFinished(VideoCacheInfo cacheInfo); 98 | } 99 | ``` 100 | 101 | ###### 1.5 设置正在播放链接 102 | ``` 103 | VideoProxyCacheManager.getInstance().setPlayingUrlMd5(ProxyCacheUtils.computeMD5(videoUrl)); 104 | ``` 105 | 106 | ###### 1.6 暂停缓存任务 107 | ``` 108 | VideoProxyCacheManager.getInstance().pauseCacheTask(mVideoUrl); 109 | ``` 110 | 111 | ###### 1.7 恢复缓存任务 112 | ``` 113 | VideoProxyCacheManager.getInstance().resumeCacheTask(mVideoUrl); 114 | ``` 115 | 116 | ###### 1.8 拖动进度条 117 | ``` 118 | long totalDuration = mPlayer.getDuration(); 119 | if (totalDuration > 0) { 120 | float percent = position * 1.0f / totalDuration; 121 | VideoProxyCacheManager.getInstance().seekToCacheTaskFromClient(mVideoUrl, percent); 122 | } 123 | ``` 124 | 125 | ###### 1.9 释放缓存任务 126 | ``` 127 | VideoProxyCacheManager.getInstance().stopCacheTask(mVideoUrl); //停止视频缓存任务 128 | VideoProxyCacheManager.getInstance().releaseProxyReleases(mVideoUrl); 129 | ``` 130 | 131 | #### Development Document 132 | > * 1.It can play the video while caching it 133 | > * 2.It supports M3U8 , MP4 and so on 134 | -------------------------------------------------------------------------------- /README_EN.md: -------------------------------------------------------------------------------- 1 | # JeffVideoCache 2 | Better than AndroidVideoCache 3 | 4 | 参考 [中文开发文档](./README.md) 5 | 6 | #### Development Document 7 | > * 1.Realize the pre-loading function without the player 8 | > * 2.Realize the video playback function while caching 9 | > * 3.Realize the M3U8 video playback function while caching 10 | > * 4.Realize the MP4 video playback function while caching 11 | > * 5.Support the player such as exoplayer and ijkplayer 12 | > * 6.Support okhttp library 13 | > * 7.Support the function of continuing to cache to the local after dragging the progress bar 14 | > * 8.Support LRU cleanup rules, you can set the expiration time of the cache 15 | 16 | #### JeffVideoCache Architecture 17 | ![](./JeffVideoCache架构.png) 18 | 19 | The core of JeffVideoCache is placed on the client, and the local server and client do a good job of data synchronization 20 | 21 | ##### 1.How to use 22 | 23 | ###### 1.1 Initialization 24 | Set JeffVideoCache when the program starts ----> SDK initialization configuration 25 | ``` 26 | File saveFile = StorageUtils.getVideoFileDir(this); 27 | if (!saveFile.exists()) { 28 | saveFile.mkdir(); 29 | } 30 | VideoProxyCacheManager.Builder builder = new VideoProxyCacheManager.Builder(). 31 | setFilePath(saveFile.getAbsolutePath()). //File location 32 | setConnTimeOut(60 * 1000). //Connection timeout 33 | setReadTimeOut(60 * 1000). //Read timeout 34 | setExpireTime(2 * 24 * 60 * 60 * 1000). //Expire timeout 35 | setMaxCacheSize(2 * 1024 * 1024 * 1024); //Cache Size limit 36 | VideoProxyCacheManager.getInstance().initProxyConfig(builder.build()); 37 | ``` 38 | Initialization configuration: 39 | > * 1.Set Cache File location 40 | > * 2.Set the Connection timeout 41 | > * 3.Set the Read timeout 42 | > * 4.Set the cache Expire timeout 43 | > * 5.Set the cache size limit 44 | 45 | ###### 1.2 Build local proxy url 46 | ``` 47 | playUrl = ProxyCacheUtils.getProxyUrl(uri.toString(), null, null); 48 | 49 | public static String getProxyUrl(String videoUrl, Map headers, Map cacheParams) 50 | ``` 51 | You can pass in headers, or pass in other additional parameters, according to your own needs 52 | 53 | The constructed url is mainly base64 encoded 54 | 55 | ###### 1.3 Initiate a request 56 | ``` 57 | VideoProxyCacheManager.getInstance().startRequestVideoInfo(videoUrl, headers, extraParams); 58 | 59 | public void startRequestVideoInfo(String videoUrl, Map headers, Map extraParams) 60 | ``` 61 | 62 | ###### 1.4 Set up cache listener 63 | ``` 64 | VideoProxyCacheManager.getInstance().addCacheListener(videoUrl, mListener); 65 | 66 | mListener: 67 | 68 | public interface IVideoCacheListener { 69 | 70 | void onCacheStart(VideoCacheInfo cacheInfo); 71 | 72 | void onCacheProgress(VideoCacheInfo cacheInfo); 73 | 74 | void onCacheError(VideoCacheInfo cacheInfo, int errorCode); 75 | 76 | void onCacheForbidden(VideoCacheInfo cacheInfo); 77 | 78 | void onCacheFinished(VideoCacheInfo cacheInfo); 79 | } 80 | ``` 81 | 82 | ###### 1.5 Set now playing link 83 | ``` 84 | VideoProxyCacheManager.getInstance().setPlayingUrlMd5(ProxyCacheUtils.computeMD5(videoUrl)); 85 | ``` 86 | 87 | ###### 1.6 Pause cache task 88 | ``` 89 | VideoProxyCacheManager.getInstance().pauseCacheTask(mVideoUrl); 90 | ``` 91 | 92 | ###### 1.7 Resume cache task 93 | ``` 94 | VideoProxyCacheManager.getInstance().resumeCacheTask(mVideoUrl); 95 | ``` 96 | 97 | ###### 1.8 Drag the video progress bar 98 | ``` 99 | long totalDuration = mPlayer.getDuration(); 100 | if (totalDuration > 0) { 101 | float percent = position * 1.0f / totalDuration; 102 | VideoProxyCacheManager.getInstance().seekToCacheTaskFromClient(mVideoUrl, percent); 103 | } 104 | ``` 105 | 106 | ###### 1.9 stop cache task and release resources 107 | ``` 108 | VideoProxyCacheManager.getInstance().stopCacheTask(mVideoUrl); 109 | VideoProxyCacheManager.getInstance().releaseProxyReleases(mVideoUrl); 110 | ``` 111 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'com.android.application' 3 | } 4 | 5 | android { 6 | compileSdkVersion 30 7 | buildToolsVersion "29.0.3" 8 | 9 | defaultConfig { 10 | applicationId "com.jeffmony.sample" 11 | minSdkVersion 19 12 | targetSdkVersion 30 13 | versionCode 1 14 | versionName "1.0" 15 | } 16 | 17 | buildTypes { 18 | release { 19 | minifyEnabled false 20 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' 21 | } 22 | } 23 | compileOptions { 24 | sourceCompatibility JavaVersion.VERSION_1_8 25 | targetCompatibility JavaVersion.VERSION_1_8 26 | } 27 | } 28 | 29 | dependencies { 30 | implementation 'androidx.appcompat:appcompat:1.1.0' 31 | implementation project(path: ':playersdk') 32 | implementation project(path: ':videocache') 33 | } -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /app/src/main/java/com/jeffmony/sample/JeffApplication.java: -------------------------------------------------------------------------------- 1 | package com.jeffmony.sample; 2 | 3 | import android.app.Application; 4 | 5 | import com.jeffmony.videocache.VideoProxyCacheManager; 6 | import com.jeffmony.videocache.utils.StorageUtils; 7 | 8 | import java.io.File; 9 | 10 | public class JeffApplication extends Application { 11 | private static final String TAG = "JeffApplication"; 12 | 13 | 14 | @Override 15 | public void onCreate() { 16 | super.onCreate(); 17 | 18 | File saveFile = StorageUtils.getVideoFileDir(this); 19 | if (!saveFile.exists()) { 20 | saveFile.mkdirs(); 21 | } 22 | VideoProxyCacheManager.Builder builder = new VideoProxyCacheManager.Builder(this). 23 | setFilePath(saveFile.getAbsolutePath()). //缓存存储位置 24 | setConnTimeOut(60 * 1000). //网络连接超时 25 | setReadTimeOut(60 * 1000). //网络读超时 26 | setExpireTime(2 * 24 * 60 * 60 * 1000). //2天的过期时间 27 | setMaxCacheSize(2 * 1024 * 1024 * 1024L); //2G的存储上限 28 | VideoProxyCacheManager.getInstance().initProxyConfig(builder.build()); 29 | 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /app/src/main/java/com/jeffmony/sample/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.jeffmony.sample; 2 | 3 | import android.app.Activity; 4 | import android.content.Intent; 5 | import android.os.Bundle; 6 | import android.text.TextUtils; 7 | import android.view.View; 8 | import android.widget.Button; 9 | import android.widget.CheckBox; 10 | import android.widget.EditText; 11 | import android.widget.RadioButton; 12 | import android.widget.RadioGroup; 13 | import android.widget.Toast; 14 | 15 | import com.jeffmony.videocache.utils.ProxyCacheUtils; 16 | 17 | import java.io.File; 18 | import java.io.IOException; 19 | 20 | public class MainActivity extends Activity { 21 | 22 | private EditText mVideoUrlEditText; 23 | private Button mVideoPlayBtn; 24 | private Button mVideoDeleteBtn; 25 | private CheckBox mLocalProxyBox; 26 | private CheckBox mUseOkHttpBox; 27 | 28 | private RadioGroup mRadioGroup; 29 | private RadioButton mExoBtn; 30 | private RadioButton mIjkBtn; 31 | 32 | private boolean mIsExoSelected; 33 | private boolean mIsIjkSelected; 34 | 35 | @Override 36 | protected void onCreate(Bundle savedInstanceState) { 37 | super.onCreate(savedInstanceState); 38 | setContentView(R.layout.activity_main); 39 | 40 | mVideoUrlEditText = findViewById(R.id.video_url_edit_text); 41 | //mVideoUrlEditText.setText(slow_url); 42 | mVideoPlayBtn = findViewById(R.id.video_play_btn); 43 | mVideoDeleteBtn = findViewById(R.id.video_delete_btn); 44 | mLocalProxyBox = findViewById(R.id.local_proxy_box); 45 | mUseOkHttpBox = findViewById(R.id.okhttp_box); 46 | mRadioGroup = findViewById(R.id.player_group); 47 | mExoBtn = findViewById(R.id.exo_play_btn); 48 | mIjkBtn = findViewById(R.id.ijk_play_btn); 49 | mExoBtn.setChecked(true); 50 | mIsExoSelected = mExoBtn.isChecked(); 51 | mIsIjkSelected = mIjkBtn.isChecked(); 52 | 53 | mRadioGroup.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() { 54 | @Override 55 | public void onCheckedChanged(RadioGroup radioGroup, int i) { 56 | mIsExoSelected = mExoBtn.isChecked(); 57 | mIsIjkSelected = mIjkBtn.isChecked(); 58 | } 59 | }); 60 | 61 | mVideoPlayBtn.setOnClickListener(view -> { 62 | String videoUrl = mVideoUrlEditText.getText().toString(); 63 | if (TextUtils.isEmpty(videoUrl)) { 64 | Toast.makeText(MainActivity.this, "The video url is empty", Toast.LENGTH_LONG).show(); 65 | } else { 66 | Intent intent = new Intent(MainActivity.this, VideoPlayActivity.class); 67 | intent.putExtra("video_url", videoUrl); 68 | intent.putExtra("local_proxy_enable", mLocalProxyBox.isChecked()); 69 | intent.putExtra("use_okttp_enable", mUseOkHttpBox.isChecked()); 70 | int type; 71 | if (mIsExoSelected) { 72 | type = 1; 73 | } else { 74 | type = 2; 75 | } 76 | intent.putExtra("player_type", type); 77 | startActivity(intent); 78 | } 79 | }); 80 | 81 | mVideoDeleteBtn.setOnClickListener(new View.OnClickListener() { 82 | @Override 83 | public void onClick(View v) { 84 | try { 85 | cleanDirectory(new File(ProxyCacheUtils.getConfig().getFilePath())); 86 | } catch (IOException e) { 87 | //throw new RuntimeException(e); 88 | } 89 | } 90 | }); 91 | } 92 | 93 | 94 | private static void cleanDirectory(File file) throws IOException { 95 | if (!file.exists()) { 96 | return; 97 | } 98 | File[] contentFiles = file.listFiles(); 99 | if (contentFiles != null) { 100 | for (File contentFile : contentFiles) { 101 | delete(contentFile); 102 | } 103 | } 104 | } 105 | 106 | private static void delete(File file) throws IOException { 107 | if (file.isFile() && file.exists()) { 108 | deleteOrThrow(file); 109 | } else { 110 | cleanDirectory(file); 111 | deleteOrThrow(file); 112 | } 113 | } 114 | 115 | private static void deleteOrThrow(File file) throws IOException { 116 | if (file.exists()) { 117 | boolean isDeleted = file.delete(); 118 | if (!isDeleted) { 119 | throw new IOException(String.format("File %s can't be deleted", file.getAbsolutePath())); 120 | } 121 | } 122 | } 123 | 124 | } -------------------------------------------------------------------------------- /app/src/main/java/com/jeffmony/sample/ScreenUtils.java: -------------------------------------------------------------------------------- 1 | package com.jeffmony.sample; 2 | 3 | import android.content.Context; 4 | import android.view.WindowManager; 5 | 6 | public class ScreenUtils { 7 | 8 | public static Size getScreenSize(Context context) { 9 | WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); 10 | int width = wm.getDefaultDisplay().getWidth(); 11 | int height = wm.getDefaultDisplay().getHeight(); 12 | Size size = new Size(width, height); 13 | return size; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /app/src/main/java/com/jeffmony/sample/Size.java: -------------------------------------------------------------------------------- 1 | package com.jeffmony.sample; 2 | 3 | public class Size { 4 | 5 | private int mWidth; 6 | private int mHeight; 7 | 8 | public Size(int width, int height) { 9 | mWidth = width; 10 | mHeight = height; 11 | } 12 | 13 | public int getWidth() { 14 | return mWidth; 15 | } 16 | 17 | public int getHeight() { 18 | return mHeight; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /app/src/main/java/com/jeffmony/sample/VideoStatus.java: -------------------------------------------------------------------------------- 1 | package com.jeffmony.sample; 2 | 3 | public enum VideoStatus { 4 | PLAY, 5 | PAUSE 6 | } 7 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-v24/ic_launcher_foreground.xml: -------------------------------------------------------------------------------- 1 | 7 | 8 | 9 | 15 | 18 | 21 | 22 | 23 | 24 | 30 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/pause_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JeffMony/JeffVideoCache/8e9d01a1012f464a1308859e7009588a7e2d130c/app/src/main/res/drawable/pause_icon.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/play_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JeffMony/JeffVideoCache/8e9d01a1012f464a1308859e7009588a7e2d130c/app/src/main/res/drawable/play_icon.png -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 11 | 21 | 22 | 28 | 36 | 37 | 44 | 45 | 46 |