Browse Source

YCVideoPlayer

潇湘剑雨 7 years ago
parent
commit
4bf4858560
100 changed files with 4261 additions and 0 deletions
  1. 91 0
      .idea/inspectionProfiles/Project_Default.xml
  2. 49 0
      .idea/misc.xml
  3. 11 0
      .idea/modules.xml
  4. 12 0
      .idea/runConfigurations.xml
  5. 6 0
      .idea/smartfox_info.xml
  6. 6 0
      .idea/vcs.xml
  7. 1 0
      YCVideoPlayerLib/.gitignore
  8. 149 0
      YCVideoPlayerLib/build.gradle
  9. 21 0
      YCVideoPlayerLib/proguard-rules.pro
  10. 2 0
      YCVideoPlayerLib/src/main/AndroidManifest.xml
  11. 312 0
      YCVideoPlayerLib/src/main/java/org/yczbj/ycvideoplayerlib/AbsVideoPlayerController.java
  12. 119 0
      YCVideoPlayerLib/src/main/java/org/yczbj/ycvideoplayerlib/ChangeClarityDialog.java
  13. 181 0
      YCVideoPlayerLib/src/main/java/org/yczbj/ycvideoplayerlib/InterVideoPlayer.java
  14. 41 0
      YCVideoPlayerLib/src/main/java/org/yczbj/ycvideoplayerlib/VideoClarity.java
  15. 23 0
      YCVideoPlayerLib/src/main/java/org/yczbj/ycvideoplayerlib/VideoLogUtil.java
  16. 895 0
      YCVideoPlayerLib/src/main/java/org/yczbj/ycvideoplayerlib/VideoPlayer.java
  17. 587 0
      YCVideoPlayerLib/src/main/java/org/yczbj/ycvideoplayerlib/VideoPlayerController.java
  18. 61 0
      YCVideoPlayerLib/src/main/java/org/yczbj/ycvideoplayerlib/VideoPlayerManager.java
  19. 138 0
      YCVideoPlayerLib/src/main/java/org/yczbj/ycvideoplayerlib/VideoPlayerUtils.java
  20. 109 0
      YCVideoPlayerLib/src/main/java/org/yczbj/ycvideoplayerlib/VideoTextureView.java
  21. 7 0
      YCVideoPlayerLib/src/main/res/color/select_change_clarity_color.xml
  22. BIN
      YCVideoPlayerLib/src/main/res/drawable-xhdpi/battery_10.png
  23. BIN
      YCVideoPlayerLib/src/main/res/drawable-xhdpi/battery_100.png
  24. BIN
      YCVideoPlayerLib/src/main/res/drawable-xhdpi/battery_20.png
  25. BIN
      YCVideoPlayerLib/src/main/res/drawable-xhdpi/battery_50.png
  26. BIN
      YCVideoPlayerLib/src/main/res/drawable-xhdpi/battery_80.png
  27. BIN
      YCVideoPlayerLib/src/main/res/drawable-xhdpi/battery_charging.png
  28. BIN
      YCVideoPlayerLib/src/main/res/drawable-xhdpi/battery_full.png
  29. BIN
      YCVideoPlayerLib/src/main/res/drawable-xhdpi/ic_palyer_brightness.png
  30. BIN
      YCVideoPlayerLib/src/main/res/drawable-xhdpi/ic_palyer_share.png
  31. BIN
      YCVideoPlayerLib/src/main/res/drawable-xhdpi/ic_palyer_volume.png
  32. BIN
      YCVideoPlayerLib/src/main/res/drawable-xhdpi/ic_player_back.png
  33. BIN
      YCVideoPlayerLib/src/main/res/drawable-xhdpi/ic_player_center_start.png
  34. BIN
      YCVideoPlayerLib/src/main/res/drawable-xhdpi/ic_player_enlarge.png
  35. BIN
      YCVideoPlayerLib/src/main/res/drawable-xhdpi/ic_player_pause.png
  36. BIN
      YCVideoPlayerLib/src/main/res/drawable-xhdpi/ic_player_replay.png
  37. BIN
      YCVideoPlayerLib/src/main/res/drawable-xhdpi/ic_player_shrink.png
  38. BIN
      YCVideoPlayerLib/src/main/res/drawable-xhdpi/ic_player_start.png
  39. BIN
      YCVideoPlayerLib/src/main/res/drawable-xhdpi/loading00.png
  40. BIN
      YCVideoPlayerLib/src/main/res/drawable-xhdpi/loading01.png
  41. BIN
      YCVideoPlayerLib/src/main/res/drawable-xhdpi/loading02.png
  42. BIN
      YCVideoPlayerLib/src/main/res/drawable-xhdpi/loading03.png
  43. BIN
      YCVideoPlayerLib/src/main/res/drawable-xhdpi/loading04.png
  44. BIN
      YCVideoPlayerLib/src/main/res/drawable-xhdpi/loading05.png
  45. BIN
      YCVideoPlayerLib/src/main/res/drawable-xhdpi/loading06.png
  46. BIN
      YCVideoPlayerLib/src/main/res/drawable-xhdpi/loading07.png
  47. BIN
      YCVideoPlayerLib/src/main/res/drawable-xhdpi/loading08.png
  48. BIN
      YCVideoPlayerLib/src/main/res/drawable-xhdpi/loading09.png
  49. BIN
      YCVideoPlayerLib/src/main/res/drawable-xhdpi/loading10.png
  50. BIN
      YCVideoPlayerLib/src/main/res/drawable-xhdpi/loading11.png
  51. BIN
      YCVideoPlayerLib/src/main/res/drawable-xhdpi/loading12.png
  52. BIN
      YCVideoPlayerLib/src/main/res/drawable-xhdpi/loading13.png
  53. BIN
      YCVideoPlayerLib/src/main/res/drawable-xhdpi/loading14.png
  54. BIN
      YCVideoPlayerLib/src/main/res/drawable-xhdpi/loading15.png
  55. BIN
      YCVideoPlayerLib/src/main/res/drawable-xhdpi/loading16.png
  56. BIN
      YCVideoPlayerLib/src/main/res/drawable-xhdpi/loading17.png
  57. BIN
      YCVideoPlayerLib/src/main/res/drawable-xhdpi/loading18.png
  58. BIN
      YCVideoPlayerLib/src/main/res/drawable-xhdpi/loading19.png
  59. BIN
      YCVideoPlayerLib/src/main/res/drawable-xhdpi/loading20.png
  60. BIN
      YCVideoPlayerLib/src/main/res/drawable-xhdpi/loading21.png
  61. BIN
      YCVideoPlayerLib/src/main/res/drawable-xhdpi/loading22.png
  62. BIN
      YCVideoPlayerLib/src/main/res/drawable-xhdpi/loading23.png
  63. BIN
      YCVideoPlayerLib/src/main/res/drawable-xhdpi/loading24.png
  64. BIN
      YCVideoPlayerLib/src/main/res/drawable-xhdpi/loading25.png
  65. BIN
      YCVideoPlayerLib/src/main/res/drawable-xhdpi/loading26.png
  66. BIN
      YCVideoPlayerLib/src/main/res/drawable-xhdpi/loading27.png
  67. BIN
      YCVideoPlayerLib/src/main/res/drawable-xhdpi/loading28.png
  68. BIN
      YCVideoPlayerLib/src/main/res/drawable-xhdpi/loading29.png
  69. BIN
      YCVideoPlayerLib/src/main/res/drawable-xhdpi/player_mask_bottom.png
  70. BIN
      YCVideoPlayerLib/src/main/res/drawable-xhdpi/player_mask_top.png
  71. 14 0
      YCVideoPlayerLib/src/main/res/drawable/bg_change_clarity_checked.xml
  72. 14 0
      YCVideoPlayerLib/src/main/res/drawable/bg_change_clarity_normal.xml
  73. 6 0
      YCVideoPlayerLib/src/main/res/drawable/bg_radius_4.xml
  74. 6 0
      YCVideoPlayerLib/src/main/res/drawable/bg_retry.xml
  75. 34 0
      YCVideoPlayerLib/src/main/res/drawable/loading.xml
  76. 17 0
      YCVideoPlayerLib/src/main/res/drawable/pb_change.xml
  77. 28 0
      YCVideoPlayerLib/src/main/res/drawable/seek_progress.xml
  78. 5 0
      YCVideoPlayerLib/src/main/res/drawable/seek_thumb.xml
  79. 24 0
      YCVideoPlayerLib/src/main/res/drawable/seek_thumb_normal.xml
  80. 23 0
      YCVideoPlayerLib/src/main/res/drawable/seek_thumb_pressed.xml
  81. 7 0
      YCVideoPlayerLib/src/main/res/drawable/select_change_clarity.xml
  82. 10 0
      YCVideoPlayerLib/src/main/res/layout/change_video_clarity.xml
  83. 321 0
      YCVideoPlayerLib/src/main/res/layout/custom_video_player.xml
  84. 4 0
      YCVideoPlayerLib/src/main/res/values/colors.xml
  85. 3 0
      YCVideoPlayerLib/src/main/res/values/strings.xml
  86. 10 0
      YCVideoPlayerLib/src/main/res/values/styles.xml
  87. 1 0
      app/.gitignore
  88. 84 0
      app/build.gradle
  89. 21 0
      app/proguard-rules.pro
  90. 26 0
      app/src/androidTest/java/org/yczbj/ycvideoplayer/ExampleInstrumentedTest.java
  91. 74 0
      app/src/main/AndroidManifest.xml
  92. 23 0
      app/src/main/assets/jzvd.html
  93. BIN
      app/src/main/assets/local_video.mp4
  94. 29 0
      app/src/main/java/org/yczbj/ycvideoplayer/api/Constant.java
  95. 132 0
      app/src/main/java/org/yczbj/ycvideoplayer/base/AppManager.java
  96. 142 0
      app/src/main/java/org/yczbj/ycvideoplayer/base/BaseActivity.java
  97. 120 0
      app/src/main/java/org/yczbj/ycvideoplayer/base/BaseApplication.java
  98. 75 0
      app/src/main/java/org/yczbj/ycvideoplayer/base/BaseDelegateAdapter.java
  99. 111 0
      app/src/main/java/org/yczbj/ycvideoplayer/base/BaseFragment.java
  100. 76 0
      app/src/main/java/org/yczbj/ycvideoplayer/base/BasePagerAdapter.java

+ 91 - 0
.idea/inspectionProfiles/Project_Default.xml

@@ -0,0 +1,91 @@
+<component name="InspectionProjectProfileManager">
+  <profile version="1.0">
+    <option name="myName" value="Project Default" />
+    <inspection_tool class="AliAccessStaticViaInstance" enabled="false" level="BLOCKER" enabled_by_default="false" />
+    <inspection_tool class="AliAccessToNonThreadSafeStaticFieldFromInstance" enabled="false" level="CRITICAL" enabled_by_default="false" />
+    <inspection_tool class="AliArrayNamingShouldHaveBracket" enabled="false" level="MAJOR" enabled_by_default="false" />
+    <inspection_tool class="AliControlFlowStatementWithoutBraces" enabled="false" level="BLOCKER" enabled_by_default="false" />
+    <inspection_tool class="AliDeprecation" enabled="false" level="CRITICAL" enabled_by_default="false" />
+    <inspection_tool class="AliEqualsAvoidNull" enabled="false" level="CRITICAL" enabled_by_default="false" />
+    <inspection_tool class="AliLongLiteralsEndingWithLowercaseL" enabled="false" level="BLOCKER" enabled_by_default="false" />
+    <inspection_tool class="AliMissingOverrideAnnotation" enabled="false" level="BLOCKER" enabled_by_default="false" />
+    <inspection_tool class="AliWrapperTypeEquality" enabled="false" level="BLOCKER" enabled_by_default="false" />
+    <inspection_tool class="AlibabaAbstractClassShouldStartWithAbstractNaming" enabled="false" level="CRITICAL" enabled_by_default="false" />
+    <inspection_tool class="AlibabaAbstractMethodOrInterfaceMethodMustUseJavadoc" enabled="false" level="MAJOR" enabled_by_default="false" />
+    <inspection_tool class="AlibabaAvoidApacheBeanUtilsCopy" enabled="false" level="BLOCKER" enabled_by_default="false" />
+    <inspection_tool class="AlibabaAvoidCommentBehindStatement" enabled="false" level="MAJOR" enabled_by_default="false" />
+    <inspection_tool class="AlibabaAvoidComplexCondition" enabled="false" level="MAJOR" enabled_by_default="false" />
+    <inspection_tool class="AlibabaAvoidConcurrentCompetitionRandom" enabled="false" level="MAJOR" enabled_by_default="false" />
+    <inspection_tool class="AlibabaAvoidManuallyCreateThread" enabled="false" level="CRITICAL" enabled_by_default="false" />
+    <inspection_tool class="AlibabaAvoidMissUseOfMathRandom" enabled="false" level="MAJOR" enabled_by_default="false" />
+    <inspection_tool class="AlibabaAvoidNewDateGetTime" enabled="false" level="BLOCKER" enabled_by_default="false" />
+    <inspection_tool class="AlibabaAvoidPatternCompileInMethod" enabled="false" level="BLOCKER" enabled_by_default="false" />
+    <inspection_tool class="AlibabaAvoidReturnInFinally" enabled="false" level="CRITICAL" enabled_by_default="false" />
+    <inspection_tool class="AlibabaAvoidStartWithDollarAndUnderLineNaming" enabled="false" level="CRITICAL" enabled_by_default="false" />
+    <inspection_tool class="AlibabaAvoidUseTimer" enabled="false" level="BLOCKER" enabled_by_default="false" />
+    <inspection_tool class="AlibabaBooleanPropertyShouldNotStartWithIs" enabled="false" level="CRITICAL" enabled_by_default="false" />
+    <inspection_tool class="AlibabaClassCastExceptionWithSubListToArrayList" enabled="false" level="CRITICAL" enabled_by_default="false" />
+    <inspection_tool class="AlibabaClassCastExceptionWithToArray" enabled="false" level="CRITICAL" enabled_by_default="false" />
+    <inspection_tool class="AlibabaClassMustHaveAuthor" enabled="false" level="MAJOR" enabled_by_default="false" />
+    <inspection_tool class="AlibabaClassNamingShouldBeCamel" enabled="false" level="MAJOR" enabled_by_default="false" />
+    <inspection_tool class="AlibabaCollectionInitShouldAssignCapacity" enabled="false" level="MAJOR" enabled_by_default="false" />
+    <inspection_tool class="AlibabaCommentsMustBeJavadocFormat" enabled="false" level="MAJOR" enabled_by_default="false" />
+    <inspection_tool class="AlibabaConcurrentExceptionWithModifyOriginSubList" enabled="false" level="CRITICAL" enabled_by_default="false" />
+    <inspection_tool class="AlibabaConstantFieldShouldBeUpperCase" enabled="false" level="CRITICAL" enabled_by_default="false" />
+    <inspection_tool class="AlibabaCountDownShouldInFinally" enabled="false" level="MAJOR" enabled_by_default="false" />
+    <inspection_tool class="AlibabaDontModifyInForeachCircle" enabled="false" level="BLOCKER" enabled_by_default="false" />
+    <inspection_tool class="AlibabaEnumConstantsMustHaveComment" enabled="false" level="CRITICAL" enabled_by_default="false" />
+    <inspection_tool class="AlibabaExceptionClassShouldEndWithException" enabled="false" level="CRITICAL" enabled_by_default="false" />
+    <inspection_tool class="AlibabaIbatisMethodQueryForList" enabled="false" level="MAJOR" enabled_by_default="false" />
+    <inspection_tool class="AlibabaLowerCamelCaseVariableNaming" enabled="false" level="CRITICAL" enabled_by_default="false" />
+    <inspection_tool class="AlibabaMethodReturnWrapperType" enabled="false" level="MAJOR" enabled_by_default="false" />
+    <inspection_tool class="AlibabaPackageNaming" enabled="false" level="MAJOR" enabled_by_default="false" />
+    <inspection_tool class="AlibabaPojoMustOverrideToString" enabled="false" level="MAJOR" enabled_by_default="false" />
+    <inspection_tool class="AlibabaPojoMustUsePrimitiveField" enabled="false" level="MAJOR" enabled_by_default="false" />
+    <inspection_tool class="AlibabaPojoNoDefaultValue" enabled="false" level="MAJOR" enabled_by_default="false" />
+    <inspection_tool class="AlibabaRemoveCommentedCode" enabled="false" level="MAJOR" enabled_by_default="false" />
+    <inspection_tool class="AlibabaServiceOrDaoClassShouldEndWithImpl" enabled="false" level="CRITICAL" enabled_by_default="false" />
+    <inspection_tool class="AlibabaStringConcat" enabled="false" level="MAJOR" enabled_by_default="false" />
+    <inspection_tool class="AlibabaSwitchStatement" enabled="false" level="CRITICAL" enabled_by_default="false" />
+    <inspection_tool class="AlibabaTestClassShouldEndWithTestNaming" enabled="false" level="MAJOR" enabled_by_default="false" />
+    <inspection_tool class="AlibabaThreadLocalShouldRemove" enabled="false" level="CRITICAL" enabled_by_default="false" />
+    <inspection_tool class="AlibabaThreadPoolCreation" enabled="false" level="BLOCKER" enabled_by_default="false" />
+    <inspection_tool class="AlibabaThreadShouldSetName" enabled="false" level="CRITICAL" enabled_by_default="false" />
+    <inspection_tool class="AlibabaTransactionMustHaveRollback" enabled="false" level="MAJOR" enabled_by_default="false" />
+    <inspection_tool class="AlibabaUndefineMagicConstant" enabled="false" level="MAJOR" enabled_by_default="false" />
+    <inspection_tool class="AlibabaUnsupportedExceptionWithModifyAsList" enabled="false" level="CRITICAL" enabled_by_default="false" />
+    <inspection_tool class="AlibabaUseQuietReferenceNotation" enabled="false" level="MAJOR" enabled_by_default="false" />
+    <inspection_tool class="JavaDoc" enabled="true" level="WARNING" enabled_by_default="true">
+      <option name="TOP_LEVEL_CLASS_OPTIONS">
+        <value>
+          <option name="ACCESS_JAVADOC_REQUIRED_FOR" value="none" />
+          <option name="REQUIRED_TAGS" value="" />
+        </value>
+      </option>
+      <option name="INNER_CLASS_OPTIONS">
+        <value>
+          <option name="ACCESS_JAVADOC_REQUIRED_FOR" value="none" />
+          <option name="REQUIRED_TAGS" value="" />
+        </value>
+      </option>
+      <option name="METHOD_OPTIONS">
+        <value>
+          <option name="ACCESS_JAVADOC_REQUIRED_FOR" value="none" />
+          <option name="REQUIRED_TAGS" value="@return@param@throws or @exception" />
+        </value>
+      </option>
+      <option name="FIELD_OPTIONS">
+        <value>
+          <option name="ACCESS_JAVADOC_REQUIRED_FOR" value="none" />
+          <option name="REQUIRED_TAGS" value="" />
+        </value>
+      </option>
+      <option name="IGNORE_DEPRECATED" value="false" />
+      <option name="IGNORE_JAVADOC_PERIOD" value="true" />
+      <option name="IGNORE_DUPLICATED_THROWS" value="false" />
+      <option name="IGNORE_POINT_TO_ITSELF" value="false" />
+      <option name="myAdditionalJavadocTags" value="date" />
+    </inspection_tool>
+    <inspection_tool class="MapOrSetKeyShouldOverrideHashCodeEquals" enabled="false" level="CRITICAL" enabled_by_default="false" />
+  </profile>
+</component>

+ 49 - 0
.idea/misc.xml

@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="NullableNotNullManager">
+    <option name="myDefaultNullable" value="android.support.annotation.Nullable" />
+    <option name="myDefaultNotNull" value="android.support.annotation.NonNull" />
+    <option name="myNullables">
+      <value>
+        <list size="4">
+          <item index="0" class="java.lang.String" itemvalue="org.jetbrains.annotations.Nullable" />
+          <item index="1" class="java.lang.String" itemvalue="javax.annotation.Nullable" />
+          <item index="2" class="java.lang.String" itemvalue="edu.umd.cs.findbugs.annotations.Nullable" />
+          <item index="3" class="java.lang.String" itemvalue="android.support.annotation.Nullable" />
+        </list>
+      </value>
+    </option>
+    <option name="myNotNulls">
+      <value>
+        <list size="4">
+          <item index="0" class="java.lang.String" itemvalue="org.jetbrains.annotations.NotNull" />
+          <item index="1" class="java.lang.String" itemvalue="javax.annotation.Nonnull" />
+          <item index="2" class="java.lang.String" itemvalue="edu.umd.cs.findbugs.annotations.NonNull" />
+          <item index="3" class="java.lang.String" itemvalue="android.support.annotation.NonNull" />
+        </list>
+      </value>
+    </option>
+  </component>
+  <component name="ProjectRootManager" version="2" languageLevel="JDK_1_7" default="true" project-jdk-name="1.8" project-jdk-type="JavaSDK">
+    <output url="file://$PROJECT_DIR$/build/classes" />
+  </component>
+  <component name="ProjectType">
+    <option name="id" value="Android" />
+  </component>
+  <component name="masterDetails">
+    <states>
+      <state key="ProjectJDKs.UI">
+        <settings>
+          <last-edited>1.8</last-edited>
+          <splitter-proportions>
+            <option name="proportions">
+              <list>
+                <option value="0.2" />
+              </list>
+            </option>
+          </splitter-proportions>
+        </settings>
+      </state>
+    </states>
+  </component>
+</project>

+ 11 - 0
.idea/modules.xml

@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="ProjectModuleManager">
+    <modules>
+      <module fileurl="file://$PROJECT_DIR$/YCVideoPlayer.iml" filepath="$PROJECT_DIR$/YCVideoPlayer.iml" />
+      <module fileurl="file://$PROJECT_DIR$/YCVideoPlayerLib/YCVideoPlayerLib.iml" filepath="$PROJECT_DIR$/YCVideoPlayerLib/YCVideoPlayerLib.iml" />
+      <module fileurl="file://$PROJECT_DIR$/app/app.iml" filepath="$PROJECT_DIR$/app/app.iml" />
+      <module fileurl="file://$PROJECT_DIR$/jiaozivideoplayer/jiaozivideoplayer.iml" filepath="$PROJECT_DIR$/jiaozivideoplayer/jiaozivideoplayer.iml" />
+    </modules>
+  </component>
+</project>

+ 12 - 0
.idea/runConfigurations.xml

@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="RunConfigurationProducerService">
+    <option name="ignoredProducers">
+      <set>
+        <option value="org.jetbrains.plugins.gradle.execution.test.runner.AllInPackageGradleConfigurationProducer" />
+        <option value="org.jetbrains.plugins.gradle.execution.test.runner.TestClassGradleConfigurationProducer" />
+        <option value="org.jetbrains.plugins.gradle.execution.test.runner.TestMethodGradleConfigurationProducer" />
+      </set>
+    </option>
+  </component>
+</project>

+ 6 - 0
.idea/smartfox_info.xml

@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="SmartFoxProjectConfig">
+    <option name="projectInspectionClosed" value="true" />
+  </component>
+</project>

+ 6 - 0
.idea/vcs.xml

@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="VcsDirectoryMappings">
+    <mapping directory="$PROJECT_DIR$" vcs="Git" />
+  </component>
+</project>

+ 1 - 0
YCVideoPlayerLib/.gitignore

@@ -0,0 +1 @@
+/build

+ 149 - 0
YCVideoPlayerLib/build.gradle

@@ -0,0 +1,149 @@
+apply plugin: 'com.android.library'
+
+android {
+    compileSdkVersion 25
+    buildToolsVersion "25.0.3"
+
+
+    defaultConfig {
+        minSdkVersion 17
+        targetSdkVersion 25
+        versionCode 1
+        versionName "1.0"
+
+        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
+
+    }
+
+    buildTypes {
+        release {
+            minifyEnabled false
+            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
+        }
+    }
+
+}
+
+dependencies {
+    compile fileTree(dir: 'libs', include: ['*.jar'])
+    compile 'com.android.support:appcompat-v7:25.4.0'
+    //这两个是必须要加的,其它的可供选择
+    compile 'tv.danmaku.ijk.media:ijkplayer-java:0.8.4'
+    compile 'tv.danmaku.ijk.media:ijkplayer-armv7a:0.8.4'
+}
+
+/** 以下开始是将Android Library上传到jcenter的相关配置**/
+apply plugin: 'com.github.dcendents.android-maven'
+apply plugin: 'com.jfrog.bintray'
+
+//项目主页
+def siteUrl = 'https://github.com/yangchong211/YCVideoPlayer'    // project homepage
+//项目的版本控制地址
+def gitUrl = 'https://github.com/yangchong211/YCVideoPlayer.git' // project git
+
+//发布到组织名称名字,必须填写
+group = "cn.yc"
+//发布到JCenter上的项目名字,必须填写
+def libName = "YCVideoPlayerLib"
+// 版本号,下次更新是只需要更改版本号即可
+version = "1.1"
+/**  上面配置后上传至jcenter后的编译路径是这样的: compile 'cn.yc:YCVideoPlayerLib:1.1'  **/
+
+//生成源文件
+task sourcesJar(type: Jar) {
+    from android.sourceSets.main.java.srcDirs
+    classifier = 'sources'
+}
+//生成文档
+task javadoc(type: Javadoc) {
+    source = android.sourceSets.main.java.srcDirs
+    classpath += project.files(android.getBootClasspath().join(File.pathSeparator))
+    options.encoding "UTF-8"
+    options.charSet 'UTF-8'
+    options.author true
+    options.version true
+    options.links "https://github.com/linglongxin24/FastDev/tree/master/mylibrary/docs/javadoc"
+    failOnError false
+}
+
+//文档打包成jar
+task javadocJar(type: Jar, dependsOn: javadoc) {
+    classifier = 'javadoc'
+    from javadoc.destinationDir
+}
+//拷贝javadoc文件
+task copyDoc(type: Copy) {
+    from "${buildDir}/docs/"
+    into "docs"
+}
+
+//上传到jcenter所需要的源码文件
+artifacts {
+    archives javadocJar
+    archives sourcesJar
+}
+
+// 配置maven库,生成POM.xml文件
+install {
+    repositories.mavenInstaller {
+        // This generates POM.xml with proper parameters
+        pom {
+            project {
+                packaging 'aar'
+                //项目描述,自由填写
+                name 'This is videoPlayer lib'
+                url siteUrl
+                licenses {
+                    license {
+                        //开源协议
+                        name 'The Apache Software License, Version 2.0'
+                        url 'http://www.apache.org/licenses/LICENSE-2.0.txt'
+                    }
+                }
+                developers {
+                    developer {
+                        //开发者的个人信息,根据个人信息填写
+                        id 'yangchong'
+                        name 'yc'
+                        email 'yangchong211@163.com'
+                    }
+                }
+                scm {
+                    connection gitUrl
+                    developerConnection gitUrl
+                    url siteUrl
+                }
+            }
+        }
+    }
+}
+
+//上传到jcenter
+Properties properties = new Properties()
+properties.load(project.rootProject.file('local.properties').newDataInputStream())
+bintray {
+    user = properties.getProperty("bintray.user")    //读取 local.properties 文件里面的 bintray.user
+    key = properties.getProperty("bintray.apikey")  //读取 local.properties 文件里面的 bintray.apikey
+    configurations = ['archives']
+    pkg {
+        repo = "maven"
+        name = libName    //发布到JCenter上的项目名字,必须填写
+        desc = 'android videoPlayer'    //项目描述
+        websiteUrl = siteUrl
+        vcsUrl = gitUrl
+        licenses = ["Apache-2.0"]
+        publish = true
+    }
+}
+
+javadoc {
+    options {
+        //如果你的项目里面有中文注释的话,必须将格式设置为UTF-8,不然会出现乱码
+        encoding "UTF-8"
+        charSet 'UTF-8'
+        author true
+        version true
+        links "http://docs.oracle.com/javase/7/docs/api"
+    }
+}
+

+ 21 - 0
YCVideoPlayerLib/proguard-rules.pro

@@ -0,0 +1,21 @@
+# Add project specific ProGuard rules here.
+# You can control the set of applied configuration files using the
+# proguardFiles setting in build.gradle.
+#
+# For more details, see
+#   http://developer.android.com/guide/developing/tools/proguard.html
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+#   public *;
+#}
+
+# Uncomment this to preserve the line number information for
+# debugging stack traces.
+#-keepattributes SourceFile,LineNumberTable
+
+# If you keep the line number information, uncomment this to
+# hide the original source file name.
+#-renamesourcefileattribute SourceFile

+ 2 - 0
YCVideoPlayerLib/src/main/AndroidManifest.xml

@@ -0,0 +1,2 @@
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="org.yczbj.ycvideoplayerlib" />

+ 312 - 0
YCVideoPlayerLib/src/main/java/org/yczbj/ycvideoplayerlib/AbsVideoPlayerController.java

@@ -0,0 +1,312 @@
+package org.yczbj.ycvideoplayerlib;
+
+import android.content.Context;
+import android.support.annotation.DrawableRes;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.WindowManager;
+import android.widget.FrameLayout;
+import android.widget.ImageView;
+
+import java.util.Timer;
+import java.util.TimerTask;
+
+/**
+ * @author yc
+ * @date 2017/12/4
+ * 参考项目:
+ * https://github.com/CarGuo/GSYVideoPlayer
+ * https://github.com/danylovolokh/VideoPlayerManager
+ * https://github.com/HotBitmapGG/bilibili-android-client
+ * https://github.com/jjdxmashl/jjdxm_ijkplayer
+ * https://github.com/JasonChow1989/JieCaoVideoPlayer-develop          2年前
+ * https://github.com/open-android/JieCaoVideoPlayer                   1年前
+ * https://github.com/lipangit/JiaoZiVideoPlayer                       4个月前
+ * 个人感觉jiaozi这个播放器,与JieCaoVideoPlayer-develop有惊人的类同,借鉴了上面两个项目[JieCao]
+ *
+ *
+ * 注意:在对应的播放Activity页面,清单文件中一定要添加
+ * android:configChanges="orientation|keyboardHidden|screenSize"
+ * android:screenOrientation="portrait"
+ *
+ * 关于我的github:https://github.com/yangchong211
+ * 关于我的个人网站:www.ycbjie.cn或者www.yczbj.org
+ *
+ * 控制器抽象类
+ */
+
+public abstract class AbsVideoPlayerController extends FrameLayout implements View.OnTouchListener {
+
+    private Context mContext;
+    protected InterVideoPlayer mNiceVideoPlayer;
+    private Timer mUpdateProgressTimer;
+    private TimerTask mUpdateProgressTimerTask;
+    private float mDownX;
+    private float mDownY;
+    private boolean mNeedChangePosition;
+    private boolean mNeedChangeVolume;
+    private boolean mNeedChangeBrightness;
+    private static final int THRESHOLD = 80;
+    private long mGestureDownPosition;
+    private float mGestureDownBrightness;
+    private int mGestureDownVolume;
+    private long mNewPosition;
+
+
+    public AbsVideoPlayerController(Context context) {
+        super(context);
+        mContext = context;
+        this.setOnTouchListener(this);
+    }
+
+    public void setNiceVideoPlayer(InterVideoPlayer niceVideoPlayer) {
+        mNiceVideoPlayer = niceVideoPlayer;
+    }
+
+    /**
+     * 设置播放的视频的标题
+     *
+     * @param title 视频标题
+     */
+    public abstract void setTitle(String title);
+
+    /**
+     * 视频底图
+     *
+     * @param resId 视频底图资源
+     */
+    public abstract void setImage(@DrawableRes int resId);
+
+    /**
+     * 视频底图ImageView控件,提供给外部用图片加载工具来加载网络图片
+     *
+     * @return 底图ImageView
+     */
+    public abstract ImageView imageView();
+
+    /**
+     * 设置总时长.
+     */
+    public abstract void setLength(long length);
+
+    /**
+     * 当播放器的播放状态发生变化,在此方法中国你更新不同的播放状态的UI
+     *
+     * @param playState 播放状态:
+     *                  <ul>
+     *                  <li>{@link VideoPlayer#STATE_IDLE}</li>
+     *                  <li>{@link VideoPlayer#STATE_PREPARING}</li>
+     *                  <li>{@link VideoPlayer#STATE_PREPARED}</li>
+     *                  <li>{@link VideoPlayer#STATE_PLAYING}</li>
+     *                  <li>{@link VideoPlayer#STATE_PAUSED}</li>
+     *                  <li>{@link VideoPlayer#STATE_BUFFERING_PLAYING}</li>
+     *                  <li>{@link VideoPlayer#STATE_BUFFERING_PAUSED}</li>
+     *                  <li>{@link VideoPlayer#STATE_ERROR}</li>
+     *                  <li>{@link VideoPlayer#STATE_COMPLETED}</li>
+     *                  </ul>
+     */
+    protected abstract void onPlayStateChanged(int playState);
+
+    /**
+     * 当播放器的播放模式发生变化,在此方法中更新不同模式下的控制器界面。
+     *
+     * @param playMode 播放器的模式:
+     *                 <ul>
+     *                 <li>{@link VideoPlayer#MODE_NORMAL}</li>
+     *                 <li>{@link VideoPlayer#MODE_FULL_SCREEN}</li>
+     *                 <li>{@link VideoPlayer#MODE_TINY_WINDOW}</li>
+     *                 </ul>
+     */
+    protected abstract void onPlayModeChanged(int playMode);
+
+    /**
+     * 重置控制器,将控制器恢复到初始状态。
+     */
+    protected abstract void reset();
+
+    /**
+     * 开启更新进度的计时器。
+     */
+    protected void startUpdateProgressTimer() {
+        cancelUpdateProgressTimer();
+        if (mUpdateProgressTimer == null) {
+            mUpdateProgressTimer = new Timer();
+        }
+        if (mUpdateProgressTimerTask == null) {
+            mUpdateProgressTimerTask = new TimerTask() {
+                @Override
+                public void run() {
+                    AbsVideoPlayerController.this.post(new Runnable() {
+                        @Override
+                        public void run() {
+                            updateProgress();
+                        }
+                    });
+                }
+            };
+        }
+        mUpdateProgressTimer.schedule(mUpdateProgressTimerTask, 0, 1000);
+    }
+
+    /**
+     * 取消更新进度的计时器。
+     */
+    protected void cancelUpdateProgressTimer() {
+        if (mUpdateProgressTimer != null) {
+            mUpdateProgressTimer.cancel();
+            mUpdateProgressTimer = null;
+        }
+        if (mUpdateProgressTimerTask != null) {
+            mUpdateProgressTimerTask.cancel();
+            mUpdateProgressTimerTask = null;
+        }
+    }
+
+    /**
+     * 更新进度,包括进度条进度,展示的当前播放位置时长,总时长等。
+     */
+    protected abstract void updateProgress();
+
+    @Override
+    public boolean onTouch(View v, MotionEvent event) {
+        // 只有全屏的时候才能拖动位置、亮度、声音
+        if (!mNiceVideoPlayer.isFullScreen()) {
+            return false;
+        }
+        // 只有在播放、暂停、缓冲的时候能够拖动改变位置、亮度和声音
+        if (mNiceVideoPlayer.isIdle() || mNiceVideoPlayer.isError() || mNiceVideoPlayer.isPreparing()
+                || mNiceVideoPlayer.isPrepared() || mNiceVideoPlayer.isCompleted()) {
+            hideChangePosition();
+            hideChangeBrightness();
+            hideChangeVolume();
+            return false;
+        }
+        float x = event.getX();
+        float y = event.getY();
+        switch (event.getAction()) {
+            case MotionEvent.ACTION_DOWN:
+                mDownX = x;
+                mDownY = y;
+                mNeedChangePosition = false;
+                mNeedChangeVolume = false;
+                mNeedChangeBrightness = false;
+                break;
+            case MotionEvent.ACTION_MOVE:
+                float deltaX = x - mDownX;
+                float deltaY = y - mDownY;
+                float absDeltaX = Math.abs(deltaX);
+                float absDeltaY = Math.abs(deltaY);
+                if (!mNeedChangePosition && !mNeedChangeVolume && !mNeedChangeBrightness) {
+                    // 只有在播放、暂停、缓冲的时候能够拖动改变位置、亮度和声音
+                    if (absDeltaX >= THRESHOLD) {
+                        cancelUpdateProgressTimer();
+                        mNeedChangePosition = true;
+                        mGestureDownPosition = mNiceVideoPlayer.getCurrentPosition();
+                    } else if (absDeltaY >= THRESHOLD) {
+                        if (mDownX < getWidth() * 0.5f) {
+                            // 左侧改变亮度
+                            mNeedChangeBrightness = true;
+                            mGestureDownBrightness = VideoPlayerUtils.scanForActivity(mContext)
+                                    .getWindow().getAttributes().screenBrightness;
+                        } else {
+                            // 右侧改变声音
+                            mNeedChangeVolume = true;
+                            mGestureDownVolume = mNiceVideoPlayer.getVolume();
+                        }
+                    }
+                }
+                if (mNeedChangePosition) {
+                    long duration = mNiceVideoPlayer.getDuration();
+                    long toPosition = (long) (mGestureDownPosition + duration * deltaX / getWidth());
+                    mNewPosition = Math.max(0, Math.min(duration, toPosition));
+                    int newPositionProgress = (int) (100f * mNewPosition / duration);
+                    showChangePosition(duration, newPositionProgress);
+                }
+                if (mNeedChangeBrightness) {
+                    deltaY = -deltaY;
+                    float deltaBrightness = deltaY * 3 / getHeight();
+                    float newBrightness = mGestureDownBrightness + deltaBrightness;
+                    newBrightness = Math.max(0, Math.min(newBrightness, 1));
+                    float newBrightnessPercentage = newBrightness;
+                    WindowManager.LayoutParams params = VideoPlayerUtils.scanForActivity(mContext)
+                            .getWindow().getAttributes();
+                    params.screenBrightness = newBrightnessPercentage;
+                    VideoPlayerUtils.scanForActivity(mContext).getWindow().setAttributes(params);
+                    int newBrightnessProgress = (int) (100f * newBrightnessPercentage);
+                    showChangeBrightness(newBrightnessProgress);
+                }
+                if (mNeedChangeVolume) {
+                    deltaY = -deltaY;
+                    int maxVolume = mNiceVideoPlayer.getMaxVolume();
+                    int deltaVolume = (int) (maxVolume * deltaY * 3 / getHeight());
+                    int newVolume = mGestureDownVolume + deltaVolume;
+                    newVolume = Math.max(0, Math.min(maxVolume, newVolume));
+                    mNiceVideoPlayer.setVolume(newVolume);
+                    int newVolumeProgress = (int) (100f * newVolume / maxVolume);
+                    showChangeVolume(newVolumeProgress);
+                }
+                break;
+            case MotionEvent.ACTION_CANCEL:
+            case MotionEvent.ACTION_UP:
+                if (mNeedChangePosition) {
+                    mNiceVideoPlayer.seekTo(mNewPosition);
+                    hideChangePosition();
+                    startUpdateProgressTimer();
+                    return true;
+                }
+                if (mNeedChangeBrightness) {
+                    hideChangeBrightness();
+                    return true;
+                }
+                if (mNeedChangeVolume) {
+                    hideChangeVolume();
+                    return true;
+                }
+                break;
+        }
+        return false;
+    }
+
+    /**
+     * 手势左右滑动改变播放位置时,显示控制器中间的播放位置变化视图,
+     * 在手势滑动ACTION_MOVE的过程中,会不断调用此方法。
+     *
+     * @param duration            视频总时长ms
+     * @param newPositionProgress 新的位置进度,取值0到100。
+     */
+    protected abstract void showChangePosition(long duration, int newPositionProgress);
+
+    /**
+     * 手势左右滑动改变播放位置后,手势up或者cancel时,隐藏控制器中间的播放位置变化视图,
+     * 在手势ACTION_UP或ACTION_CANCEL时调用。
+     */
+    protected abstract void hideChangePosition();
+
+    /**
+     * 手势在右侧上下滑动改变音量时,显示控制器中间的音量变化视图,
+     * 在手势滑动ACTION_MOVE的过程中,会不断调用此方法。
+     *
+     * @param newVolumeProgress 新的音量进度,取值1到100。
+     */
+    protected abstract void showChangeVolume(int newVolumeProgress);
+
+    /**
+     * 手势在左侧上下滑动改变音量后,手势up或者cancel时,隐藏控制器中间的音量变化视图,
+     * 在手势ACTION_UP或ACTION_CANCEL时调用。
+     */
+    protected abstract void hideChangeVolume();
+
+    /**
+     * 手势在左侧上下滑动改变亮度时,显示控制器中间的亮度变化视图,
+     * 在手势滑动ACTION_MOVE的过程中,会不断调用此方法。
+     *
+     * @param newBrightnessProgress 新的亮度进度,取值1到100。
+     */
+    protected abstract void showChangeBrightness(int newBrightnessProgress);
+
+    /**
+     * 手势在左侧上下滑动改变亮度后,手势up或者cancel时,隐藏控制器中间的亮度变化视图,
+     * 在手势ACTION_UP或ACTION_CANCEL时调用。
+     */
+    protected abstract void hideChangeBrightness();
+}

+ 119 - 0
YCVideoPlayerLib/src/main/java/org/yczbj/ycvideoplayerlib/ChangeClarityDialog.java

@@ -0,0 +1,119 @@
+package org.yczbj.ycvideoplayerlib;
+
+import android.app.Dialog;
+import android.content.Context;
+import android.view.Gravity;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.WindowManager;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+import java.util.List;
+
+/**
+ * 切换清晰度对话框(仿腾讯视频切换清晰度的对话框).
+ */
+public class ChangeClarityDialog extends Dialog {
+
+    private LinearLayout mLinearLayout;
+    private int mCurrentCheckedIndex;
+
+    ChangeClarityDialog(Context context) {
+        super(context, R.style.dialog_change_clarity);
+        init(context);
+    }
+
+    @Override
+    public void onBackPressed() {
+        // 按返回键时回调清晰度没有变化
+        if (mListener != null) {
+            mListener.onClarityNotChanged();
+        }
+        super.onBackPressed();
+    }
+
+    private void init(Context context) {
+        mLinearLayout = new LinearLayout(context);
+        mLinearLayout.setGravity(Gravity.CENTER);
+        mLinearLayout.setOrientation(LinearLayout.VERTICAL);
+        mLinearLayout.setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                if (mListener != null) {
+                    mListener.onClarityNotChanged();
+                }
+                ChangeClarityDialog.this.dismiss();
+            }
+        });
+        ViewGroup.LayoutParams params = new ViewGroup.LayoutParams(
+                ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.MarginLayoutParams.MATCH_PARENT);
+        setContentView(mLinearLayout, params);
+        if(getWindow()!=null){
+            WindowManager.LayoutParams windowParams = getWindow().getAttributes();
+            windowParams.width = VideoPlayerUtils.getScreenHeight(context);
+            windowParams.height = VideoPlayerUtils.getScreenWidth(context);
+            getWindow().setAttributes(windowParams);
+        }
+    }
+
+    /**
+     * 设置清晰度等级
+     * @param items          清晰度等级items
+     * @param defaultChecked 默认选中的清晰度索引
+     */
+    public void setClarityGrade(List<String> items, int defaultChecked) {
+        mCurrentCheckedIndex = defaultChecked;
+        for (int i = 0; i < items.size(); i++) {
+            TextView itemView = (TextView) LayoutInflater.from(getContext())
+                    .inflate(R.layout.change_video_clarity, mLinearLayout, false);
+            itemView.setTag(i);
+            itemView.setOnClickListener(new View.OnClickListener() {
+                @Override
+                public void onClick(View v) {
+                    if (mListener != null) {
+                        int checkIndex = (int) v.getTag();
+                        if (checkIndex != mCurrentCheckedIndex) {
+                            for (int j = 0; j < mLinearLayout.getChildCount(); j++) {
+                                mLinearLayout.getChildAt(j).setSelected(checkIndex == j);
+                            }
+                            mListener.onClarityChanged(checkIndex);
+                            mCurrentCheckedIndex = checkIndex;
+                        } else {
+                            mListener.onClarityNotChanged();
+                        }
+                    }
+                    ChangeClarityDialog.this.dismiss();
+                }
+            });
+            itemView.setText(items.get(i));
+            itemView.setSelected(i == defaultChecked);
+            ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams)
+                    itemView.getLayoutParams();
+            params.topMargin = (i == 0) ? 0 : VideoPlayerUtils.dp2px(getContext(), 16f);
+            mLinearLayout.addView(itemView, params);
+        }
+    }
+
+    public interface OnClarityChangedListener {
+        /**
+         * 切换清晰度后回调
+         *
+         * @param clarityIndex 切换到的清晰度的索引值
+         */
+        void onClarityChanged(int clarityIndex);
+
+        /**
+         * 清晰度没有切换,比如点击了空白位置,或者点击的是之前的清晰度
+         */
+        void onClarityNotChanged();
+    }
+
+    private OnClarityChangedListener mListener;
+    void setOnClarityCheckedListener(OnClarityChangedListener listener) {
+        mListener = listener;
+    }
+
+
+}

+ 181 - 0
YCVideoPlayerLib/src/main/java/org/yczbj/ycvideoplayerlib/InterVideoPlayer.java

@@ -0,0 +1,181 @@
+package org.yczbj.ycvideoplayerlib;
+
+import java.util.Map;
+
+/**
+ * VideoPlayer抽象接口
+ */
+public interface InterVideoPlayer {
+
+    /**
+     * 设置视频Url,以及headers
+     *
+     * @param url           视频地址,可以是本地,也可以是网络视频
+     * @param headers       请求header.
+     */
+    void setUp(String url, Map<String, String> headers);
+
+    /**
+     * 开始播放
+     */
+    void start();
+
+    /**
+     * 从指定的位置开始播放
+     *
+     * @param position      播放位置
+     */
+    void start(long position);
+
+    /**
+     * 重新播放,播放器被暂停、播放错误、播放完成后,需要调用此方法重新播放
+     */
+    void restart();
+
+    /**
+     * 暂停播放
+     */
+    void pause();
+
+    /**
+     * seek到制定的位置继续播放
+     *
+     * @param pos 播放位置
+     */
+    void seekTo(long pos);
+
+    /**
+     * 设置音量
+     *
+     * @param volume 音量值
+     */
+    void setVolume(int volume);
+
+    /**
+     * 设置播放速度,目前只有IjkPlayer有效果,原生MediaPlayer暂不支持
+     *
+     * @param speed 播放速度
+     */
+    void setSpeed(float speed);
+
+    /**
+     * 开始播放时,是否从上一次的位置继续播放
+     *
+     * @param continueFromLastPosition true 接着上次的位置继续播放,false从头开始播放
+     */
+    void continueFromLastPosition(boolean continueFromLastPosition);
+
+
+    /**------------------以下9个方法是播放器在当前的播放状态----------------------------*/
+    boolean isIdle();
+    boolean isPreparing();
+    boolean isPrepared();
+    boolean isBufferingPlaying();
+    boolean isBufferingPaused();
+    boolean isPlaying();
+    boolean isPaused();
+    boolean isError();
+    boolean isCompleted();
+
+    /**------------------以下3个方法是播放器的模式----------------------------*/
+
+    /**
+     * 是否是全屏播放
+     */
+    boolean isFullScreen();
+    /**
+     * 是否是小窗口播放
+     */
+    boolean isTinyWindow();
+    /**
+     * 是否是正常播放
+     */
+    boolean isNormal();
+
+    /**
+     * 获取最大音量
+     *
+     * @return 最大音量值
+     */
+    int getMaxVolume();
+
+    /**
+     * 获取当前音量
+     *
+     * @return 当前音量值
+     */
+    int getVolume();
+
+    /**
+     * 获取办法给总时长,毫秒
+     *
+     * @return 视频总时长ms
+     */
+    long getDuration();
+
+    /**
+     * 获取当前播放的位置,毫秒
+     *
+     * @return 当前播放位置,ms
+     */
+    long getCurrentPosition();
+
+    /**
+     * 获取视频缓冲百分比
+     *
+     * @return 缓冲白百分比
+     */
+    int getBufferPercentage();
+
+    /**
+     * 获取播放速度
+     *
+     * @param speed 播放速度
+     * @return 播放速度
+     */
+    float getSpeed(float speed);
+
+    /**
+     * 获取网络加载速度
+     *
+     * @return 网络加载速度
+     */
+    long getTcpSpeed();
+
+    /**
+     * 进入全屏模式
+     */
+    void enterFullScreen();
+
+    /**
+     * 退出全屏模式
+     *
+     * @return true 退出
+     */
+    boolean exitFullScreen();
+
+    /**
+     * 进入小窗口模式
+     */
+    void enterTinyWindow();
+
+    /**
+     * 退出小窗口模式
+     *
+     * @return true 退出小窗口
+     */
+    boolean exitTinyWindow();
+
+    /**
+     * 此处只释放播放器(如果要释放播放器并恢复控制器状态需要调用{@link #release()}方法)
+     * 不管是全屏、小窗口还是Normal状态下控制器的UI都不恢复初始状态
+     * 这样以便在当前播放器状态下可以方便的切换不同的清晰度的视频地址
+     */
+    void releasePlayer();
+
+    /**
+     * 释放INiceVideoPlayer,释放后,内部的播放器被释放掉,同时如果在全屏、小窗口模式下都会退出
+     * 并且控制器的UI也应该恢复到最初始的状态.
+     */
+    void release();
+}

+ 41 - 0
YCVideoPlayerLib/src/main/java/org/yczbj/ycvideoplayerlib/VideoClarity.java

@@ -0,0 +1,41 @@
+package org.yczbj.ycvideoplayerlib;
+
+/**
+ * 清晰度
+ */
+public class VideoClarity {
+
+    private String grade;           // 清晰度等级
+    private String p;               // 270P、480P、720P、1080P、4K ...
+    private String videoUrl;        // 视频链接地址
+
+    public VideoClarity(String grade, String p, String videoUrl) {
+        this.grade = grade;
+        this.p = p;
+        this.videoUrl = videoUrl;
+    }
+
+    public String getGrade() {
+        return grade;
+    }
+
+    public void setGrade(String grade) {
+        this.grade = grade;
+    }
+
+    public String getP() {
+        return p;
+    }
+
+    public void setP(String p) {
+        this.p = p;
+    }
+
+    public String getVideoUrl() {
+        return videoUrl;
+    }
+
+    public void setVideoUrl(String videoUrl) {
+        this.videoUrl = videoUrl;
+    }
+}

+ 23 - 0
YCVideoPlayerLib/src/main/java/org/yczbj/ycvideoplayerlib/VideoLogUtil.java

@@ -0,0 +1,23 @@
+package org.yczbj.ycvideoplayerlib;
+
+import android.util.Log;
+
+/**
+ * log工具
+ */
+public class VideoLogUtil {
+
+    private static final String TAG = "NiceVideoPlayer";
+
+    static void d(String message) {
+        Log.d(TAG, message);
+    }
+
+    static void i(String message) {
+        Log.i(TAG, message);
+    }
+
+    static void e(String message, Throwable throwable) {
+        Log.e(TAG, message, throwable);
+    }
+}

+ 895 - 0
YCVideoPlayerLib/src/main/java/org/yczbj/ycvideoplayerlib/VideoPlayer.java

@@ -0,0 +1,895 @@
+package org.yczbj.ycvideoplayerlib;
+
+import android.content.Context;
+import android.content.pm.ActivityInfo;
+import android.graphics.Color;
+import android.graphics.SurfaceTexture;
+import android.media.AudioManager;
+import android.net.Uri;
+import android.util.AttributeSet;
+import android.view.Gravity;
+import android.view.Surface;
+import android.view.TextureView;
+import android.view.ViewGroup;
+import android.widget.FrameLayout;
+
+import java.io.IOException;
+import java.util.Map;
+
+import tv.danmaku.ijk.media.player.AndroidMediaPlayer;
+import tv.danmaku.ijk.media.player.IMediaPlayer;
+import tv.danmaku.ijk.media.player.IjkMediaPlayer;
+import tv.danmaku.ijk.media.player.IjkTimedText;
+
+
+/**
+ * @author yc
+ * @date 2017/11/29
+ * 参考项目:
+ * https://github.com/CarGuo/GSYVideoPlayer
+ * https://github.com/danylovolokh/VideoPlayerManager
+ * https://github.com/HotBitmapGG/bilibili-android-client
+ * https://github.com/jjdxmashl/jjdxm_ijkplayer
+ * https://github.com/JasonChow1989/JieCaoVideoPlayer-develop          2年前
+ * https://github.com/open-android/JieCaoVideoPlayer                   1年前
+ * https://github.com/lipangit/JiaoZiVideoPlayer                       4个月前
+ * 个人感觉jiaozi这个播放器,与JieCaoVideoPlayer-develop有惊人的类同,借鉴了上面两个项目[JieCao]
+ *
+ *
+ * 注意:在对应的播放Activity页面,清单文件中一定要添加
+ * android:configChanges="orientation|keyboardHidden|screenSize"
+ * android:screenOrientation="portrait"
+ *
+ * 关于我的github:https://github.com/yangchong211
+ * 关于我的个人网站:www.ycbjie.cn或者www.yczbj.org
+ *
+ * 播放器
+ */
+
+public class VideoPlayer extends FrameLayout implements InterVideoPlayer{
+
+    /**
+     * 播放错误
+     **/
+    public static final int STATE_ERROR = -1;
+    /**
+     * 播放未开始
+     **/
+    public static final int STATE_IDLE = 0;
+    /**
+     * 播放准备中
+     **/
+    public static final int STATE_PREPARING = 1;
+    /**
+     * 播放准备就绪
+     **/
+    public static final int STATE_PREPARED = 2;
+    /**
+     * 正在播放
+     **/
+    public static final int STATE_PLAYING = 3;
+    /**
+     * 暂停播放
+     **/
+    public static final int STATE_PAUSED = 4;
+    /**
+     * 正在缓冲(播放器正在播放时,缓冲区数据不足,进行缓冲,缓冲区数据足够后恢复播放)
+     **/
+    public static final int STATE_BUFFERING_PLAYING = 5;
+    /**
+     * 正在缓冲(播放器正在播放时,缓冲区数据不足,进行缓冲,此时暂停播放器,继续缓冲,缓冲区数据足够后恢复暂停
+     **/
+    public static final int STATE_BUFFERING_PAUSED = 6;
+    /**
+     * 播放完成
+     **/
+    public static final int STATE_COMPLETED = 7;
+
+    /**
+     * 普通模式
+     **/
+    public static final int MODE_NORMAL = 10;
+    /**
+     * 全屏模式
+     **/
+    public static final int MODE_FULL_SCREEN = 11;
+    /**
+     * 小窗口模式
+     **/
+    public static final int MODE_TINY_WINDOW = 12;
+
+    /**
+     * IjkPlayer,基于IjkPlayer封装播放器
+     **/
+    public static final int TYPE_IJK = 111;
+    /**
+     * MediaPlayer,基于原生自带的播放器控件
+     **/
+    public static final int TYPE_NATIVE = 222;
+    /**
+     * 播放类型
+     * TYPE_IJK             基于IjkPlayer封装播放器
+     * TYPE_NATIVE          基于原生自带的播放器控件
+     **/
+    private int mPlayerType = TYPE_IJK;
+    /**
+     * 播放状态,错误,开始播放,暂停播放,缓存中等等状态
+     **/
+    private int mCurrentState = STATE_IDLE;
+    /**
+     * 播放模式,普通模式,小窗口模式,正常模式等等
+     **/
+    private int mCurrentMode = MODE_NORMAL;
+
+
+    private Context mContext;
+    private AudioManager mAudioManager;
+    private IMediaPlayer mMediaPlayer;
+    private FrameLayout mContainer;
+    private VideoTextureView mTextureView;
+    private AbsVideoPlayerController mController;
+    private SurfaceTexture mSurfaceTexture;
+    private Surface mSurface;
+    private String mUrl;
+    private Map<String, String> mHeaders;
+    private int mBufferPercentage;
+    private boolean continueFromLastPosition = true;
+    private long skipToPosition;
+
+    public VideoPlayer(Context context) {
+        this(context, null);
+    }
+
+    public VideoPlayer(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        mContext = context;
+        init();
+    }
+
+    /**
+     * 初始化
+     */
+    private void init() {
+        mContainer = new FrameLayout(mContext);
+        //设置背景颜色,目前设置为纯黑色
+        mContainer.setBackgroundColor(Color.BLACK);
+        LayoutParams params = new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
+                ViewGroup.LayoutParams.MATCH_PARENT);
+        this.addView(mContainer, params);
+    }
+
+    /**
+     * 设置,必须设置
+     * @param url               视频地址,可以是本地,也可以是网络视频
+     * @param headers           请求header.
+     */
+    public void setUp(String url, Map<String, String> headers) {
+        mUrl = url;
+        mHeaders = headers;
+    }
+
+    /**
+     * 设置视频控制器,必须设置
+     * @param controller        AbsVideoPlayerController子类对象,可用VideoPlayerController,也可自定义
+     */
+    public void setController(AbsVideoPlayerController controller) {
+        mContainer.removeView(mController);
+        mController = controller;
+        mController.reset();
+        mController.setNiceVideoPlayer(this);
+        LayoutParams params = new LayoutParams(
+                ViewGroup.LayoutParams.MATCH_PARENT,
+                ViewGroup.LayoutParams.MATCH_PARENT);
+        mContainer.addView(mController, params);
+    }
+
+    /**
+     * 设置播放器类型,必须设置
+     * @param playerType IjkPlayer or MediaPlayer.
+     */
+    public void setPlayerType(int playerType) {
+        mPlayerType = playerType;
+    }
+
+    /**
+     * 是否从上一次的位置继续播放,不必须
+     *
+     * @param continueFromLastPosition true从上一次的位置继续播放
+     */
+    @Override
+    public void continueFromLastPosition(boolean continueFromLastPosition) {
+        this.continueFromLastPosition = continueFromLastPosition;
+    }
+
+    /**
+     * 设置播放速度,不必须
+     * @param speed                     播放速度
+     */
+    @Override
+    public void setSpeed(float speed) {
+        if (mMediaPlayer instanceof IjkMediaPlayer) {
+            ((IjkMediaPlayer) mMediaPlayer).setSpeed(speed);
+        } else {
+            VideoLogUtil.d("只有IjkPlayer才能设置播放速度");
+        }
+    }
+
+    /**
+     * 开始播放
+     */
+    @Override
+    public void start() {
+        if (mCurrentState == STATE_IDLE) {
+            VideoPlayerManager.instance().setCurrentNiceVideoPlayer(this);
+            initAudioManager();
+            initMediaPlayer();
+            initTextureView();
+            addTextureView();
+        } else {
+            VideoLogUtil.d("NiceVideoPlayer只有在mCurrentState == STATE_IDLE时才能调用start方法.");
+        }
+    }
+
+    /**
+     * 开始播放
+     * @param position                 播放位置
+     */
+    @Override
+    public void start(long position) {
+        skipToPosition = position;
+        start();
+    }
+
+    /**
+     * 重新播放
+     */
+    @Override
+    public void restart() {
+        if (mCurrentState == STATE_PAUSED) {
+            mMediaPlayer.start();
+            mCurrentState = STATE_PLAYING;
+            mController.onPlayStateChanged(mCurrentState);
+            VideoLogUtil.d("STATE_PLAYING");
+        } else if (mCurrentState == STATE_BUFFERING_PAUSED) {
+            mMediaPlayer.start();
+            mCurrentState = STATE_BUFFERING_PLAYING;
+            mController.onPlayStateChanged(mCurrentState);
+            VideoLogUtil.d("STATE_BUFFERING_PLAYING");
+        } else if (mCurrentState == STATE_COMPLETED || mCurrentState == STATE_ERROR) {
+            mMediaPlayer.reset();
+            openMediaPlayer();
+        } else {
+            VideoLogUtil.d("NiceVideoPlayer在mCurrentState == " + mCurrentState + "时不能调用restart()方法.");
+        }
+    }
+
+    /**
+     * 暂停播放
+     */
+    @Override
+    public void pause() {
+        if (mCurrentState == STATE_PLAYING) {
+            mMediaPlayer.pause();
+            mCurrentState = STATE_PAUSED;
+            mController.onPlayStateChanged(mCurrentState);
+            VideoLogUtil.d("STATE_PAUSED");
+        }
+        if (mCurrentState == STATE_BUFFERING_PLAYING) {
+            mMediaPlayer.pause();
+            mCurrentState = STATE_BUFFERING_PAUSED;
+            mController.onPlayStateChanged(mCurrentState);
+            VideoLogUtil.d("STATE_BUFFERING_PAUSED");
+        }
+    }
+
+    /**
+     * 设置播放位置
+     * @param pos                   播放位置
+     */
+    @Override
+    public void seekTo(long pos) {
+        if (mMediaPlayer != null) {
+            mMediaPlayer.seekTo(pos);
+        }
+    }
+
+    /**
+     * 设置音量
+     * @param volume                音量值
+     */
+    @Override
+    public void setVolume(int volume) {
+        if (mAudioManager != null) {
+            mAudioManager.setStreamVolume(AudioManager.STREAM_MUSIC, volume, 0);
+        }
+    }
+
+    /**
+     * 判断是否开始播放
+     * @return                      true表示播放未开始
+     */
+    @Override
+    public boolean isIdle() {
+        return mCurrentState == STATE_IDLE;
+    }
+
+    /**
+     * 判断视频是否播放准备中
+     * @return                      true表示播放准备中
+     */
+    @Override
+    public boolean isPreparing() {
+        return mCurrentState == STATE_PREPARING;
+    }
+
+    /**
+     * 判断视频是否
+     * @return                      true表示播放准备就绪
+     */
+    @Override
+    public boolean isPrepared() {
+        return mCurrentState == STATE_PREPARED;
+    }
+
+    /**
+     * 判断视频是否正在缓冲(播放器正在播放时,缓冲区数据不足,进行缓冲,缓冲区数据足够后恢复播放)
+     * @return                      true表示正在缓冲
+     */
+    @Override
+    public boolean isBufferingPlaying() {
+        return mCurrentState == STATE_BUFFERING_PLAYING;
+    }
+
+    @Override
+    public boolean isBufferingPaused() {
+        return mCurrentState == STATE_BUFFERING_PAUSED;
+    }
+
+    @Override
+    public boolean isPlaying() {
+        return mCurrentState == STATE_PLAYING;
+    }
+
+    @Override
+    public boolean isPaused() {
+        return mCurrentState == STATE_PAUSED;
+    }
+
+    @Override
+    public boolean isError() {
+        return mCurrentState == STATE_ERROR;
+    }
+
+    @Override
+    public boolean isCompleted() {
+        return mCurrentState == STATE_COMPLETED;
+    }
+
+    @Override
+    public boolean isFullScreen() {
+        return mCurrentMode == MODE_FULL_SCREEN;
+    }
+
+    @Override
+    public boolean isTinyWindow() {
+        return mCurrentMode == MODE_TINY_WINDOW;
+    }
+
+    @Override
+    public boolean isNormal() {
+        return mCurrentMode == MODE_NORMAL;
+    }
+
+    /**
+     * 获取最大音量
+     * @return                  音量值
+     */
+    @Override
+    public int getMaxVolume() {
+        if (mAudioManager != null) {
+            return mAudioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC);
+        }
+        return 0;
+    }
+
+    /**
+     * 获取音量值
+     * @return                  音量值
+     */
+    @Override
+    public int getVolume() {
+        if (mAudioManager != null) {
+            return mAudioManager.getStreamVolume(AudioManager.STREAM_MUSIC);
+        }
+        return 0;
+    }
+
+    /**
+     * 获取持续时长
+     * @return                  long时间值
+     */
+    @Override
+    public long getDuration() {
+        return mMediaPlayer != null ? mMediaPlayer.getDuration() : 0;
+    }
+
+    /**
+     * 获取播放位置
+     * @return                  位置
+     */
+    @Override
+    public long getCurrentPosition() {
+        return mMediaPlayer != null ? mMediaPlayer.getCurrentPosition() : 0;
+    }
+
+    /**
+     * 获取缓冲区百分比
+     * @return                  百分比
+     */
+    @Override
+    public int getBufferPercentage() {
+        return mBufferPercentage;
+    }
+
+    /**
+     * 获取播放速度
+     * @param speed             播放速度
+     * @return
+     */
+    @Override
+    public float getSpeed(float speed) {
+        if (mMediaPlayer instanceof IjkMediaPlayer) {
+            return ((IjkMediaPlayer) mMediaPlayer).getSpeed(speed);
+        }
+        return 0;
+    }
+
+    /**
+     *
+     * @return
+     */
+    @Override
+    public long getTcpSpeed() {
+        if (mMediaPlayer instanceof IjkMediaPlayer) {
+            return ((IjkMediaPlayer) mMediaPlayer).getTcpSpeed();
+        }
+        return 0;
+    }
+
+    /**
+     * 初始化音频管理器
+     */
+    private void initAudioManager() {
+        if (mAudioManager == null) {
+            mAudioManager = (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE);
+            if (mAudioManager != null) {
+                mAudioManager.requestAudioFocus(null, AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN);
+            }
+        }
+    }
+
+    /**
+     * 初始化视频管理器
+     */
+    private void initMediaPlayer() {
+        if (mMediaPlayer == null) {
+            switch (mPlayerType) {
+                //MediaPlayer       基于原生
+                case TYPE_NATIVE:
+                    mMediaPlayer = new AndroidMediaPlayer();
+                    break;
+                //IjkMediaPlayer    基于Ijk
+                case TYPE_IJK:
+                default:
+                    mMediaPlayer = new IjkMediaPlayer();
+                    ((IjkMediaPlayer)mMediaPlayer).setOption(1, "analyzemaxduration", 100L);
+                    ((IjkMediaPlayer)mMediaPlayer).setOption(1, "probesize", 10240L);
+                    ((IjkMediaPlayer)mMediaPlayer).setOption(1, "flush_packets", 1L);
+                    ((IjkMediaPlayer)mMediaPlayer).setOption(4, "packet-buffering", 0L);
+                    ((IjkMediaPlayer)mMediaPlayer).setOption(4, "framedrop", 1L);
+                    break;
+            }
+            mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
+        }
+    }
+
+    /**
+     * 初始化TextureView
+     */
+    private void initTextureView() {
+        if (mTextureView == null) {
+            mTextureView = new VideoTextureView(mContext);
+            mTextureView.setSurfaceTextureListener(new TextureView.SurfaceTextureListener() {
+                @Override
+                public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
+                    if (mSurfaceTexture == null) {
+                        mSurfaceTexture = surface;
+                        openMediaPlayer();
+                    } else {
+                        mTextureView.setSurfaceTexture(mSurfaceTexture);
+                    }
+                }
+
+                @Override
+                public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
+
+                }
+
+                @Override
+                public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
+                    return mSurfaceTexture == null;
+                }
+
+                @Override
+                public void onSurfaceTextureUpdated(SurfaceTexture surface) {
+
+                }
+            });
+        }
+    }
+
+    /**
+     * 添加TextureView到视图中
+     */
+    private void addTextureView() {
+        mContainer.removeView(mTextureView);
+        LayoutParams params = new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
+                ViewGroup.LayoutParams.MATCH_PARENT, Gravity.CENTER);
+        mContainer.addView(mTextureView, 0, params);
+    }
+
+
+    /**
+     * 打开MediaPlayer播放器
+     */
+    private void openMediaPlayer() {
+        // 屏幕常亮
+        mContainer.setKeepScreenOn(true);
+        // 设置监听,可以查看ijk中的IMediaPlayer源码监听事件
+        // 设置准备视频播放监听事件
+        mMediaPlayer.setOnPreparedListener(mOnPreparedListener);
+        // 设置视频播放完成监听事件
+        mMediaPlayer.setOnCompletionListener(mOnCompletionListener);
+        // 设置视频缓冲更新监听事件
+        mMediaPlayer.setOnBufferingUpdateListener(mOnBufferingUpdateListener);
+        // 设置视频seek完成监听事件
+        mMediaPlayer.setOnSeekCompleteListener(mOnSeekCompleteListener);
+        // 设置视频大小更改监听器
+        mMediaPlayer.setOnVideoSizeChangedListener(mOnVideoSizeChangedListener);
+        // 设置视频错误监听器
+        mMediaPlayer.setOnErrorListener(mOnErrorListener);
+        // 设置视频信息监听器
+        mMediaPlayer.setOnInfoListener(mOnInfoListener);
+        // 设置时间文本监听器
+        mMediaPlayer.setOnTimedTextListener(mOnTimedTextListener);
+        // 设置dataSource
+        try {
+            mMediaPlayer.setDataSource(mContext.getApplicationContext(), Uri.parse(mUrl), mHeaders);
+            if (mSurface == null) {
+                mSurface = new Surface(mSurfaceTexture);
+            }
+            mMediaPlayer.setSurface(mSurface);
+            mMediaPlayer.prepareAsync();
+            mCurrentState = STATE_PREPARING;
+            mController.onPlayStateChanged(mCurrentState);
+            VideoLogUtil.d("STATE_PREPARING");
+        } catch (IOException e) {
+            e.printStackTrace();
+            VideoLogUtil.e("打开播放器发生错误", e);
+        }
+    }
+
+    /**
+     * 设置准备视频播放监听事件
+     */
+    private IMediaPlayer.OnPreparedListener mOnPreparedListener = new IMediaPlayer.OnPreparedListener() {
+        @Override
+        public void onPrepared(IMediaPlayer mp) {
+            mCurrentState = STATE_PREPARED;
+            mController.onPlayStateChanged(mCurrentState);
+            VideoLogUtil.d("onPrepared ——> STATE_PREPARED");
+            mp.start();
+            // 从上次的保存位置播放
+            if (continueFromLastPosition) {
+                long savedPlayPosition = VideoPlayerUtils.getSavedPlayPosition(mContext, mUrl);
+                mp.seekTo(savedPlayPosition);
+            }
+            // 跳到指定位置播放
+            if (skipToPosition != 0) {
+                mp.seekTo(skipToPosition);
+            }
+        }
+    };
+
+
+    /**
+     * 设置视频播放完成监听事件
+     */
+    private IMediaPlayer.OnCompletionListener mOnCompletionListener = new IMediaPlayer.OnCompletionListener() {
+        @Override
+        public void onCompletion(IMediaPlayer mp) {
+            mCurrentState = STATE_COMPLETED;
+            mController.onPlayStateChanged(mCurrentState);
+            VideoLogUtil.d("onCompletion ——> STATE_COMPLETED");
+            // 清除屏幕常亮
+            mContainer.setKeepScreenOn(false);
+        }
+    };
+
+    /**
+     * 设置视频缓冲更新监听事件
+     */
+    private IMediaPlayer.OnBufferingUpdateListener mOnBufferingUpdateListener = new IMediaPlayer.OnBufferingUpdateListener() {
+        @Override
+        public void onBufferingUpdate(IMediaPlayer mp, int percent) {
+            mBufferPercentage = percent;
+        }
+    };
+
+    /**
+     * 设置视频seek完成监听事件
+     */
+    private IMediaPlayer.OnSeekCompleteListener mOnSeekCompleteListener = new IMediaPlayer.OnSeekCompleteListener() {
+        @Override
+        public void onSeekComplete(IMediaPlayer iMediaPlayer) {
+
+        }
+    };
+
+    /**
+     * 设置视频大小更改监听器
+     */
+    private IMediaPlayer.OnVideoSizeChangedListener mOnVideoSizeChangedListener = new IMediaPlayer.OnVideoSizeChangedListener() {
+        @Override
+        public void onVideoSizeChanged(IMediaPlayer mp, int width, int height, int sar_num, int sar_den) {
+            mTextureView.adaptVideoSize(width, height);
+            VideoLogUtil.d("onVideoSizeChanged ——> width:" + width + ", height:" + height);
+        }
+    };
+
+    /**
+     * 设置视频错误监听器
+     */
+    private IMediaPlayer.OnErrorListener mOnErrorListener = new IMediaPlayer.OnErrorListener() {
+        @Override
+        public boolean onError(IMediaPlayer mp, int what, int extra) {
+            // 直播流播放时去调用mediaPlayer.getDuration会导致-38和-2147483648错误,忽略该错误
+            if (what != -38 && what != -2147483648 && extra != -38 && extra != -2147483648) {
+                mCurrentState = STATE_ERROR;
+                mController.onPlayStateChanged(mCurrentState);
+                VideoLogUtil.d("onError ——> STATE_ERROR ———— what:" + what + ", extra: " + extra);
+            }
+            return true;
+        }
+    };
+
+    /**
+     * 设置视频信息监听器
+     */
+    private IMediaPlayer.OnInfoListener mOnInfoListener = new IMediaPlayer.OnInfoListener() {
+        @Override
+        public boolean onInfo(IMediaPlayer mp, int what, int extra) {
+            if (what == IMediaPlayer.MEDIA_INFO_VIDEO_RENDERING_START) {
+                // 播放器开始渲染
+                mCurrentState = STATE_PLAYING;
+                mController.onPlayStateChanged(mCurrentState);
+                VideoLogUtil.d("onInfo ——> MEDIA_INFO_VIDEO_RENDERING_START:STATE_PLAYING");
+            } else if (what == IMediaPlayer.MEDIA_INFO_BUFFERING_START) {
+                // MediaPlayer暂时不播放,以缓冲更多的数据
+                if (mCurrentState == STATE_PAUSED || mCurrentState == STATE_BUFFERING_PAUSED) {
+                    mCurrentState = STATE_BUFFERING_PAUSED;
+                    VideoLogUtil.d("onInfo ——> MEDIA_INFO_BUFFERING_START:STATE_BUFFERING_PAUSED");
+                } else {
+                    mCurrentState = STATE_BUFFERING_PLAYING;
+                    VideoLogUtil.d("onInfo ——> MEDIA_INFO_BUFFERING_START:STATE_BUFFERING_PLAYING");
+                }
+                mController.onPlayStateChanged(mCurrentState);
+            } else if (what == IMediaPlayer.MEDIA_INFO_BUFFERING_END) {
+                // 填充缓冲区后,MediaPlayer恢复播放/暂停
+                if (mCurrentState == STATE_BUFFERING_PLAYING) {
+                    mCurrentState = STATE_PLAYING;
+                    mController.onPlayStateChanged(mCurrentState);
+                    VideoLogUtil.d("onInfo ——> MEDIA_INFO_BUFFERING_END: STATE_PLAYING");
+                }
+                if (mCurrentState == STATE_BUFFERING_PAUSED) {
+                    mCurrentState = STATE_PAUSED;
+                    mController.onPlayStateChanged(mCurrentState);
+                    VideoLogUtil.d("onInfo ——> MEDIA_INFO_BUFFERING_END: STATE_PAUSED");
+                }
+            } else if (what == IMediaPlayer.MEDIA_INFO_VIDEO_ROTATION_CHANGED) {
+                // 视频旋转了extra度,需要恢复
+                if (mTextureView != null) {
+                    mTextureView.setRotation(extra);
+                    VideoLogUtil.d("视频旋转角度:" + extra);
+                }
+            } else if (what == IMediaPlayer.MEDIA_INFO_NOT_SEEKABLE) {
+                VideoLogUtil.d("视频不能seekTo,为直播视频");
+            } else {
+                VideoLogUtil.d("onInfo ——> what:" + what);
+            }
+            return true;
+        }
+    };
+
+    /**
+     * 设置时间文本监听器
+     */
+    private IMediaPlayer.OnTimedTextListener mOnTimedTextListener = new IMediaPlayer.OnTimedTextListener() {
+        @Override
+        public void onTimedText(IMediaPlayer iMediaPlayer, IjkTimedText ijkTimedText) {
+
+        }
+    };
+
+    /**
+     * 全屏,将mContainer(内部包含mTextureView和mController)从当前容器中移除,并添加到android.R.content中.
+     * 切换横屏时需要在manifest的activity标签下添加android:configChanges="orientation|keyboardHidden|screenSize"配置,
+     * 以避免Activity重新走生命周期
+     */
+    @Override
+    public void enterFullScreen() {
+        if (mCurrentMode == MODE_FULL_SCREEN){
+            return;
+        }
+        // 隐藏ActionBar、状态栏,并横屏
+        VideoPlayerUtils.hideActionBar(mContext);
+        VideoPlayerUtils.scanForActivity(mContext).setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
+        ViewGroup contentView = (ViewGroup) VideoPlayerUtils.scanForActivity(mContext).findViewById(android.R.id.content);
+        if (mCurrentMode == MODE_TINY_WINDOW) {
+            contentView.removeView(mContainer);
+        } else {
+            this.removeView(mContainer);
+        }
+        LayoutParams params = new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
+                ViewGroup.LayoutParams.MATCH_PARENT);
+        contentView.addView(mContainer, params);
+
+        mCurrentMode = MODE_FULL_SCREEN;
+        mController.onPlayModeChanged(mCurrentMode);
+        VideoLogUtil.d("MODE_FULL_SCREEN");
+    }
+
+    /**
+     * 退出全屏,移除mTextureView和mController,并添加到非全屏的容器中。
+     * 切换竖屏时需要在manifest的activity标签下添加android:configChanges="orientation|keyboardHidden|screenSize"配置,
+     * 以避免Activity重新走生命周期.
+     *
+     * @return true退出全屏.
+     */
+    @Override
+    public boolean exitFullScreen() {
+        if (mCurrentMode == MODE_FULL_SCREEN) {
+            VideoPlayerUtils.showActionBar(mContext);
+            VideoPlayerUtils.scanForActivity(mContext).setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
+            ViewGroup contentView = (ViewGroup) VideoPlayerUtils.scanForActivity(mContext).findViewById(android.R.id.content);
+            contentView.removeView(mContainer);
+            LayoutParams params = new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
+            this.addView(mContainer, params);
+            mCurrentMode = MODE_NORMAL;
+            mController.onPlayModeChanged(mCurrentMode);
+            VideoLogUtil.d("MODE_NORMAL");
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * 进入小窗口播放,小窗口播放的实现原理与全屏播放类似。
+     */
+    @Override
+    public void enterTinyWindow() {
+        //如果是小窗口模式,则不执行下面代码
+        if (mCurrentMode == MODE_TINY_WINDOW) {
+            return;
+        }
+        this.removeView(mContainer);
+        ViewGroup contentView = (ViewGroup) VideoPlayerUtils.scanForActivity(mContext)
+                .findViewById(android.R.id.content);
+        // 小窗口的宽度为屏幕宽度的60%,长宽比默认为16:9,右边距、下边距为8dp。
+        LayoutParams params = new LayoutParams(
+                (int) (VideoPlayerUtils.getScreenWidth(mContext) * 0.6f),
+                (int) (VideoPlayerUtils.getScreenWidth(mContext) * 0.6f * 9f / 16f));
+        params.gravity = Gravity.BOTTOM | Gravity.END;
+        params.rightMargin = VideoPlayerUtils.dp2px(mContext, 8f);
+        params.bottomMargin = VideoPlayerUtils.dp2px(mContext, 8f);
+
+        contentView.addView(mContainer, params);
+
+        mCurrentMode = MODE_TINY_WINDOW;
+        mController.onPlayModeChanged(mCurrentMode);
+        VideoLogUtil.d("MODE_TINY_WINDOW");
+    }
+
+    /**
+     * 退出小窗口播放
+     */
+    @Override
+    public boolean exitTinyWindow() {
+        if (mCurrentMode == MODE_TINY_WINDOW) {
+            ViewGroup contentView = (ViewGroup) VideoPlayerUtils.scanForActivity(mContext).findViewById(android.R.id.content);
+            contentView.removeView(mContainer);
+            LayoutParams params = new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
+            this.addView(mContainer, params);
+            mCurrentMode = MODE_NORMAL;
+            mController.onPlayModeChanged(mCurrentMode);
+            VideoLogUtil.d("MODE_NORMAL");
+            return true;
+        }
+        return false;
+    }
+
+
+    /**
+     * 释放,内部的播放器被释放掉,同时如果在全屏、小窗口模式下都会退出
+     * 逻辑
+     * 1.先保存播放位置
+     * 2.退出全屏或小窗口,回复播放模式为正常模式
+     * 3.释放播放器
+     * 4.恢复控制器
+     * 5.gc回收
+     */
+    @Override
+    public void release() {
+        // 保存播放位置
+        if (isPlaying() || isBufferingPlaying() || isBufferingPaused() || isPaused()) {
+            VideoPlayerUtils.savePlayPosition(mContext, mUrl, getCurrentPosition());
+        } else if (isCompleted()) {
+            //如果播放完成,则保存播放位置为0,也就是初始位置
+            VideoPlayerUtils.savePlayPosition(mContext, mUrl, 0);
+        }
+        // 退出全屏或小窗口
+        if (isFullScreen()) {
+            exitFullScreen();
+        }
+        if (isTinyWindow()) {
+            exitTinyWindow();
+        }
+        mCurrentMode = MODE_NORMAL;
+
+        // 释放播放器
+        releasePlayer();
+
+        // 恢复控制器
+        if (mController != null) {
+            mController.reset();
+        }
+        // gc回收
+        Runtime.getRuntime().gc();
+    }
+
+    /**
+     * 释放播放器,注意一定要判断对象是否为空,增强严谨性
+     * 关于我的github:https://github.com/yangchong211
+     * 关于我的个人网站:www.ycbjie.cn或者www.yczbj.org
+     * 杨充修改:
+     *      17年12月23日,添加释放音频和TextureView
+     */
+    @Override
+    public void releasePlayer() {
+        if (mAudioManager != null) {
+            //放弃音频焦点。使以前的焦点所有者(如果有的话)接收焦点。
+            mAudioManager.abandonAudioFocus(null);
+            //置空
+            mAudioManager = null;
+        }
+        if (mMediaPlayer != null) {
+            //释放视频焦点
+            mMediaPlayer.release();
+            mMediaPlayer = null;
+        }
+        //从视图中移除TextureView
+        mContainer.removeView(mTextureView);
+        if (mSurface != null) {
+            mSurface.release();
+            mSurface = null;
+        }
+        //如果SurfaceTexture不为null,则释放
+        if (mSurfaceTexture != null) {
+            mSurfaceTexture.release();
+            mSurfaceTexture = null;
+        }
+        mCurrentState = STATE_IDLE;
+    }
+
+
+}

+ 587 - 0
YCVideoPlayerLib/src/main/java/org/yczbj/ycvideoplayerlib/VideoPlayerController.java

@@ -0,0 +1,587 @@
+package org.yczbj.ycvideoplayerlib;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.BatteryManager;
+import android.os.CountDownTimer;
+import android.support.annotation.DrawableRes;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.ProgressBar;
+import android.widget.SeekBar;
+import android.widget.TextView;
+import android.widget.Toast;
+
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+import java.util.Locale;
+
+
+/**
+ * @author yc
+ * @date 2017/12/4
+ * 参考项目:
+ * https://github.com/CarGuo/GSYVideoPlayer
+ * https://github.com/danylovolokh/VideoPlayerManager
+ * https://github.com/HotBitmapGG/bilibili-android-client
+ * https://github.com/jjdxmashl/jjdxm_ijkplayer
+ * https://github.com/JasonChow1989/JieCaoVideoPlayer-develop          2年前
+ * https://github.com/open-android/JieCaoVideoPlayer                   1年前
+ * https://github.com/lipangit/JiaoZiVideoPlayer                       4个月前
+ * 个人感觉jiaozi这个播放器,与JieCaoVideoPlayer-develop有惊人的类同,借鉴了上面两个项目[JieCao]
+ *
+ *
+ * 注意:在对应的播放Activity页面,清单文件中一定要添加
+ * android:configChanges="orientation|keyboardHidden|screenSize"
+ * android:screenOrientation="portrait"
+ *
+ * 关于我的github:https://github.com/yangchong211
+ * 关于我的个人网站:www.ycbjie.cn或者www.yczbj.org
+ *
+ * 仿视频热点列表页播放器控制器
+ */
+
+public class VideoPlayerController extends AbsVideoPlayerController implements View.OnClickListener{
+
+    private Context mContext;
+    private ImageView mImage;
+    private ImageView mCenterStart;
+
+    private LinearLayout mTop;
+    private ImageView mBack;
+    private TextView mTitle;
+    private LinearLayout mBatteryTime;
+    private ImageView mBattery;
+    private TextView mTime;
+
+    private LinearLayout mBottom;
+    private ImageView mRestartPause;
+    private TextView mPosition;
+    private TextView mDuration;
+    private SeekBar mSeek;
+    private TextView mClarity;
+    private ImageView mFullScreen;
+
+    private TextView mLength;
+
+    private LinearLayout mLoading;
+    private TextView mLoadText;
+
+    private LinearLayout mChangePositon;
+    private TextView mChangePositionCurrent;
+    private ProgressBar mChangePositionProgress;
+
+    private LinearLayout mChangeBrightness;
+    private ProgressBar mChangeBrightnessProgress;
+
+    private LinearLayout mChangeVolume;
+    private ProgressBar mChangeVolumeProgress;
+
+    private LinearLayout mError;
+    private TextView mRetry;
+
+    private LinearLayout mCompleted;
+    private TextView mReplay;
+    private TextView mShare;
+
+    private boolean topBottomVisible;
+    private CountDownTimer mDismissTopBottomCountDownTimer;
+
+    private List<VideoClarity> clarities;
+    private int defaultClarityIndex;
+
+    private ChangeClarityDialog mClarityDialog;
+    /**
+     * 是否已经注册了电池广播
+     */
+    private boolean hasRegisterBatteryReceiver;
+
+    public VideoPlayerController(Context context) {
+        super(context);
+        mContext = context;
+        init();
+    }
+
+    private void init() {
+        LayoutInflater.from(mContext).inflate(R.layout.custom_video_player, this, true);
+        initFindViewById();
+        initListener();
+    }
+
+    private void initFindViewById() {
+        mCenterStart = (ImageView) findViewById(R.id.center_start);
+        mImage = (ImageView) findViewById(R.id.image);
+        mTop = (LinearLayout) findViewById(R.id.top);
+        mBack = (ImageView) findViewById(R.id.back);
+        mTitle = (TextView) findViewById(R.id.title);
+        mBatteryTime = (LinearLayout) findViewById(R.id.battery_time);
+        mBattery = (ImageView) findViewById(R.id.battery);
+        mTime = (TextView) findViewById(R.id.time);
+        mBottom = (LinearLayout) findViewById(R.id.bottom);
+        mRestartPause = (ImageView) findViewById(R.id.restart_or_pause);
+        mPosition = (TextView) findViewById(R.id.position);
+        mDuration = (TextView) findViewById(R.id.duration);
+        mSeek = (SeekBar) findViewById(R.id.seek);
+        mFullScreen = (ImageView) findViewById(R.id.full_screen);
+        mClarity = (TextView) findViewById(R.id.clarity);
+        mLength = (TextView) findViewById(R.id.length);
+        mLoading = (LinearLayout) findViewById(R.id.loading);
+        mLoadText = (TextView) findViewById(R.id.load_text);
+        mChangePositon = (LinearLayout) findViewById(R.id.change_position);
+        mChangePositionCurrent = (TextView) findViewById(R.id.change_position_current);
+        mChangePositionProgress = (ProgressBar) findViewById(R.id.change_position_progress);
+        mChangeBrightness = (LinearLayout) findViewById(R.id.change_brightness);
+        mChangeBrightnessProgress = (ProgressBar) findViewById(R.id.change_brightness_progress);
+        mChangeVolume = (LinearLayout) findViewById(R.id.change_volume);
+        mChangeVolumeProgress = (ProgressBar) findViewById(R.id.change_volume_progress);
+        mError = (LinearLayout) findViewById(R.id.error);
+        mRetry = (TextView) findViewById(R.id.retry);
+        mCompleted = (LinearLayout) findViewById(R.id.completed);
+        mReplay = (TextView) findViewById(R.id.replay);
+        mShare = (TextView) findViewById(R.id.share);
+    }
+
+    private void initListener() {
+        mCenterStart.setOnClickListener(this);
+        mBack.setOnClickListener(this);
+        mRestartPause.setOnClickListener(this);
+        mFullScreen.setOnClickListener(this);
+        mClarity.setOnClickListener(this);
+        mRetry.setOnClickListener(this);
+        mReplay.setOnClickListener(this);
+        mShare.setOnClickListener(this);
+        mSeek.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
+            @Override
+            public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
+
+            }
+
+            @Override
+            public void onStartTrackingTouch(SeekBar seekBar) {
+
+            }
+
+            @Override
+            public void onStopTrackingTouch(SeekBar seekBar) {
+                if (mNiceVideoPlayer.isBufferingPaused() || mNiceVideoPlayer.isPaused()) {
+                    mNiceVideoPlayer.restart();
+                }
+                long position = (long) (mNiceVideoPlayer.getDuration() * seekBar.getProgress() / 100f);
+                mNiceVideoPlayer.seekTo(position);
+                startDismissTopBottomTimer();
+            }
+        });
+        this.setOnClickListener(this);
+    }
+
+    /**
+     * 设置视频标题
+     * @param title             视频标题
+     */
+    @Override
+    public void setTitle(String title) {
+        mTitle.setText(title);
+    }
+
+    /**
+     * 获取ImageView的对象
+     * @return                  对象
+     */
+    @Override
+    public ImageView imageView() {
+        return mImage;
+    }
+
+    /**
+     * 设置图片
+     * @param resId             视频底图资源
+     */
+    @Override
+    public void setImage(@DrawableRes int resId) {
+        mImage.setImageResource(resId);
+    }
+
+    /**
+     * 设置视频时长
+     * @param length            时长
+     */
+    @Override
+    public void setLength(long length) {
+        mLength.setText(VideoPlayerUtils.formatTime(length));
+    }
+
+    /**
+     * 设置播放器
+     * @param niceVideoPlayer   播放器
+     */
+    @Override
+    public void setNiceVideoPlayer(InterVideoPlayer niceVideoPlayer) {
+        super.setNiceVideoPlayer(niceVideoPlayer);
+        // 给播放器配置视频链接地址
+        if (clarities != null && clarities.size() > 1) {
+            mNiceVideoPlayer.setUp(clarities.get(defaultClarityIndex).getVideoUrl(), null);
+        }
+    }
+
+    /**
+     * 设置清晰度
+     * @param clarities                         清晰度
+     * @param defaultClarityIndex               默认清晰度
+     */
+    public void setClarity(final List<VideoClarity> clarities, int defaultClarityIndex) {
+        if (clarities != null && clarities.size() > 1) {
+            this.clarities = clarities;
+            this.defaultClarityIndex = defaultClarityIndex;
+            List<String> clarityGrades = new ArrayList<>();
+            for (VideoClarity clarity : clarities) {
+                clarityGrades.add(clarity.getGrade() + " " + clarity.getP());
+            }
+            mClarity.setText(clarities.get(defaultClarityIndex).getGrade());
+            // 初始化切换清晰度对话框
+            mClarityDialog = new ChangeClarityDialog(mContext);
+            mClarityDialog.setClarityGrade(clarityGrades, defaultClarityIndex);
+            mClarityDialog.setOnClarityCheckedListener(new ChangeClarityDialog.OnClarityChangedListener() {
+                @Override
+                public void onClarityChanged(int clarityIndex) {
+                    // 根据切换后的清晰度索引值,设置对应的视频链接地址,并从当前播放位置接着播放
+                    VideoClarity clarity = clarities.get(clarityIndex);
+                    mClarity.setText(clarity.getGrade());
+                    long currentPosition = mNiceVideoPlayer.getCurrentPosition();
+                    mNiceVideoPlayer.releasePlayer();
+                    mNiceVideoPlayer.setUp(clarity.getVideoUrl(), null);
+                    mNiceVideoPlayer.start(currentPosition);
+                }
+
+                @Override
+                public void onClarityNotChanged() {
+                    // 清晰度没有变化,对话框消失后,需要重新显示出top、bottom
+                    setTopBottomVisible(true);
+                }
+            });
+            // 给播放器配置视频链接地址
+            if (mNiceVideoPlayer != null) {
+                mNiceVideoPlayer.setUp(clarities.get(defaultClarityIndex).getVideoUrl(), null);
+            }
+        }
+    }
+
+    /**
+     * 当播放状态发生改变时
+     * @param playState 播放状态:
+     *                  <ul>
+     *                  <li>{@link VideoPlayer#STATE_IDLE}</li>
+     *                  <li>{@link VideoPlayer#STATE_PREPARING}</li>
+     *                  <li>{@link VideoPlayer#STATE_PREPARED}</li>
+     *                  <li>{@link VideoPlayer#STATE_PLAYING}</li>
+     *                  <li>{@link VideoPlayer#STATE_PAUSED}</li>
+     *                  <li>{@link VideoPlayer#STATE_BUFFERING_PLAYING}</li>
+     *                  <li>{@link VideoPlayer#STATE_BUFFERING_PAUSED}</li>
+     *                  <li>{@link VideoPlayer#STATE_ERROR}</li>
+     *                  <li>{@link VideoPlayer#STATE_COMPLETED}</li>
+     */
+    @Override
+    protected void onPlayStateChanged(int playState) {
+        switch (playState) {
+            case VideoPlayer.STATE_IDLE:
+                break;
+            case VideoPlayer.STATE_PREPARING:                           //播放准备中
+                mImage.setVisibility(View.GONE);
+                mLoading.setVisibility(View.VISIBLE);
+                mLoadText.setText("正在准备...");
+                mError.setVisibility(View.GONE);
+                mCompleted.setVisibility(View.GONE);
+                mTop.setVisibility(View.GONE);
+                mBottom.setVisibility(View.GONE);
+                mCenterStart.setVisibility(View.GONE);
+                mLength.setVisibility(View.GONE);
+                break;
+            case VideoPlayer.STATE_PREPARED:                            //播放准备就绪
+                startUpdateProgressTimer();
+                break;
+            case VideoPlayer.STATE_PLAYING:                             //正在播放
+                mLoading.setVisibility(View.GONE);
+                mRestartPause.setImageResource(R.drawable.ic_player_pause);
+                startDismissTopBottomTimer();
+                break;
+            case VideoPlayer.STATE_PAUSED:                              //暂停播放
+                mLoading.setVisibility(View.GONE);
+                mRestartPause.setImageResource(R.drawable.ic_player_start);
+                cancelDismissTopBottomTimer();
+                break;
+            case VideoPlayer.STATE_BUFFERING_PLAYING:                   //正在缓冲(播放器正在播放时,缓冲区数据不足,进行缓冲,缓冲区数据足够后恢复播放)
+                mLoading.setVisibility(View.VISIBLE);
+                mRestartPause.setImageResource(R.drawable.ic_player_pause);
+                mLoadText.setText("正在缓冲...");
+                startDismissTopBottomTimer();
+                break;
+            case VideoPlayer.STATE_BUFFERING_PAUSED:                    //正在缓冲
+                mLoading.setVisibility(View.VISIBLE);
+                mRestartPause.setImageResource(R.drawable.ic_player_start);
+                mLoadText.setText("正在缓冲...");
+                cancelDismissTopBottomTimer();
+                break;
+            case VideoPlayer.STATE_ERROR:                               //播放错误
+                cancelUpdateProgressTimer();
+                setTopBottomVisible(false);
+                mTop.setVisibility(View.VISIBLE);
+                mError.setVisibility(View.VISIBLE);
+                break;
+            case VideoPlayer.STATE_COMPLETED:                           //播放完成
+                cancelUpdateProgressTimer();
+                setTopBottomVisible(false);
+                mImage.setVisibility(View.VISIBLE);
+                mCompleted.setVisibility(View.VISIBLE);
+                break;
+        }
+    }
+
+    /**
+     * 当播放器的播放模式发生变化时
+     * @param playMode 播放器的模式:
+     *                 <ul>
+     *                 <li>{@link VideoPlayer#MODE_NORMAL}</li>
+     *                 <li>{@link VideoPlayer#MODE_FULL_SCREEN}</li>
+     *                 <li>{@link VideoPlayer#MODE_TINY_WINDOW}</li>
+     */
+    @Override
+    protected void onPlayModeChanged(int playMode) {
+        switch (playMode) {
+            case VideoPlayer.MODE_NORMAL:                               //普通模式
+                mBack.setVisibility(View.GONE);
+                mFullScreen.setImageResource(R.drawable.ic_player_enlarge);
+                mFullScreen.setVisibility(View.VISIBLE);
+                mClarity.setVisibility(View.GONE);
+                mBatteryTime.setVisibility(View.GONE);
+                if (hasRegisterBatteryReceiver) {
+                    mContext.unregisterReceiver(mBatterReceiver);
+                    hasRegisterBatteryReceiver = false;
+                }
+                break;
+            case VideoPlayer.MODE_FULL_SCREEN:                          //全屏模式
+                mBack.setVisibility(View.VISIBLE);
+                mFullScreen.setVisibility(View.GONE);
+                mFullScreen.setImageResource(R.drawable.ic_player_shrink);
+                if (clarities != null && clarities.size() > 1) {
+                    mClarity.setVisibility(View.VISIBLE);
+                }
+                mBatteryTime.setVisibility(View.VISIBLE);
+                if (!hasRegisterBatteryReceiver) {
+                    mContext.registerReceiver(mBatterReceiver, new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
+                    hasRegisterBatteryReceiver = true;
+                }
+                break;
+            case VideoPlayer.MODE_TINY_WINDOW:                          //小窗口模式
+                mBack.setVisibility(View.VISIBLE);
+                mClarity.setVisibility(View.GONE);
+                break;
+        }
+    }
+
+    /**
+     * 电池状态即电量变化广播接收器
+     */
+    private BroadcastReceiver mBatterReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            int status = intent.getIntExtra(BatteryManager.EXTRA_STATUS, BatteryManager.BATTERY_STATUS_UNKNOWN);
+            if (status == BatteryManager.BATTERY_STATUS_CHARGING) {
+                // 充电中
+                mBattery.setImageResource(R.drawable.battery_charging);
+            } else if (status == BatteryManager.BATTERY_STATUS_FULL) {
+                // 充电完成
+                mBattery.setImageResource(R.drawable.battery_full);
+            } else {
+                int level = intent.getIntExtra(BatteryManager.EXTRA_LEVEL, 0);
+                int scale = intent.getIntExtra(BatteryManager.EXTRA_SCALE, 0);
+                int percentage = (int) (((float) level / scale) * 100);
+                if (percentage <= 10) {
+                    mBattery.setImageResource(R.drawable.battery_10);
+                } else if (percentage <= 20) {
+                    mBattery.setImageResource(R.drawable.battery_20);
+                } else if (percentage <= 50) {
+                    mBattery.setImageResource(R.drawable.battery_50);
+                } else if (percentage <= 80) {
+                    mBattery.setImageResource(R.drawable.battery_80);
+                } else if (percentage <= 100) {
+                    mBattery.setImageResource(R.drawable.battery_100);
+                }
+            }
+        }
+    };
+
+    @Override
+    protected void reset() {
+        topBottomVisible = false;
+        cancelUpdateProgressTimer();
+        cancelDismissTopBottomTimer();
+        mSeek.setProgress(0);
+        mSeek.setSecondaryProgress(0);
+
+        mCenterStart.setVisibility(View.VISIBLE);
+        mImage.setVisibility(View.VISIBLE);
+
+        mBottom.setVisibility(View.GONE);
+        mFullScreen.setImageResource(R.drawable.ic_player_enlarge);
+
+        mLength.setVisibility(View.VISIBLE);
+
+        mTop.setVisibility(View.VISIBLE);
+        mBack.setVisibility(View.GONE);
+
+        mLoading.setVisibility(View.GONE);
+        mError.setVisibility(View.GONE);
+        mCompleted.setVisibility(View.GONE);
+    }
+
+    /**
+     * 尽量不要在onClick中直接处理控件的隐藏、显示及各种UI逻辑。
+     * UI相关的逻辑都尽量到{@link #onPlayStateChanged}和{@link #onPlayModeChanged}中处理.
+     */
+    @Override
+    public void onClick(View v) {
+        if (v == mCenterStart) {
+            if (mNiceVideoPlayer.isIdle()) {
+                mNiceVideoPlayer.start();
+            }
+        } else if (v == mBack) {
+            if (mNiceVideoPlayer.isFullScreen()) {
+                mNiceVideoPlayer.exitFullScreen();
+            } else if (mNiceVideoPlayer.isTinyWindow()) {
+                mNiceVideoPlayer.exitTinyWindow();
+            }
+        } else if (v == mRestartPause) {
+            if (mNiceVideoPlayer.isPlaying() || mNiceVideoPlayer.isBufferingPlaying()) {
+                mNiceVideoPlayer.pause();
+            } else if (mNiceVideoPlayer.isPaused() || mNiceVideoPlayer.isBufferingPaused()) {
+                mNiceVideoPlayer.restart();
+            }
+        } else if (v == mFullScreen) {
+            if (mNiceVideoPlayer.isNormal() || mNiceVideoPlayer.isTinyWindow()) {
+                mNiceVideoPlayer.enterFullScreen();
+            } else if (mNiceVideoPlayer.isFullScreen()) {
+                mNiceVideoPlayer.exitFullScreen();
+            }
+        } else if (v == mClarity) {
+            setTopBottomVisible(false); // 隐藏top、bottom
+            mClarityDialog.show();     // 显示清晰度对话框
+        } else if (v == mRetry) {
+            mNiceVideoPlayer.restart();
+        } else if (v == mReplay) {
+            mRetry.performClick();
+        } else if (v == mShare) {
+            Toast.makeText(mContext, "分享", Toast.LENGTH_SHORT).show();
+        } else if (v == this) {
+            if (mNiceVideoPlayer.isPlaying()
+                    || mNiceVideoPlayer.isPaused()
+                    || mNiceVideoPlayer.isBufferingPlaying()
+                    || mNiceVideoPlayer.isBufferingPaused()) {
+                setTopBottomVisible(!topBottomVisible);
+            }
+        }
+    }
+
+
+    /**
+     * 设置top、bottom的显示和隐藏
+     * @param visible true显示,false隐藏.
+     */
+    private void setTopBottomVisible(boolean visible) {
+        mTop.setVisibility(visible ? View.VISIBLE : View.GONE);
+        mBottom.setVisibility(visible ? View.VISIBLE : View.GONE);
+        topBottomVisible = visible;
+        if (visible) {
+            if (!mNiceVideoPlayer.isPaused() && !mNiceVideoPlayer.isBufferingPaused()) {
+                startDismissTopBottomTimer();
+            }
+        } else {
+            cancelDismissTopBottomTimer();
+        }
+    }
+
+    /**
+     * 开启top、bottom自动消失的timer
+     */
+    private void startDismissTopBottomTimer() {
+        cancelDismissTopBottomTimer();
+        if (mDismissTopBottomCountDownTimer == null) {
+            mDismissTopBottomCountDownTimer = new CountDownTimer(8000, 8000) {
+                @Override
+                public void onTick(long millisUntilFinished) {
+
+                }
+
+                @Override
+                public void onFinish() {
+                    setTopBottomVisible(false);
+                }
+            };
+        }
+        mDismissTopBottomCountDownTimer.start();
+    }
+
+    /**
+     * 取消top、bottom自动消失的timer
+     */
+    private void cancelDismissTopBottomTimer() {
+        if (mDismissTopBottomCountDownTimer != null) {
+            mDismissTopBottomCountDownTimer.cancel();
+        }
+    }
+
+    @Override
+    protected void updateProgress() {
+        long position = mNiceVideoPlayer.getCurrentPosition();
+        long duration = mNiceVideoPlayer.getDuration();
+        int bufferPercentage = mNiceVideoPlayer.getBufferPercentage();
+        mSeek.setSecondaryProgress(bufferPercentage);
+        int progress = (int) (100f * position / duration);
+        mSeek.setProgress(progress);
+        mPosition.setText(VideoPlayerUtils.formatTime(position));
+        mDuration.setText(VideoPlayerUtils.formatTime(duration));
+        // 更新时间
+        mTime.setText(new SimpleDateFormat("HH:mm", Locale.CHINA).format(new Date()));
+    }
+
+    @Override
+    protected void showChangePosition(long duration, int newPositionProgress) {
+        mChangePositon.setVisibility(View.VISIBLE);
+        long newPosition = (long) (duration * newPositionProgress / 100f);
+        mChangePositionCurrent.setText(VideoPlayerUtils.formatTime(newPosition));
+        mChangePositionProgress.setProgress(newPositionProgress);
+        mSeek.setProgress(newPositionProgress);
+        mPosition.setText(VideoPlayerUtils.formatTime(newPosition));
+    }
+
+    @Override
+    protected void hideChangePosition() {
+        mChangePositon.setVisibility(View.GONE);
+    }
+
+    @Override
+    protected void showChangeVolume(int newVolumeProgress) {
+        mChangeVolume.setVisibility(View.VISIBLE);
+        mChangeVolumeProgress.setProgress(newVolumeProgress);
+    }
+
+    @Override
+    protected void hideChangeVolume() {
+        mChangeVolume.setVisibility(View.GONE);
+    }
+
+    @Override
+    protected void showChangeBrightness(int newBrightnessProgress) {
+        mChangeBrightness.setVisibility(View.VISIBLE);
+        mChangeBrightnessProgress.setProgress(newBrightnessProgress);
+    }
+
+    @Override
+    protected void hideChangeBrightness() {
+        mChangeBrightness.setVisibility(View.GONE);
+    }
+}

+ 61 - 0
YCVideoPlayerLib/src/main/java/org/yczbj/ycvideoplayerlib/VideoPlayerManager.java

@@ -0,0 +1,61 @@
+package org.yczbj.ycvideoplayerlib;
+
+/**
+ * 视频播放器管理器.
+ */
+public class VideoPlayerManager {
+
+    private VideoPlayer mVideoPlayer;
+
+    private VideoPlayerManager() {}
+
+    private static VideoPlayerManager sInstance;
+
+    public static synchronized VideoPlayerManager instance() {
+        if (sInstance == null) {
+            sInstance = new VideoPlayerManager();
+        }
+        return sInstance;
+    }
+
+    public VideoPlayer getCurrentNiceVideoPlayer() {
+        return mVideoPlayer;
+    }
+
+    public void setCurrentNiceVideoPlayer(VideoPlayer videoPlayer) {
+        if (mVideoPlayer != videoPlayer) {
+            releaseNiceVideoPlayer();
+            mVideoPlayer = videoPlayer;
+        }
+    }
+
+    public void suspendNiceVideoPlayer() {
+        if (mVideoPlayer != null && (mVideoPlayer.isPlaying() || mVideoPlayer.isBufferingPlaying())) {
+            mVideoPlayer.pause();
+        }
+    }
+
+    public void resumeNiceVideoPlayer() {
+        if (mVideoPlayer != null && (mVideoPlayer.isPaused() || mVideoPlayer.isBufferingPaused())) {
+            mVideoPlayer.restart();
+        }
+    }
+
+    public void releaseNiceVideoPlayer() {
+        if (mVideoPlayer != null) {
+            mVideoPlayer.release();
+            mVideoPlayer = null;
+        }
+    }
+
+    public boolean onBackPressd() {
+        if (mVideoPlayer != null) {
+            if (mVideoPlayer.isFullScreen()) {
+                return mVideoPlayer.exitFullScreen();
+            } else if (mVideoPlayer.isTinyWindow()) {
+                return mVideoPlayer.exitTinyWindow();
+            }
+        }
+        return false;
+    }
+}

+ 138 - 0
YCVideoPlayerLib/src/main/java/org/yczbj/ycvideoplayerlib/VideoPlayerUtils.java

@@ -0,0 +1,138 @@
+package org.yczbj.ycvideoplayerlib;
+
+import android.annotation.SuppressLint;
+import android.app.Activity;
+import android.content.Context;
+import android.content.ContextWrapper;
+import android.support.v7.app.ActionBar;
+import android.support.v7.app.AppCompatActivity;
+import android.support.v7.view.ContextThemeWrapper;
+import android.util.TypedValue;
+import android.view.WindowManager;
+
+import java.util.Formatter;
+import java.util.Locale;
+
+/**
+ * 工具类.
+ */
+public class VideoPlayerUtils {
+
+    /**
+     * Get activity from context object
+     *
+     * @param context       上下文
+     * @return              对象的活动对象,如果它不是活动对象,则为空。
+     */
+    static Activity scanForActivity(Context context) {
+        if (context == null) return null;
+        if (context instanceof Activity) {
+            return (Activity) context;
+        } else if (context instanceof ContextWrapper) {
+            return scanForActivity(((ContextWrapper) context).getBaseContext());
+        }
+        return null;
+    }
+
+    /**
+     * Get AppCompatActivity from context
+     *
+     * @param context
+     * @return AppCompatActivity if it's not null
+     */
+    private static AppCompatActivity getAppCompActivity(Context context) {
+        if (context == null) return null;
+        if (context instanceof AppCompatActivity) {
+            return (AppCompatActivity) context;
+        } else if (context instanceof ContextThemeWrapper) {
+            return getAppCompActivity(((ContextThemeWrapper) context).getBaseContext());
+        }
+        return null;
+    }
+
+    @SuppressLint("RestrictedApi")
+    static void showActionBar(Context context) {
+        ActionBar ab = getAppCompActivity(context).getSupportActionBar();
+        if (ab != null) {
+            ab.setShowHideAnimationEnabled(false);
+            ab.show();
+        }
+        scanForActivity(context).getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
+    }
+
+    @SuppressLint("RestrictedApi")
+    static void hideActionBar(Context context) {
+        ActionBar ab = getAppCompActivity(context).getSupportActionBar();
+        if (ab != null) {
+            ab.setShowHideAnimationEnabled(false);
+            ab.hide();
+        }
+        scanForActivity(context).getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
+                        WindowManager.LayoutParams.FLAG_FULLSCREEN);
+    }
+
+    /**
+     * 获取屏幕宽度
+     */
+    static int getScreenWidth(Context context) {
+        return context.getResources().getDisplayMetrics().widthPixels;
+    }
+
+    /**
+     * 获取屏幕高度
+     */
+    static int getScreenHeight(Context context) {
+        return context.getResources().getDisplayMetrics().heightPixels;
+    }
+
+    /**
+     * dp转px
+     */
+    static int dp2px(Context context, float dpVal) {
+        return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dpVal,
+                context.getResources().getDisplayMetrics());
+    }
+
+    /**
+     * 将毫秒数格式化为"##:##"的时间
+     * @param milliseconds 毫秒数
+     * @return ##:##
+     */
+    static String formatTime(long milliseconds) {
+        if (milliseconds <= 0 || milliseconds >= 24 * 60 * 60 * 1000) {
+            return "00:00";
+        }
+        long totalSeconds = milliseconds / 1000;
+        long seconds = totalSeconds % 60;
+        long minutes = (totalSeconds / 60) % 60;
+        long hours = totalSeconds / 3600;
+        StringBuilder stringBuilder = new StringBuilder();
+        Formatter mFormatter = new Formatter(stringBuilder, Locale.getDefault());
+        if (hours > 0) {
+            return mFormatter.format("%d:%02d:%02d", hours, minutes, seconds).toString();
+        } else {
+            return mFormatter.format("%02d:%02d", minutes, seconds).toString();
+        }
+    }
+
+    /**
+     * 保存播放位置,以便下次播放时接着上次的位置继续播放.
+     * @param context           上下文
+     * @param url               视频链接url
+     */
+    static void savePlayPosition(Context context, String url, long position) {
+        context.getSharedPreferences("VIDEO_PLAYER_PLAY_POSITION",
+                Context.MODE_PRIVATE).edit().putLong(url, position).apply();
+    }
+
+    /**
+     * 取出上次保存的播放位置
+     * @param context
+     * @param url     视频链接url
+     * @return 上次保存的播放位置
+     */
+    static long getSavedPlayPosition(Context context, String url) {
+        return context.getSharedPreferences("VIDEO_PLAYER_PLAY_POSITION",
+                Context.MODE_PRIVATE).getLong(url, 0);
+    }
+}

+ 109 - 0
YCVideoPlayerLib/src/main/java/org/yczbj/ycvideoplayerlib/VideoTextureView.java

@@ -0,0 +1,109 @@
+package org.yczbj.ycvideoplayerlib;
+
+import android.content.Context;
+import android.view.TextureView;
+
+/**
+ * @author yc
+ * @date 2017/12/29
+ * 重写TextureView,适配视频的宽高和旋转.
+ * 参考项目:https://github.com/JasonChow1989/JieCaoVideoPlayer-develop          2年前
+ *          https://github.com/open-android/JieCaoVideoPlayer                   1年前
+ *          https://github.com/lipangit/JiaoZiVideoPlayer                       4个月前
+ *          个人感觉jiaozi这个播放器,与JieCaoVideoPlayer-develop有惊人的类同,借鉴了上面两个项目
+ */
+
+public class VideoTextureView extends TextureView {
+
+    private int videoHeight;
+    private int videoWidth;
+
+    public VideoTextureView(Context context) {
+        super(context);
+    }
+
+    public void adaptVideoSize(int videoWidth, int videoHeight) {
+        if (this.videoWidth != videoWidth && this.videoHeight != videoHeight) {
+            this.videoWidth = videoWidth;
+            this.videoHeight = videoHeight;
+            requestLayout();
+        }
+    }
+
+    @Override
+    public void setRotation(float rotation) {
+        if (rotation != getRotation()) {
+            super.setRotation(rotation);
+            requestLayout();
+        }
+    }
+
+    @Override
+    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        float viewRotation = getRotation();
+        // 如果判断成立,则说明显示的TextureView和本身的位置是有90度的旋转的,所以需要交换宽高参数。
+        if (viewRotation == 90f || viewRotation == 270f) {
+            int tempMeasureSpec = widthMeasureSpec;
+            //noinspection SuspiciousNameCombination
+            widthMeasureSpec = heightMeasureSpec;
+            heightMeasureSpec = tempMeasureSpec;
+        }
+
+        int width = getDefaultSize(videoWidth, widthMeasureSpec);
+        int height = getDefaultSize(videoHeight, heightMeasureSpec);
+        if (videoWidth > 0 && videoHeight > 0) {
+
+            int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec);
+            int widthSpecSize = MeasureSpec.getSize(widthMeasureSpec);
+            int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec);
+            int heightSpecSize = MeasureSpec.getSize(heightMeasureSpec);
+
+            if (widthSpecMode == MeasureSpec.EXACTLY && heightSpecMode == MeasureSpec.EXACTLY) {
+                // the size is fixed
+                width = widthSpecSize;
+                height = heightSpecSize;
+                // for compatibility, we adjust size based on aspect ratio
+                if (videoWidth * height < width * videoHeight) {
+                    width = height * videoWidth / videoHeight;
+                } else if (videoWidth * height > width * videoHeight) {
+                    height = width * videoHeight / videoWidth;
+                }
+            } else if (widthSpecMode == MeasureSpec.EXACTLY) {
+                // only the width is fixed, adjust the height to match aspect ratio if possible
+                width = widthSpecSize;
+                height = width * videoHeight / videoWidth;
+                if (heightSpecMode == MeasureSpec.AT_MOST && height > heightSpecSize) {
+                    // couldn't match aspect ratio within the constraints
+                    height = heightSpecSize;
+                    width = height * videoWidth / videoHeight;
+                }
+            } else if (heightSpecMode == MeasureSpec.EXACTLY) {
+                // only the height is fixed, adjust the width to match aspect ratio if possible
+                height = heightSpecSize;
+                width = height * videoWidth / videoHeight;
+                if (widthSpecMode == MeasureSpec.AT_MOST && width > widthSpecSize) {
+                    // couldn't match aspect ratio within the constraints
+                    width = widthSpecSize;
+                    height = width * videoHeight / videoWidth;
+                }
+            } else {
+                // neither the width nor the height are fixed, try to use actual video size
+                width = videoWidth;
+                height = videoHeight;
+                if (heightSpecMode == MeasureSpec.AT_MOST && height > heightSpecSize) {
+                    // too tall, decrease both width and height
+                    height = heightSpecSize;
+                    width = height * videoWidth / videoHeight;
+                }
+                if (widthSpecMode == MeasureSpec.AT_MOST && width > widthSpecSize) {
+                    // too wide, decrease both width and height
+                    width = widthSpecSize;
+                    height = width * videoHeight / videoWidth;
+                }
+            }
+        } else {
+            // no size yet, just adopt the given spec sizes
+        }
+        setMeasuredDimension(width, height);
+    }
+}

+ 7 - 0
YCVideoPlayerLib/src/main/res/color/select_change_clarity_color.xml

@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:color="#FF7000"
+          android:state_selected="true"/>
+    <item android:color="#ffffff"
+          android:state_selected="false"/>
+</selector>

BIN
YCVideoPlayerLib/src/main/res/drawable-xhdpi/battery_10.png


BIN
YCVideoPlayerLib/src/main/res/drawable-xhdpi/battery_100.png


BIN
YCVideoPlayerLib/src/main/res/drawable-xhdpi/battery_20.png


BIN
YCVideoPlayerLib/src/main/res/drawable-xhdpi/battery_50.png


BIN
YCVideoPlayerLib/src/main/res/drawable-xhdpi/battery_80.png


BIN
YCVideoPlayerLib/src/main/res/drawable-xhdpi/battery_charging.png


BIN
YCVideoPlayerLib/src/main/res/drawable-xhdpi/battery_full.png


BIN
YCVideoPlayerLib/src/main/res/drawable-xhdpi/ic_palyer_brightness.png


BIN
YCVideoPlayerLib/src/main/res/drawable-xhdpi/ic_palyer_share.png


BIN
YCVideoPlayerLib/src/main/res/drawable-xhdpi/ic_palyer_volume.png


BIN
YCVideoPlayerLib/src/main/res/drawable-xhdpi/ic_player_back.png


BIN
YCVideoPlayerLib/src/main/res/drawable-xhdpi/ic_player_center_start.png


BIN
YCVideoPlayerLib/src/main/res/drawable-xhdpi/ic_player_enlarge.png


BIN
YCVideoPlayerLib/src/main/res/drawable-xhdpi/ic_player_pause.png


BIN
YCVideoPlayerLib/src/main/res/drawable-xhdpi/ic_player_replay.png


BIN
YCVideoPlayerLib/src/main/res/drawable-xhdpi/ic_player_shrink.png


BIN
YCVideoPlayerLib/src/main/res/drawable-xhdpi/ic_player_start.png


BIN
YCVideoPlayerLib/src/main/res/drawable-xhdpi/loading00.png


BIN
YCVideoPlayerLib/src/main/res/drawable-xhdpi/loading01.png


BIN
YCVideoPlayerLib/src/main/res/drawable-xhdpi/loading02.png


BIN
YCVideoPlayerLib/src/main/res/drawable-xhdpi/loading03.png


BIN
YCVideoPlayerLib/src/main/res/drawable-xhdpi/loading04.png


BIN
YCVideoPlayerLib/src/main/res/drawable-xhdpi/loading05.png


BIN
YCVideoPlayerLib/src/main/res/drawable-xhdpi/loading06.png


BIN
YCVideoPlayerLib/src/main/res/drawable-xhdpi/loading07.png


BIN
YCVideoPlayerLib/src/main/res/drawable-xhdpi/loading08.png


BIN
YCVideoPlayerLib/src/main/res/drawable-xhdpi/loading09.png


BIN
YCVideoPlayerLib/src/main/res/drawable-xhdpi/loading10.png


BIN
YCVideoPlayerLib/src/main/res/drawable-xhdpi/loading11.png


BIN
YCVideoPlayerLib/src/main/res/drawable-xhdpi/loading12.png


BIN
YCVideoPlayerLib/src/main/res/drawable-xhdpi/loading13.png


BIN
YCVideoPlayerLib/src/main/res/drawable-xhdpi/loading14.png


BIN
YCVideoPlayerLib/src/main/res/drawable-xhdpi/loading15.png


BIN
YCVideoPlayerLib/src/main/res/drawable-xhdpi/loading16.png


BIN
YCVideoPlayerLib/src/main/res/drawable-xhdpi/loading17.png


BIN
YCVideoPlayerLib/src/main/res/drawable-xhdpi/loading18.png


BIN
YCVideoPlayerLib/src/main/res/drawable-xhdpi/loading19.png


BIN
YCVideoPlayerLib/src/main/res/drawable-xhdpi/loading20.png


BIN
YCVideoPlayerLib/src/main/res/drawable-xhdpi/loading21.png


BIN
YCVideoPlayerLib/src/main/res/drawable-xhdpi/loading22.png


BIN
YCVideoPlayerLib/src/main/res/drawable-xhdpi/loading23.png


BIN
YCVideoPlayerLib/src/main/res/drawable-xhdpi/loading24.png


BIN
YCVideoPlayerLib/src/main/res/drawable-xhdpi/loading25.png


BIN
YCVideoPlayerLib/src/main/res/drawable-xhdpi/loading26.png


BIN
YCVideoPlayerLib/src/main/res/drawable-xhdpi/loading27.png


BIN
YCVideoPlayerLib/src/main/res/drawable-xhdpi/loading28.png


BIN
YCVideoPlayerLib/src/main/res/drawable-xhdpi/loading29.png


BIN
YCVideoPlayerLib/src/main/res/drawable-xhdpi/player_mask_bottom.png


BIN
YCVideoPlayerLib/src/main/res/drawable-xhdpi/player_mask_top.png


+ 14 - 0
YCVideoPlayerLib/src/main/res/drawable/bg_change_clarity_checked.xml

@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+       android:shape="rectangle">
+    <solid android:color="#00000000"/>
+    <corners android:radius="32dp"/>
+    <stroke
+        android:width="1.5dp"
+        android:color="#FF7000"/>
+    <padding
+        android:bottom="7dp"
+        android:left="12dp"
+        android:right="12dp"
+        android:top="6dp"/>
+</shape>

+ 14 - 0
YCVideoPlayerLib/src/main/res/drawable/bg_change_clarity_normal.xml

@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+       android:shape="rectangle">
+    <solid android:color="#00000000"/>
+    <corners android:radius="32dp"/>
+    <stroke
+        android:width="1.5dp"
+        android:color="#00000000"/>
+    <padding
+        android:bottom="7dp"
+        android:left="12dp"
+        android:right="12dp"
+        android:top="6dp"/>
+</shape>

+ 6 - 0
YCVideoPlayerLib/src/main/res/drawable/bg_radius_4.xml

@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+       android:shape="rectangle">
+    <corners android:radius="6dp"/>
+    <solid android:color="#c8000000"/>
+</shape>

+ 6 - 0
YCVideoPlayerLib/src/main/res/drawable/bg_retry.xml

@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+       android:shape="rectangle">
+    <corners android:radius="20dp"/>
+    <solid android:color="#323232"/>
+</shape>

+ 34 - 0
YCVideoPlayerLib/src/main/res/drawable/loading.xml

@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<animation-list xmlns:android="http://schemas.android.com/apk/res/android"
+                android:oneshot="false">
+    <item android:drawable="@drawable/loading00" android:duration="30"/>
+    <item android:drawable="@drawable/loading01" android:duration="30"/>
+    <item android:drawable="@drawable/loading02" android:duration="30"/>
+    <item android:drawable="@drawable/loading03" android:duration="30"/>
+    <item android:drawable="@drawable/loading04" android:duration="30"/>
+    <item android:drawable="@drawable/loading05" android:duration="30"/>
+    <item android:drawable="@drawable/loading06" android:duration="30"/>
+    <item android:drawable="@drawable/loading07" android:duration="30"/>
+    <item android:drawable="@drawable/loading08" android:duration="30"/>
+    <item android:drawable="@drawable/loading09" android:duration="30"/>
+    <item android:drawable="@drawable/loading10" android:duration="30"/>
+    <item android:drawable="@drawable/loading11" android:duration="30"/>
+    <item android:drawable="@drawable/loading12" android:duration="30"/>
+    <item android:drawable="@drawable/loading13" android:duration="30"/>
+    <item android:drawable="@drawable/loading14" android:duration="30"/>
+    <item android:drawable="@drawable/loading15" android:duration="30"/>
+    <item android:drawable="@drawable/loading16" android:duration="30"/>
+    <item android:drawable="@drawable/loading17" android:duration="30"/>
+    <item android:drawable="@drawable/loading18" android:duration="30"/>
+    <item android:drawable="@drawable/loading19" android:duration="30"/>
+    <item android:drawable="@drawable/loading20" android:duration="30"/>
+    <item android:drawable="@drawable/loading21" android:duration="30"/>
+    <item android:drawable="@drawable/loading22" android:duration="30"/>
+    <item android:drawable="@drawable/loading23" android:duration="30"/>
+    <item android:drawable="@drawable/loading24" android:duration="30"/>
+    <item android:drawable="@drawable/loading25" android:duration="30"/>
+    <item android:drawable="@drawable/loading26" android:duration="30"/>
+    <item android:drawable="@drawable/loading27" android:duration="30"/>
+    <item android:drawable="@drawable/loading28" android:duration="30"/>
+    <item android:drawable="@drawable/loading29" android:duration="30"/>
+</animation-list>

+ 17 - 0
YCVideoPlayerLib/src/main/res/drawable/pb_change.xml

@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="utf-8"?>
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:id="@android:id/background">
+        <shape>
+            <solid android:color="#7dffffff" />
+            <corners android:radius="2dp" />
+        </shape>
+    </item>
+    <item android:id="@android:id/progress">
+        <clip>
+            <shape>
+                <solid android:color="#FFffffff" />
+                <corners android:radius="2dp" />
+            </shape>
+        </clip>
+    </item>
+</layer-list>

+ 28 - 0
YCVideoPlayerLib/src/main/res/drawable/seek_progress.xml

@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:id="@android:id/background">
+        <shape>
+            <solid android:color="#7dffffff" />
+            <size android:height="2dp" />
+            <corners android:radius="2dp" />
+        </shape>
+    </item>
+    <item android:id="@android:id/secondaryProgress">
+        <clip>
+            <shape>
+                <solid android:color="#ffffffff" />
+                <size android:height="2dp" />
+                <corners android:radius="2dp" />
+            </shape>
+        </clip>
+    </item>
+    <item android:id="@android:id/progress">
+        <clip>
+            <shape>
+                <solid android:color="#FF7000" />
+                <size android:height="2dp" />
+                <corners android:radius="2dp" />
+            </shape>
+        </clip>
+    </item>
+</layer-list>

+ 5 - 0
YCVideoPlayerLib/src/main/res/drawable/seek_thumb.xml

@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:drawable="@drawable/seek_thumb_pressed" android:state_pressed="true" />
+    <item android:drawable="@drawable/seek_thumb_normal" />
+</selector>

+ 24 - 0
YCVideoPlayerLib/src/main/res/drawable/seek_thumb_normal.xml

@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+
+    <item>
+        <shape android:shape="oval">
+            <solid android:color="#5aff7000"/>
+            <size
+                android:width="16dp"
+                android:height="16dp"/>
+        </shape>
+    </item>
+    <item
+        android:bottom="4dp"
+        android:left="4dp"
+        android:right="4dp"
+        android:top="4dp">
+        <shape android:shape="oval">
+            <solid android:color="#FF7000"/>
+            <size
+                android:width="8dp"
+                android:height="8dp"/>
+        </shape>
+    </item>
+</layer-list>

+ 23 - 0
YCVideoPlayerLib/src/main/res/drawable/seek_thumb_pressed.xml

@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
+    <item >
+        <shape android:shape="oval">
+            <solid android:color="#96ff7000"/>
+            <size
+                android:width="16dp"
+                android:height="16dp"/>
+        </shape>
+    </item>
+    <item
+        android:bottom="4dp"
+        android:left="4dp"
+        android:right="4dp"
+        android:top="4dp">
+        <shape android:shape="oval">
+            <solid android:color="#FF7000"/>
+            <size
+                android:width="8dp"
+                android:height="8dp"/>
+        </shape>
+    </item>
+</layer-list>

+ 7 - 0
YCVideoPlayerLib/src/main/res/drawable/select_change_clarity.xml

@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:drawable="@drawable/bg_change_clarity_checked"
+          android:state_selected="true"/>
+    <item android:drawable="@drawable/bg_change_clarity_normal"
+          android:state_selected="false"/>
+</selector>

+ 10 - 0
YCVideoPlayerLib/src/main/res/layout/change_video_clarity.xml

@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<TextView xmlns:android="http://schemas.android.com/apk/res/android"
+          android:layout_width="wrap_content"
+          android:layout_height="wrap_content"
+          android:layout_marginTop="0dp"
+          android:background="@drawable/select_change_clarity"
+          android:gravity="center"
+          android:text="标清 270P"
+          android:textColor="@color/select_change_clarity_color"
+          android:textSize="15sp"/>

+ 321 - 0
YCVideoPlayerLib/src/main/res/layout/custom_video_player.xml

@@ -0,0 +1,321 @@
+<?xml version="1.0" encoding="utf-8"?>
+<RelativeLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+
+    <!--底图-->
+    <ImageView
+        android:id="@+id/image"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:scaleType="fitXY"
+        android:visibility="visible"/>
+
+    <!--加载动画view-->
+    <LinearLayout
+        android:id="@+id/loading"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:gravity="center"
+        android:orientation="vertical"
+        android:visibility="gone">
+        <ProgressBar
+            android:layout_width="27dp"
+            android:layout_height="10dp"
+            android:indeterminateDrawable="@drawable/loading"/>
+        <TextView
+            android:id="@+id/load_text"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_marginTop="8dp"
+            android:text="正在缓冲..."
+            android:textColor="@android:color/white"
+            android:textSize="12sp"/>
+    </LinearLayout>
+
+
+    <!--改变播放位置-->
+    <LinearLayout
+        android:id="@+id/change_position"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_centerInParent="true"
+        android:background="@drawable/bg_radius_4"
+        android:gravity="center"
+        android:orientation="vertical"
+        android:padding="8dp"
+        android:visibility="gone">
+        <TextView
+            android:id="@+id/change_position_current"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="00:00"
+            android:textColor="@android:color/white"
+            android:textSize="28sp"/>
+        <ProgressBar
+            android:id="@+id/change_position_progress"
+            style="@android:style/Widget.ProgressBar.Horizontal"
+            android:layout_width="100dp"
+            android:layout_height="2dp"
+            android:layout_marginBottom="4dp"
+            android:layout_marginTop="8dp"
+            android:max="100"
+            android:progressDrawable="@drawable/pb_change"/>
+    </LinearLayout>
+
+
+    <!--改变亮度-->
+    <LinearLayout
+        android:id="@+id/change_brightness"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_centerInParent="true"
+        android:background="@drawable/bg_radius_4"
+        android:gravity="center"
+        android:orientation="vertical"
+        android:padding="8dp"
+        android:visibility="gone">
+        <ImageView
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:src="@drawable/ic_palyer_brightness"/>
+        <ProgressBar
+            android:id="@+id/change_brightness_progress"
+            style="@android:style/Widget.ProgressBar.Horizontal"
+            android:layout_width="100dp"
+            android:layout_height="2dp"
+            android:layout_marginBottom="4dp"
+            android:layout_marginTop="8dp"
+            android:max="100"
+            android:progressDrawable="@drawable/pb_change"/>
+    </LinearLayout>
+
+
+    <!--改变声音-->
+    <LinearLayout
+        android:id="@+id/change_volume"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_centerInParent="true"
+        android:background="@drawable/bg_radius_4"
+        android:gravity="center"
+        android:orientation="vertical"
+        android:padding="8dp"
+        android:visibility="gone">
+        <ImageView
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:src="@drawable/ic_palyer_volume"/>
+        <ProgressBar
+            android:id="@+id/change_volume_progress"
+            style="@android:style/Widget.ProgressBar.Horizontal"
+            android:layout_width="100dp"
+            android:layout_height="2dp"
+            android:layout_marginBottom="4dp"
+            android:layout_marginTop="8dp"
+            android:max="100"
+            android:progressDrawable="@drawable/pb_change"/>
+    </LinearLayout>
+
+    <!--播放完成-->
+    <LinearLayout
+        android:id="@+id/completed"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:background="#6c0b0b0b"
+        android:gravity="center"
+        android:orientation="horizontal"
+        android:visibility="gone">
+        <TextView
+            android:id="@+id/replay"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:drawableLeft="@drawable/ic_player_replay"
+            android:drawablePadding="4dp"
+            android:padding="8dp"
+            android:text="重新播放"
+            android:textColor="@android:color/white"
+            android:textSize="13sp"/>
+        <TextView
+            android:id="@+id/share"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_marginLeft="64dp"
+            android:drawableLeft="@drawable/ic_palyer_share"
+            android:drawablePadding="4dp"
+            android:padding="8dp"
+            android:text="分享"
+            android:textColor="@android:color/white"
+            android:textSize="13sp"/>
+    </LinearLayout>
+
+
+    <!--播放错误-->
+    <LinearLayout
+        android:id="@+id/error"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:background="@android:color/black"
+        android:gravity="center"
+        android:orientation="vertical"
+        android:visibility="gone">
+        <TextView
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="播放错误,请重试。"
+            android:textColor="@android:color/white"
+            android:textSize="13sp"/>
+        <TextView
+            android:id="@+id/retry"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_marginTop="8dp"
+            android:background="@drawable/bg_retry"
+            android:paddingBottom="5dp"
+            android:paddingLeft="12dp"
+            android:paddingRight="12dp"
+            android:paddingTop="4dp"
+            android:text="点击重试"
+            android:textColor="@android:color/white"
+            android:textSize="13sp"/>
+    </LinearLayout>
+
+
+    <!--顶部控制区-->
+    <LinearLayout
+        android:id="@+id/top"
+        android:layout_width="match_parent"
+        android:layout_height="42dp"
+        android:background="@drawable/player_mask_top"
+        android:gravity="center_vertical"
+        android:paddingLeft="8dp"
+        android:paddingRight="8dp">
+        <ImageView
+            android:id="@+id/back"
+            android:layout_width="30dp"
+            android:layout_height="30dp"
+            android:src="@drawable/ic_player_back"
+            android:visibility="visible"/>
+        <TextView
+            android:id="@+id/title"
+            android:layout_width="0dp"
+            android:layout_height="wrap_content"
+            android:layout_weight="1"
+            android:ellipsize="end"
+            android:maxLines="2"
+            android:text="真实死亡游戏“蓝鲸”疑似进入国内,家长们要注意了"
+            android:textColor="@android:color/white"
+            android:textSize="14sp"/>
+        <LinearLayout
+            android:id="@+id/battery_time"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_marginRight="8dp"
+            android:orientation="vertical"
+            android:visibility="gone">
+            <ImageView
+                android:id="@+id/battery"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:src="@drawable/battery_100"/>
+            <TextView
+                android:id="@+id/time"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:text="00:00"
+                android:textColor="@android:color/white"
+                android:textSize="10sp"/>
+        </LinearLayout>
+    </LinearLayout>
+
+
+    <!--底部控制区-->
+    <LinearLayout
+        android:id="@+id/bottom"
+        android:layout_width="match_parent"
+        android:layout_height="42dp"
+        android:layout_alignParentBottom="true"
+        android:background="@drawable/player_mask_bottom"
+        android:gravity="center_vertical"
+        android:paddingLeft="8dp"
+        android:paddingRight="8dp">
+        <ImageView
+            android:id="@+id/restart_or_pause"
+            android:layout_width="24dp"
+            android:layout_height="24dp"
+            android:src="@drawable/ic_player_start"/>
+        <TextView
+            android:id="@+id/position"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_marginLeft="8dp"
+            android:text="00:00"
+            android:textColor="@android:color/white"
+            android:textSize="12sp"/>
+        <TextView
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="/"
+            android:textColor="@android:color/white"
+            android:textSize="14sp"/>
+        <TextView
+            android:id="@+id/duration"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="00:00"
+            android:textColor="@android:color/white"
+            android:textSize="12sp"/>
+        <SeekBar
+            android:id="@+id/seek"
+            android:layout_width="0dp"
+            android:layout_height="wrap_content"
+            android:layout_gravity="center_vertical"
+            android:layout_weight="1"
+            android:background="@null"
+            android:max="100"
+            android:maxHeight="1.5dp"
+            android:minHeight="1.5dp"
+            android:progressDrawable="@drawable/seek_progress"
+            android:thumb="@drawable/seek_thumb"/>
+        <TextView
+            android:id="@+id/clarity"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:paddingRight="4dp"
+            android:paddingLeft="8dp"
+            android:text="超清"
+            android:textColor="@android:color/white"
+            android:textSize="14sp"
+            android:visibility="gone"/>
+        <ImageView
+            android:id="@+id/full_screen"
+            android:layout_width="24dp"
+            android:layout_height="24dp"
+            android:src="@drawable/ic_player_enlarge"/>
+    </LinearLayout>
+
+
+    <!--右下角初始显示的总时长-->
+    <TextView
+        android:id="@+id/length"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_alignParentBottom="true"
+        android:layout_alignParentEnd="true"
+        android:layout_marginBottom="12dp"
+        android:layout_marginEnd="8dp"
+        android:padding="4dp"
+        android:text="00:00"
+        android:textColor="@android:color/white"
+        android:textSize="12sp"/>
+    <!--中间开始播放按钮-->
+    <ImageView
+        android:id="@+id/center_start"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_centerInParent="true"
+        android:src="@drawable/ic_player_center_start"
+        android:visibility="visible"/>
+
+</RelativeLayout>

+ 4 - 0
YCVideoPlayerLib/src/main/res/values/colors.xml

@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+    <color name="dialog_bg">#bc000000</color>
+</resources>

+ 3 - 0
YCVideoPlayerLib/src/main/res/values/strings.xml

@@ -0,0 +1,3 @@
+<resources>
+    <string name="app_name">YCVideoPlayerLib</string>
+</resources>

+ 10 - 0
YCVideoPlayerLib/src/main/res/values/styles.xml

@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+    <style name="dialog_change_clarity" parent="@style/Theme.AppCompat.Light.Dialog">
+        <item name="android:windowNoTitle">true</item>
+        <item name="android:windowFullscreen">true</item>
+        <item name="android:backgroundDimEnabled">false</item>
+        <item name="android:windowBackground">@color/dialog_bg</item>
+    </style>
+</resources>

+ 1 - 0
app/.gitignore

@@ -0,0 +1 @@
+/build

+ 84 - 0
app/build.gradle

@@ -0,0 +1,84 @@
+apply plugin: 'com.android.application'
+apply plugin: 'com.neenbedankt.android-apt'
+
+android {
+    compileSdkVersion 25
+    buildToolsVersion "25.0.3"
+    defaultConfig {
+        applicationId "org.yczbj.ycvideoplayer"
+        minSdkVersion 17
+        targetSdkVersion 25
+        versionCode 1
+        versionName "1.0"
+        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
+    }
+    buildTypes {
+        release {
+            minifyEnabled false
+            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
+        }
+    }
+
+    android {
+        lintOptions {
+            checkReleaseBuilds false
+            // Or, if you prefer, you can continue to check for errors in release builds,
+            // but continue the build even when errors are found:
+            abortOnError false
+        }
+    }
+}
+
+dependencies {
+    compile fileTree(include: ['*.jar'], dir: 'libs')
+    //官方库
+    compile 'com.android.support:appcompat-v7:25.4.0'
+    compile 'com.android.support:support-v4:25.4.0'
+    compile 'com.android.support:recyclerview-v7:25.4.0'
+    compile 'com.android.support:design:25.4.0'
+    compile 'com.android.support:cardview-v7:25.4.0'
+    compile 'com.android.support:palette-v7:25.4.0'
+    compile 'com.android.support:percent:25.4.0'
+    compile 'com.android.support:support-annotations:25.3.1'
+    compile 'com.android.support:multidex:1.0.2'
+
+    //网络请求retrofit2+Rx
+    compile 'com.squareup.okhttp3:logging-interceptor:3.4.1'
+    compile 'com.squareup.okhttp3:okhttp:3.4.1'
+    compile 'com.squareup.retrofit2:retrofit:2.3.0'
+    compile 'com.squareup.retrofit2:converter-gson:2.1.0'
+    compile 'com.squareup.retrofit2:adapter-rxjava:2.1.0'
+    compile 'io.reactivex:rxandroid:1.1.0'
+    compile 'io.reactivex:rxjava:1.1.0'
+
+
+    //注解
+    compile 'com.jakewharton:butterknife:7.0.1'                     //黄牛刀
+    compile 'com.google.dagger:dagger:2.13'                         //注解
+    apt 'com.google.dagger:dagger-compiler:2.13'
+
+    //其他库
+    compile 'com.flyco.tablayout:FlycoTabLayout_Lib:2.1.0@aar'      //导航栏
+    compile 'com.blankj:utilcode:1.7.1'                             //工具类
+    compile project(':jiaozivideoplayer')
+    //compile 'cn.jzvd:jiaozivideoplayer:6.2.3'                       //视频库
+    compile 'com.squareup.picasso:picasso:2.5.2'                    //图片
+    compile 'com.github.bumptech.glide:glide:3.7.0'                 //谷歌图片加载库
+    compile 'jp.wasabeef:glide-transformations:2.0.1'
+    compile('com.alibaba.android:vlayout:1.2.2@aar') {              //阿里巴巴UI
+        transitive = true
+    }
+    compile 'com.liulishuo.filedownloader:library:1.6.9'            //下载框架
+
+
+    //自己封装的库【欢迎star】:https://github.com/yangchong211
+    compile 'cn.yc:YCUtilsLib:1.5'                                  //公共类
+    compile 'cn.yc:YCStateLib:1.1'                                  //状态管理
+    compile 'cn.yc:YCBannerLib:1.2'                                 //轮播图
+    compile 'org.yczbj:YCRefreshViewLib:1.1'                        //RecyclerView封装
+    compile 'cn.yc:YCBaseAdapterLib:1.2'                            //adapter封装
+    compile 'cn.yc:YCDialogLib:3.2'                                 //弹窗
+    compile 'cn.yc:YCVideoPlayerLib:1.1'                            //播放器
+    //compile project(':YCVideoPlayerLib')
+
+}

+ 21 - 0
app/proguard-rules.pro

@@ -0,0 +1,21 @@
+# Add project specific ProGuard rules here.
+# You can control the set of applied configuration files using the
+# proguardFiles setting in build.gradle.
+#
+# For more details, see
+#   http://developer.android.com/guide/developing/tools/proguard.html
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+#   public *;
+#}
+
+# Uncomment this to preserve the line number information for
+# debugging stack traces.
+#-keepattributes SourceFile,LineNumberTable
+
+# If you keep the line number information, uncomment this to
+# hide the original source file name.
+#-renamesourcefileattribute SourceFile

+ 26 - 0
app/src/androidTest/java/org/yczbj/ycvideoplayer/ExampleInstrumentedTest.java

@@ -0,0 +1,26 @@
+package org.yczbj.ycvideoplayer;
+
+import android.content.Context;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import static org.junit.Assert.*;
+
+/**
+ * Instrumented test, which will execute on an Android device.
+ *
+ * @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
+ */
+@RunWith(AndroidJUnit4.class)
+public class ExampleInstrumentedTest {
+    @Test
+    public void useAppContext() throws Exception {
+        // Context of the app under test.
+        Context appContext = InstrumentationRegistry.getTargetContext();
+
+        assertEquals("org.yczbj.ycvideoplayer", appContext.getPackageName());
+    }
+}

+ 74 - 0
app/src/main/AndroidManifest.xml

@@ -0,0 +1,74 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="org.yczbj.ycvideoplayer">
+
+    <uses-permission android:name="android.permission.INTERNET"/>
+    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
+    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
+
+    <application
+        android:name=".base.BaseApplication"
+        android:allowBackup="true"
+        android:icon="@mipmap/ic_launcher"
+        android:label="@string/app_name"
+        android:roundIcon="@mipmap/ic_launcher_round"
+        android:supportsRtl="true"
+        android:theme="@style/AppTheme">
+        <activity android:name=".ui.main.view.MainActivity">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+
+
+
+        <!--下面这些均是测试视频播放器-->
+        <activity android:name=".ui.test.TestActivity"/>
+        <activity android:name=".ui.test.view.first.TestFirstActivity"/>
+        <activity android:name=".ui.test.view.first.TestApiFirstActivity"/>
+        <activity android:name=".ui.test.view.first.TestApiSecondActivity"/>
+        <activity android:name=".ui.test.view.first.TestApiThreeActivity"/>
+        <activity android:name=".ui.test.view.first.TestApiFourActivity"/>
+        <activity android:name=".ui.test.view.first.TestApiFiveActivity"/>
+        <activity android:name=".ui.test.view.first.TestApiSixActivity"/>
+        <activity android:name=".ui.test.view.second.TestSecondActivity"/>
+        <activity android:name=".ui.test.view.second.TestListFirstActivity"/>
+        <activity android:name=".ui.test.view.second.TestListSecondActivity"/>
+        <activity android:name=".ui.test.view.second.TestListThirdActivity"/>
+        <activity android:name=".ui.test.view.second.TestListFourActivity"/>
+        <activity android:name=".ui.test.view.second.TestListFiveActivity"/>
+        <activity android:name=".ui.test.view.three.TestThreeActivity"/>
+        <activity android:name=".ui.test.view.three.TestTinyFirstActivity"/>
+        <activity android:name=".ui.test.view.three.TestTinyThirdActivity"/>
+        <activity android:name=".ui.test.view.three.TestTinyFourActivity"/>
+        <activity android:name=".ui.test.view.three.TestTinyFiveActivity"/>
+        <activity android:name=".ui.test.view.four.TestFourActivity"/>
+        <activity android:name=".ui.test.view.five.TestFiveActivity"/>
+        <activity android:name=".ui.test.view.six.TestSixActivity"/>
+
+        <activity android:name=".ui.test2.TestMyActivity"
+            android:configChanges="orientation|keyboardHidden|screenSize"
+            android:screenOrientation="portrait"/>
+        <activity android:name=".ui.test2.view.TestMyFirstActivity"
+            android:configChanges="orientation|keyboardHidden|screenSize"
+            android:screenOrientation="portrait"/>
+        <activity android:name=".ui.test2.view.TestMySecondActivity"
+            android:configChanges="orientation|keyboardHidden|screenSize"
+            android:screenOrientation="portrait"/>
+        <activity android:name=".ui.test2.view.TestMyThirdActivity"
+            android:configChanges="orientation|keyboardHidden|screenSize"
+            android:screenOrientation="portrait"/>
+        <activity android:name=".ui.test2.view.TestMyFourActivity"
+            android:configChanges="orientation|keyboardHidden|screenSize"
+            android:screenOrientation="portrait"/>
+        <activity android:name=".ui.test2.view.TestMyFiveActivity"
+            android:configChanges="orientation|keyboardHidden|screenSize"
+            android:screenOrientation="portrait"/>
+        <activity android:name=".ui.test2.view.TestMySixActivity"
+            android:configChanges="orientation|keyboardHidden|screenSize"
+            android:screenOrientation="portrait"/>
+    </application>
+
+</manifest>

+ 23 - 0
app/src/main/assets/jzvd.html

@@ -0,0 +1,23 @@
+<!DOCTYPE html>
+<html>
+<body>
+<div class="content"></div>
+<div id="cont" style="width:100%;height:200px">
+</div>
+<div style="height:100px"></div>
+<h3 style="width:100%;text-align:center">This is webview</h3>
+<div style="height:700px"></div>
+<div id="cont1" style="width:65%;height:200px;float:right;">
+</div>
+<div style="height:800px"></div>
+<script>
+    var cont=document.getElementById("cont");
+    jzvd.adViewJiaoZiVideoPlayer(-1,200,0,0,0)
+    <!--jzvd.adViewJiaoZiVideoPlayer(cont1.width,cont1.height,cont1.offsetTop,cont1.offsetLeft)-->
+
+    var cont1=document.getElementById("cont1");
+    jzvd.adViewJiaoZiVideoPlayer(210,120,cont1.offsetTop,cont1.offsetLeft,1)
+
+</script>
+</body>
+</html>

BIN
app/src/main/assets/local_video.mp4


+ 29 - 0
app/src/main/java/org/yczbj/ycvideoplayer/api/Constant.java

@@ -0,0 +1,29 @@
+package org.yczbj.ycvideoplayer.api;
+
+/**
+ * Description:
+ * Update:
+ * CreatedTime:2018/01/03
+ * Author:yc
+ */
+
+public class Constant {
+
+
+    public interface viewType{
+        int typeView = 0;           //自定义
+        int typeBanner = 1;         //轮播图
+        int typeGv = 2;             //九宫格
+        int typeTitle = 3;          //标题
+        int typeMore = 4;           //更多
+        int typeAd = 5;             //广告
+        int typeList2 = 6;          //list2
+        int typeAd2 = 7 ;           //广告2
+        int typeGv3 = 8;            //list3
+        int typeList4 = 9;          //list4
+        int typeGvBottom = 10;      //九宫格
+        int typeList5 = 11;          //list4
+    }
+
+
+}

+ 132 - 0
app/src/main/java/org/yczbj/ycvideoplayer/base/AppManager.java

@@ -0,0 +1,132 @@
+package org.yczbj.ycvideoplayer.base;
+
+import android.app.Activity;
+
+import java.util.Stack;
+
+/**
+ * ================================================
+ * 作    者:杨充
+ * 版    本:1.0
+ * 创建日期:2017/1/18
+ * 描    述:Activity容器
+ * 修订历史:
+ * 备注:如果在BaseActivity中添加入栈和出栈,将会导致activityStack内存泄漏
+ *      建议:在Application中用registerActivityLifecycleCallbacks进行Activity生命周期的栈管理
+ * ================================================
+ */
+public class AppManager {
+
+    //栈:也就是stack
+    private static Stack<Activity> activityStack;
+    private volatile static AppManager instance;
+
+    private AppManager() {
+
+    }
+
+    /**
+     * 单一实例
+     */
+    public static AppManager getAppManager() {
+        if (instance == null) {
+            synchronized (AppManager.class) {
+                if (instance == null) {
+                    instance = new AppManager();
+                }
+            }
+        }
+        return instance;
+    }
+
+    /**
+     * 添加Activity到堆栈
+     */
+    public void addActivity(Activity activity) {
+        if(activityStack == null){
+            activityStack = new Stack<>();
+        }
+        activityStack.add(activity);
+    }
+
+    /**
+     * 获取当前Activity(堆栈中最后一个压入的)
+     */
+    public Activity currentActivity() {
+        if(activityStack.size()==0){
+            return null;
+        }
+        Activity activity = activityStack.lastElement();
+        return activity;
+    }
+
+    /**
+     * 结束当前Activity(堆栈中最后一个压入的)
+     */
+    public void finishActivity() {
+        if(activityStack!=null && activityStack.size()>0){
+            Activity activity = activityStack.lastElement();
+            finishActivity(activity);
+        }
+    }
+
+    /**
+     * 结束指定的Activity
+     */
+    public void finishActivity(Activity activity) {
+        if (activity != null && !activity.isFinishing()) {
+            activityStack.remove(activity);
+            activity.finish();
+            activity = null;
+        }
+    }
+
+    /**
+     * 移除指定的Activity
+     * @param activity
+     */
+    public void removeActivity(Activity activity) {
+        if (activity != null) {
+            activityStack.remove(activity);
+        }
+    }
+
+    /**
+     * 结束指定类名的Activity
+     */
+    public void finishActivity(Class<?> cls) {
+        for (Activity activity : activityStack) {
+            if (activity.getClass().equals(cls)) {
+                finishActivity(activity);
+            }
+        }
+    }
+
+    /**
+     * 结束所有Activity
+     */
+    private void finishAllActivity() {
+        for (int i = 0, size = activityStack.size(); i < size; i++) {
+            if (null != activityStack.get(i)) {
+                activityStack.get(i).finish();
+            }
+        }
+        activityStack.clear();
+    }
+
+    /**
+     * 退出应用程序
+     */
+    public void AppExit() {
+        try {
+            finishAllActivity();
+            android.os.Process.killProcess(android.os.Process.myPid());
+            System.exit(0);
+        } catch (Exception e) {
+            //
+        } finally {
+            //
+        }
+    }
+
+}

+ 142 - 0
app/src/main/java/org/yczbj/ycvideoplayer/base/BaseActivity.java

@@ -0,0 +1,142 @@
+package org.yczbj.ycvideoplayer.base;
+
+import android.content.Intent;
+import android.content.pm.ActivityInfo;
+import android.os.Build;
+import android.os.Bundle;
+import android.support.annotation.Nullable;
+import android.support.v7.app.AppCompatActivity;
+import android.view.WindowManager;
+
+import com.blankj.utilcode.util.NetworkUtils;
+import com.blankj.utilcode.util.ToastUtils;
+
+import butterknife.ButterKnife;
+
+/**
+ * ================================================
+ * 作    者:杨充
+ * 版    本:1.0
+ * 创建日期:2017/5/18
+ * 描    述:所有Activity的父类
+ * 修订历史:
+ * ================================================
+ */
+public abstract class BaseActivity extends AppCompatActivity {
+
+
+    @Override
+    protected void onCreate(@Nullable Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(getContentView());
+        ButterKnife.bind(this);
+        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);              //避免切换横竖屏
+        AppManager.getAppManager().addActivity(this);                                   //将当前Activity添加到容器
+        initView();
+        initListener();
+        initData();
+        if(!NetworkUtils.isConnected()){
+            ToastUtils.showShort("请检查网络是否连接");
+        }
+    }
+
+    @Override
+    protected void onDestroy() {
+        super.onDestroy();
+        initLeakCanary();             //测试内存泄漏,正式一定要隐藏
+        AppManager.getAppManager().removeActivity(this);                                //将当前Activity移除到容器
+        //AppManager.getAppManager().finishActivity(this);
+    }
+
+
+    @Override
+    protected void onRestart() {
+        super.onRestart();
+    }
+
+    @Override
+    protected void onResume() {
+        super.onResume();
+    }
+
+    @Override
+    protected void onPause() {
+        super.onPause();
+    }
+
+
+    /** 返回一个用于显示界面的布局id */
+    public abstract int getContentView();
+
+    /** 初始化View的代码写在这个方法中 */
+    public abstract void initView();
+
+    /** 初始化监听器的代码写在这个方法中 */
+    public abstract void initListener();
+
+    /** 初始数据的代码写在这个方法中,用于从服务器获取数据 */
+    public abstract void initData();
+
+
+    /**
+     * 沉浸式状态栏
+     */
+    protected void initState() {
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
+            //透明状态栏
+            getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
+            //透明导航栏
+            //getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);
+            // 隐藏状态栏
+            //getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,WindowManager.LayoutParams.FLAG_FULLSCREEN); // 隐藏状态栏
+        }
+    }
+
+    /**
+     * 通过Class跳转界面
+     **/
+    public void startActivity(Class<?> cls) {
+        startActivity(cls, null);
+    }
+
+    /**
+     * 通过Class跳转界面
+     **/
+    public void startActivityForResult(Class<?> cls, int requestCode) {
+        startActivityForResult(cls, null, requestCode);
+    }
+
+    /**
+     * 含有Bundle通过Class跳转界面
+     **/
+    public void startActivityForResult(Class<?> cls, Bundle bundle, int requestCode) {
+        Intent intent = new Intent();
+        intent.setClass(this, cls);
+        if (bundle != null) {
+            intent.putExtras(bundle);
+        }
+        startActivityForResult(intent, requestCode);
+    }
+
+    /**
+     * 含有Bundle通过Class跳转界面
+     **/
+    public void startActivity(Class<?> cls, Bundle bundle) {
+        Intent intent = new Intent();
+        intent.setClass(this, cls);
+        if (bundle != null) {
+            intent.putExtras(bundle);
+        }
+        startActivity(intent);
+    }
+
+    /**
+     * 用来检测所有Activity的内存泄漏
+     */
+    private void initLeakCanary() {
+        /*RefWatcher refWatcher = BaseApplication.getRefWatcher(this);
+        refWatcher.watch(this);*/
+    }
+
+
+}

+ 120 - 0
app/src/main/java/org/yczbj/ycvideoplayer/base/BaseApplication.java

@@ -0,0 +1,120 @@
+package org.yczbj.ycvideoplayer.base;
+
+import android.app.Application;
+import android.content.Context;
+import android.content.res.Configuration;
+import android.support.multidex.MultiDex;
+import android.util.Log;
+
+import com.blankj.utilcode.util.Utils;
+
+import org.yczbj.ycvideoplayer.util.LogUtils;
+
+/**
+ * ================================================
+ * 作    者:杨充
+ * 版    本:1.0
+ * 创建日期:2017/8/18
+ * 描    述:BaseApplication
+ * 修订历史:
+ * ================================================
+ */
+public class BaseApplication extends Application {
+
+
+    private static BaseApplication instance;
+    public static synchronized BaseApplication getInstance() {
+        if (null == instance) {
+            instance = new BaseApplication();
+        }
+        return instance;
+    }
+
+    public BaseApplication(){}
+
+    /*public static BaseApplication getInstance() {
+        if (null == instance) {
+            synchronized (BaseApplication.class){
+                if(instance == null){
+                    instance = new BaseApplication();
+                }
+            }
+        }
+        return instance;
+    }*/
+
+
+    /**
+     * 这个最先执行
+     */
+    @Override
+    protected void attachBaseContext(Context base) {
+        super.attachBaseContext(base);
+        MultiDex.install(this);
+    }
+
+
+    /**
+     * 程序启动的时候执行
+     */
+    @Override
+    public void onCreate() {
+        Log.d("Application", "onCreate");
+        super.onCreate();
+        instance = this;
+        initUtils();
+        LogUtils.logDebug = true;
+    }
+
+
+    /**
+     * 程序终止的时候执行
+     */
+    @Override
+    public void onTerminate() {
+        Log.d("Application", "onTerminate");
+        super.onTerminate();
+    }
+
+
+    /**
+     * 低内存的时候执行
+     */
+    @Override
+    public void onLowMemory() {
+        Log.d("Application", "onLowMemory");
+        super.onLowMemory();
+    }
+
+
+    /**
+     * HOME键退出应用程序
+     * 程序在内存清理的时候执行
+     */
+    @Override
+    public void onTrimMemory(int level) {
+        Log.d("Application", "onTrimMemory");
+        super.onTrimMemory(level);
+    }
+
+
+    /**
+     * onConfigurationChanged
+     */
+    @Override
+    public void onConfigurationChanged(Configuration newConfig) {
+        Log.d("Application", "onConfigurationChanged");
+        super.onConfigurationChanged(newConfig);
+    }
+
+
+    /**
+     * 初始化utils工具类
+     */
+    private void initUtils() {
+        Utils.init(this);
+    }
+
+}
+
+

+ 75 - 0
app/src/main/java/org/yczbj/ycvideoplayer/base/BaseDelegateAdapter.java

@@ -0,0 +1,75 @@
+package org.yczbj.ycvideoplayer.base;
+
+import android.content.Context;
+import android.view.LayoutInflater;
+import android.view.ViewGroup;
+
+import com.alibaba.android.vlayout.DelegateAdapter;
+import com.alibaba.android.vlayout.LayoutHelper;
+import com.yc.cn.ycbaseadapterlib.first.BaseViewHolder;
+
+
+/**
+ * ================================================
+ * 作    者:杨充
+ * 版    本:1.0
+ * 创建日期:2017/9/18
+ * 描    述:Vlayout框架基类适配器
+ * 修订历史:
+ * ================================================
+ */
+public class BaseDelegateAdapter extends DelegateAdapter.Adapter<BaseViewHolder> {
+
+    private LayoutHelper mLayoutHelper;
+    private int mCount = -1;
+    private int mLayoutId = -1;
+    private Context mContext;
+    private int mViewTypeItem = -1;
+
+    protected BaseDelegateAdapter(Context context, LayoutHelper layoutHelper, int layoutId, int count, int viewTypeItem) {
+        this.mContext = context;
+        this.mCount = count;
+        this.mLayoutHelper = layoutHelper;
+        this.mLayoutId = layoutId;
+        this.mViewTypeItem = viewTypeItem;
+    }
+
+    @Override
+    public LayoutHelper onCreateLayoutHelper() {
+        return mLayoutHelper;
+    }
+
+    @Override
+    public BaseViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
+        if (viewType == mViewTypeItem) {
+            return new BaseViewHolder(LayoutInflater.from(mContext).inflate(mLayoutId, parent, false));
+        }
+        return null;
+    }
+
+    /**
+     * 子类adapter实现
+     * @param holder                    holder
+     * @param position                  索引
+     */
+    @Override
+    public void onBindViewHolder(BaseViewHolder holder, int position) {
+
+    }
+
+    /**
+     * 必须重写不然会出现滑动不流畅的情况
+     */
+    @Override
+    public int getItemViewType(int position) {
+        return mViewTypeItem;
+    }
+
+    /**
+     * 条目数量
+     */
+    @Override
+    public int getItemCount() {
+        return mCount;
+    }
+}

+ 111 - 0
app/src/main/java/org/yczbj/ycvideoplayer/base/BaseFragment.java

@@ -0,0 +1,111 @@
+package org.yczbj.ycvideoplayer.base;
+
+import android.content.Intent;
+import android.os.Bundle;
+import android.support.annotation.Nullable;
+import android.support.v4.app.Fragment;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+import butterknife.ButterKnife;
+
+
+/**
+ * ================================================
+ * 作    者:杨充
+ * 版    本:1.0
+ * 创建日期:2017/5/18
+ * 描    述:所有Fragment的父类
+ * 修订历史:
+ * ================================================
+ */
+public abstract class BaseFragment extends Fragment {
+
+    @Nullable
+    @Override
+    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
+        View view = inflater.inflate(getContentView(), container , false);
+        ButterKnife.bind(this, view);
+        return view;
+    }
+
+    @Override
+    public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
+        super.onViewCreated(view, savedInstanceState);
+        initView();
+        initListener();
+        initData();
+    }
+
+    @Override
+    public void onDestroyView() {
+        super.onDestroyView();
+    }
+
+    @Override
+    public void onDestroy() {
+        super.onDestroy();
+        ButterKnife.unbind(this);
+        initLeakCanary();             //测试内存泄漏,正式一定要隐藏
+    }
+
+    /** 返回一个用于显示界面的布局id */
+    public abstract int getContentView();
+
+    /** 初始化View的代码写在这个方法中 */
+    public abstract void initView();
+
+    /** 初始化监听器的代码写在这个方法中 */
+    public abstract void initListener();
+
+    /** 初始数据的代码写在这个方法中,用于从服务器获取数据 */
+    public abstract void initData();
+
+    /**
+     * 通过Class跳转界面
+     **/
+    public void startActivity(Class<?> cls) {
+        startActivity(cls, null);
+    }
+
+    /**
+     * 通过Class跳转界面
+     **/
+    public void startActivityForResult(Class<?> cls, int requestCode) {
+        startActivityForResult(cls, null, requestCode);
+    }
+
+    /**
+     * 含有Bundle通过Class跳转界面
+     **/
+    public void startActivityForResult(Class<?> cls, Bundle bundle, int requestCode) {
+        Intent intent = new Intent();
+        intent.setClass(getActivity(), cls);
+        if (bundle != null) {
+            intent.putExtras(bundle);
+        }
+        startActivityForResult(intent, requestCode);
+    }
+
+    /**
+     * 含有Bundle通过Class跳转界面
+     **/
+    public void startActivity(Class<?> cls, Bundle bundle) {
+        Intent intent = new Intent();
+        intent.setClass(getActivity(), cls);
+        if (bundle != null) {
+            intent.putExtras(bundle);
+        }
+        startActivity(intent);
+    }
+
+    /**用来检测所有Fragment的内存泄漏*/
+    private void initLeakCanary() {
+        /*RefWatcher refWatcher = BaseApplication.getRefWatcher(getActivity());
+        refWatcher.watch(this);*/
+    }
+
+
+
+}

+ 76 - 0
app/src/main/java/org/yczbj/ycvideoplayer/base/BasePagerAdapter.java

@@ -0,0 +1,76 @@
+package org.yczbj.ycvideoplayer.base;
+
+import android.support.v4.app.Fragment;
+import android.support.v4.app.FragmentManager;
+import android.support.v4.app.FragmentPagerAdapter;
+import android.view.ViewGroup;
+
+import java.util.List;
+
+/**
+ * ================================================
+ * 作    者:杨充
+ * 版    本:1.0
+ * 创建日期:2017/6/21
+ * 描    述:指示器adapter的公共类
+ * 修订历史:
+ * ================================================
+ */
+public class BasePagerAdapter extends FragmentPagerAdapter {
+
+    private List<?> mFragment;
+    private List<String> mTitleList;
+
+    /**
+     * 普通,主页使用
+     */
+    public BasePagerAdapter(FragmentManager fm, List<?> mFragment) {
+        super(fm);
+        this.mFragment = mFragment;
+    }
+
+    /**
+     * 接收首页传递的标题
+     */
+    public BasePagerAdapter(FragmentManager fm, List<?> mFragment, List<String> mTitleList) {
+        super(fm);
+        this.mFragment = mFragment;
+        this.mTitleList = mTitleList;
+    }
+
+    @Override
+    public Fragment getItem(int position) {
+        return (Fragment) mFragment.get(position);
+    }
+
+    @Override
+    public int getCount() {
+        return mFragment.size();
+    }
+
+    @Override
+    public void destroyItem(ViewGroup container, int position, Object object) {
+        super.destroyItem(container, position, object);
+    }
+
+    /**
+     * 首页显示title,每日推荐等..
+     * 若有问题,移到对应单独页面
+     */
+    @Override
+    public CharSequence getPageTitle(int position) {
+        if (mTitleList != null) {
+            return mTitleList.get(position);
+        } else {
+            return "";
+        }
+    }
+
+    public void addFragmentList(List<?> fragment) {
+        this.mFragment.clear();
+        this.mFragment = null;
+        this.mFragment = fragment;
+        notifyDataSetChanged();
+    }
+
+}

Some files were not shown because too many files changed in this diff