├── .github └── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md ├── .gitignore ├── LICENSE ├── README.English.md ├── README.md ├── SUMMARY.md ├── _config.yml ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ ├── assets │ ├── assets_video.mp4 │ └── video.json │ ├── java │ └── org │ │ └── salient │ │ └── artvideoplayer │ │ ├── BaseActivity.kt │ │ ├── BaseApplication.kt │ │ ├── DensityUtil.kt │ │ ├── activity │ │ ├── FullscreenActivity.kt │ │ ├── MainActivity.kt │ │ └── TinyWindowActivity.kt │ │ └── bean │ │ ├── MovieData.kt │ │ └── VideoBean.kt │ └── res │ ├── layout │ ├── activity_api.xml │ ├── activity_api_common.xml │ ├── activity_api_raw_assets.xml │ ├── activity_extension.xml │ ├── activity_fullscreen.xml │ ├── activity_list.xml │ ├── activity_main.xml │ ├── activity_orientation.xml │ ├── activity_recycler_view.xml │ ├── activity_tiny.xml │ ├── content_main.xml │ └── item_video_view.xml │ ├── menu │ └── menu_bar_setting.xml │ ├── mipmap-hdpi │ └── ic_launcher.png │ ├── mipmap-mdpi │ └── ic_launcher.png │ ├── mipmap-xhdpi │ └── ic_launcher.png │ ├── mipmap-xxhdpi │ └── ic_launcher.png │ ├── mipmap-xxxhdpi │ └── ic_launcher.png │ ├── raw │ └── raw_video.mp4 │ └── values │ ├── colors.xml │ ├── strings.xml │ └── styles.xml ├── artPlayer-arm64 ├── .gitignore ├── bintary_push.gradle ├── build.gradle ├── gradle.properties ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ └── res │ └── values │ └── strings.xml ├── artPlayer-armv5 ├── .gitignore ├── bintary_push.gradle ├── build.gradle ├── gradle.properties ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ └── res │ └── values │ └── strings.xml ├── artPlayer-armv7a ├── .gitignore ├── bintary_push.gradle ├── build.gradle ├── gradle.properties ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ └── res │ └── values │ └── strings.xml ├── artPlayer-x86 ├── .gitignore ├── bintary_push.gradle ├── build.gradle ├── gradle.properties ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ └── res │ └── values │ └── strings.xml ├── artPlayer-x86_64 ├── .gitignore ├── bintary_push.gradle ├── build.gradle ├── gradle.properties ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ └── res │ └── values │ └── strings.xml ├── artplayer-core ├── .gitignore ├── bintary_push.gradle ├── build.gradle ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── org │ │ └── salient │ │ └── artplayer │ │ ├── MediaPlayerManager.kt │ │ ├── audio │ │ ├── DefaultAudioFocusChangeListener.kt │ │ ├── DefaultAudioManager.kt │ │ └── IAudioManager.kt │ │ ├── bean │ │ ├── VideoInfo.kt │ │ └── VideoSize.kt │ │ ├── conduction │ │ ├── PlayerState.kt │ │ ├── ScaleType.kt │ │ └── WindowType.kt │ │ ├── extend │ │ └── Utils.kt │ │ ├── player │ │ ├── IMediaPlayer.kt │ │ └── SystemMediaPlayer.kt │ │ └── ui │ │ ├── FullscreenVideoView.kt │ │ ├── IFullscreenVideoView.kt │ │ ├── ITinyVideoView.kt │ │ ├── IVideoView.kt │ │ ├── ResizeTextureView.kt │ │ ├── TinyVideoView.kt │ │ ├── VideoView.kt │ │ └── extend │ │ ├── FullscreenGestureListener.kt │ │ ├── OrientationEventManager.kt │ │ └── TinyViewGestureListener.kt │ └── res │ └── values │ ├── attrs.xml │ ├── ids.xml │ └── strings.xml ├── artplayer-exo ├── .gitignore ├── bintary_push.gradle ├── build.gradle ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── org │ │ └── salient │ │ └── artplayer │ │ └── exo │ │ ├── ExoMediaPlayer.kt │ │ ├── ExoSourceBuilder.kt │ │ └── ExoSourceManager.kt │ └── res │ └── values │ └── strings.xml ├── artplayer-ijk ├── .gitignore ├── bintary_push.gradle ├── build.gradle ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── org │ │ └── salient │ │ └── artplayer │ │ └── ijk │ │ ├── IjkPlayer.kt │ │ └── RawDataSourceProvider.kt │ └── res │ └── values │ └── strings.xml ├── artplayer-ui ├── .gitignore ├── bintary_push.gradle ├── build.gradle ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── org │ │ └── salient │ │ └── artplayer │ │ └── ui │ │ ├── ControlPanel.kt │ │ ├── VideoGestureListener.kt │ │ └── listener │ │ └── OrientationChangeListener.kt │ └── res │ ├── drawable-hdpi │ ├── salient_brightness.png │ └── salient_volume.png │ ├── drawable-mdpi │ ├── salient_brightness.png │ └── salient_volume.png │ ├── drawable-xhdpi │ ├── salient_bg_loading.png │ ├── salient_brightness.png │ ├── salient_icon_back.png │ ├── salient_icon_full_screen.png │ ├── salient_icon_narrow.png │ ├── salient_icon_pause.png │ ├── salient_icon_start.png │ ├── salient_icon_volume.png │ ├── salient_icon_volume_hover.png │ └── salient_volume.png │ ├── drawable-xxhdpi │ ├── salient_bg_loading.png │ ├── salient_bottom_pause.png │ ├── salient_bottom_play.png │ ├── salient_brightness.png │ ├── salient_icon_back.png │ ├── salient_icon_full_screen.png │ ├── salient_icon_narrow.png │ ├── salient_icon_pause.png │ ├── salient_icon_start.png │ ├── salient_icon_volume.png │ ├── salient_icon_volume_hover.png │ └── salient_volume.png │ ├── drawable │ ├── progress_custom.xml │ ├── salient_bg_btn_corner_stroke_white.xml │ ├── salient_seek_bar_video_white.xml │ ├── salient_seek_thumb_video_white.xml │ ├── salient_selector_bottom_video_play.xml │ ├── salient_selector_video_play.xml │ ├── salient_selector_volume.xml │ └── salient_video_loading.xml │ └── layout │ └── salient_layout_video_control_panel.xml ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── pic ├── api.png ├── apkqrcode.png ├── extension.png ├── list.png ├── main.png ├── mediaplayer.png └── recyclerview.png └── settings.gradle /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | 5 | --- 6 | 7 | **Describe the bug** 8 | A clear and concise description of what the bug is. 9 | 10 | **To Reproduce** 11 | Steps to reproduce the behavior: 12 | 1. Go to '...' 13 | 2. Click on '....' 14 | 3. Scroll down to '....' 15 | 4. See error 16 | 17 | **Expected behavior** 18 | A clear and concise description of what you expected to happen. 19 | 20 | **Screenshots** 21 | If applicable, add screenshots to help explain your problem. 22 | 23 | **Desktop (please complete the following information):** 24 | - OS: [e.g. iOS] 25 | - Browser [e.g. chrome, safari] 26 | - Version [e.g. 22] 27 | 28 | **Smartphone (please complete the following information):** 29 | - Device: [e.g. iPhone6] 30 | - OS: [e.g. iOS8.1] 31 | - Browser [e.g. stock browser, safari] 32 | - Version [e.g. 22] 33 | 34 | **Additional context** 35 | Add any other context about the problem here. 36 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | 5 | --- 6 | 7 | **Is your feature request related to a problem? Please describe.** 8 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 9 | 10 | **Describe the solution you'd like** 11 | A clear and concise description of what you want to happen. 12 | 13 | **Describe alternatives you've considered** 14 | A clear and concise description of any alternative solutions or features you've considered. 15 | 16 | **Additional context** 17 | Add any other context or screenshots about the feature request here. 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/libraries 5 | /.idea/modules.xml 6 | /.idea/workspace.xml 7 | .DS_Store 8 | /build 9 | /captures 10 | .externalNativeBuild 11 | /.idea 12 | -------------------------------------------------------------------------------- /README.English.md: -------------------------------------------------------------------------------- 1 | English | [简体中文](https://github.com/maiwenchang/ArtVideoPlayer/blob/master/README.md) 2 | # ArtPlayer 3 | 4 | ![GitHub top language](https://img.shields.io/github/languages/top/maiwenchang/artPlayer) 5 | [![Hex.pm](https://img.shields.io/hexpm/l/plug.svg)](https://github.com/maiwenchang/ArtVideoPlayer/blob/master/LICENSE) 6 | [![API](https://img.shields.io/badge/API-21%2B-brightgreen.svg?style=flat)](https://android-arsenal.com/api?level=21) 7 | ![GitHub release (latest by date)](https://img.shields.io/github/v/release/maiwenchang/ArtPlayer?color=g) 8 | 9 | ### Introduction 10 | This is a flexible video player. MediaPlayer is completely separate from VideoView and can be replaced with other player kernels such as ExoPlayer and ijkPlayer. Developers can fully customize the player view, which we call the control panel. In addition, developers can use MediaPlayerManager to control playback behaviours, such as full-screen mode, small screen mode, and smart matching modes in RecyclerView. 11 | 12 |

13 | 14 |

15 | 16 | [Full Wiki of ArtPlayer](https://github.com/maiwenchang/ArtPlayer/wiki) 17 | 18 | ### Features 19 | - Fullscreen,TinyWindow play 20 | - Support for playing in RecyclerView 21 | - Custom UI 22 | - Global playback in APP 23 | - Mute 24 | - Loop Playback 25 | - Gesture manipulation (small window: single finger drag, double finger zoom; full screen: volume, brightness, fast forward) 26 | - ijkPlayer support 27 | - ExoPlayer support 28 | - Gravity sensor support 29 | - Raw/Assets, and local playback support 30 | 31 | ### Getting started 32 | basic dependency 33 | ``` 34 | implementation 'org.salient.artvideoplayer:artplayer-core:1.1.0' 35 | ``` 36 | 37 | using ExoPlayer 38 | ``` 39 | implementation "org.salient.artvideoplayer:artplayer-exo:1.1.0" 40 | ``` 41 | 42 | using IjkPlayer 43 | ``` 44 | implementation 'org.salient.artvideoplayer:artplayer-ijk:1.1.0' 45 | implementation "org.salient.artvideoplayer:artplayer-armv7a:1.1.0" 46 | ``` 47 | 48 | support different cpu architecture 49 | ``` 50 | implementation "org.salient.artvideoplayer:artplayer-armv5:1.1.0" 51 | implementation "org.salient.artvideoplayer:artplayer-x86:1.1.0" 52 | //required minSdk version >= 21 53 | implementation "org.salient.artvideoplayer:artplayer-arm64:1.1.0" 54 | implementation "org.salient.artvideoplayer:artplayer-x86_64:1.1.0" 55 | ``` 56 | 57 | ### 使用方法 58 | 59 | kotlin 60 | ``` kotlin 61 | import org.salient.artplayer.VideoView 62 | 63 | val videoView = VideoView(context) 64 | videoView.mediaPlayer = SystemMediaPlayer().apply{ 65 | setDataSource(context, Uri.parse("http://vfx.mtime.cn/Video/2018/07/06/mp4/180706094003288023.mp4")) 66 | } 67 | videoView.prepare() 68 | ``` 69 | 70 | xml 71 | ``` xml 72 | 76 | ``` 77 | 78 | `AndroidManifest.xml` 79 | ``` xml 80 | 83 | ``` 84 | 85 | Activity 86 | ``` kotlin 87 | // block the backpress event of the fullscreen playback 88 | override fun onBackPressed() { 89 | if (MediaPlayerManager.blockBackPress(this)) { 90 | return 91 | } 92 | super.onBackPressed() 93 | } 94 | ``` 95 | 96 | setup cover 97 | ``` java 98 | //If using the ControlPanel,we can get the ImageView of the cover by `findViewById()` method 99 | //of the ControlPanel which extends FrameLayout: 100 | Glide.with(context) 101 | .load("http://img5.mtime.cn/mg/2018/07/06/093947.51483272.jpg") 102 | .into(videoView.cover); 103 | ``` 104 | 105 | 106 | ### Support 107 | - Public technical discussion on github is preferred.[Technical problems](https://github.com/maiwenchang/ArtPlayer/issues) 108 | - [Wiki](https://github.com/maiwenchang/ArtPlayer/wiki) 109 | 110 | ### My Build Environment 111 | - Java 1.8 112 | - Android Studio 3.6.0 113 | - Gradle 5.6.4 114 | - IjkPlayer 0.8.8 115 | - ExoPlayer 2.11.3 116 | 117 | ### Authors 118 | - [maiwenchang](https://github.com/maiwenchang) 119 | - [ironman6121](https://github.com/ironman6121) 120 | 121 | ### Contact 122 | - cv.stronger@gmail.com 123 | 124 | ### License 125 | 126 | ``` 127 | Copyright 2018 maiwenchang 128 | 129 | Licensed under the Apache License, Version 2.0 (the "License"); 130 | you may not use this file except in compliance with the License. 131 | You may obtain a copy of the License at 132 | 133 | http://www.apache.org/licenses/LICENSE-2.0 134 | 135 | Unless required by applicable law or agreed to in writing, software 136 | distributed under the License is distributed on an "AS IS" BASIS, 137 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 138 | See the License for the specific language governing permissions and 139 | limitations under the License. 140 | ``` 141 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [English](https://github.com/maiwenchang/ArtVideoPlayer/blob/master/README.English.md) | 简体中文 2 | # ArtPlayer 3 | 4 | ![GitHub top language](https://img.shields.io/github/languages/top/maiwenchang/artPlayer) 5 | [![Hex.pm](https://img.shields.io/hexpm/l/plug.svg)](https://github.com/maiwenchang/ArtVideoPlayer/blob/master/LICENSE) 6 | [![API](https://img.shields.io/badge/API-21%2B-brightgreen.svg?style=flat)](https://android-arsenal.com/api?level=21) 7 | ![GitHub release (latest by date)](https://img.shields.io/github/v/release/maiwenchang/ArtPlayer?color=g) 8 | 9 | ### 简介 10 | Kotlin实现的视频播放器,将MediaPlayer与VideoView解耦合,支持切换播放器内核(如ExoPlayer和ijkPlayer),支持自定义控制视图,提供MediaPlayerManager实现全屏模式,小屏幕模式等。 11 | 12 |

13 | 14 |

15 | 16 | [查看详细文档](https://github.com/maiwenchang/ArtPlayer/wiki) 17 | 18 | ### 特点 19 | - ijkPlayer支持 20 | - ExoPlayer支持 21 | - 全屏,小屏播放 22 | - 完全自定义UI 23 | - 静音 24 | - 循环播放 25 | - 倍速播放(IjkPlayer支持) 26 | - 多播放器同时播放 27 | - Raw/Assets,本地视频文件播放支持 28 | - Activity生命周期感知,实现了onPause暂停播放,onDestory停止播放并释放资源 29 | - 手势操作支持(小窗:单指拖动,双指缩放;全屏:音量,亮度,快进) 30 | - 重力感应支持 31 | 32 | ### 开始使用 33 | 核心依赖 34 | ``` 35 | implementation 'org.salient.artvideoplayer:artplayer-core:1.1.0' 36 | ``` 37 | 38 | 选择使用ExoPlayer 39 | ``` 40 | implementation "org.salient.artvideoplayer:artplayer-exo:1.1.0" 41 | ``` 42 | 43 | 选择使用IjkPlayer 44 | ``` 45 | implementation 'org.salient.artvideoplayer:artplayer-ijk:1.1.0' 46 | implementation "org.salient.artvideoplayer:artplayer-armv7a:1.1.0" 47 | ``` 48 | 49 | 需要支持不同的cpu架构 50 | ``` 51 | implementation "org.salient.artvideoplayer:artplayer-armv5:1.1.0" 52 | implementation "org.salient.artvideoplayer:artplayer-x86:1.1.0" 53 | //下面两个需要minSdk version >= 21 54 | implementation "org.salient.artvideoplayer:artplayer-arm64:1.1.0" 55 | implementation "org.salient.artvideoplayer:artplayer-x86_64:1.1.0" 56 | ``` 57 | 58 | ### 使用方法 59 | 60 | kotlin 61 | ``` kotlin 62 | import org.salient.artplayer.VideoView 63 | 64 | val videoView = VideoView(context) 65 | videoView.mediaPlayer = SystemMediaPlayer().apply{ 66 | setDataSource(context, Uri.parse("http://vfx.mtime.cn/Video/2018/07/06/mp4/180706094003288023.mp4")) 67 | } 68 | videoView.prepare() 69 | ``` 70 | 71 | xml 72 | ``` xml 73 | 77 | ``` 78 | 79 | `AndroidManifest.xml` 80 | ``` xml 81 | 84 | ``` 85 | 86 | Activity 87 | ``` kotlin 88 | //拦截全屏时的返回事件 89 | override fun onBackPressed() { 90 | if (MediaPlayerManager.blockBackPress(this)) { 91 | return 92 | } 93 | super.onBackPressed() 94 | } 95 | ``` 96 | 97 | 设置封面 98 | ``` java 99 | //绑定封面图片资源到VideoView的`cover`字段 100 | Glide.with(context) 101 | .load("http://img5.mtime.cn/mg/2018/07/06/093947.51483272.jpg") 102 | .into(videoView.cover); 103 | ``` 104 | 105 | ### 支持 106 | - 请在 github 上公开讨论[技术问题](https://github.com/maiwenchang/ArtPlayer/issues) 107 | - 详细的说明文档请查看[Wiki](https://github.com/maiwenchang/ArtPlayer/wiki) 108 | 109 | ### 构建环境 110 | - Kotlin 1.37.2 111 | - Java 1.8 112 | - Android Studio 3.6.0 113 | - Gradle 5.6.4 114 | - IjkPlayer 0.8.8 115 | - ExoPlayer 2.11.3 116 | 117 | ### 作者 118 | - [maiwenchang](https://github.com/maiwenchang) 119 | - [ironman6121](https://github.com/ironman6121) 120 | 121 | ### 联系方式 122 | - cv.stronger@gmail.com 123 | 124 | ### License 125 | 126 | ``` 127 | Copyright 2018 maiwenchang 128 | Licensed under the Apache License, Version 2.0 (the "License"); 129 | you may not use this file except in compliance with the License. 130 | You may obtain a copy of the License at 131 | http://www.apache.org/licenses/LICENSE-2.0 132 | Unless required by applicable law or agreed to in writing, software 133 | distributed under the License is distributed on an "AS IS" BASIS, 134 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 135 | See the License for the specific language governing permissions and 136 | limitations under the License. 137 | ``` 138 | -------------------------------------------------------------------------------- /SUMMARY.md: -------------------------------------------------------------------------------- 1 | # Table of contents 2 | 3 | * [Initial page](README.md) 4 | 5 | -------------------------------------------------------------------------------- /_config.yml: -------------------------------------------------------------------------------- 1 | theme: jekyll-theme-cayman -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | apply plugin: 'kotlin-android' 3 | apply plugin: 'kotlin-android-extensions' 4 | apply plugin: 'kotlin-kapt' 5 | 6 | android { 7 | compileSdkVersion rootProject.compileSdkVersion 8 | defaultConfig { 9 | applicationId "org.salient.artvideoplayer" 10 | minSdkVersion rootProject.minSdkVersion 11 | targetSdkVersion rootProject.targetSdkVersion 12 | versionCode 1 13 | versionName "1.0" 14 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" 15 | ndk { 16 | //设置支持的SO库架构 17 | abiFilters 'armeabi-v7a', 'armeabi', 'x86', 'arm64-v8a', 'x86_64' 18 | } 19 | } 20 | buildTypes { 21 | debug { 22 | minifyEnabled false 23 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 24 | } 25 | release { 26 | minifyEnabled false 27 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 28 | } 29 | android.applicationVariants.all { 30 | variant -> 31 | variant.outputs.all { 32 | output -> 33 | def outputFile = output.outputFile 34 | if (outputFile.name.contains("release")) { 35 | outputFileName = new File("./", "artplayer-release.apk") 36 | } else if (outputFile.name.contains("debug")) { 37 | outputFileName = new File("./", "artplayer-debug.apk") 38 | } 39 | } 40 | } 41 | } 42 | 43 | sourceSets { 44 | main { 45 | jniLibs.srcDirs = ['libs'] 46 | } 47 | } 48 | 49 | compileOptions { 50 | targetCompatibility JavaVersion.VERSION_1_8 51 | sourceCompatibility JavaVersion.VERSION_1_8 52 | } 53 | 54 | lintOptions { 55 | abortOnError false 56 | } 57 | 58 | dependencies { 59 | implementation fileTree(include: ['*.jar'], dir: 'libs') 60 | implementation "androidx.appcompat:appcompat:$compactVersion" 61 | //design 62 | implementation "com.google.android.material:material:1.5.0" 63 | implementation 'androidx.constraintlayout:constraintlayout:2.1.3' 64 | //FlexboxLayout 65 | implementation 'com.google.android.flexbox:flexbox:3.0.0' 66 | androidTestImplementation 'com.android.support.test:runner:1.0.2' 67 | androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2' 68 | implementation 'com.google.code.gson:gson:2.8.6' 69 | implementation 'com.github.bumptech.glide:glide:4.9.0' 70 | debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.8.1' 71 | releaseImplementation 'com.squareup.leakcanary:leakcanary-android:2.8.1' 72 | //releaseImplementation 'com.squareup.leakcanary:leakcanary-android-no-op:1.5.4' 73 | testImplementation 'com.squareup.leakcanary:leakcanary-android-no-op:1.5.4' 74 | 75 | //required 76 | implementation project(':artplayer-core') 77 | implementation project(':artplayer-exo') 78 | implementation project(':artplayer-ijk') 79 | implementation project(':artplayer-armv7a') 80 | // implementation "org.salient.artvideoplayer:artplayer-armv7a:1.0.0" 81 | // implementation "org.salient.artvideoplayer:artplayer-armv5:1.0.0" 82 | // implementation "org.salient.artvideoplayer:artplayer-x86:1.0.0" 83 | // implementation "org.salient.artvideoplayer:artplayer-arm64:1.0.0" 84 | // implementation "org.salient.artvideoplayer:artplayer-x86_64:1.0.0" 85 | 86 | } 87 | } 88 | dependencies { 89 | implementation "androidx.core:core-ktx:$ktx_version" 90 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" 91 | } 92 | 93 | configurations.all { 94 | resolutionStrategy { 95 | force "androidx.core:core-ktx:$ktx_version" 96 | } 97 | } 98 | 99 | -------------------------------------------------------------------------------- /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 22 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | 9 | 17 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 36 | 41 | 45 | 49 | 54 | 58 | 63 | 67 | 72 | 76 | 77 | 78 | -------------------------------------------------------------------------------- /app/src/main/assets/assets_video.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maiwenchang/ArtPlayer/0cf40d65493852881bda6deaed94eef4c642d821/app/src/main/assets/assets_video.mp4 -------------------------------------------------------------------------------- /app/src/main/java/org/salient/artvideoplayer/BaseActivity.kt: -------------------------------------------------------------------------------- 1 | package org.salient.artvideoplayer 2 | 3 | import android.content.Context 4 | import android.content.res.Configuration 5 | import android.os.Bundle 6 | import android.util.Log 7 | import android.view.Menu 8 | import android.view.MenuItem 9 | import android.view.View 10 | import android.view.inputmethod.InputMethodManager 11 | import androidx.appcompat.app.AppCompatActivity 12 | import org.salient.artplayer.MediaPlayerManager 13 | import org.salient.artplayer.MediaPlayerManager.blockBackPress 14 | import org.salient.artplayer.exo.ExoMediaPlayer 15 | import org.salient.artplayer.ijk.IjkPlayer 16 | import org.salient.artplayer.player.SystemMediaPlayer 17 | import org.salient.artvideoplayer.bean.VideoBean 18 | import java.util.* 19 | 20 | /** 21 | * description: Activity基类 22 | * 23 | * @author Maiwenchang 24 | * email: cv.stronger@gmail.com 25 | * date: 2020-05-20 09:06 AM. 26 | */ 27 | abstract class BaseActivity : AppCompatActivity() { 28 | 29 | val allComing: List 30 | get() { 31 | val list: MutableList = ArrayList() 32 | val mMovieData = BaseApplication.movieData 33 | if (mMovieData != null) { 34 | val moviecomings = mMovieData.moviecomings ?: emptyList() 35 | for (moviecomingsBean in moviecomings) { 36 | val videos = moviecomingsBean.videos 37 | if (videos != null && videos.size > 0) { 38 | list.add(videos[0]) 39 | } 40 | } 41 | } 42 | return list 43 | } 44 | 45 | val allAttention: List 46 | get() { 47 | val list: MutableList = ArrayList() 48 | val mMovieData = BaseApplication.movieData 49 | if (mMovieData != null) { 50 | val attentions = mMovieData.attention ?: emptyList() 51 | for (attentionBean in attentions) { 52 | val videos = attentionBean.videos 53 | if (videos != null && videos.size > 0) { 54 | list.add(videos[0]) 55 | } 56 | } 57 | } 58 | return list 59 | } 60 | 61 | val randomVideo: VideoBean? 62 | get() { 63 | val mMovieData = BaseApplication.movieData 64 | if (mMovieData != null) { 65 | val allAttention = allAttention 66 | return allAttention[getRandomInt(0, allAttention.size)] 67 | } 68 | return null 69 | } 70 | 71 | fun getRandomInt(min: Int, max: Int): Int { 72 | var i = (System.currentTimeMillis() % max).toInt() 73 | if (i < min) { 74 | i = i + min 75 | } 76 | Log.d("BaseActivity", "#getRandomInt():$i") 77 | return i 78 | } 79 | 80 | override fun onBackPressed() { 81 | if (MediaPlayerManager.blockBackPress(this)) { 82 | return 83 | } 84 | super.onBackPressed() 85 | } 86 | 87 | override fun onPause() { 88 | super.onPause() 89 | hideSoftInput() 90 | } 91 | 92 | //显示软键盘 93 | fun showSoftInput(view: View) { 94 | val imm = getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager? 95 | if (imm != null) { 96 | view.requestFocus() 97 | imm.showSoftInput(view, InputMethodManager.SHOW_IMPLICIT) 98 | } 99 | } 100 | 101 | //收起软键盘 102 | fun hideSoftInput() { 103 | val imm = getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager? 104 | imm?.hideSoftInputFromWindow(window.decorView.windowToken, 0) 105 | } 106 | 107 | override fun onConfigurationChanged(newConfig: Configuration) { 108 | super.onConfigurationChanged(newConfig) 109 | hideSoftInput() 110 | } 111 | 112 | } -------------------------------------------------------------------------------- /app/src/main/java/org/salient/artvideoplayer/BaseApplication.kt: -------------------------------------------------------------------------------- 1 | package org.salient.artvideoplayer 2 | 3 | import android.app.Application 4 | import android.text.TextUtils 5 | import com.google.gson.Gson 6 | import org.salient.artvideoplayer.bean.MovieData 7 | import java.io.BufferedReader 8 | import java.io.IOException 9 | import java.io.InputStreamReader 10 | import java.util.concurrent.Executors 11 | 12 | /** 13 | * Created by Mai on 2018/7/17 14 | * * 15 | * Description: 16 | * * 17 | */ 18 | class BaseApplication : Application() { 19 | override fun onCreate() { 20 | super.onCreate() 21 | Executors.newSingleThreadExecutor().submit { jsonString = readAssetsFile("video.json") } 22 | } 23 | 24 | /** 25 | * 读取assets中的文件 26 | * 27 | * @param path File Path 28 | * @return File Content String 29 | */ 30 | fun readAssetsFile(path: String?): String { 31 | var result = "" 32 | try { // read file content from file 33 | val sb = StringBuilder("") 34 | val reader = InputStreamReader(resources.assets.open(path!!)) 35 | val br = BufferedReader(reader) 36 | var str: String? 37 | while (br.readLine().also { str = it } != null) { 38 | sb.append(str) 39 | } 40 | result = sb.toString() 41 | br.close() 42 | reader.close() 43 | } catch (e: IOException) { 44 | e.printStackTrace() 45 | } 46 | return result 47 | } 48 | 49 | companion object { 50 | private var jsonString = "" 51 | val movieData: MovieData? 52 | get() = if (TextUtils.isEmpty(jsonString)) { 53 | null 54 | } else { 55 | Gson().fromJson(jsonString, MovieData::class.java) 56 | } 57 | } 58 | } -------------------------------------------------------------------------------- /app/src/main/java/org/salient/artvideoplayer/DensityUtil.kt: -------------------------------------------------------------------------------- 1 | package org.salient.artvideoplayer 2 | 3 | import android.app.Activity 4 | import android.content.Context 5 | import android.util.DisplayMetrics 6 | 7 | /** 8 | * Created by Mai on 2018/5/18 9 | * * 10 | * Description:屏幕像素转换类 11 | * * 12 | */ 13 | object DensityUtil { 14 | /** 15 | * dip转像素 16 | */ 17 | fun dip2px(context: Context, dip: Int): Int { 18 | val SCALE = context.resources.displayMetrics.density 19 | return (dip.toFloat() * SCALE + 0.5f).toInt() 20 | } 21 | 22 | /** 23 | * 像素转dip 24 | */ 25 | fun px2dip(context: Context, Pixels: Int): Float { 26 | val SCALE = context.resources.displayMetrics.density 27 | return Pixels / SCALE 28 | } 29 | 30 | /** 31 | * 屏幕分辨率宽 32 | */ 33 | fun getWindowWidth(activity: Activity): Int { 34 | val dm = DisplayMetrics() 35 | activity.windowManager.defaultDisplay.getMetrics(dm) 36 | return dm.widthPixels 37 | } 38 | 39 | /** 40 | * 屏幕分辩类高 41 | */ 42 | fun getWindowHeight(activity: Activity): Int { 43 | val dm = DisplayMetrics() 44 | activity.windowManager.defaultDisplay.getMetrics(dm) 45 | return dm.heightPixels 46 | } 47 | 48 | /** 49 | * 屏幕的dpi 50 | */ 51 | fun getDmDensityDpi(activity: Activity): Float { 52 | val dm = DisplayMetrics() 53 | activity.windowManager.defaultDisplay.getMetrics(dm) 54 | return dm.density 55 | } 56 | } -------------------------------------------------------------------------------- /app/src/main/java/org/salient/artvideoplayer/activity/FullscreenActivity.kt: -------------------------------------------------------------------------------- 1 | package org.salient.artvideoplayer.activity 2 | 3 | import android.content.res.Configuration 4 | import android.net.Uri 5 | import android.os.Bundle 6 | import android.view.Gravity 7 | import android.view.View 8 | import android.widget.FrameLayout 9 | import androidx.lifecycle.Observer 10 | import kotlinx.android.synthetic.main.activity_fullscreen.* 11 | import kotlinx.android.synthetic.main.activity_tiny.* 12 | import org.salient.artplayer.MediaPlayerManager 13 | import org.salient.artplayer.player.SystemMediaPlayer 14 | import org.salient.artplayer.ui.FullscreenVideoView 15 | import org.salient.artplayer.ui.TinyVideoView 16 | import org.salient.artplayer.ui.VideoView 17 | import org.salient.artplayer.ui.extend.OrientationEventManager 18 | import org.salient.artvideoplayer.BaseActivity 19 | import org.salient.artvideoplayer.DensityUtil.getWindowHeight 20 | import org.salient.artvideoplayer.DensityUtil.getWindowWidth 21 | import org.salient.artvideoplayer.R 22 | 23 | /** 24 | * description:全屏播放demo 25 | * 26 | * @author Maiwenchang 27 | * email: cv.stronger@gmail.com 28 | * date: 2020-05-20 09:06 AM. 29 | */ 30 | class FullscreenActivity : BaseActivity() { 31 | 32 | private val orientationEventManager = OrientationEventManager() 33 | private val orientationEventListener = object : OrientationEventManager.OnOrientationChangeListener { 34 | override fun onOrientationLandscape(videoView: VideoView?) { 35 | //横屏 36 | videoView?.let { 37 | MediaPlayerManager.startFullscreen(this@FullscreenActivity, it as FullscreenVideoView) 38 | } 39 | } 40 | 41 | override fun onOrientationReverseLandscape(videoView: VideoView?) { 42 | //反向横屏 43 | videoView?.let { 44 | MediaPlayerManager.startFullscreenReverse(this@FullscreenActivity, it as FullscreenVideoView) 45 | } 46 | } 47 | 48 | override fun onOrientationPortrait(videoView: VideoView?) { 49 | //竖屏 50 | videoView?.let { 51 | MediaPlayerManager.dismissFullscreen(this@FullscreenActivity) 52 | } 53 | } 54 | 55 | } 56 | 57 | override fun onCreate(savedInstanceState: Bundle?) { 58 | super.onCreate(savedInstanceState) 59 | setContentView(R.layout.activity_fullscreen) 60 | } 61 | 62 | override fun onConfigurationChanged(newConfig: Configuration) { 63 | super.onConfigurationChanged(newConfig) 64 | } 65 | 66 | fun onClick(view: View) { 67 | when (view.id) { 68 | R.id.start -> { 69 | val fullScreenVideoView = FullscreenVideoView(context = this, origin = video_view).apply { 70 | this.isVolumeGestureEnable = cb_volume_gesture_enable.isChecked 71 | this.isBrightnessGestureEnable = cb_brightness_gesture_enable.isChecked 72 | this.isProgressGestureEnable = cb_progress_gesture_enable.isChecked 73 | } 74 | val systemMediaPlayer = SystemMediaPlayer() 75 | systemMediaPlayer.setDataSource(this, Uri.parse(randomVideo?.url)) 76 | fullScreenVideoView.mediaPlayer = systemMediaPlayer 77 | video_view.mediaPlayer = systemMediaPlayer 78 | if (cb_auto_orientate_enable.isChecked) { 79 | orientationEventManager.orientationEnable(this, fullScreenVideoView, orientationEventListener) 80 | } else { 81 | orientationEventManager.orientationDisable() 82 | } 83 | //开始播放 84 | fullScreenVideoView.prepare() 85 | MediaPlayerManager.startFullscreen(this, fullScreenVideoView) 86 | } 87 | } 88 | } 89 | 90 | override fun onResume() { 91 | super.onResume() 92 | } 93 | 94 | override fun onPause() { 95 | super.onPause() 96 | } 97 | 98 | override fun onBackPressed() { 99 | super.onBackPressed() 100 | } 101 | } -------------------------------------------------------------------------------- /app/src/main/java/org/salient/artvideoplayer/activity/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package org.salient.artvideoplayer.activity 2 | 3 | import android.content.Intent 4 | import android.net.Uri 5 | import android.os.Bundle 6 | import android.view.Menu 7 | import android.view.MenuItem 8 | import android.view.View 9 | import androidx.appcompat.widget.Toolbar 10 | import kotlinx.android.synthetic.main.content_main.* 11 | import org.salient.artplayer.MediaPlayerManager 12 | import org.salient.artplayer.conduction.PlayerState 13 | import org.salient.artplayer.exo.ExoMediaPlayer 14 | import org.salient.artplayer.exo.ExoSourceBuilder 15 | import org.salient.artplayer.ijk.IjkPlayer 16 | import org.salient.artplayer.player.IMediaPlayer 17 | import org.salient.artplayer.player.SystemMediaPlayer 18 | import org.salient.artplayer.ui.FullscreenVideoView 19 | import org.salient.artplayer.ui.TinyVideoView 20 | import org.salient.artvideoplayer.BaseActivity 21 | import org.salient.artvideoplayer.R 22 | import java.io.IOException 23 | 24 | /** 25 | * description: 首页 26 | * 27 | * @author Maiwenchang 28 | * email: cv.stronger@gmail.com 29 | * date: 2020-05-20 09:06 AM. 30 | */ 31 | class MainActivity : BaseActivity() { 32 | 33 | override fun onCreate(savedInstanceState: Bundle?) { 34 | super.onCreate(savedInstanceState) 35 | setContentView(R.layout.activity_main) 36 | val toolbar = findViewById(R.id.toolbar) as Toolbar 37 | setSupportActionBar(toolbar) 38 | 39 | setupMediaPlayer(SystemMediaPlayer()) 40 | 41 | btn_start.setOnClickListener { 42 | //开始播放 43 | if (artVideoView.playerState == PlayerState.INITIALIZED) { 44 | artVideoView.prepare() 45 | } else if (artVideoView.playerState == PlayerState.STOPPED) { 46 | artVideoView.prepare() 47 | } else if (!artVideoView.isPlaying) { 48 | artVideoView.start() 49 | } 50 | } 51 | 52 | btn_pause.setOnClickListener { 53 | artVideoView.pause() 54 | } 55 | 56 | btn_stop.setOnClickListener { 57 | artVideoView.stop() 58 | } 59 | 60 | btn_fullscreen.setOnClickListener { 61 | //开启全屏 62 | val fullScreenVideoView = FullscreenVideoView(this, origin = artVideoView) 63 | fullScreenVideoView.mediaPlayer = artVideoView.mediaPlayer 64 | MediaPlayerManager.startFullscreen(this, fullScreenVideoView) 65 | 66 | fullScreenVideoView.setOnClickListener { 67 | if (!fullScreenVideoView.isPlaying) { 68 | fullScreenVideoView.start() 69 | } 70 | } 71 | } 72 | 73 | btn_tiny.setOnClickListener { 74 | //开启小窗 75 | val tinyVideoView = TinyVideoView(this, origin = artVideoView) 76 | tinyVideoView.mediaPlayer = artVideoView.mediaPlayer 77 | MediaPlayerManager.startTinyWindow(this, tinyVideoView) 78 | 79 | tinyVideoView.setOnClickListener { 80 | if (!tinyVideoView.isPlaying) { 81 | tinyVideoView.start() 82 | } 83 | } 84 | } 85 | 86 | } 87 | 88 | private fun setupMediaPlayer(mediaPlayer: IMediaPlayer<*>) { 89 | artVideoView.mediaPlayer?.release() 90 | artVideoView.mediaPlayer = mediaPlayer 91 | when (mediaPlayer) { 92 | is SystemMediaPlayer -> { 93 | mediaPlayer.setDataSource(this, Uri.parse("http://vfx.mtime.cn/Video/2018/07/06/mp4/180706094003288023.mp4")) 94 | } 95 | is IjkPlayer -> { 96 | mediaPlayer.setDataSource(this, Uri.parse("http://vfx.mtime.cn/Video/2018/07/06/mp4/180706094003288023.mp4")) 97 | } 98 | is ExoMediaPlayer -> { 99 | val mediaSource = ExoSourceBuilder(this, "http://vfx.mtime.cn/Video/2018/07/06/mp4/180706094003288023.mp4") 100 | .apply { 101 | this.isLooping = false 102 | this.cacheEnable = true 103 | } 104 | .build() 105 | mediaPlayer.mediaSource = mediaSource 106 | } 107 | } 108 | 109 | 110 | } 111 | 112 | fun onClick(view: View) { 113 | when (view.id) { 114 | R.id.play -> { 115 | val url = edUrl!!.text.toString() 116 | SystemMediaPlayer().also { 117 | try { 118 | it.impl.setDataSource(this, Uri.parse(url)) 119 | } catch (e: IOException) { 120 | e.printStackTrace() 121 | } 122 | }.let { 123 | artVideoView.mediaPlayer = it 124 | } 125 | artVideoView.prepare() 126 | } 127 | R.id.fullWindow -> { 128 | startActivity(Intent(this, FullscreenActivity::class.java)) 129 | } 130 | R.id.tinyWindow -> { 131 | startActivity(Intent(this, TinyWindowActivity::class.java)) 132 | } 133 | } 134 | } 135 | 136 | protected var mMenu: Menu? = null 137 | 138 | override fun onCreateOptionsMenu(menu: Menu): Boolean { // Inflate the menu; this adds items to the action bar if it is present. 139 | menuInflater.inflate(R.menu.menu_bar_setting, menu) 140 | mMenu = menu 141 | refreshMenuState() 142 | return true 143 | } 144 | 145 | override fun onMenuOpened(featureId: Int, menu: Menu): Boolean { 146 | if (mMenu == null) return super.onMenuOpened(featureId, menu) 147 | refreshMenuState() 148 | return super.onMenuOpened(featureId, mMenu!!) 149 | } 150 | 151 | override fun onOptionsItemSelected(item: MenuItem): Boolean { 152 | if (item.isChecked) return super.onOptionsItemSelected(item) 153 | val id = item.itemId 154 | when (id) { 155 | R.id.menu_MediaPlayer -> { 156 | mMenu?.getItem(0)?.title = "Using: MediaPlayer" 157 | setupMediaPlayer(SystemMediaPlayer()) 158 | } 159 | R.id.menu_IjkPlayer -> { 160 | mMenu?.getItem(0)?.title = "Using: IjkPlayer" 161 | setupMediaPlayer(IjkPlayer()) 162 | } 163 | R.id.menu_ExoPlayer -> { 164 | mMenu?.getItem(0)?.title = "Using: ExoPlayer" 165 | setupMediaPlayer(ExoMediaPlayer(this)) 166 | } 167 | } 168 | return super.onOptionsItemSelected(item) 169 | } 170 | 171 | /** 172 | * 刷新标题栏菜单状态 173 | */ 174 | private fun refreshMenuState() { 175 | mMenu?.also { 176 | when (artVideoView.mediaPlayer) { 177 | is SystemMediaPlayer -> { 178 | it.getItem(1).getSubMenu().getItem(0).setChecked(true); 179 | it.getItem(0).setTitle("Using: MediaPlayer"); 180 | } 181 | is IjkPlayer -> { 182 | it.getItem(1).getSubMenu().getItem(1).setChecked(true); 183 | it.getItem(0).setTitle("Using: IjkPlayer"); 184 | } 185 | is ExoMediaPlayer -> { 186 | it.getItem(1).getSubMenu().getItem(2).setChecked(true); 187 | it.getItem(0).setTitle("Using: ExoPlayer"); 188 | } 189 | } 190 | } 191 | } 192 | } -------------------------------------------------------------------------------- /app/src/main/java/org/salient/artvideoplayer/activity/TinyWindowActivity.kt: -------------------------------------------------------------------------------- 1 | package org.salient.artvideoplayer.activity 2 | 3 | import android.content.res.Configuration 4 | import android.net.Uri 5 | import android.os.Bundle 6 | import android.view.Gravity 7 | import android.view.View 8 | import android.widget.FrameLayout 9 | import kotlinx.android.synthetic.main.activity_tiny.* 10 | import org.salient.artplayer.MediaPlayerManager 11 | import org.salient.artplayer.player.SystemMediaPlayer 12 | import org.salient.artplayer.ui.TinyVideoView 13 | import org.salient.artvideoplayer.BaseActivity 14 | import org.salient.artvideoplayer.DensityUtil.getWindowHeight 15 | import org.salient.artvideoplayer.DensityUtil.getWindowWidth 16 | import org.salient.artvideoplayer.R 17 | 18 | /** 19 | * description: 小窗播放demo 20 | * 21 | * @author Maiwenchang 22 | * email: cv.stronger@gmail.com 23 | * date: 2020-05-20 09:06 AM. 24 | */ 25 | class TinyWindowActivity : BaseActivity() { 26 | override fun onCreate(savedInstanceState: Bundle?) { 27 | super.onCreate(savedInstanceState) 28 | setContentView(R.layout.activity_tiny) 29 | } 30 | 31 | override fun onConfigurationChanged(newConfig: Configuration) { 32 | super.onConfigurationChanged(newConfig) 33 | hideSoftInput() 34 | } 35 | 36 | fun onClick(view: View) { 37 | when (view.id) { 38 | R.id.start -> { 39 | hideSoftInput() 40 | //set LayoutParams 41 | val windowWidth = getWindowWidth(this) 42 | val windowHeight = getWindowHeight(this) 43 | var width = Integer.valueOf(width.text.toString()) 44 | var height = Integer.valueOf(height.text.toString()) 45 | if (width > windowWidth) { 46 | width = windowWidth 47 | } 48 | if (height > windowHeight) { 49 | height = windowHeight 50 | } 51 | val layoutParams = FrameLayout.LayoutParams(width, height) 52 | var leftRight = Gravity.END 53 | if (left.isChecked) { 54 | leftRight = Gravity.START 55 | } 56 | var topBottom = Gravity.BOTTOM 57 | if (top.isChecked) { 58 | topBottom = Gravity.TOP 59 | } 60 | layoutParams.gravity = leftRight or topBottom 61 | var marginLeft = Integer.valueOf(marginLeft.text.toString()) 62 | var marginTop = Integer.valueOf(marginTop.text.toString()) 63 | var marginRight = Integer.valueOf(marginRight.text.toString()) 64 | var marginBottom = Integer.valueOf(marginBottom.text.toString()) 65 | if (marginLeft > windowWidth - width) { 66 | marginLeft = windowWidth - width 67 | } 68 | if (marginRight > windowWidth - width) { 69 | marginRight = windowWidth - width 70 | } 71 | if (marginTop > windowHeight - height) { 72 | marginTop = windowHeight - height 73 | } 74 | if (marginBottom > windowHeight - height) { 75 | marginBottom = windowHeight - height 76 | } 77 | layoutParams.setMargins(marginLeft, marginTop, marginRight, marginBottom) 78 | val tinyVideoView = TinyVideoView(context = this, params = layoutParams).apply { 79 | mediaPlayer = SystemMediaPlayer().apply { 80 | val uri = Uri.parse(randomVideo?.url) 81 | setDataSource(this@TinyWindowActivity, uri) 82 | } 83 | isMovable = cb_isMovable.isChecked 84 | isScalable = cb_isScalable.isChecked 85 | } 86 | tinyVideoView.prepare() 87 | MediaPlayerManager.startTinyWindow(this@TinyWindowActivity, tinyVideoView) 88 | } 89 | } 90 | } 91 | 92 | override fun onResume() { 93 | super.onResume() 94 | } 95 | 96 | override fun onPause() { 97 | super.onPause() 98 | } 99 | 100 | override fun onBackPressed() { 101 | super.onBackPressed() 102 | } 103 | } -------------------------------------------------------------------------------- /app/src/main/java/org/salient/artvideoplayer/bean/MovieData.kt: -------------------------------------------------------------------------------- 1 | package org.salient.artvideoplayer.bean 2 | 3 | /** 4 | * Created by Mai on 2018/7/17 5 | * * 6 | * Description: 7 | * * 8 | */ 9 | class MovieData { 10 | var attention: List? = null 11 | var moviecomings: List? = null 12 | 13 | class AttentionBean { 14 | /** 15 | * actor1 : 道恩·强森 16 | * actor2 : 内芙·坎贝尔 17 | * director : 罗森·马歇尔·瑟伯 18 | * id : 234573 19 | * image : http://img5.mtime.cn/mt/2018/07/11/151451.75772708_1280X720X2.jpg 20 | * isFilter : false 21 | * isTicket : false 22 | * isVideo : true 23 | * locationName : 美国 24 | * rDay : 20 25 | * rMonth : 7 26 | * rYear : 2018 27 | * releaseDate : 7月20日上映 28 | * title : 摩天营救 29 | * type : 动作 / 冒险 / 剧情 30 | * videoCount : 3 31 | * videos : [{"hightUrl":"","image":"http://img5.mtime.cn/mg/2018/06/27/094527.12278962.jpg","length":61,"title":"摩天营救 定档预告片","url":"http://vfx.mtime.cn/Video/2018/06/27/mp4/180627094726195356.mp4","videoId":71043},{"hightUrl":"","image":"http://img5.mtime.cn/mg/2018/02/05/144143.61155408.jpg","length":159,"title":"摩天营救 中文版预告片","url":"http://vfx.mtime.cn/Video/2018/02/05/mp4/180205170620160029.mp4","videoId":69545},{"hightUrl":"","image":"http://img5.mtime.cn/mg/2018/02/03/085022.69184529.jpg","length":123,"title":"摩天营救 先导预告片","url":"http://vfx.mtime.cn/Video/2018/02/03/mp4/180203084924515223.mp4","videoId":69520}] 32 | * wantedCount : 853 33 | */ 34 | var actor1: String? = null 35 | var actor2: String? = null 36 | var director: String? = null 37 | var id = 0 38 | var image: String? = null 39 | var isIsFilter = false 40 | private set 41 | var isIsTicket = false 42 | private set 43 | var isIsVideo = false 44 | private set 45 | var locationName: String? = null 46 | var rDay = 0 47 | var rMonth = 0 48 | var rYear = 0 49 | var releaseDate: String? = null 50 | var title: String? = null 51 | var type: String? = null 52 | var videoCount = 0 53 | var wantedCount = 0 54 | var videos: List? = null 55 | 56 | fun setIsFilter(isFilter: Boolean) { 57 | isIsFilter = isFilter 58 | } 59 | 60 | fun setIsTicket(isTicket: Boolean) { 61 | isIsTicket = isTicket 62 | } 63 | 64 | fun setIsVideo(isVideo: Boolean) { 65 | isIsVideo = isVideo 66 | } 67 | 68 | } 69 | 70 | class MoviecomingsBean { 71 | /** 72 | * actor1 : 方城淞 73 | * actor2 : 74 | * director : 高建国 75 | * id : 258415 76 | * image : http://img5.mtime.cn/mt/2018/06/20/113940.34629012_1280X720X2.jpg 77 | * isFilter : false 78 | * isTicket : false 79 | * isVideo : false 80 | * locationName : 中国 81 | * rDay : 19 82 | * rMonth : 7 83 | * rYear : 2018 84 | * releaseDate : 7月19日上映 85 | * title : 八只鸡 86 | * type : 87 | * videoCount : 0 88 | * videos : [] 89 | * wantedCount : 25 90 | */ 91 | var actor1: String? = null 92 | var actor2: String? = null 93 | var director: String? = null 94 | var id = 0 95 | var image: String? = null 96 | var isIsFilter = false 97 | private set 98 | var isIsTicket = false 99 | private set 100 | var isIsVideo = false 101 | private set 102 | var locationName: String? = null 103 | var rDay = 0 104 | var rMonth = 0 105 | var rYear = 0 106 | var releaseDate: String? = null 107 | var title: String? = null 108 | var type: String? = null 109 | var videoCount = 0 110 | var wantedCount = 0 111 | var videos: List? = null 112 | 113 | fun setIsFilter(isFilter: Boolean) { 114 | isIsFilter = isFilter 115 | } 116 | 117 | fun setIsTicket(isTicket: Boolean) { 118 | isIsTicket = isTicket 119 | } 120 | 121 | fun setIsVideo(isVideo: Boolean) { 122 | isIsVideo = isVideo 123 | } 124 | 125 | } 126 | } -------------------------------------------------------------------------------- /app/src/main/java/org/salient/artvideoplayer/bean/VideoBean.kt: -------------------------------------------------------------------------------- 1 | package org.salient.artvideoplayer.bean 2 | 3 | /** 4 | * Created by Mai on 2018/7/17 5 | * * 6 | * Description: 7 | * * 8 | */ 9 | class VideoBean { 10 | /** 11 | * hightUrl : 12 | * image : http://img5.mtime.cn/mg/2018/06/27/094527.12278962.jpg 13 | * length : 61 14 | * title : 摩天营救 定档预告片 15 | * url : http://vfx.mtime.cn/Video/2018/06/27/mp4/180627094726195356.mp4 16 | * videoId : 71043 17 | */ 18 | var hightUrl: String? = null 19 | var image: String? = null 20 | var length = 0 21 | var title: String? = null 22 | var url: String? = null 23 | var videoId = 0 24 | var listPosition = 0 25 | 26 | } -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_api.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 |